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