]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/plugins/radius/radiusclient/lib/buildreq.c
Added RADIUS suppport.
[ppp.git] / pppd / plugins / radius / radiusclient / lib / buildreq.c
diff --git a/pppd/plugins/radius/radiusclient/lib/buildreq.c b/pppd/plugins/radius/radiusclient/lib/buildreq.c
new file mode 100644 (file)
index 0000000..507a25c
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * $Id: buildreq.c,v 1.1 2002/01/22 16:03:02 dfs Exp $
+ *
+ * Copyright (C) 1995,1997 Lars Fenneberg
+ *
+ * See the file COPYRIGHT for the respective terms and conditions.
+ * If the file is missing contact me at lf@elemental.net
+ * and I'll send you a copy.
+ *
+ */
+
+#include <config.h>
+#include <includes.h>
+#include <radiusclient.h>
+
+unsigned char rc_get_seqnbr(void);
+
+/*
+ * Function: rc_buildreq
+ *
+ * Purpose: builds a skeleton RADIUS request using information from the
+ *         config file.
+ *
+ */
+
+void rc_buildreq(SEND_DATA *data, int code, char *server, unsigned short port,
+                int timeout, int retries)
+{
+       data->server = server;
+       data->svc_port = port;
+       data->seq_nbr = rc_get_seqnbr();
+       data->timeout = timeout;
+       data->retries = retries;
+       data->code = code;
+}
+
+/*
+ * Function: rc_guess_seqnbr
+ *
+ * Purpose: return a random sequence number
+ *
+ */
+
+static unsigned char rc_guess_seqnbr(void)
+{
+       srandom((unsigned int)(time(NULL)+getpid()));
+       return (unsigned char)(random() & UCHAR_MAX);
+}
+
+/*
+ * Function: rc_get_seqnbr
+ *
+ * Purpose: generate a sequence number
+ *
+ */
+
+unsigned char rc_get_seqnbr(void)
+{
+       FILE *sf;
+       int tries = 1;
+       int seq_nbr;
+       char *seqfile = rc_conf_str("seqfile");
+
+       if ((sf = fopen(seqfile, "a+")) == NULL)
+       {
+               rc_log(LOG_ERR,"rc_get_seqnbr: couldn't open sequence file %s: %s", seqfile, strerror(errno));
+               /* well, so guess a sequence number */
+               return rc_guess_seqnbr();
+       }
+
+       while (do_lock_exclusive(fileno(sf))!= 0)
+       {
+               if (errno != EWOULDBLOCK) {
+                       rc_log(LOG_ERR, "rc_get_seqnbr: flock failure: %s: %s", seqfile, strerror(errno));
+                       fclose(sf);
+                       return rc_guess_seqnbr();
+               }
+               tries++;
+               if (tries <= 10)
+                       rc_mdelay(500);
+               else
+                       break;
+       }
+
+       if (tries > 10) {
+               rc_log(LOG_ERR,"rc_get_seqnbr: couldn't get lock after %d tries: %s", tries-1, seqfile);
+               fclose(sf);
+               return rc_guess_seqnbr();
+       }
+
+       rewind(sf);
+       if (fscanf(sf, "%d", &seq_nbr) != 1) {
+               rc_log(LOG_ERR,"rc_get_seqnbr: fscanf failure: %s", seqfile);
+               seq_nbr = rc_guess_seqnbr();
+       }
+
+       rewind(sf);
+       ftruncate(fileno(sf),0);
+       fprintf(sf,"%d\n", (seq_nbr+1) & UCHAR_MAX);
+
+       fflush(sf); /* fflush because a process may read it between the do_unlock and fclose */
+
+       if (do_unlock(fileno(sf)) != 0)
+               rc_log(LOG_ERR, "rc_get_seqnbr: couldn't release lock on %s: %s", seqfile, strerror(errno));
+
+       fclose(sf);
+
+       return (unsigned char)seq_nbr;
+}
+
+/*
+ * Function: rc_auth
+ *
+ * Purpose: Builds an authentication request for port id client_port
+ *         with the value_pairs send and submits it to a server
+ *
+ * Returns: received value_pairs in received, messages from the server in msg
+ *         and 0 on success, negative on failure as return value
+ *
+ */
+
+int rc_auth(UINT4 client_port, VALUE_PAIR *send, VALUE_PAIR **received,
+           char *msg)
+{
+       SEND_DATA       data;
+       UINT4           client_id;
+       int             result;
+       int             i;
+       SERVER          *authserver = rc_conf_srv("authserver");
+       int             timeout = rc_conf_int("radius_timeout");
+       int             retries = rc_conf_int("radius_retries");
+
+       data.send_pairs = send;
+       data.receive_pairs = NULL;
+
+       /*
+        * Fill in NAS-IP-Address
+        */
+
+       if ((client_id = rc_own_ipaddress()) == 0)
+               return (ERROR_RC);
+
+       if (rc_avpair_add(&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0, VENDOR_NONE) == NULL)
+               return (ERROR_RC);
+
+       /*
+        * Fill in NAS-Port
+        */
+
+       if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL)
+               return (ERROR_RC);
+
+       result = ERROR_RC;
+       for(i=0; (i<authserver->max) && (result != OK_RC) && (result != BADRESP_RC)
+               ; i++)
+       {
+               if (data.receive_pairs != NULL) {
+                       rc_avpair_free(data.receive_pairs);
+                       data.receive_pairs = NULL;
+               }
+               rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i],
+                           authserver->port[i], timeout, retries);
+
+               result = rc_send_server (&data, msg);
+       }
+
+       *received = data.receive_pairs;
+
+       return result;
+}
+
+/*
+ * Function: rc_auth_proxy
+ *
+ * Purpose: Builds an authentication request
+ *         with the value_pairs send and submits it to a server.
+ *         Works for a proxy; does not add IP address, and does
+ *         does not rely on config file.
+ *
+ * Returns: received value_pairs in received, messages from the server in msg
+ *         and 0 on success, negative on failure as return value
+ *
+ */
+
+int rc_auth_proxy(VALUE_PAIR *send, VALUE_PAIR **received, char *msg)
+{
+       SEND_DATA       data;
+       int             result;
+       int             i;
+       SERVER          *authserver = rc_conf_srv("authserver");
+       int             timeout = rc_conf_int("radius_timeout");
+       int             retries = rc_conf_int("radius_retries");
+
+       data.send_pairs = send;
+       data.receive_pairs = NULL;
+
+       result = ERROR_RC;
+       for(i=0; (i<authserver->max) && (result != OK_RC) && (result != BADRESP_RC)
+               ; i++)
+       {
+               if (data.receive_pairs != NULL) {
+                       rc_avpair_free(data.receive_pairs);
+                       data.receive_pairs = NULL;
+               }
+               rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i],
+                           authserver->port[i], timeout, retries);
+
+               result = rc_send_server (&data, msg);
+       }
+
+       *received = data.receive_pairs;
+
+       return result;
+}
+
+
+/*
+ * Function: rc_acct
+ *
+ * Purpose: Builds an accounting request for port id client_port
+ *         with the value_pairs send
+ *
+ * Remarks: NAS-IP-Address, NAS-Port and Acct-Delay-Time get filled
+ *         in by this function, the rest has to be supplied.
+ */
+
+int rc_acct(UINT4 client_port, VALUE_PAIR *send)
+{
+       SEND_DATA       data;
+       VALUE_PAIR      *adt_vp;
+       UINT4           client_id;
+       int             result;
+       time_t          start_time, dtime;
+       char            msg[4096];
+       int             i;
+       SERVER          *acctserver = rc_conf_srv("acctserver");
+       int             timeout = rc_conf_int("radius_timeout");
+       int             retries = rc_conf_int("radius_retries");
+
+       data.send_pairs = send;
+       data.receive_pairs = NULL;
+
+       /*
+        * Fill in NAS-IP-Address
+        */
+
+       if ((client_id = rc_own_ipaddress()) == 0)
+               return (ERROR_RC);
+
+       if (rc_avpair_add(&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0, VENDOR_NONE) == NULL)
+               return (ERROR_RC);
+
+       /*
+        * Fill in NAS-Port
+        */
+
+       if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL)
+               return (ERROR_RC);
+
+       /*
+        * Fill in Acct-Delay-Time
+        */
+
+       dtime = 0;
+       if ((adt_vp = rc_avpair_add(&(data.send_pairs), PW_ACCT_DELAY_TIME, &dtime, 0, VENDOR_NONE)) == NULL)
+               return (ERROR_RC);
+
+       start_time = time(NULL);
+       result = ERROR_RC;
+       for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC)
+               ; i++)
+       {
+               if (data.receive_pairs != NULL) {
+                       rc_avpair_free(data.receive_pairs);
+                       data.receive_pairs = NULL;
+               }
+               rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i],
+                           acctserver->port[i], timeout, retries);
+
+               dtime = time(NULL) - start_time;
+               rc_avpair_assign(adt_vp, &dtime, 0);
+
+               result = rc_send_server (&data, msg);
+       }
+
+       rc_avpair_free(data.receive_pairs);
+
+       return result;
+}
+
+/*
+ * Function: rc_acct_proxy
+ *
+ * Purpose: Builds an accounting request with the value_pairs send
+ *
+ */
+
+int rc_acct_proxy(VALUE_PAIR *send)
+{
+       SEND_DATA       data;
+       int             result;
+       char            msg[4096];
+       int             i;
+       SERVER          *acctserver = rc_conf_srv("authserver");
+       int             timeout = rc_conf_int("radius_timeout");
+       int             retries = rc_conf_int("radius_retries");
+
+       data.send_pairs = send;
+       data.receive_pairs = NULL;
+
+       result = ERROR_RC;
+       for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC)
+               ; i++)
+       {
+               if (data.receive_pairs != NULL) {
+                       rc_avpair_free(data.receive_pairs);
+                       data.receive_pairs = NULL;
+               }
+               rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i],
+                           acctserver->port[i], timeout, retries);
+
+               result = rc_send_server (&data, msg);
+       }
+
+       rc_avpair_free(data.receive_pairs);
+
+       return result;
+}
+
+/*
+ * Function: rc_check
+ *
+ * Purpose: ask the server hostname on the specified port for a
+ *         status message
+ *
+ */
+
+int rc_check(char *host, unsigned short port, char *msg)
+{
+       SEND_DATA       data;
+       int             result;
+       UINT4           client_id, service_type;
+       int             timeout = rc_conf_int("radius_timeout");
+       int             retries = rc_conf_int("radius_retries");
+
+       data.send_pairs = data.receive_pairs = NULL;
+
+       /*
+        * Fill in NAS-IP-Address, although it isn't neccessary
+        */
+
+       if ((client_id = rc_own_ipaddress()) == 0)
+               return (ERROR_RC);
+
+       rc_avpair_add(&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0, VENDOR_NONE);
+
+       /*
+        * Fill in Service-Type
+        */
+
+       service_type = PW_ADMINISTRATIVE;
+       rc_avpair_add(&(data.send_pairs), PW_SERVICE_TYPE, &service_type, 0, VENDOR_NONE);
+
+       rc_buildreq(&data, PW_STATUS_SERVER, host, port, timeout, retries);
+       result = rc_send_server (&data, msg);
+
+       rc_avpair_free(data.receive_pairs);
+
+       return result;
+}