PAM RADIUS user authorization

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello,

I would like to submit my code changes to PAM RADIUS authentication module.
This code segment does user authorization (delivers user's privilege from RADIUS server configuration database).

1. I introduced new flag service_type for PAM RADIUS configuration file and attached sample configuration file.
2. _pam_parse routine checks if user authorization is required and sets internal flag service_type while parse arguments
static int _pam_parse(int argc, const char **argv, radius_conf_t *conf)
3. Add more RADIUS server response validations:
    a. Check for the correct sequence number.
    b. Check for the Access-Accept code value in response packet
Argument for verify_packet has been changed  
-verify_packet(char *secret, AUTH_HDR *response, unsigned char *vector)
+verify_packet(char *secret, AUTH_HDR *response, AUTH_HDR *request)
4. Introduced routine to analyze RADIUS server response packet
+DecodeResponse(pam_handle_t *pamh, AUTH_HDR *response)
This routine parses response packet and searches for Service-Type attribute in packet.
Value of Service-Type attribute RADIUS server reads from user's database and delivers in response packet.
Value of Service-Type has been saved in pam environment variable "Privilege" and is acceptable from calling application or any other module/functions

Please, let me know if you need further explanation. How I can include my changes in RADIUS module?

Best regards,

Leon


$ more sample.pam
#%PAM-1.0
#
# VALUE   Service-Type    Login-User               1
# VALUE   Service-Type    Framed-User              2
# VALUE   Service-Type    Callback-Login-User      3
# VALUE   Service-Type    Callback-Framed-User     4
# VALUE   Service-Type    Outbound-User            5
# VALUE   Service-Type    Administrative-User      6
# VALUE   Service-Type    NAS-Prompt-User          7
# VALUE   Service-Type    Authenticate-Only-User   8
# VALUE   Service-Type    Callback-NAS-Prompt-User 9

auth required /lib/security/pam_radius_auth.so debug use_first_pass retry=1 service_type

$ diff -u ../pam_radius/pam_radius_auth.c pam_radius_auth.c

@@ -46,6 +46,8 @@
 static radius_server_t *live_server = NULL;
 static time_t session_time;
 
+int service_type = 0;
+
 /* logging */
 static void _pam_log(int err, const char *format, ...)
 {
@@ -84,6 +86,11 @@
     } else if (!strcmp(*argv, "skip_passwd")) {
       ctrl |= PAM_SKIP_PASSWD;
 
+    } else if (!strcmp(*argv, "service_type")) {
+      service_type = 1;
+
 #ifdef RETRY
     } else if (!strncmp(*argv,"retry=",6)) {
       int i = atoi(*argv+6);
@@ -352,16 +359,110 @@
   MD5Final(request->vector, &my_md5);      /* set the final vector */
 }
 
+
+typedef struct {
+        unsigned char cAttribute;
+        unsigned char cLength;
+        char     sValue[AUTH_PASS_LEN + 1];
+} RToken_t;
+
+#define PW_SERVICE_TYPE                 6       /* number */
+
+/*********************************************************
+*  Function: DecodeResponse
+*
+*  Description: Parses RADIUS server response attribute, sets user privilege
+*               based on Service-Type configuration in RADIUS database
+*
+*  Samples of configuration file /etc/raddb# more users
+*  admin   Password = "admin"
+*          Service-Type = Administrative-User
+*  user    Password = "user"
+*          Service-Type = NAS-Prompt-User
+* 
+*  Responses samples from RADIUS server:
+*  Tue Mar 20 11:57:22 2001: [18482] Sending Accept of id 66 to x.x.x.x
+*  Tue Mar 20 11:57:22 2001: [18482] Service-Type = Administrative-User
+* 
+*  Tue Mar 20 11:09:57 2001: [18482] Sending Accept of id 216 to x.x.x.x
+*  Tue Mar 20 11:09:57 2001: [18482] Service-Type = NAS-Prompt-User
+* 
+*  Input:  pam_handle_t *pamh - PAM structure handle
+*          AUTH_HDR *response - Response packet from RADIUS server
+*  Output: none
+*
+*  Algorithm:
+*
+*********************************************************/
+static void
+DecodeResponse(pam_handle_t *pamh, AUTH_HDR *response)
+{
+        char *pAttribute;
+        AUTH_HDR *pHeader = (AUTH_HDR *) response;
+        RToken_t *pToken;
+        char sPrivilege[128];
+        int nRetval;
+
+       /* u_char pHeader->code; u_char pHeader->id; u_short pHeader->length; */
+        for (pAttribute = (char *) response + AUTH_VECTOR_LEN + sizeof(u_char) + sizeof(u_char) + sizeof(u_short);
+            pAttribute < (char *) response + ntohs(pHeader->length);) {
+         pToken = (RToken_t *) pAttribute;
+         if (pToken->cAttribute == PW_SERVICE_TYPE) {
+           if (service_type) { /* this option has been set in radius configuration file */
+             sprintf(sPrivilege, "Privilege=%d", pToken->sValue[3]);
+             printf("sPrivilege %s\n", sPrivilege);
+             nRetval = pam_putenv(pamh, sPrivilege);
+             if (nRetval != PAM_SUCCESS) {
+               syslog(LOG_WARNING, "%s: unable to set privilege level for PAM", __FUNCTION__);
+               printf("***pam_radius  %s: unable to set privilege level for PAM\n", __FUNCTION__);
+             }
+           } /* if (service_type) */
+         }
+         pAttribute += pToken->cLength;
+        }
+} /* DecodeResponse */
+
/*
  * Verify the response from the server
  */
 static int
-verify_packet(char *secret, AUTH_HDR *response, unsigned char *vector)
+verify_packet(char *secret, AUTH_HDR *response, AUTH_HDR *request)
 {
   MD5_CTX my_md5;
   unsigned char        calculated[AUTH_VECTOR_LEN];
   unsigned char        reply[AUTH_VECTOR_LEN];
+  unsigned char *vector;
  
+  vector = (unsigned char *) request->vector;
+
+  /*
+   * Check for the correct sequence number.
+   */

+  if (response->id != request->id) {
+    printf("***pam_radius %s: Bad message-id received [%d/%d]\n", __FUNCTION__, request->id, response->id);
+    return FALSE;
+  }
+
+  /*
+   * Check for the Access-Accept code value
+   */
+  if (response->code != PW_AUTHENTICATION_ACK) {
+    printf("***pam_radius %s: Bad code [%d/%d]\n", __FUNCTION__, PW_AUTHENTICATION_ACK, response->code);
+    return FALSE;
+  }
+
   /*
    * We could dispense with the memcpy, and do MD5's of the packet
    * + vector piece by piece.  This is easier understand, and maybe faster.

@@ -826,14 +953,15 @@
            if (conf->accounting_bug) {
              p = "";
            }
          }
-
-         if (!verify_packet(p, response, request->vector)) {
+         if (!verify_packet(p, response, request)) {
            _pam_log(LOG_ERR, "packet from RADIUS server %s fails verification",
                      server->hostname);
            ok = FALSE;
            break;
          }
@@ -1100,23 +1260,29 @@
   /* Whew! Done the pasword checks, look for an authentication acknowledge */
   if (response->code == PW_AUTHENTICATION_ACK) {
+    DecodeResponse(pamh, response);
     retval = PAM_SUCCESS;
   } else {
 #ifdef RETRY

[Index of Archives]     [Fedora Users]     [Kernel]     [Red Hat Install]     [Linux for the blind]     [Gimp]

  Powered by Linux