Commit f83c4c45 authored by venaas's avatar venaas Committed by venaas

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
parent 25cada62
...@@ -1687,8 +1687,9 @@ int tlslistener() { ...@@ -1687,8 +1687,9 @@ int tlslistener() {
} }
void addrealm(char *value, char *server) { void addrealm(char *value, char *server) {
int i; int i, n;
struct realm *realm; struct realm *realm;
char *s, *regex = NULL;
for (i = 0; i < server_count; i++) for (i = 0; i < server_count; i++)
if (!strcasecmp(server, servers[i].peer.host)) if (!strcasecmp(server, servers[i].peer.host))
...@@ -1696,13 +1697,31 @@ void addrealm(char *value, char *server) { ...@@ -1696,13 +1697,31 @@ void addrealm(char *value, char *server) {
if (i == server_count) if (i == server_count)
debugx(1, DBG_ERR, "addrealm failed, no server %s", server); debugx(1, DBG_ERR, "addrealm failed, no server %s", server);
/* temporary warnings */ if (*value != '/') {
if (*value == '*') /* not a regexp, let us make it one */
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 == '*' && !value[1])
if (value[strlen(value) - 1] != '$' && value[strlen(value) - 1] != '*') { regex = stringcopy(".*", 0);
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"); else {
sleep(3); 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++; realm_count++;
realms = realloc(realms, realm_count * sizeof(struct realm)); realms = realloc(realms, realm_count * sizeof(struct realm));
if (!realms) if (!realms)
...@@ -1710,9 +1729,13 @@ void addrealm(char *value, char *server) { ...@@ -1710,9 +1729,13 @@ void addrealm(char *value, char *server) {
realm = realms + realm_count - 1; realm = realms + realm_count - 1;
memset(realm, 0, sizeof(struct realm)); memset(realm, 0, sizeof(struct realm));
realm->name = stringcopy(value, 0); realm->name = stringcopy(value, 0);
if (!realm->name)
debugx(1, DBG_ERR, "malloc failed");
realm->server = servers + i; realm->server = servers + i;
if (regcomp(&realm->regex, value, REG_ICASE | REG_NOSUB)) if (regcomp(&realm->regex, regex ? regex : value + 1, REG_ICASE | REG_NOSUB))
debugx(1, DBG_ERR, "addrealm: failed to compile regular expression %s", value); 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); debug(DBG_DBG, "addrealm: added realm %s for server %s", value, server);
} }
...@@ -1977,36 +2000,35 @@ struct peer *server_create(char type) { ...@@ -1977,36 +2000,35 @@ struct peer *server_create(char type) {
return server; return server;
} }
/* returns 0 on error, 1 if ok. E.g. "" will return token with empty string */ /* returns NULL on error, where to continue parsing if token and ok. E.g. "" will return token with empty string */
int strtokenquote(char *s, char **token, char *del, char *quote, char *comment) { char *strtokenquote(char *s, char **token, char *del, char *quote) {
char *t = s, *q; char *t = s, *q, *r;
if (!t || !token || !del) if (!t || !token || !del)
return 0; return NULL;
while (strchr(del, *t)) while (*t && strchr(del, *t))
t++; t++;
if (!*t || comment && strchr(comment, *t)) { if (!*t) {
*token = NULL; *token = NULL;
return 1; return t + 1; /* needs to be non-NULL, but value doesn't matter */
} }
if (quote && (q = strchr(quote, *t))) { if (quote && (q = strchr(quote, *t))) {
t++; t++;
r = t;
while (*t && *t != *q) while (*t && *t != *q)
t++; t++;
if (!*t) if (!*t || (t[1] && !strchr(del, t[1])))
return 0; return NULL;
if (t[1] && !strchr(del, t[1]))
return 0;
*t = '\0'; *t = '\0';
*token = q + 1; *token = r;
return 1; return t + 1;
} }
*token = t; *token = t;
t++; t++;
while (*t && !strchr(del, *t)) while (*t && !strchr(del, *t))
t++; t++;
*t = '\0'; *t = '\0';
return 1; return t + 1;
} }
/* Parses config with following syntax: /* Parses config with following syntax:
...@@ -2023,17 +2045,23 @@ void getgeneralconfig(FILE *f, char *block, ...) { ...@@ -2023,17 +2045,23 @@ void getgeneralconfig(FILE *f, char *block, ...) {
va_list ap; va_list ap;
char line[1024]; char line[1024];
/* initialise lots of stuff to avoid stupid compiler warnings */ /* 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; int type = 0, tcount, conftype = 0;
void (*cbk)(FILE *, char *, char *) = NULL; void (*cbk)(FILE *, char *, char *) = NULL;
while (fgets(line, 1024, f)) { while (fgets(line, 1024, f)) {
tokens[0] = strtok(line, " \t\n"); s = line;
if (!*tokens || **tokens == '#') 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; continue;
for (tcount = 1; tcount < 3 && (tokens[tcount] = strtok(NULL, " \t\n")); tcount++);
if (tcount && **tokens == '}') { if (**tokens == '}') {
if (block) if (block)
return; return;
debugx(1, DBG_ERR, "configuration error, found } with no matching {"); debugx(1, DBG_ERR, "configuration error, found } with no matching {");
...@@ -2065,6 +2093,9 @@ void getgeneralconfig(FILE *f, char *block, ...) { ...@@ -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]); 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); va_start(ap, block);
while ((word = va_arg(ap, char *))) { while ((word = va_arg(ap, char *))) {
type = va_arg(ap, int); type = va_arg(ap, int);
......
...@@ -33,12 +33,14 @@ TLSCertificateKeyPassword follow the white rabbit ...@@ -33,12 +33,14 @@ TLSCertificateKeyPassword follow the white rabbit
#also the lines above may be in any order, except that a realm #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. #can only be configured to use a server that is previously configured.
#Also note that case insensitive regexp is used for realms, matching #A realm can be a literal domain name, * which matches all, or a
#the entire username string. The matching is done in the order the #regexp. A regexp is specified by the character prefix /
#realms are specified, using the first match found. Some examples are #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$". #"@example\.com$", "\.com$", ".*" and "^[a-z].*@example\.com$".
#To treat local users separately you might try first specifying "@" #To treat local users separately you might try first specifying "@"
#and after that ".*". #and after that "*".
client 2001:db8::1 { client 2001:db8::1 {
type tls type tls
...@@ -57,7 +59,7 @@ server 127.0.0.1 { ...@@ -57,7 +59,7 @@ server 127.0.0.1 {
type UDP type UDP
secret secret secret secret
} }
realm @eduroam\.cc$ { realm eduroam.cc {
server 127.0.0.1 server 127.0.0.1
} }
...@@ -73,12 +75,14 @@ server radius.example.com { ...@@ -73,12 +75,14 @@ server radius.example.com {
# statusserver is optional, can be on or off. Off is default # 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 server 2001:db8::1
} }
realm \.com$ { realm /\.com$ {
server 2001:db8::1 server 2001:db8::1
} }
realm .* { # The realm below is equivalent to /.*
realm * {
server radius.example.com server radius.example.com
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment