Index: USAGE =================================================================== RCS file: /source/pam_radius/USAGE,v retrieving revision 1.4 diff -u -r1.4 USAGE --- USAGE 31 Mar 2003 17:13:04 -0000 1.4 +++ USAGE 20 Mar 2007 02:41:32 -0000 @@ -72,6 +72,10 @@ i.e. try cracklib to be sure it's secure, then go update the RADIUS server. +ruser - If PAM_USER is root, Use the value of PAM_RUSER instead + of PAM_USER to determine the username to authenticate via + RADIUS. This is to allow 'su' to act like 'sudo'. + accounting_bug - When used, the accounting response vector is NOT validated. This option will probably only be necessary on REALLY OLD (i.e. Livingston 1.16) servers. Index: pam_radius_auth.c =================================================================== RCS file: /source/pam_radius/pam_radius_auth.c,v retrieving revision 1.32 diff -u -r1.32 pam_radius_auth.c --- pam_radius_auth.c 5 Apr 2005 23:08:30 -0000 1.32 +++ pam_radius_auth.c 20 Mar 2007 02:41:33 -0000 @@ -124,8 +124,8 @@ } else if (!strncmp(*argv,"retry=",6)) { int i = atoi(*argv+6); - i &= 0x03; /* keep the low 3 bits only */ - ctrl |= (i << 4); + i &= 0x03; /* keep the low 2 bits only */ + ctrl |= (i << 5); /* keep in sync with PAM_RETRY */ } else if (!strncmp(*argv, "client_id=", 10)) { if (conf->client_id) { @@ -136,6 +136,9 @@ } else if (!strcmp(*argv, "accounting_bug")) { conf->accounting_bug = TRUE; + } else if (!strcmp(*argv, "ruser")) { + ctrl |= PAM_RUSER_ARG; + conf->ruser = 1; } else if (!strcmp(*argv, "debug")) { ctrl |= PAM_DEBUG_ARG; conf->debug = 1; @@ -1053,6 +1056,7 @@ pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc,CONST char **argv) { CONST char *user; + CONST char **userinfo; char *password = NULL; CONST char *rhost; char *resp2challenge = NULL; @@ -1067,7 +1071,7 @@ int tries; ctrl = _pam_parse(argc, argv, &config); - tries = ((ctrl & PAM_RETRY) >> 4) + 1; + tries = ((ctrl & PAM_RETRY) >> 5) + 1; /* grab the user name */ retval = pam_get_user(pamh, &user, NULL); @@ -1083,9 +1087,21 @@ DPRINT(LOG_DEBUG, "User name was NULL, or too long"); return PAM_USER_UNKNOWN; } - DPRINT(LOG_DEBUG, "Got user name %s", user); + if (ctrl & PAM_RUSER_ARG) { + retval = pam_get_item(pamh, PAM_RUSER, (CONST void **) &userinfo); + PAM_FAIL_CHECK; + DPRINT(LOG_DEBUG, "Got PAM_RUSER name %s", userinfo); + + if (!strcmp("root", user)) { + user = userinfo; + DPRINT(LOG_DEBUG, "Username now %s from ruser", user); + } else { + DPRINT(LOG_DEBUG, "Skipping ruser for non-root auth"); + }; + }; + /* * Get the IP address of the authentication server * Then, open a socket, and bind it to a port @@ -1169,7 +1185,7 @@ while (response->code == PW_ACCESS_CHALLENGE) { attribute_t *a_state, *a_reply; char challenge[BUFFER_SIZE]; - + /* Now we do a bit more work: challenge the user, and get a response */ if (((a_state = find_attribute(response, PW_STATE)) == NULL) || ((a_reply = find_attribute(response, PW_REPLY_MESSAGE)) == NULL)) { @@ -1182,14 +1198,15 @@ * Security fixes. */ if ((a_state->length <= 2) || (a_reply->length <= 2)) { + /* Actually, State isn't required. */ _pam_log(LOG_ERR, "RADIUS Access-Challenge received with invalid State or Reply-Message"); retval = PAM_AUTHINFO_UNAVAIL; goto error; } - + memcpy(challenge, a_reply->data, a_reply->length - 2); challenge[a_reply->length - 2] = 0; - + /* It's full challenge-response, we might as well have echo on */ retval = rad_converse(pamh, PAM_PROMPT_ECHO_ON, challenge, &resp2challenge); Index: pam_radius_auth.h =================================================================== RCS file: /source/pam_radius/pam_radius_auth.h,v retrieving revision 1.7 diff -u -r1.7 pam_radius_auth.h --- pam_radius_auth.h 19 Sep 2003 14:41:32 -0000 1.7 +++ pam_radius_auth.h 20 Mar 2007 02:41:33 -0000 @@ -51,6 +51,7 @@ int accounting_bug; int sockfd; int debug; + int ruser; } radius_conf_t; @@ -82,8 +83,9 @@ #define PAM_SKIP_PASSWD 2 #define PAM_USE_FIRST_PASS 4 #define PAM_TRY_FIRST_PASS 8 +#define PAM_RUSER_ARG 16 -#define PAM_RETRY 0x30 +#define PAM_RETRY 0x60 /* Module defines */ #ifndef BUFFER_SIZE