This is the bigger part of the modular session framework. It is not ready to
authorpacman <pacman>
Thu, 19 Oct 2000 22:11:57 +0000 (22:11 +0000)
committerpacman <pacman>
Thu, 19 Oct 2000 22:11:57 +0000 (22:11 +0000)
be used yet, but is getting closer.

18 files changed:
raddb/radiusd.conf.in
src/include/modules.h
src/include/radiusd.h
src/main/Makefile
src/main/modules.c
src/main/radutmp.c
src/main/session.c [new file with mode: 0644]
src/modules/rlm_acct_unique/rlm_acct_unique.c
src/modules/rlm_detail/rlm_detail.c
src/modules/rlm_dictionary/rlm_dictionary.c
src/modules/rlm_example/rlm_example.c
src/modules/rlm_files/rlm_files.c
src/modules/rlm_ldap/rlm_ldap.c
src/modules/rlm_pam/rlm_pam.c
src/modules/rlm_preprocess/rlm_preprocess.c
src/modules/rlm_realm/rlm_realm.c
src/modules/rlm_sql/rlm_sql.c
src/modules/rlm_unix/rlm_unix.c

index 5920045..cbb2c4b 100644 (file)
@@ -652,3 +652,9 @@ accounting {
        detail
        unix
 }
+
+# Session database, used for checking Simultaneous-Use. The radutmp module
+# handles this
+session {
+       radutmp
+}
index 03a69f7..aa8bc5e 100644 (file)
@@ -25,7 +25,8 @@ typedef int (*RLM_ACCOUNTING_FUNCP)(REQUEST *request);
 #define RLM_COMPONENT_AUTZ 1
 #define RLM_COMPONENT_PREACCT 2
 #define RLM_COMPONENT_ACCT 3
