Adding a realm to username with pam_radius_auth

Walter Goulet wgoulet at gmail.com
Wed Nov 23 06:12:03 CET 2005


Alan DeKok wrote:
> Walter Goulet <wgoulet at gmail.com> wrote:
> 
>>Quick question regarding pam_radius_auth. Since you have to have a
>>local account on the client machine using pam_radius_auth to
>>authenticate ssh sessions, how would you go about adding a realm to
>>the username portion of the authentication request?
> 
> 
>   Edit the source code to the PAM module, and re-compile.
> 
> 
>>Can I specify this with the client-id option in the pam_radius_auth
>>configuration file?
> 
> 
>   No.
> 
>   Alan DeKok.
> - 
> List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
> 

I took a stab at adding support for specifying a realm as an additional 
option to the pam module configuration. You can specify the realm that 
will be appended to all outgoing RADIUS access requests in the 
application specific pam config files in /etc/pam.d.

auth       sufficient   pam_radius_auth.so debug realm=test.com

I tested this configuration by using openbsd's port of the 
radius-cistron 1.6.7 server as my RADIUS proxy server and freeradius 
1.0.5 as the radius authenticator that owns the realm. Seems to work ok; 
I took a peek at the RADIUS dialog via Ethereal and the access request 
is routed correctly to the freeradius server.

I haven't really programmed in C in a while, so please forgive any silly 
errors I may have made in the code. Also note that I used svn locally to 
keep track of my work, so my revision 1 corresponds to 1.3.16 downloaded 
from the freeradius site.

Patch text follows.

Thanks,
Walter

Index: pam_radius_auth.c
===================================================================
--- pam_radius_auth.c   (revision 1)
+++ pam_radius_auth.c   (revision 6)
@@ -25,6 +25,7 @@
   *          no options.  Patch from Jon Nelson <jnelson at securepipe.com>
   * 1.3.14 - Don't use PATH_MAX, so it builds on GNU Hurd.
   * 1.3.15 - Implement retry option, miscellanous bug fixes.
+
   *
   *
   *   This program is free software; you can redistribute it and/or modify
@@ -83,12 +84,12 @@

      va_start(args, format);
      vsprintf(buffer, format, args);
-    /* don't do openlog or closelog, but put our name in to be friendly */
+    // don't do openlog or closelog, but put our name in to be friendly
      syslog(err, "%s: %s", pam_module_name, buffer);
      va_end(args);
+    printf("Debug Err: %s: %s",pam_module_name,buffer);
  }

-/* argument parsing */
  static int _pam_parse(int argc, CONST char **argv, radius_conf_t *conf)
  {
    int ctrl=0;
@@ -131,6 +132,8 @@
        } else {
         conf->client_id = (char *) *argv+10; /* point to the client-id */
        }
+    } else if (!strncmp(*argv, "realm=", 6)) {
+      conf->client_realm = (char *) *argv+6; /* point to the 
client-realm */
      } else if (!strcmp(*argv, "accounting_bug")) {
        conf->accounting_bug = TRUE;

@@ -1050,6 +1053,7 @@
  PAM_EXTERN int
  pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc,CONST char 
**argv)
  {
+  char *user_and_realm;
    CONST char *user;
    char *password = NULL;
    CONST char *rhost;
@@ -1063,10 +1067,13 @@
    AUTH_HDR *response = (AUTH_HDR *) recv_buffer;
    radius_conf_t config;
    int tries;
+  int realm_specified = 0;

    ctrl = _pam_parse(argc, argv, &config);
    tries = ((ctrl & PAM_RETRY) >> 4) + 1;

+  realm_specified = strlen(config.client_realm);
+
    /* grab the user name */
    retval = pam_get_user(pamh, &user, NULL);
    PAM_FAIL_CHECK;
@@ -1084,6 +1091,16 @@

    DPRINT(LOG_DEBUG, "Got user name %s", user);

+  if(realm_specified)
+  {
+      user_and_realm = malloc(strlen(user) + MAXPWNAM); /* making 
maxlen of realm value MAXPWNAM seems
+                                                           reasonable. */
+      memset(user_and_realm, 0, strlen(user_and_realm));
+      strncat(user_and_realm,user,strlen(user));
+      strncat(user_and_realm,"@",1);
+ 
strncat(user_and_realm,config.client_realm,strlen(config.client_realm));
+  }
+
    /*
     * Get the IP address of the authentication server
     * Then, open a socket, and bind it to a port
@@ -1133,7 +1150,14 @@
      }
    } /* end of password == NULL */

-  build_radius_packet(request, user, password, &config);
+  if(realm_specified)
+  {
+      build_radius_packet(request, user_and_realm, password, &config);
+  }
+  else
+  {
+      build_radius_packet(request, user_and_realm, password, &config);
+  }
    /* not all servers understand this service type, but some do */
    add_int_attribute(request, PW_USER_SERVICE_TYPE, PW_AUTHENTICATE_ONLY);

@@ -1183,7 +1207,14 @@
      retval = rad_converse(pamh, PAM_PROMPT_ECHO_ON, challenge, 
&resp2challenge);

      /* now that we've got a response, build a new radius packet */
-    build_radius_packet(request, user, resp2challenge, &config);
+    if(realm_specified)
+    {
+        build_radius_packet(request, user_and_realm, resp2challenge, 
&config);
+    }
+    else
+    {
+        build_radius_packet(request, user, resp2challenge, &config);
+    }
      /* request->code is already PW_AUTHENTICATION_REQUEST */
      request->id++;             /* one up from the request */

@@ -1214,6 +1245,11 @@
              , retval==PAM_SUCCESS ? "succeeded":"failed" );
    }

