Enable building #WITHOUT_PROXY
[freeradius.git] / src / modules / rlm_files / rlm_files.c
index 7c1fa52..e0bc59a 100644 (file)
  *
  *   You should have received a copy of the GNU General Public License
  *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  *
- * Copyright 2002  The FreeRADIUS server project
+ * Copyright 2002,2006  The FreeRADIUS server project
  * Copyright 2000  Jeff Carneal <jeff@apex.net>
  */
 
-static const char rcsid[] = "$Id$";
+#include       <freeradius-devel/ident.h>
+RCSID("$Id$")
 
-#include       <freeradius-devel/autoconf.h>
-
-#include       <sys/stat.h>
+#include       <freeradius-devel/radiusd.h>
+#include       <freeradius-devel/modules.h>
 
-#include       <stdlib.h>
-#include       <string.h>
-#include       <netdb.h>
 #include       <ctype.h>
 #include       <fcntl.h>
 #include       <limits.h>
 
-#include       <freeradius-devel/radiusd.h>
-#include       <freeradius-devel/modules.h>
-
 struct file_instance {
        char *compat_mode;
 
+       char *key;
+
        /* autz */
        char *usersfile;
-       PAIR_LIST *users;
+       fr_hash_table_t *users;
+
+
+       /* authenticate */
+       char *auth_usersfile;
+       fr_hash_table_t *auth_users;
 
        /* preacct */
        char *acctusersfile;
-       PAIR_LIST *acctusers;
+       fr_hash_table_t *acctusers;
 
+#ifdef WITH_PROXY
        /* pre-proxy */
        char *preproxy_usersfile;
-       PAIR_LIST *preproxy_users;
-
-       /* authenticate */
-       char *auth_usersfile;
-       PAIR_LIST *auth_users;
+       fr_hash_table_t *preproxy_users;
 
        /* post-proxy */
        char *postproxy_usersfile;
-       PAIR_LIST *postproxy_users;
+       fr_hash_table_t *postproxy_users;
+#endif
 
        /* post-authenticate */
        char *postauth_usersfile;
-       PAIR_LIST *postauth_users;
+       fr_hash_table_t *postauth_users;
 };
 
+
 /*
  *     See if a VALUE_PAIR list contains Fall-Through = Yes
  */
 static int fallthrough(VALUE_PAIR *vp)
 {
        VALUE_PAIR *tmp;
-       tmp = pairfind(vp, PW_FALL_THROUGH);
+       tmp = pairfind(vp, PW_FALL_THROUGH, 0);
 
-       return tmp ? tmp->lvalue : 0;
+       return tmp ? tmp->vp_integer : 0;
 }
 
 static const CONF_PARSER module_config[] = {
@@ -81,26 +81,54 @@ static const CONF_PARSER module_config[] = {
          offsetof(struct file_instance,usersfile), NULL, NULL },
        { "acctusersfile", PW_TYPE_FILENAME,
          offsetof(struct file_instance,acctusersfile), NULL, NULL },
+#ifdef WITH_PROXY
        { "preproxy_usersfile", PW_TYPE_FILENAME,
          offsetof(struct file_instance,preproxy_usersfile), NULL, NULL },
-       { "auth_usersfile", PW_TYPE_FILENAME,
-         offsetof(struct file_instance,auth_usersfile), NULL, NULL },
        { "postproxy_usersfile", PW_TYPE_FILENAME,
          offsetof(struct file_instance,postproxy_usersfile), NULL, NULL },
+#endif
+       { "auth_usersfile", PW_TYPE_FILENAME,
+         offsetof(struct file_instance,auth_usersfile), NULL, NULL },
        { "postauth_usersfile", PW_TYPE_FILENAME,
          offsetof(struct file_instance,postauth_usersfile), NULL, NULL },
        { "compat",        PW_TYPE_STRING_PTR,
          offsetof(struct file_instance,compat_mode), NULL, "cistron" },
+       { "key",           PW_TYPE_STRING_PTR,
+         offsetof(struct file_instance,key), NULL, NULL },
        { NULL, -1, 0, NULL, NULL }
 };
 