-#define RLM_COMPONENT_COUNT 4 /* How many components are there */
+#define RLM_COMPONENT_SESS 4
+#define RLM_COMPONENT_COUNT 5 /* How many components are there */
 
 typedef struct module_t {
        const char      *name;
@@ -36,6 +37,7 @@ typedef struct module_t {
        int     (*authenticate)(void *instance, REQUEST *request);
        int     (*preaccounting)(void *instance, REQUEST *request);
        int     (*accounting)(void *instance, REQUEST *request);
+       int     (*checksimul)(void *instance, REQUEST *request);
        int     (*detach)(void *instance);
        int     (*destroy)(void);
 } module_t;
@@ -58,5 +60,6 @@ int module_authorize(REQUEST *request);
 int module_authenticate(int type, REQUEST *request);
 int module_preacct(REQUEST *request);
 int module_accounting(REQUEST *request);
+int module_checksimul(REQUEST *request, int maxsimul);
 
 #endif /* RADIUS_MODULES_H */
index 013ab94..6f18583 100644 (file)
@@ -55,6 +55,10 @@ typedef struct auth_req {
        int                     proxy_try_count;
        time_t                  proxy_next_try;
 
+       int                     simul_max;
+       int                     simul_count;
+       int                     simul_mpp; /* WEIRD: 1 is false, 2 is true */
+
        int                     finished;
        struct auth_req         *prev;
        struct auth_req         *next;
@@ -171,6 +175,13 @@ int                radutmp_add(REQUEST *);
 int            radutmp_zap(uint32_t nas, int port, char *user, time_t t);
 int            radutmp_checksimul(char *name, VALUE_PAIR *, int maxsimul);
 
+/* session.c */
+int            rad_check_ts(uint32_t nasaddr, int port, const char *user,
+                            const char *sessionid);
+int            session_zap(uint32_t nasaddr, int port, const char *user,
+                           const char *sessionid, uint32_t cliaddr,
+                           char proto, time_t t);
+
 /* radiusd.c */
 void           debug_pair(FILE *, VALUE_PAIR *);
 int            log_err (char *);
index 36b282c..62b4ff5 100644 (file)
@@ -55,6 +55,9 @@ modules.o:  modules.c $(INCLUDES)
 radutmp.o:  radutmp.c $(INCLUDES)
        $(CC) $(CFLAGS) -c radutmp.c
 
+session.o:  session.c $(INCLUDES)
+       $(CC) $(CFLAGS) -c session.c
+
 proxy.o:  proxy.c $(INCLUDES)
        $(CC) $(CFLAGS) -c proxy.c
 
index 420bc4d..936791a 100644 (file)
@@ -62,6 +62,7 @@ static config_module_t *authorize = NULL;
 static indexed_config_module_t *authenticate = NULL;
 static config_module_t *preacct = NULL;
 static config_module_t *accounting = NULL;
+static config_module_t *session = NULL;
 
 static void config_list_free(config_module_t **cf)
 {
@@ -113,6 +114,7 @@ static void module_list_free(void)
        config_list_free(&authorize);
        config_list_free(&preacct);
        config_list_free(&accounting);
+       config_list_free(&session);
 
        instance_list_free(&module_instance_list);
 
@@ -583,6 +585,17 @@ static void load_module_section(CONF_SECTION *cs, int comp, const char *filename
                        }
                        add_to_list(&accounting, this);
                        break;
+               case RLM_COMPONENT_SESS:
+                       if (!this->entry->module->checksimul) {
+                               radlog(L_ERR|L_CONS,
+                                       "%s[%d] Module %s does not contain "
+                                       "a 'checksimul' entry\n",
+                                       filename, modreflineno,
+                                       this->entry->module->name);
+                               exit(1);
+                       }
+                       add_to_list(&session, this);
+                       break;
                default:
                        radlog(L_ERR|L_CONS, "%s[%d] Unknown component %d.\n",
                                filename, modreflineno, comp);
@@ -652,6 +665,7 @@ int setup_modules(void)
                case RLM_COMPONENT_AUTZ: control="authorize"; break;
                case RLM_COMPONENT_PREACCT: control="preacct"; break;
                case RLM_COMPONENT_ACCT: control="accounting"; break;
+               case RLM_COMPONENT_SESS: control="session"; break;
                default: control="unknown";
                }
                
@@ -843,6 +857,44 @@ int module_accounting(REQUEST *request)
 }
 
 /*
+ *     See if a user is already logged in.
+ *
+ *     Returns: 0 == OK, 1 == double logins, 2 == multilink attempt
+ */
+int module_checksimul(REQUEST *request, int maxsimul)
+{
+       config_module_t *this;
+       int             rcode;
+
+       if(!session)
+               return 0;
+
+       if(!request->username)
+               return 0;
+
+       request->simul_count = 0;
+       request->simul_max = maxsimul;
+       request->simul_mpp = 1;
+
+       this = session;
+       rcode = RLM_MODULE_FAIL;
+
+       while (this && (rcode == RLM_MODULE_FAIL)) {
+               DEBUG2("  checksimul: %s", this->instance->entry->module->name);
+               rcode = (this->instance->entry->module->checksimul)
+                               (this->instance->insthandle, request);
+               this = this->next;
+       }
+
+       if(rcode != RLM_MODULE_OK) {
+               /* FIXME: Good spot for a *rate-limited* warning to the log */
+               return 0;
+       }
+
+       return (request->simul_count < maxsimul) ? 0 : request->simul_mpp;
+}
+
+/*
  *     Module malloc() call, which does stuff if the malloc fails.
  *
  *     This call ALWAYS succeeds!
index cc7083a..fa7e2a6 100644 (file)
@@ -449,8 +449,8 @@ static void alrm_handler(int sig)
 /*
  *     Check one terminal server to see if a user is logged in.
  */
-static int rad_check_ts(uint32_t nasaddr, int portnum, const char *user,
-                        const char *session_id)
+int rad_check_ts(uint32_t nasaddr, int portnum, const char *user,
+                 const char *session_id)
 {
        int     pid, st, e;
        int     n;
diff --git a/src/main/session.c b/src/main/session.c
new file mode 100644 (file)
index 0000000..8f16a7c
--- /dev/null
@@ -0,0 +1,199 @@
+#include       "autoconf.h"
+
+#include       <stdio.h>
+#include       <string.h>
+#include       <time.h>
+#include       <unistd.h>
+#include       <signal.h>
+#include       <errno.h>
+#include       <sys/wait.h>
+
+#include       "radiusd.h"
+#include       "modules.h"
+
+/* End a session by faking a Stop packet to all accounting modules */
+int session_zap(uint32_t nasaddr, int port, const char *user,
+               const char *sessionid, uint32_t cliaddr, char proto, time_t t)
+{
+  static unsigned char id=0;
+
+  REQUEST stopreq;
+  RADIUS_PACKET stoppkt;
+  VALUE_PAIR *vp, *userpair;
+  int modret;
+  int ret;
+
+  memset(&stoppkt, 0, sizeof stoppkt);
+  stoppkt.data=0;
+  stoppkt.sockfd=-1;
+  stoppkt.code=PW_ACCOUNTING_REQUEST;
+  stoppkt.id=id++;
+  stoppkt.timestamp=t?t:time(0);
+  stoppkt.vps=0;
+
+  /* Hold your breath */
+#define PAIR(n,v,t,e) do { \
+    if(!(vp=paircreate(n, t))) { \
+      radlog(L_ERR|L_CONS, "no memory"); \
+      pairfree(stoppkt.vps); \
+      return 0; \
+    } \
+    vp->e=v; \
+    pairadd(&stoppkt.vps, vp); \
+  } while(0)
+#define INTPAIR(n,v) PAIR(n,v,PW_TYPE_INTEGER,lvalue)
+#define IPPAIR(n,v) PAIR(n,v,PW_TYPE_IPADDR,lvalue)
+#define STRINGPAIR(n,v) do { \
+    if(!(vp=paircreate(n, PW_TYPE_STRING))) { \
+      radlog(L_ERR|L_CONS, "no memory"); \
+      pairfree(stoppkt.vps); \
+      return 0; \
+    } \
+    strNcpy((char *)vp->strvalue, v, sizeof vp->strvalue); \
+    vp->length=strlen(v); \
+    pairadd(&stoppkt.vps, vp); \
+  } while(0)
+
+  INTPAIR(PW_ACCT_STATUS_TYPE, PW_STATUS_STOP);
+  IPPAIR(PW_NAS_IP_ADDRESS, nasaddr);
+  INTPAIR(PW_ACCT_DELAY_TIME, 0);
+  STRINGPAIR(PW_USER_NAME, user);
+  userpair=vp;
+  INTPAIR(PW_NAS_PORT_ID, port);
+  STRINGPAIR(PW_ACCT_SESSION_ID, sessionid);
+  if(proto=='P') {
+    INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER);
+    INTPAIR(PW_FRAMED_PROTOCOL, PW_PPP);
+  } else if(proto=='S') {
+    INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER);
+    INTPAIR(PW_FRAMED_PROTOCOL, PW_SLIP);
+  } else {
+    INTPAIR(PW_SERVICE_TYPE, PW_LOGIN_USER); /* A guess, really */
+  }
+  if(cliaddr)
+    IPPAIR(PW_FRAMED_IP_ADDRESS, cliaddr);
+  INTPAIR(PW_ACCT_SESSION_TIME, 0);
+  INTPAIR(PW_ACCT_INPUT_OCTETS, 0);
+  INTPAIR(PW_ACCT_OUTPUT_OCTETS, 0);
+  INTPAIR(PW_ACCT_INPUT_PACKETS, 0);
+  INTPAIR(PW_ACCT_OUTPUT_PACKETS, 0);
+
+  memset(&stopreq, 0, sizeof stopreq);
+  stopreq.packet=&stoppkt;
+  stopreq.proxy=0;
+  stopreq.reply=0;
+  stopreq.config_items=0;
+  stopreq.username=userpair;
+  stopreq.child_pid=-1;
+  stopreq.timestamp=stoppkt.timestamp;
+  stopreq.next=0;
+
+  /* FIXME: Need to run preaccouting, so replication can work */
+  modret = module_accounting(&stopreq);
+  if(modret==RLM_MODULE_NOOP ||
+     modret==RLM_MODULE_OK ||
+     modret==RLM_MODULE_UPDATED ||
+     modret==RLM_MODULE_HANDLED)
+    ret=1;
+  else
+    ret=0;
+
+  pairfree(stoppkt.vps);
+  return ret;
+}
+
+
+/*
+ *     Timeout handler (10 secs)
+ */
+static volatile int got_alrm;
+static void alrm_handler(int s)
+{
+       (void)s;
+       got_alrm = 1;
+}
+
+/*
+ *     Check one terminal server to see if a user is logged in.
+ */
+int rad_check_ts(uint32_t nasaddr, int portnum, const char *user,
+                const char *session_id)
+{
+       int     pid, st, e;
+       int     n;
+       NAS     *nas;
+       char    address[16];
+       char    port[8];
+       void    (*handler)(int);
+
+       /*
+        *      Find NAS type.
+        */
+       if ((nas = nas_find(nasaddr)) == NULL) {
+               radlog(L_ERR, "Accounting: unknown NAS");
+               return -1;
+       }
+
+       /*
+        *      Fork.
+        */
+       handler = signal(SIGCHLD, SIG_DFL);
+       if ((pid = fork()) < 0) {
+               radlog(L_ERR, "Accounting: fork: %s", strerror(errno));
+               signal(SIGCHLD, handler);
+               return -1;
+       }
+
+       if (pid > 0) {
+               /*
+                *      Parent - Wait for checkrad to terminate.
+                *      We timeout in 10 seconds.
+                */
+               got_alrm = 0;
+               signal(SIGALRM, alrm_handler);
+               alarm(10);
+               while((e = waitpid(pid, &st, 0)) != pid)
+                       if (e < 0 && (errno != EINTR || got_alrm))
+                               break;
+               alarm(0);
+               signal(SIGCHLD, handler);
+               if (got_alrm) {
+                       kill(pid, SIGTERM);
+                       sleep(1);
+                       kill(pid, SIGKILL);
+                       radlog(L_ERR, "Check-TS: timeout waiting for checkrad");
+                       return 2;
+               }
+               if (e < 0) {
+                       radlog(L_ERR, "Check-TS: unknown error in waitpid()");
+                       return 2;
+               }
+               return WEXITSTATUS(st);
+       }
+
+       /*
+        *      Child - exec checklogin with the right parameters.
+        */
+       for (n = 32; n >= 3; n--)
+               close(n);
+
+       ip_ntoa(address, nasaddr);
+       sprintf(port, "%d", portnum);
+
+#ifdef __EMX__
+       /* OS/2 can't directly execute scripts then we call the command
+          processor to execute checkrad
+       */
+       execl(getenv("COMSPEC"), "", "/C","checkrad",nas->nastype, address, port,
+               user, session_id, NULL);
+#else
+       execl(CHECKRAD, "checkrad",nas->nastype, address, port,
+               user, session_id, NULL);
+#endif
+       radlog(L_ERR, "Check-TS: exec %s: %s", CHECKRAD, strerror(errno));
+
+       /*
+        *      Exit - 2 means "some error occured".
+        */
+       exit(2);
+}
index 42e627f..93d2394 100644 (file)
@@ -221,6 +221,7 @@ module_t rlm_acct_unique = {
   NULL,                                /* authentication */
   NULL,                                /* preaccounting */
   unique_accounting,           /* accounting */
+  NULL,                                /* checksimul */
   unique_detach,                               /* detach */
   NULL,                                /* destroy */
 };
