Jeff Carneal <jeff@apex.net>
authorjcarneal <jcarneal>
Wed, 8 Nov 2000 17:07:20 +0000 (17:07 +0000)
committerjcarneal <jcarneal>
Wed, 8 Nov 2000 17:07:20 +0000 (17:07 +0000)
o Added function rad_cleandir() to sanitize directory input
o Added function rad_mkdir() to create all needed directories

src/modules/rlm_detail/rlm_detail.c

index a78902c..95f09e5 100644 (file)
@@ -22,13 +22,14 @@ static const char rcsid[] = "$Id$";
 
 #include       "radiusd.h"
 #include       "modules.h"
+#define        DIRLEN  8192
 
 struct detail_instance {
        /* detail file */
        const char *detailfile;
 
-        /* detail file permissions */
-        int detailperm;
+       /* detail file permissions */
+       int detailperm;
 
        /* directory permissions */
        int dirperm;
@@ -45,50 +46,120 @@ static struct detail_instance config;
 
 static CONF_PARSER module_config[] = {
        { "detailfile",    PW_TYPE_STRING_PTR, &config.detailfile, "%A/%n/detail" },
-        { "detailperm",    PW_TYPE_INTEGER,    &config.detailperm, "0600" },
+       { "detailperm",    PW_TYPE_INTEGER,    &config.detailperm, "0600" },
        { "dirperm",       PW_TYPE_INTEGER,    &config.dirperm,    "0755" },
        { NULL, -1, NULL, NULL }
 };
 
 /*
- *     (Re-)read radiusd.conf into memory.
+ *     Sanitize the name for security!  Only permit letters, numbers,
+ *     -, _, / and \.  Anything else will be rejected.
  */
-static int detail_instantiate(CONF_SECTION *conf, void **instance)
-{
-        struct detail_instance *inst;
+static int rad_cleandir(const char *dirbuf, int length) {
+
        size_t p=0;
 
-        inst = malloc(sizeof *inst);
-        if (!inst) {
-                radlog(L_ERR|L_CONS, "rlm_detail: Out of memory\n");
-                return -1;
-        }
+       DEBUG2("HERE:  %s", dirbuf);
+       if (strstr(dirbuf, "..")) {
+               radlog(L_ERR, "rlm_detail: Directory \"%s\" contains \"..\" which is not valid.",
+                       dirbuf);
+               return -1;
+       }
 
-        if (cf_section_parse(conf, module_config) < 0) {
-                free(inst);
-                return -1;
-        }
+       p = strspn(dirbuf, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_/%.");
+
+       if (p != length) {
+               radlog(L_ERR|L_CONS, "rlm_detail: Illegal character in detail filename.");
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * Make non-existant directories
+ * This function is admitedly ugly
+ */
+static char *rad_mkdir(const char *dirbuf, int perm) {
+       char *tmpbuf=0, *cur=0, *last=0;
+       int madeone = 0;
+       struct stat     st;
+
+       /* 
+        * We need a copy we can play with 
+        * so we make one here
+        */
+       tmpbuf = strdup(dirbuf);
 
        /*
-        *      Sanitize the name for security!  Only permit letters, numbers,
-        *      -, _, / and \.  Anything else will be rejected.
+        * We have to skip the first char if
+        * it's a '/'
         */
+       cur = tmpbuf;
+       if(*cur == '/')
+               cur++;
 
-       p = strspn(config.detailfile, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_/%.");
+       while((cur = strchr(cur, '/')) != NULL) {
+               *cur = '\0';
 
-       if (p != strlen(config.detailfile)) {
-               radlog(L_ERR|L_CONS, "rlm_detail: Illegal character in detail filename.");
+               /* 
+                * If the dir doesn't exist, make it
+                */
+               if((stat(tmpbuf, &st) < 0)) {
+                       DEBUG2("rad_mkdir:  Making %s", tmpbuf); 
+                       if ((mkdir(tmpbuf, perm) < 0) &&
+                                       (errno != EEXIST)) {
+                               radlog(L_ERR, "rlm_mkdir: Couldn't create %s: %s",
+                                                               tmpbuf, strerror(errno));
+                               return NULL;
+                       } else {
+                               madeone++;
+                        DEBUG2("rad_mkdir:  Made %s", tmpbuf); 
+                       }
+               }
+
+               *cur = '/';
+               last = cur;
+               cur++;
+       }
+       if(madeone) {
+               *last = '\0';
+               return tmpbuf;
+       } else {
+               return NULL;
+       }
+}
+
+/*
+ *     (Re-)read radiusd.conf into memory.
+ */
+static int detail_instantiate(CONF_SECTION *conf, void **instance)
+{
+       struct detail_instance *inst;
+
+       inst = malloc(sizeof *inst);
+       if (!inst) {
+               radlog(L_ERR|L_CONS, "rlm_detail: Out of memory\n");
                return -1;
        }
-                       
-        inst->detailfile = config.detailfile;
-        inst->detailperm = config.detailperm;
+
+       if (cf_section_parse(conf, module_config) < 0) {
+               free(inst);
+               return -1;
+       }
+
+       inst->detailfile = config.detailfile;
+       inst->detailperm = config.detailperm;
        inst->dirperm = config.dirperm;
        inst->last_made_directory = NULL;
        config.detailfile = NULL;
 
-        *instance = inst;
-        return 0;
+       if(rad_cleandir(inst->detailfile, strlen(inst->detailfile)) < 0) {
+               return -1;
+       }
+
+       *instance = inst;
+       return 0;
 }
 
 /*
@@ -98,9 +169,8 @@ static int detail_accounting(void *instance, REQUEST *request)
 {
        int             outfd;
        FILE            *outfp;
-       char            buffer[8192];
-       char            *p;
-       size_t          l;
+       char            buffer[DIRLEN];
+       char            *p, *lastdir;
        VALUE_PAIR      *pair;
        int             ret = RLM_MODULE_OK;
        struct stat     st;
@@ -118,22 +188,7 @@ static int detail_accounting(void *instance, REQUEST *request)
        radius_xlat2(buffer, sizeof(buffer), inst->detailfile, request,
                     request->reply->vps);
 
-       /*
-        *      Sanitize the name for security!  Only permit letters, numbers,
-        *      -, _, / and \.  Anything else will be rejected.
-        */
-
-       if (strstr(buffer, "..")) {
-               radlog(L_ERR, "rlm_detail: Directory \"%s\" contains \"..\" which is not valid.",
-                       buffer);
-               return RLM_MODULE_FAIL;
-       }
-
-       l = strspn(buffer, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_/.");
-
-       if (l != strlen(buffer)) {
-               radlog(L_ERR, "rlm_detail: Directory \"%s\" contains an invalid character.",
-                      buffer);
+       if(rad_cleandir(buffer, strlen(buffer)) < 0) {
                return RLM_MODULE_FAIL;
        }
                        
@@ -143,11 +198,11 @@ static int detail_accounting(void *instance, REQUEST *request)
        p = strrchr(buffer,'/');
 
        /*
-        *      There WAS a directory delimiter there, so let's
-        *      go create the relevant directories.
+        *      There WAS a directory delimiter there, and
+        *      the dir doesn't exist, so
+        *      we create it (them)
         */
-       if (p) {
-               *p = '\0';
+       if ((p) && (stat(buffer, &st) < 0)) {
                
                /*
                 *      NO previously cached directory name, so we've
@@ -160,8 +215,7 @@ static int detail_accounting(void *instance, REQUEST *request)
                 *      so we've got to create a new one.
                 */
                if ((inst->last_made_directory == NULL) ||
-                   (strcmp(inst->last_made_directory, buffer) != 0) ||
-                   (stat(buffer, &st) == -1)) {
+                   (strcmp(inst->last_made_directory, buffer) != 0)) { 
                        
                        /*
                         *      Free any previously cached name.
@@ -174,26 +228,15 @@ static int detail_accounting(void *instance, REQUEST *request)
                        /*
                         *      Try to create the new directory.
                         */
-                       if ((mkdir(buffer, inst->dirperm) == -1) &&
-                           (errno != EEXIST)) {
-                               radlog(L_ERR, "rlm_detail: Couldn't create %s: %s",
-                                      buffer, strerror(errno));
-                               
-                               return RLM_MODULE_FAIL;
+                       if((lastdir = rad_mkdir(buffer, inst->dirperm)) != NULL) {
+                               /*
+                                *      Save a copy of the directory name that
+                                *      we just created.
+                                */
+                               inst->last_made_directory = strdup(lastdir);
                        }
-                       
-                       /*
-                        *      Save a copy of the directory name that
-                        *      we just created.
-                        */
-                       inst->last_made_directory = strdup(buffer);
                }
                
-               /*
-                *      Re-create the file name, by replacing the
-                *      directory delimiter that we removed above.
-                */
-               *p = '/';
        } /* else there was no directory delimiter. */
 
        /*