PAM Module Patch and Feature
Frank Cusack
fcusack at fcusack.com
Tue Mar 20 03:50:19 CET 2007
On March 15, 2007 2:40:42 PM -0600 David Mitchell <mitchell at ucar.edu> wrote:
> Greetings,
>
> I am working on using FreeRadius with token authentication and ran into
> a small snag. Under Linux, attempts to authenticate 'su' result in a
> query to the Radius server for the user 'root'. What we would like to
> happen is for the query to be for the requesting user. This is how the
> 'sudo' application handles it's PAM requests.
Interesting. Why don't you just use 'sudo' then? Having 'su' be distinct
and accept the actual root password can be useful.
> I of course do not want to change the default behavior of the module, so
> I added an option. I named it 'ruser' since it works by causing the PAM
> module to authenticate using the value of PAM_RUSER (requesting user).
It actually stands for remote user.
...
> I'm not sure who maintains the PAM portion of FreeRadius, so I'm
> throwing this out for discussion. Does this seem like something which
> could be included in the distribution?
I don't see why not.
I've cleaned up the patch, how does it look?
You were stepping on PAM_RETRY, not really your fault, the code for
that part is pretty ... awful. Otherwise, I just deferred looking for
PAM_RUSER until it might actually be used. I'm happy to put it back
the way you had it if you specifically wanted it that way for some reason.
-frank
-------------- next part --------------
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
More information about the Freeradius-Devel
mailing list