-static int getusersfile(const char *filename, PAIR_LIST **pair_list, char *compat_mode_str)
+
+static uint32_t pairlist_hash(const void *data)
+{
+       return fr_hash_string(((const PAIR_LIST *)data)->name);
+}
+
+static int pairlist_cmp(const void *a, const void *b)
+{
+       return strcmp(((const PAIR_LIST *)a)->name,
+                     ((const PAIR_LIST *)b)->name);
+}
+
+static void my_pairlist_free(void *data)
+{
+       PAIR_LIST *pl = data;
+
+       pairlist_free(&pl);
+}
+
+
+static int getusersfile(const char *filename, fr_hash_table_t **pht,
+                       char *compat_mode_str)
 {
        int rcode;
        PAIR_LIST *users = NULL;
+       PAIR_LIST *entry, *next;
+       fr_hash_table_t *ht, *tailht;
+       int order = 0;
 
        if (!filename) {
-               *pair_list = NULL;
+               *pht = NULL;
                return 0;
        }
 
@@ -115,7 +143,6 @@ static int getusersfile(const char *filename, PAIR_LIST **pair_list, char *compa
         */
        if ((debug_flag) ||
            (strcmp(compat_mode_str, "cistron") == 0)) {
-               PAIR_LIST *entry;
                VALUE_PAIR *vp;
                int compat_mode = FALSE;
 
@@ -152,7 +179,7 @@ static int getusersfile(const char *filename, PAIR_LIST **pair_list, char *compa
                                 *      or it's a wire protocol,
                                 *      ensure it has '=='.
                                 */
-                               if (((vp->attribute & ~0xffff) != 0) ||
+                               if ((vp->vendor != 0) ||
                                                (vp->attribute < 0x100)) {
                                        if (!compat_mode) {
                                                DEBUG("[%s]:%d WARNING! Changing '%s =' to '%s =='\n\tfor comparing RADIUS attribute in check item list for user %s",
@@ -198,7 +225,6 @@ static int getusersfile(const char *filename, PAIR_LIST **pair_list, char *compa
 
                        } /* end of loop over check items */
 
-
                        /*
                         *      Look for server configuration items
                         *      in the reply list.
@@ -214,7 +240,7 @@ static int getusersfile(const char *filename, PAIR_LIST **pair_list, char *compa
                                 *      then bitch about it, giving a
                                 *      good warning message.
                                 */
-                               if (!(vp->attribute & ~0xffff) &&
+                                if ((vp->vendor == 0) &&
                                        (vp->attribute > 0xff) &&
                                        (vp->attribute > 1000)) {
                                        log_debug("[%s]:%d WARNING! Check item \"%s\"\n"
@@ -231,7 +257,62 @@ static int getusersfile(const char *filename, PAIR_LIST **pair_list, char *compa
 
        }
 
-       *pair_list = users;
+       ht = fr_hash_table_create(pairlist_hash, pairlist_cmp,
+                                   my_pairlist_free);
+       if (!ht) {
+               pairlist_free(&users);
+               return -1;
+       }
+
+       tailht = fr_hash_table_create(pairlist_hash, pairlist_cmp,
+                                       NULL);
+       if (!tailht) {
+               fr_hash_table_free(ht);
+               pairlist_free(&users);
+               return -1;
+       }
+
+       /*
+        *      Now that we've read it in, put the entries into a hash
+        *      for faster access.
+        */
+       for (entry = users; entry != NULL; entry = next) {
+               PAIR_LIST *tail;
+
+               next = entry->next;
+               entry->next = NULL;
+               entry->order = order++;
+
+               /*
+                *      Insert it into the hash table, and remember
+                *      the tail of the linked list.
+                */
+               tail = fr_hash_table_finddata(tailht, entry);
+               if (!tail) {
+                       /*
+                        *      Insert it into the head & tail.
+                        */
+                       if (!fr_hash_table_insert(ht, entry) ||
+                           !fr_hash_table_insert(tailht, entry)) {
+                               pairlist_free(&next);
+                               fr_hash_table_free(ht);
+                               fr_hash_table_free(tailht);
+                               return -1;
+                       }
+               } else {
+                       tail->next = entry;
+                       if (!fr_hash_table_replace(tailht, entry)) {
+                               pairlist_free(&next);
+                               fr_hash_table_free(ht);
+                               fr_hash_table_free(tailht);
+                               return -1;
+                       }
+               }
+       }
+
+       fr_hash_table_free(tailht);
+       *pht = ht;
+
        return 0;
 }
 
@@ -241,19 +322,14 @@ static int getusersfile(const char *filename, PAIR_LIST **pair_list, char *compa
 static int file_detach(void *instance)
 {
        struct file_instance *inst = instance;
-       pairlist_free(&inst->users);
-       pairlist_free(&inst->acctusers);
-       pairlist_free(&inst->preproxy_users);
-       pairlist_free(&inst->auth_users);
-       pairlist_free(&inst->postproxy_users);
-       pairlist_free(&inst->postauth_users);
-       free(inst->usersfile);
-       free(inst->acctusersfile);
-       free(inst->preproxy_usersfile);
-       free(inst->auth_usersfile);
-       free(inst->postproxy_usersfile);
-       free(inst->postauth_usersfile);
-       free(inst->compat_mode);
+       fr_hash_table_free(inst->users);
+       fr_hash_table_free(inst->acctusers);
+#ifdef WITH_PROXY
+       fr_hash_table_free(inst->preproxy_users);
+       fr_hash_table_free(inst->postproxy_users);
+#endif
+       fr_hash_table_free(inst->auth_users);
+       fr_hash_table_free(inst->postauth_users);
        free(inst);
        return 0;
 }
@@ -281,7 +357,7 @@ static int file_instantiate(CONF_SECTION *conf, void **instance)
 
        rcode = getusersfile(inst->usersfile, &inst->users, inst->compat_mode);
        if (rcode != 0) {
-               radlog(L_ERR|L_CONS, "Errors reading %s", inst->usersfile);
+         radlog(L_ERR|L_CONS, "Errors reading %s", inst->usersfile);
                file_detach(inst);
                return -1;
        }
@@ -293,6 +369,7 @@ static int file_instantiate(CONF_SECTION *conf, void **instance)
                return -1;
        }
 
+#ifdef WITH_PROXY
        /*
         *  Get the pre-proxy stuff
         */
@@ -303,16 +380,17 @@ static int file_instantiate(CONF_SECTION *conf, void **instance)
                return -1;
        }
 
-       rcode = getusersfile(inst->auth_usersfile, &inst->auth_users, inst->compat_mode);
+       rcode = getusersfile(inst->postproxy_usersfile, &inst->postproxy_users, inst->compat_mode);
        if (rcode != 0) {
-               radlog(L_ERR|L_CONS, "Errors reading %s", inst->auth_usersfile);
+               radlog(L_ERR|L_CONS, "Errors reading %s", inst->postproxy_usersfile);
                file_detach(inst);
                return -1;
        }
+#endif
 
-       rcode = getusersfile(inst->postproxy_usersfile, &inst->postproxy_users, inst->compat_mode);
+       rcode = getusersfile(inst->auth_usersfile, &inst->auth_users, inst->compat_mode);
        if (rcode != 0) {
-               radlog(L_ERR|L_CONS, "Errors reading %s", inst->postproxy_usersfile);
+               radlog(L_ERR|L_CONS, "Errors reading %s", inst->auth_usersfile);
                file_detach(inst);
                return -1;
        }
@@ -332,42 +410,78 @@ static int file_instantiate(CONF_SECTION *conf, void **instance)
  *     Common code called by everything below.
  */
 static int file_common(struct file_instance *inst, REQUEST *request,
-                      const char *filename, const PAIR_LIST *list,
+                      const char *filename, fr_hash_table_t *ht,
                       VALUE_PAIR *request_pairs, VALUE_PAIR **reply_pairs)
 {
-       VALUE_PAIR      *namepair;
-       const char      *name;
+       const char      *name, *match;
        VALUE_PAIR      **config_pairs;
        VALUE_PAIR      *check_tmp;
        VALUE_PAIR      *reply_tmp;
-       const PAIR_LIST *pl;
+       const PAIR_LIST *user_pl, *default_pl;
        int             found = 0;
+       PAIR_LIST       my_pl;
+       char            buffer[256];
 
-       inst = inst;            /* -Wunused fix later? */
+       if (!inst->key) {
+               VALUE_PAIR      *namepair;
+
+               namepair = request->username;
+               name = namepair ? (char *) namepair->vp_strvalue : "NONE";
+       } else {
+               int len;
+
+               len = radius_xlat(buffer, sizeof(buffer), inst->key,
+                                 request, NULL);
+               if (len) name = buffer;
+               else name = "NONE";
+       }
 
-       namepair = request->username;
-       name = namepair ? (char *) namepair->vp_strvalue : "NONE";
        config_pairs = &request->config_items;
 
-       if (!list) return RLM_MODULE_NOOP;
+       if (!ht) return RLM_MODULE_NOOP;
+
+       my_pl.name = name;
+       user_pl = fr_hash_table_finddata(ht, &my_pl);
+       my_pl.name = "DEFAULT";
+       default_pl = fr_hash_table_finddata(ht, &my_pl);
 
        /*
         *      Find the entry for the user.
         */
-       for (pl = list; pl; pl = pl->next) {
-               if (strcmp(name, pl->name) && strcmp(pl->name, "DEFAULT"))
-                       continue;
+       while (user_pl || default_pl) {
+               const PAIR_LIST *pl;
+
+               if (!default_pl && user_pl) {
+                       pl = user_pl;
+                       match = name;
+                       user_pl = user_pl->next;
+
+               } else if (!user_pl && default_pl) {
+                       pl = default_pl;
+                       match = "DEFAULT";
+                       default_pl = default_pl->next;
+
+               } else if (user_pl->order < default_pl->order) {
+                       pl = user_pl;
+                       match = name;
+                       user_pl = user_pl->next;
+
+               } else {
+                       pl = default_pl;
+                       match = "DEFAULT";
+                       default_pl = default_pl->next;
+               }
 
                if (paircompare(request, request_pairs, pl->check, reply_pairs) == 0) {
-                       DEBUG2("    %s: Matched entry %s at line %d",
-                              filename, pl->name, pl->lineno);
+                       RDEBUG2("%s: Matched entry %s at line %d",
+                              filename, match, pl->lineno);
                        found = 1;
                        check_tmp = paircopy(pl->check);
                        reply_tmp = paircopy(pl->reply);
                        pairxlatmove(request, reply_pairs, &reply_tmp);
                        pairmove(config_pairs, &check_tmp);
                        pairfree(&reply_tmp);
-                       pairfree(&check_tmp); /* should be NULL */
+                       pairfree(&check_tmp);
 
                        /*
                         *      Fallthrough?
@@ -380,7 +494,7 @@ static int file_common(struct file_instance *inst, REQUEST *request,
        /*
         *      Remove server internal parameters.
         */
-       pairdelete(reply_pairs, PW_FALL_THROUGH);
+       pairdelete(reply_pairs, PW_FALL_THROUGH, 0);
 
        /*
         *      See if we succeeded.
@@ -421,6 +535,7 @@ static int file_preacct(void *instance, REQUEST *request)
                           request->packet->vps, &request->reply->vps);
 }
 
+#ifdef WITH_PROXY
 static int file_preproxy(void *instance, REQUEST *request)
 {
        struct file_instance *inst = instance;
@@ -438,6 +553,7 @@ static int file_postproxy(void *instance, REQUEST *request)
                           inst->postproxy_users,
                           request->proxy_reply->vps, &request->reply->vps);
 }
+#endif
 
 static int file_authenticate(void *instance, REQUEST *request)
 {
@@ -462,7 +578,7 @@ static int file_postauth(void *instance, REQUEST *request)
 module_t rlm_files = {
        RLM_MODULE_INIT,
        "files",
-       0,                              /* type: reserved */
+       RLM_TYPE_CHECK_CONFIG_SAFE | RLM_TYPE_HUP_SAFE,
        file_instantiate,               /* instantiation */
        file_detach,                    /* detach */
        {
@@ -471,8 +587,12 @@ module_t rlm_files = {
                file_preacct,           /* preaccounting */
                NULL,                   /* accounting */
                NULL,                   /* checksimul */
+#ifdef WITH_PROXY
                file_preproxy,          /* pre-proxy */
                file_postproxy,         /* post-proxy */
+#else
+               NULL, NULL,
+#endif
                file_postauth           /* post-auth */
        },
 };