#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;
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;
}
/*
{
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;
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;
}
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
* 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.
/*
* 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. */
/*