]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/plugins/radius/radius.c
Fixing CLang [-Wpointer-sign] warning in radius.c
[ppp.git] / pppd / plugins / radius / radius.c
index 264b0ade4a0391eeb7e520f39f563a02350599bb..43238200eb8a6eca256d1fa5a476c4588bf5c02b 100644 (file)
 *
 ***********************************************************************/
 static char const RCSID[] =
-"$Id: radius.c,v 1.26 2004/10/28 00:22:54 paulus Exp $";
+"$Id: radius.c,v 1.32 2008/05/26 09:18:08 paulus Exp $";
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
 
 #include "pppd.h"
 #include "chap-new.h"
 #ifdef CHAPMS
 #include "chap_ms.h"
 #ifdef MPPE
+#include "mppe.h"
 #include "md5.h"
 #endif
 #endif
@@ -41,11 +46,15 @@ static char const RCSID[] =
 #include <sys/types.h>
 #include <sys/time.h>
 #include <string.h>
+#include <netinet/in.h>
+#include <stdlib.h>
 
 #define BUF_LEN 1024
 
 #define MD5_HASH_SIZE  16
 
+#define MSDNS 1
+
 static char *config_file = NULL;
 static int add_avp(char **);
 static struct avpopt {
@@ -103,7 +112,6 @@ static int radius_setmppekeys2(VALUE_PAIR *vp, REQUEST_INFO *req_info);
 #endif
 
 struct radius_state {
-    int accounting_started;
     int initialized;
     int client_port;
     int choose_ip;
@@ -282,7 +290,8 @@ radius_pap_auth(char *user,
     if (*remote_number) {
        rc_avpair_add(&send, PW_CALLING_STATION_ID, remote_number, 0,
                       VENDOR_NONE);
-    }
+    } else if (ipparam)
+       rc_avpair_add(&send, PW_CALLING_STATION_ID, ipparam, 0, VENDOR_NONE);
 
     /* Add user specified vp's */
     if (rstate.avp)
@@ -407,18 +416,14 @@ radius_chap_verify(char *user, char *ourname, int id,
     case CHAP_MICROSOFT:
     {
        /* MS-CHAP-Challenge and MS-CHAP-Response */
-       MS_ChapResponse *rmd = (MS_ChapResponse *) response;
        u_char *p = cpassword;
 
        if (response_len != MS_CHAP_RESPONSE_LEN)
            return 0;
        *p++ = id;
        /* The idiots use a different field order in RADIUS than PPP */
-       memcpy(p, rmd->UseNT, sizeof(rmd->UseNT));
-       p += sizeof(rmd->UseNT);
-       memcpy(p, rmd->LANManResp, sizeof(rmd->LANManResp));
-       p += sizeof(rmd->LANManResp);
-       memcpy(p, rmd->NTResp, sizeof(rmd->NTResp));
+       *p++ = response[MS_CHAP_USENT];
+       memcpy(p, response, MS_CHAP_LANMANRESP_LEN + MS_CHAP_NTRESP_LEN);
 
        rc_avpair_add(&send, PW_MS_CHAP_CHALLENGE,
                      challenge, challenge_len, VENDOR_MICROSOFT);
@@ -430,20 +435,15 @@ radius_chap_verify(char *user, char *ourname, int id,
     case CHAP_MICROSOFT_V2:
     {
        /* MS-CHAP-Challenge and MS-CHAP2-Response */
-       MS_Chap2Response *rmd = (MS_Chap2Response *) response;
        u_char *p = cpassword;
 
        if (response_len != MS_CHAP2_RESPONSE_LEN)
            return 0;
        *p++ = id;
        /* The idiots use a different field order in RADIUS than PPP */
-       memcpy(p, rmd->Flags, sizeof(rmd->Flags));
-       p += sizeof(rmd->Flags);
-       memcpy(p, rmd->PeerChallenge, sizeof(rmd->PeerChallenge));
-       p += sizeof(rmd->PeerChallenge);
-       memcpy(p, rmd->Reserved, sizeof(rmd->Reserved));
-       p += sizeof(rmd->Reserved);
-       memcpy(p, rmd->NTResp, sizeof(rmd->NTResp));
+       *p++ = response[MS_CHAP2_FLAGS];
+       memcpy(p, response, (MS_CHAP2_PEER_CHAL_LEN + MS_CHAP2_RESERVED_LEN
+                            + MS_CHAP2_NTRESP_LEN));
 
        rc_avpair_add(&send, PW_MS_CHAP_CHALLENGE,
                      challenge, challenge_len, VENDOR_MICROSOFT);
@@ -457,7 +457,8 @@ radius_chap_verify(char *user, char *ourname, int id,
     if (*remote_number) {
        rc_avpair_add(&send, PW_CALLING_STATION_ID, remote_number, 0,
                       VENDOR_NONE);
-    }
+    } else if (ipparam)
+       rc_avpair_add(&send, PW_CALLING_STATION_ID, ipparam, 0, VENDOR_NONE);
 
     /* Add user specified vp's */
     if (rstate.avp)
@@ -476,6 +477,8 @@ radius_chap_verify(char *user, char *ourname, int id,
                         req_info);
     }
 
+    strlcpy(message, radius_msg, message_space);
+
     if (result == OK_RC) {
        if (!rstate.done_chap_once) {
            if (radius_setparams(received, radius_msg, req_info, digest,
@@ -546,6 +549,14 @@ radius_setparams(VALUE_PAIR *vp, char *msg, REQUEST_INFO *req_info,
     int mppe_enc_policy = 0;
     int mppe_enc_types = 0;
 #endif
+#ifdef MSDNS
+    ipcp_options *wo = &ipcp_wantoptions[0];
+    ipcp_options *ao = &ipcp_allowoptions[0];
+    int got_msdns_1 = 0;
+    int got_msdns_2 = 0;
+    int got_wins_1 = 0;
+    int got_wins_2 = 0;
+#endif
 
     /* Send RADIUS attributes to anyone else who might be interested */
     if (radius_attributes_hook) {
@@ -584,6 +595,18 @@ radius_setparams(VALUE_PAIR *vp, char *msg, REQUEST_INFO *req_info,
                /* Session timeout */
                maxconnect = vp->lvalue;
                break;
+           case PW_FILTER_ID:
+               /* packet filter, will be handled via ip-(up|down) script */
+               script_setenv("RADIUS_FILTER_ID", (char*) vp->strvalue, 1);
+               break;
+           case PW_FRAMED_ROUTE:
+               /* route, will be handled via ip-(up|down) script */
+               script_setenv("RADIUS_FRAMED_ROUTE", (char*) vp->strvalue, 1);
+               break;
+           case PW_IDLE_TIMEOUT:
+               /* idle parameter */
+               idle_time_limit = vp->lvalue;
+               break;
 #ifdef MAXOCTETS
            case PW_SESSION_OCTETS_LIMIT:
                /* Session traffic limit */
@@ -622,6 +645,9 @@ radius_setparams(VALUE_PAIR *vp, char *msg, REQUEST_INFO *req_info,
                    rstate.ip_addr = remote;
                }
                break;
+            case PW_NAS_IP_ADDRESS:
+                wo->ouraddr = htonl(vp->lvalue);
+                break;
            case PW_CLASS:
                /* Save Class attribute to pass it in accounting request */
                if (vp->lvalue <= MAXCLASSLEN) {
@@ -629,19 +655,22 @@ radius_setparams(VALUE_PAIR *vp, char *msg, REQUEST_INFO *req_info,
                    memcpy(rstate.class, vp->strvalue, rstate.class_len);
                } /* else too big for our buffer - ignore it */
                break;
+           case PW_FRAMED_MTU:
+               netif_set_mtu(rstate.client_port,MIN(netif_get_mtu(rstate.client_port),vp->lvalue));
+               break;
            }
 
 
-#ifdef CHAPMS
        } else if (vp->vendorcode == VENDOR_MICROSOFT) {
+#ifdef CHAPMS
            switch (vp->attribute) {
            case PW_MS_CHAP2_SUCCESS:
-               if ((vp->lvalue != 43) || strncmp(vp->strvalue + 1, "S=", 2)) {
+               if ((vp->lvalue != 43) || strncmp((char*) vp->strvalue + 1, "S=", 2)) {
                    slprintf(msg,BUF_LEN,"RADIUS: bad MS-CHAP2-Success packet");
                    return -1;
                }
                if (message != NULL)
-                   strlcpy(message, vp->strvalue + 1, message_space);
+                   strlcpy(message, (char*) vp->strvalue + 1, message_space);
                ms_chap2_success = 1;
                break;
 
@@ -676,13 +705,32 @@ radius_setparams(VALUE_PAIR *vp, char *msg, REQUEST_INFO *req_info,
                break;
 
 #endif /* MPPE */
-#if 0
+#ifdef MSDNS
            case PW_MS_PRIMARY_DNS_SERVER:
+               ao->dnsaddr[0] = htonl(vp->lvalue);
+               got_msdns_1 = 1;
+               if (!got_msdns_2)
+                   ao->dnsaddr[1] = ao->dnsaddr[0];
+               break;
            case PW_MS_SECONDARY_DNS_SERVER:
+               ao->dnsaddr[1] = htonl(vp->lvalue);
+               got_msdns_2 = 1;
+               if (!got_msdns_1)
+                   ao->dnsaddr[0] = ao->dnsaddr[1];
+               break;
            case PW_MS_PRIMARY_NBNS_SERVER:
+               ao->winsaddr[0] = htonl(vp->lvalue);
+               got_wins_1 = 1;
+               if (!got_wins_2)
+                   ao->winsaddr[1] = ao->winsaddr[0];
+               break;
            case PW_MS_SECONDARY_NBNS_SERVER:
+               ao->winsaddr[1] = htonl(vp->lvalue);
+               got_wins_2 = 1;
+               if (!got_wins_1)
+                   ao->winsaddr[0] = ao->winsaddr[1];
                break;
-#endif
+#endif /* MSDNS */
            }
 #endif /* CHAPMS */
        }
@@ -699,11 +747,12 @@ radius_setparams(VALUE_PAIR *vp, char *msg, REQUEST_INFO *req_info,
      * Note that if the policy value was '0' we don't set the key!
      */
     if (mppe_enc_policy && mppe_enc_keys) {
-       mppe_keys_set = 1;
        /* Set/modify allowed encryption types. */
        if (mppe_enc_types)
-           set_mppe_enc_types(mppe_enc_policy, mppe_enc_types);
+           mppe_set_enc_types(mppe_enc_policy, mppe_enc_types);
+       return 0;
     }
+    mppe_clear_keys();
 #endif
 
     return 0;
@@ -738,18 +787,18 @@ radius_setmppekeys(VALUE_PAIR *vp, REQUEST_INFO *req_info,
 
     memcpy(plain, vp->strvalue, sizeof(plain));
 
-    MD5Init(&Context);
-    MD5Update(&Context, req_info->secret, strlen(req_info->secret));
-    MD5Update(&Context, req_info->request_vector, AUTH_VECTOR_LEN);
-    MD5Final(buf, &Context);
+    MD5_Init(&Context);
+    MD5_Update(&Context, req_info->secret, strlen(req_info->secret));
+    MD5_Update(&Context, req_info->request_vector, AUTH_VECTOR_LEN);
+    MD5_Final(buf, &Context);
 
     for (i = 0; i < 16; i++)
        plain[i] ^= buf[i];
 
-    MD5Init(&Context);
-    MD5Update(&Context, req_info->secret, strlen(req_info->secret));
-    MD5Update(&Context, vp->strvalue, 16);
-    MD5Final(buf, &Context);
+    MD5_Init(&Context);
+    MD5_Update(&Context, req_info->secret, strlen(req_info->secret));
+    MD5_Update(&Context, vp->strvalue, 16);
+    MD5_Final(buf, &Context);
 
     for(i = 0; i < 16; i++)
        plain[i + 16] ^= buf[i];
@@ -759,7 +808,7 @@ radius_setmppekeys(VALUE_PAIR *vp, REQUEST_INFO *req_info,
      * the NAS (us) doesn't need; we only need the start key.  So we have
      * to generate the start key, sigh.  NB: We do not support the LM-Key.
      */
-    mppe_set_keys(challenge, &plain[8]);
+    mppe_set_chapv1(challenge, &plain[8]);
 
     return 0;    
 }
@@ -802,32 +851,32 @@ radius_setmppekeys2(VALUE_PAIR *vp, REQUEST_INFO *req_info)
 
     memcpy(plain, crypt, 32);
 
-    MD5Init(&Context);
-    MD5Update(&Context, req_info->secret, strlen(req_info->secret));
-    MD5Update(&Context, req_info->request_vector, AUTH_VECTOR_LEN);
-    MD5Update(&Context, salt, 2);
-    MD5Final(buf, &Context);
+    MD5_Init(&Context);
+    MD5_Update(&Context, req_info->secret, strlen(req_info->secret));
+    MD5_Update(&Context, req_info->request_vector, AUTH_VECTOR_LEN);
+    MD5_Update(&Context, salt, 2);
+    MD5_Final(buf, &Context);
 
     for (i = 0; i < 16; i++)
        plain[i] ^= buf[i];
 
-    if (plain[0] != sizeof(mppe_send_key) /* 16 */) {
+    if (plain[0] != 16) {
        error("RADIUS: Incorrect key length (%d) for MS-MPPE-%s-Key attribute",
              (int) plain[0], type);
        return -1;
     }
 
-    MD5Init(&Context);
-    MD5Update(&Context, req_info->secret, strlen(req_info->secret));
-    MD5Update(&Context, crypt, 16);
-    MD5Final(buf, &Context);
+    MD5_Init(&Context);
+    MD5_Update(&Context, req_info->secret, strlen(req_info->secret));
+    MD5_Update(&Context, crypt, 16);
+    MD5_Final(buf, &Context);
 
     plain[16] ^= buf[0]; /* only need the first byte */
 
     if (vp->attribute == PW_MS_MPPE_SEND_KEY)
-       memcpy(mppe_send_key, plain + 1, 16);
+       mppe_set_keys(plain + 1, NULL, 16);
     else
-       memcpy(mppe_recv_key, plain + 1, 16);
+       mppe_set_keys(NULL, plain + 1, 16);
 
     return 0;
 }
@@ -857,7 +906,7 @@ radius_acct_start(void)
 
     rstate.start_time = time(NULL);
 
-    strncpy(rstate.session_id, rc_mksid(), sizeof(rstate.session_id));
+    strlcpy(rstate.session_id, rc_mksid(), MAXSESSIONID);
 
     rc_avpair_add(&send, PW_ACCT_SESSION_ID,
                   rstate.session_id, 0, VENDOR_NONE);
@@ -880,7 +929,8 @@ radius_acct_start(void)
     if (*remote_number) {
        rc_avpair_add(&send, PW_CALLING_STATION_ID,
                       remote_number, 0, VENDOR_NONE);
-    }
+    } else if (ipparam)
+       rc_avpair_add(&send, PW_CALLING_STATION_ID, ipparam, 0, VENDOR_NONE);
 
     av_type = PW_RADIUS;
     rc_avpair_add(&send, PW_ACCT_AUTHENTIC, &av_type, 0, VENDOR_NONE);
@@ -910,12 +960,11 @@ radius_acct_start(void)
        /* RADIUS server could be down so make this a warning */
        syslog(LOG_WARNING,
                "Accounting START failed for %s", rstate.user);
-    } else {
-       rstate.accounting_started = 1;
-       /* Kick off periodic accounting reports */
-       if (rstate.acct_interim_interval) {
-           TIMEOUT(radius_acct_interim, NULL, rstate.acct_interim_interval);
-       }
+    }
+
+    /* Kick off periodic accounting reports */
+    if (rstate.acct_interim_interval) {
+       TIMEOUT(radius_acct_interim, NULL, rstate.acct_interim_interval);
     }
 }
 
@@ -941,16 +990,18 @@ radius_acct_stop(void)
        return;
     }
 
-    if (!rstate.accounting_started) {
-       return;
-    }
+    if (rstate.acct_interim_interval)
+       UNTIMEOUT(radius_acct_interim, NULL);
 
-    rstate.accounting_started = 0;
     rc_avpair_add(&send, PW_ACCT_SESSION_ID, rstate.session_id,
                   0, VENDOR_NONE);
 
     rc_avpair_add(&send, PW_USER_NAME, rstate.user, 0, VENDOR_NONE);
 
+    if (rstate.class_len > 0)
+       rc_avpair_add(&send, PW_CLASS,
+                     rstate.class, rstate.class_len, VENDOR_NONE);
+
     av_type = PW_STATUS_STOP;
     rc_avpair_add(&send, PW_ACCT_STATUS_TYPE, &av_type, 0, VENDOR_NONE);
 
@@ -984,7 +1035,8 @@ radius_acct_stop(void)
     if (*remote_number) {
        rc_avpair_add(&send, PW_CALLING_STATION_ID,
                       remote_number, 0, VENDOR_NONE);
-    }
+    } else if (ipparam)
+       rc_avpair_add(&send, PW_CALLING_STATION_ID, ipparam, 0, VENDOR_NONE);
 
     av_type = ( using_pty ? PW_VIRTUAL : ( sync_serial ? PW_SYNC : PW_ASYNC ) );
     rc_avpair_add(&send, PW_NAS_PORT_TYPE, &av_type, 0, VENDOR_NONE);
@@ -1020,6 +1072,10 @@ radius_acct_stop(void)
            av_type = PW_ACCT_IDLE_TIMEOUT;
            break;
 
+       case EXIT_CALLBACK:
+           av_type = PW_CALLBACK;
+           break;
+           
        case EXIT_CONNECT_TIME:
            av_type = PW_ACCT_SESSION_TIMEOUT;
            break;
@@ -1081,15 +1137,15 @@ radius_acct_interim(void *ignored)
        return;
     }
 
-    if (!rstate.accounting_started) {
-       return;
-    }
-
     rc_avpair_add(&send, PW_ACCT_SESSION_ID, rstate.session_id,
                   0, VENDOR_NONE);
 
     rc_avpair_add(&send, PW_USER_NAME, rstate.user, 0, VENDOR_NONE);
 
+    if (rstate.class_len > 0)
+       rc_avpair_add(&send, PW_CLASS,
+                     rstate.class, rstate.class_len, VENDOR_NONE);
+
     av_type = PW_STATUS_ALIVE;
     rc_avpair_add(&send, PW_ACCT_STATUS_TYPE, &av_type, 0, VENDOR_NONE);
 
@@ -1127,7 +1183,8 @@ radius_acct_interim(void *ignored)
     if (*remote_number) {
        rc_avpair_add(&send, PW_CALLING_STATION_ID,
                       remote_number, 0, VENDOR_NONE);
-    }
+    } else if (ipparam)
+       rc_avpair_add(&send, PW_CALLING_STATION_ID, ipparam, 0, VENDOR_NONE);
 
     av_type = ( using_pty ? PW_VIRTUAL : ( sync_serial ? PW_SYNC : PW_ASYNC ) );
     rc_avpair_add(&send, PW_NAS_PORT_TYPE, &av_type, 0, VENDOR_NONE);