+  /* don't forget to free user/realm string */
+  if(strlen(user_and_realm))
+  {
+      free(user_and_realm);
+  }
    close(config.sockfd);
    cleanup(config.server);
    _pam_forget(password);
@@ -1251,9 +1287,11 @@
                     int argc, CONST char **argv,
                     int status)
  {
+  char *user_and_realm; /* Need non-const user to add realm info */
    CONST char *user;
    int ctrl;
    int retval = PAM_AUTH_ERR;
+  int realm_specified = 0;

    char recv_buffer[4096];
    char send_buffer[4096];
@@ -1262,7 +1300,18 @@
    radius_conf_t config;

    ctrl = _pam_parse(argc, argv, &config);
+  realm_specified = strlen(config.client_realm);

+  if(realm_specified)
+  {
+      user_and_realm = malloc(strlen(user) + MAXPWNAM); /* making 
maxlen of realm value MAXPWNAM seems
+                                                           reasonable. */
+      memset(user_and_realm, 0, strlen(user_and_realm));
+      strncat(user_and_realm,user,strlen(user));
+      strncat(user_and_realm,"@",1);
+ 
strncat(user_and_realm,config.client_realm,strlen(config.client_realm));
+  }
+
    /* grab the user name */
    retval = pam_get_user(pamh, &user, NULL);
    PAM_FAIL_CHECK;
@@ -1298,7 +1347,14 @@
    get_random_vector(request->vector);
    request->id = request->vector[0]; /* this should be evenly 
distributed */

-  build_radius_packet(request, user, NULL, &config);
+  if(realm_specified)
+  {
+      build_radius_packet(request, user_and_realm, NULL, &config);
+  }
+  else
+  {
+      build_radius_packet(request, user, NULL, &config);
+  }

    add_int_attribute(request, PW_ACCT_STATUS_TYPE, status);

@@ -1323,6 +1379,12 @@
      goto error;
    }

+  /* don't forget to free user/realm string */
+  if(strlen(user_and_realm))
+  {
+      free(user_and_realm);
+  }
+
    retval = PAM_SUCCESS;

  error:
@@ -1354,13 +1416,15 @@
  PAM_EXTERN int
  pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, CONST char 
**argv)
  {
-  CONST char *user;
+  char *user_and_realm; /* Need non-const user to add realm info */
+  CONST char *user;
    char *password = NULL;
    char *new_password = NULL;
    char *check_password = NULL;
    int ctrl;
    int retval = PAM_AUTHTOK_ERR;
    int attempts;
+  int realm_specified = 0;

    char recv_buffer[4096];
    char send_buffer[4096];
@@ -1370,6 +1434,10 @@

    ctrl = _pam_parse(argc, argv, &config);

+  if(strlen(config.client_realm) > 0)
+  {
+     realm_specified = 1;
+  }
    /* grab the user name */
    retval = pam_get_user(pamh, &user, NULL);
    PAM_FAIL_CHECK;
@@ -1380,6 +1448,16 @@
      return PAM_USER_UNKNOWN;
    }

+  /* now add the realm to the user name if a realm has been specified */
+  if(realm_specified)
+  {
+      user_and_realm = malloc(strlen(user) + MAXPWNAM); /* making 
maxlen of realm value MAXPWNAM seems
+                                                           reasonable. */
+      memset(user_and_realm, 0, strlen(user_and_realm));
+      strncat(user_and_realm,user,strlen(user));
+      strncat(user_and_realm,"@",1);
+  }
+
    /*
     * Get the IP address of the authentication server
     * Then, open a socket, and bind it to a port
@@ -1430,7 +1508,15 @@
      get_random_vector(request->vector);
      request->id = request->vector[0]; /* this should be evenly 
distributed */

-    build_radius_packet(request, user, password, &config);
+    if(realm_specified)
+    {
+        build_radius_packet(request, user_and_realm, password, &config);
+    }
+    else
+    {
+        build_radius_packet(request, user, password, &config);
+    }
+
      add_int_attribute(request, PW_USER_SERVICE_TYPE, 
PW_AUTHENTICATE_ONLY);

      retval = talk_radius(&config, request, response, password, NULL, 1);
@@ -1533,7 +1619,14 @@
      _pam_forget(config.server->secret);
      config.server->secret = strdup(password); /* it's free'd later */

-    build_radius_packet(request, user, new_password, &config);
+    if(realm_specified)
+    {
+        build_radius_packet(request, user_and_realm, new_password, 
&config);
+    }
+    else
+    {
+        build_radius_packet(request, user, new_password, &config);
+    }
      add_password(request, PW_OLD_PASSWORD, password, password);

      retval = talk_radius(&config, request, response, new_password, 
password, 1);
@@ -1567,6 +1660,12 @@
      _pam_log(LOG_DEBUG, "password change %s"
              , retval==PAM_SUCCESS ? "succeeded":"failed" );
    }
+
+  /* don't forget to free user/realm string */
+  if(strlen(user_and_realm))
+  {
+      free(user_and_realm);
+  }

    close(config.sockfd);
    cleanup(config.server);
 
 
 
 
 




More information about the Freeradius-Users mailing list