From f83c4c45005f94193f146ff8460c22644f008f75 Mon Sep 17 00:00:00 2001 From: venaas Date: Tue, 29 May 2007 12:27:33 +0000 Subject: support quoting of values, realm matching literal or regexp with / prefixing a regexp git-svn-id: https://svn.testnett.uninett.no/radsecproxy/trunk@108 e88ac4ed-0b26-0410-9574-a7f39faa03bf --- radsecproxy.c | 89 ++++++++++++++++++++++++++++++++---------------- radsecproxy.conf-example | 20 ++++++----- 2 files changed, 72 insertions(+), 37 deletions(-) diff --git a/radsecproxy.c b/radsecproxy.c index 1eb84bb..107883f 100644 --- a/radsecproxy.c +++ b/radsecproxy.c @@ -1687,8 +1687,9 @@ int tlslistener() { } void addrealm(char *value, char *server) { - int i; + int i, n; struct realm *realm; + char *s, *regex = NULL; for (i = 0; i < server_count; i++) if (!strcasecmp(server, servers[i].peer.host)) @@ -1696,13 +1697,31 @@ void addrealm(char *value, char *server) { if (i == server_count) debugx(1, DBG_ERR, "addrealm failed, no server %s", server); - /* temporary warnings */ - if (*value == '*') - debugx(1, DBG_ERR, "Regexps are now used for specifying realms, a string\nstarting with '*' is meaningless, you probably want '.*' for matching everything\nEXITING\n"); - if (value[strlen(value) - 1] != '$' && value[strlen(value) - 1] != '*') { - debug(DBG_ERR, "Regexps are now used for specifying realms, you\nprobably want to rewrite this as e.g. '@example\\.com$' or '\\.com$'\nYou can even do things like '^[a-n].*@example\\.com$' to make about half of the\nusers use this server. Note that the matching is case insensitive.\n"); - sleep(3); + if (*value != '/') { + /* not a regexp, let us make it one */ + if (*value == '*' && !value[1]) + regex = stringcopy(".*", 0); + else { + for (n = 0, s = value; *s;) + if (*s++ == '.') + n++; + regex = malloc(strlen(value) + n + 3); + if (regex) { + regex[0] = '@'; + for (n = 1, s = value; *s; s++) { + if (*s == '.') + regex[n++] = '\\'; + regex[n++] = *s; + } + regex[n++] = '$'; + regex[n] = '\0'; + } + } + if (!regex) + debugx(1, DBG_ERR, "malloc failed"); + debug(DBG_DBG, "addrealm: constructed regexp %s from %s", regex, value); } + realm_count++; realms = realloc(realms, realm_count * sizeof(struct realm)); if (!realms) @@ -1710,9 +1729,13 @@ void addrealm(char *value, char *server) { realm = realms + realm_count - 1; memset(realm, 0, sizeof(struct realm)); realm->name = stringcopy(value, 0); + if (!realm->name) + debugx(1, DBG_ERR, "malloc failed"); realm->server = servers + i; - if (regcomp(&realm->regex, value, REG_ICASE | REG_NOSUB)) - debugx(1, DBG_ERR, "addrealm: failed to compile regular expression %s", value); + if (regcomp(&realm->regex, regex ? regex : value + 1, REG_ICASE | REG_NOSUB)) + debugx(1, DBG_ERR, "addrealm: failed to compile regular expression %s", regex ? regex : value + 1); + if (regex) + free(regex); debug(DBG_DBG, "addrealm: added realm %s for server %s", value, server); } @@ -1977,36 +2000,35 @@ struct peer *server_create(char type) { return server; } -/* returns 0 on error, 1 if ok. E.g. "" will return token with empty string */ -int strtokenquote(char *s, char **token, char *del, char *quote, char *comment) { - char *t = s, *q; +/* returns NULL on error, where to continue parsing if token and ok. E.g. "" will return token with empty string */ +char *strtokenquote(char *s, char **token, char *del, char *quote) { + char *t = s, *q, *r; if (!t || !token || !del) - return 0; - while (strchr(del, *t)) + return NULL; + while (*t && strchr(del, *t)) t++; - if (!*t || comment && strchr(comment, *t)) { + if (!*t) { *token = NULL; - return 1; + return t + 1; /* needs to be non-NULL, but value doesn't matter */ } if (quote && (q = strchr(quote, *t))) { t++; + r = t; while (*t && *t != *q) t++; - if (!*t) - return 0; - if (t[1] && !strchr(del, t[1])) - return 0; + if (!*t || (t[1] && !strchr(del, t[1]))) + return NULL; *t = '\0'; - *token = q + 1; - return 1; + *token = r; + return t + 1; } *token = t; t++; while (*t && !strchr(del, *t)) t++; *t = '\0'; - return 1; + return t + 1; } /* Parses config with following syntax: @@ -2023,17 +2045,23 @@ void getgeneralconfig(FILE *f, char *block, ...) { va_list ap; char line[1024]; /* initialise lots of stuff to avoid stupid compiler warnings */ - char *tokens[3], *opt = NULL, *val = NULL, *word, **str = NULL; + char *tokens[3], *s, *opt = NULL, *val = NULL, *word, **str = NULL; int type = 0, tcount, conftype = 0; void (*cbk)(FILE *, char *, char *) = NULL; while (fgets(line, 1024, f)) { - tokens[0] = strtok(line, " \t\n"); - if (!*tokens || **tokens == '#') + s = line; + for (tcount = 0; tcount < 3; tcount++) { + s = strtokenquote(s, &tokens[tcount], " \t\n", "\"'"); + if (!s) + debugx(1, DBG_ERR, "Syntax error in line starting with: %s", line); + if (!tokens[tcount]) + break; + } + if (!tcount || **tokens == '#') continue; - for (tcount = 1; tcount < 3 && (tokens[tcount] = strtok(NULL, " \t\n")); tcount++); - - if (tcount && **tokens == '}') { + + if (**tokens == '}') { if (block) return; debugx(1, DBG_ERR, "configuration error, found } with no matching {"); @@ -2065,6 +2093,9 @@ void getgeneralconfig(FILE *f, char *block, ...) { debugx(1, DBG_ERR, "configuration error, syntax error in line starting with %s", tokens[0]); } + if (!*val) + debugx(1, DBG_ERR, "configuration error, option %s needs a non-empty value", opt); + va_start(ap, block); while ((word = va_arg(ap, char *))) { type = va_arg(ap, int); diff --git a/radsecproxy.conf-example b/radsecproxy.conf-example index 27cc176..6cda59e 100644 --- a/radsecproxy.conf-example +++ b/radsecproxy.conf-example @@ -33,12 +33,14 @@ TLSCertificateKeyPassword follow the white rabbit #also the lines above may be in any order, except that a realm #can only be configured to use a server that is previously configured. -#Also note that case insensitive regexp is used for realms, matching -#the entire username string. The matching is done in the order the -#realms are specified, using the first match found. Some examples are +#A realm can be a literal domain name, * which matches all, or a +#regexp. A regexp is specified by the character prefix / +#For regexp we do case insensitive matching of the entire username string. +#The matching of realms is done in the order they are specified, using the +#first match found. Some examples are #"@example\.com$", "\.com$", ".*" and "^[a-z].*@example\.com$". #To treat local users separately you might try first specifying "@" -#and after that ".*". +#and after that "*". client 2001:db8::1 { type tls @@ -57,7 +59,7 @@ server 127.0.0.1 { type UDP secret secret } -realm @eduroam\.cc$ { +realm eduroam.cc { server 127.0.0.1 } @@ -73,12 +75,14 @@ server radius.example.com { # statusserver is optional, can be on or off. Off is default } -realm @example\.com$ { +# Equivalent to example.com +realm /@example\.com$ { server 2001:db8::1 } -realm \.com$ { +realm /\.com$ { server 2001:db8::1 } -realm .* { +# The realm below is equivalent to /.* +realm * { server radius.example.com } -- cgit v1.1