index 49debab..1b23b0e 100644 (file)
@@ -219,6 +219,7 @@ module_t rlm_detail = {
        NULL,                           /* authentication */
        NULL,                           /* preaccounting */
        detail_accounting,              /* accounting */
+       NULL,                           /* checksimul */
        detail_detach,                  /* detach */
        NULL                            /* destroy */
 };
index 1df60db..8a05636 100644 (file)
@@ -40,6 +40,7 @@ module_t rlm_dictionary = {
        NULL,                           /* authentication */
        NULL,                           /* preaccounting */
        NULL,                           /* accounting */
+       NULL,                           /* checksimul */
        NULL,                           /* detach */
        NULL                            /* destroy */
 };
index 339037d..dd8eda9 100644 (file)
@@ -157,6 +157,25 @@ static int radius_accounting(void *instance, REQUEST *request)
        return RLM_MODULE_OK;
 }
 
+/*
+ *     See if a user is already logged in. Sets request->simul_count to the
+ *     current session count for this user and sets request->simul_mpp to 2
+ *     if it looks like a multilink attempt based on the requested IP
+ *     address, otherwise leaves request->simul_mpp alone.
+ *
+ *     Check twice. If on the first pass the user exceeds his
+ *     max. number of logins, do a second pass and validate all
+ *     logins by querying the terminal server (using eg. SNMP).
+ */
+static int radius_checksimul(void *instance, REQUEST *request)
+{
+  instance = instance;
+
+  request->simul_count=0;
+
+  return RLM_MODULE_OK;
+}
+
 static int radius_detach(void *instance)
 {
        free(((struct example_config_t *)instance)->string);
@@ -174,6 +193,7 @@ module_t rlm_example = {
        radius_authenticate,            /* authentication */
        radius_preacct,                 /* preaccounting */
        radius_accounting,              /* accounting */
+       radius_checksimul,              /* checksimul */
        radius_detach,                  /* detach */
        NULL,                           /* destroy */
 };
index 1861f20..54e0523 100644 (file)
@@ -731,6 +731,7 @@ module_t rlm_files = {
        file_authenticate,              /* authentication */
        file_preacct,                   /* preaccounting */
        NULL,                           /* accounting */
+       NULL,                           /* checksimul */
        file_detach,                    /* detach */
        NULL                            /* destroy */
 };
index f18f156..76ee305 100644 (file)
@@ -846,6 +846,7 @@ module_t rlm_ldap = {
   rlm_ldap_authenticate,        /* authentication */
   NULL,                                /* preaccounting */
   NULL,                                /* accounting */
+  NULL,                        /* checksimul */
   rlm_ldap_detach,             /* detach */
   NULL,                                /* destroy */
 };
index 383dc39..3a916f9 100644 (file)
@@ -214,6 +214,7 @@ module_t rlm_pam = {
   pam_auth,                    /* authenticate */
   NULL,                                /* pre-accounting */
   NULL,                                /* accounting */
+  NULL,                                /* checksimul */
   NULL,                                /* detach */
   NULL,                                /* destroy */
 };
index 1a55184..9a558a7 100644 (file)
@@ -595,6 +595,7 @@ module_t rlm_preprocess = {
        NULL,                           /* authentication */
        preprocess_preaccounting,       /* pre-accounting */
        NULL,                           /* accounting */
+       NULL,                           /* checksimul */
        NULL,                           /* detach */
        preprocess_destroy,             /* destroy */
 };
index 09becc4..57d60ad 100644 (file)
@@ -220,6 +220,7 @@ module_t rlm_realm = {
   NULL,                                /* authentication */
   realm_preacct,               /* preaccounting */
   NULL,                                /* accounting */
+  NULL,                                /* checksimul */
   NULL,                                /* detach */
   NULL,                                /* destroy */
 };
index 9093288..f3a9c3a 100644 (file)
@@ -389,6 +389,7 @@ module_t rlm_sql = {
   rlm_sql_authenticate,        /* authentication */
   NULL,                        /* preaccounting */
   rlm_sql_accounting,  /* accounting */
+  NULL,                        /* checksimul */
   NULL,                        /* detach */
   rlm_sql_destroy,     /* destroy */
 };
index 16ff9f0..110613d 100644 (file)
@@ -580,6 +580,7 @@ module_t rlm_unix = {
   unix_authenticate,            /* authentication */
   NULL,                         /* preaccounting */
   unix_accounting,              /* accounting */
+  NULL,                        /* checksimul */
   unix_detach,                         /* detach */
   unix_destroy,                  /* destroy */
 };