Commit 604fcf38 authored by venaas's avatar venaas Committed by venaas
Browse files

refcounts for realms, rewritten some locking and subrealm stuff

git-svn-id: https://svn.testnett.uninett.no/radsecproxy/trunk@409 e88ac4ed-0b26-0410-9574-a7f39faa03bf
parent a1f132ae
...@@ -92,7 +92,7 @@ extern int optind; ...@@ -92,7 +92,7 @@ extern int optind;
extern char *optarg; extern char *optarg;
/* minimum required declarations to avoid reordering code */ /* minimum required declarations to avoid reordering code */
void adddynamicrealmserver(struct realm *realm, struct clsrvconf *conf, char *id); struct realm *adddynamicrealmserver(struct realm *realm, struct clsrvconf *conf, char *id);
int dynamicconfig(struct server *server); int dynamicconfig(struct server *server);
int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val); int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val);
void freerealm(struct realm *realm); void freerealm(struct realm *realm);
...@@ -898,7 +898,8 @@ unsigned char *attrget(unsigned char *attrs, int length, uint8_t type) { ...@@ -898,7 +898,8 @@ unsigned char *attrget(unsigned char *attrs, int length, uint8_t type) {
} }
struct request *newrqref(struct request *rq) { struct request *newrqref(struct request *rq) {
rq->refcount++; if (rq)
rq->refcount++;
return rq; return rq;
} }
...@@ -1244,19 +1245,30 @@ int msmppdecrypt(uint8_t *text, uint8_t len, uint8_t *shared, uint8_t sharedlen, ...@@ -1244,19 +1245,30 @@ int msmppdecrypt(uint8_t *text, uint8_t len, uint8_t *shared, uint8_t sharedlen,
return 1; return 1;
} }
struct realm *newrealmref(struct realm *r) {
if (r)
r->refcount++;
return r;
}
/* returns with lock on realm */
struct realm *id2realm(struct list *realmlist, char *id) { struct realm *id2realm(struct list *realmlist, char *id) {
struct list_node *entry; struct list_node *entry;
struct realm *realm, *subrealm = NULL; struct realm *realm, *subrealm;
/* need to do locking for subrealms and check subrealm timers */ /* need to do locking for subrealms and check subrealm timers */
for (entry = list_first(realmlist); entry; entry = list_next(entry)) { for (entry = list_first(realmlist); entry; entry = list_next(entry)) {
realm = (struct realm *)entry->data; realm = (struct realm *)entry->data;
if (!regexec(&realm->regex, id, 0, NULL, 0)) { if (!regexec(&realm->regex, id, 0, NULL, 0)) {
pthread_mutex_lock(&realm->subrealms_mutex); pthread_mutex_lock(&realm->mutex);
if (realm->subrealms) if (realm->subrealms) {
subrealm = id2realm(realm->subrealms, id); subrealm = id2realm(realm->subrealms, id);
pthread_mutex_unlock(&realm->subrealms_mutex); if (subrealm) {
return subrealm ? subrealm : realm; pthread_mutex_unlock(&realm->mutex);
return subrealm;
}
}
return newrealmref(realm);
} }
} }
return NULL; return NULL;
...@@ -1264,13 +1276,18 @@ struct realm *id2realm(struct list *realmlist, char *id) { ...@@ -1264,13 +1276,18 @@ struct realm *id2realm(struct list *realmlist, char *id) {
/* helper function, only used by removeserversubrealms() */ /* helper function, only used by removeserversubrealms() */
void _internal_removeserversubrealms(struct list *realmlist, struct clsrvconf *srv) { void _internal_removeserversubrealms(struct list *realmlist, struct clsrvconf *srv) {
struct list_node *entry; struct list_node *entry, *entry2;
struct realm *realm; struct realm *realm;
for (entry = list_first(realmlist); entry;) { for (entry = list_first(realmlist); entry;) {
realm = (struct realm *)entry->data; realm = newrealmref((struct realm *)entry->data);
pthread_mutex_lock(&realm->mutex);
entry = list_next(entry); entry = list_next(entry);
if (realm->srvconfs) { if (realm->srvconfs) {
for (entry2 = list_first(realm->srvconfs); entry2; entry2 = list_next(entry2))
if (entry2->data == srv)
freerealm(realm);
list_removedata(realm->srvconfs, srv); list_removedata(realm->srvconfs, srv);
if (!list_first(realm->srvconfs)) { if (!list_first(realm->srvconfs)) {
list_destroy(realm->srvconfs); list_destroy(realm->srvconfs);
...@@ -1278,6 +1295,9 @@ void _internal_removeserversubrealms(struct list *realmlist, struct clsrvconf *s ...@@ -1278,6 +1295,9 @@ void _internal_removeserversubrealms(struct list *realmlist, struct clsrvconf *s
} }
} }
if (realm->accsrvconfs) { if (realm->accsrvconfs) {
for (entry2 = list_first(realm->accsrvconfs); entry2; entry2 = list_next(entry2))
if (entry2->data == srv)
freerealm(realm);
list_removedata(realm->accsrvconfs, srv); list_removedata(realm->accsrvconfs, srv);
if (!list_first(realm->accsrvconfs)) { if (!list_first(realm->accsrvconfs)) {
list_destroy(realm->accsrvconfs); list_destroy(realm->accsrvconfs);
...@@ -1286,10 +1306,11 @@ void _internal_removeserversubrealms(struct list *realmlist, struct clsrvconf *s ...@@ -1286,10 +1306,11 @@ void _internal_removeserversubrealms(struct list *realmlist, struct clsrvconf *s
} }
/* remove subrealm if no servers */ /* remove subrealm if no servers */
if (!realm->srvconfs && !realm->accsrvconfs) { if (!realm->srvconfs && !realm->accsrvconfs)
list_removedata(realmlist, realm); list_removedata(realmlist, realm);
freerealm(realm);
} pthread_mutex_unlock(&realm->mutex);
freerealm(realm);
} }
} }
...@@ -1299,7 +1320,7 @@ void removeserversubrealms(struct list *realmlist, struct clsrvconf *srv) { ...@@ -1299,7 +1320,7 @@ void removeserversubrealms(struct list *realmlist, struct clsrvconf *srv) {
for (entry = list_first(realmlist); entry; entry = list_next(entry)) { for (entry = list_first(realmlist); entry; entry = list_next(entry)) {
realm = (struct realm *)entry->data; realm = (struct realm *)entry->data;
pthread_mutex_lock(&realm->subrealms_mutex); pthread_mutex_lock(&realm->mutex);
if (realm->subrealms) { if (realm->subrealms) {
_internal_removeserversubrealms(realm->subrealms, srv); _internal_removeserversubrealms(realm->subrealms, srv);
if (!list_first(realm->subrealms)) { if (!list_first(realm->subrealms)) {
...@@ -1307,7 +1328,7 @@ void removeserversubrealms(struct list *realmlist, struct clsrvconf *srv) { ...@@ -1307,7 +1328,7 @@ void removeserversubrealms(struct list *realmlist, struct clsrvconf *srv) {
realm->subrealms = NULL; realm->subrealms = NULL;
} }
} }
pthread_mutex_unlock(&realm->subrealms_mutex); pthread_mutex_unlock(&realm->mutex);
} }
} }
...@@ -1680,12 +1701,15 @@ struct clsrvconf *choosesrvconf(struct list *srvconfs) { ...@@ -1680,12 +1701,15 @@ struct clsrvconf *choosesrvconf(struct list *srvconfs) {
return best ? best : first; return best ? best : first;
} }
/* returns with lock on realm, protects from server changes while in use by radsrv/sendrq */
struct server *findserver(struct realm **realm, struct tlv *username, uint8_t acc) { struct server *findserver(struct realm **realm, struct tlv *username, uint8_t acc) {
struct clsrvconf *srvconf; struct clsrvconf *srvconf;
struct realm *subrealm;
char *id = (char *)tlv2str(username); char *id = (char *)tlv2str(username);
if (!id) if (!id)
return NULL; return NULL;
/* returns with lock on realm */
*realm = id2realm(realms, id); *realm = id2realm(realms, id);
if (!*realm) { if (!*realm) {
free(id); free(id);
...@@ -1697,8 +1721,15 @@ struct server *findserver(struct realm **realm, struct tlv *username, uint8_t ac ...@@ -1697,8 +1721,15 @@ struct server *findserver(struct realm **realm, struct tlv *username, uint8_t ac
free(id); free(id);
return NULL; return NULL;
} }
if (!acc && !srvconf->servers) if (!acc && !(*realm)->parent && !srvconf->servers) {
adddynamicrealmserver(*realm, srvconf, id); subrealm = adddynamicrealmserver(*realm, srvconf, id);
if (subrealm) {
pthread_mutex_lock(&subrealm->mutex);
pthread_mutex_unlock(&(*realm)->mutex);
freerealm(*realm);
*realm = subrealm;
}
}
free(id); free(id);
return srvconf->servers; return srvconf->servers;
} }
...@@ -1813,6 +1844,7 @@ int radsrv(struct request *rq) { ...@@ -1813,6 +1844,7 @@ int radsrv(struct request *rq) {
goto rmclrqexit; goto rmclrqexit;
debug(DBG_DBG, "%s with username: %s", radmsgtype2string(msg->code), userascii); debug(DBG_DBG, "%s with username: %s", radmsgtype2string(msg->code), userascii);
/* will return with lock on the realm */
to = findserver(&realm, attr, msg->code == RAD_Accounting_Request); to = findserver(&realm, attr, msg->code == RAD_Accounting_Request);
if (!realm) { if (!realm) {
debug(DBG_INFO, "radsrv: ignoring request, don't know where to send it"); debug(DBG_INFO, "radsrv: ignoring request, don't know where to send it");
...@@ -1867,6 +1899,8 @@ int radsrv(struct request *rq) { ...@@ -1867,6 +1899,8 @@ int radsrv(struct request *rq) {
free(userascii); free(userascii);
rq->to = to; rq->to = to;
sendrq(rq); sendrq(rq);
pthread_mutex_unlock(&realm->mutex);
freerealm(realm);
return 1; return 1;
rmclrqexit: rmclrqexit:
...@@ -1874,6 +1908,10 @@ int radsrv(struct request *rq) { ...@@ -1874,6 +1908,10 @@ int radsrv(struct request *rq) {
exit: exit:
freerq(rq); freerq(rq);
free(userascii); free(userascii);
if (realm) {
pthread_mutex_unlock(&realm->mutex);
freerealm(realm);
}
return 1; return 1;
} }
...@@ -2483,22 +2521,21 @@ struct list *addsrvconfs(char *value, char **names) { ...@@ -2483,22 +2521,21 @@ struct list *addsrvconfs(char *value, char **names) {
void freerealm(struct realm *realm) { void freerealm(struct realm *realm) {
if (!realm) if (!realm)
return; return;
debug(DBG_DBG, "freerealm: called with refcount %d", realm->refcount);
if (--realm->refcount)
return;
free(realm->name); free(realm->name);
free(realm->message); free(realm->message);
regfree(&realm->regex); regfree(&realm->regex);
pthread_mutex_destroy(&realm->subrealms_mutex); pthread_mutex_destroy(&realm->mutex);
if (realm->subrealms) /* if refcount == 0, all subrealms gone */
list_destroy(realm->subrealms); list_destroy(realm->subrealms);
if (realm->srvconfs) { /* if refcount == 0, all srvconfs gone */
/* emptying list without freeing data */ list_destroy(realm->srvconfs);
while (list_shift(realm->srvconfs)); /* if refcount == 0, all accsrvconfs gone */
list_destroy(realm->srvconfs); list_destroy(realm->accsrvconfs);
} freerealm(realm->parent);
if (realm->accsrvconfs) {
/* emptying list without freeing data */
while (list_shift(realm->accsrvconfs));
list_destroy(realm->accsrvconfs);
}
free(realm); free(realm);
} }
...@@ -2546,7 +2583,7 @@ struct realm *addrealm(struct list *realmlist, char *value, char **servers, char ...@@ -2546,7 +2583,7 @@ struct realm *addrealm(struct list *realmlist, char *value, char **servers, char
} }
memset(realm, 0, sizeof(struct realm)); memset(realm, 0, sizeof(struct realm));
if (pthread_mutex_init(&realm->subrealms_mutex, NULL)) { if (pthread_mutex_init(&realm->mutex, NULL)) {
debug(DBG_ERR, "mutex init failed"); debug(DBG_ERR, "mutex init failed");
free(realm); free(realm);
realm = NULL; realm = NULL;
...@@ -2584,7 +2621,7 @@ struct realm *addrealm(struct list *realmlist, char *value, char **servers, char ...@@ -2584,7 +2621,7 @@ struct realm *addrealm(struct list *realmlist, char *value, char **servers, char
if (!list_push(realmlist, realm)) { if (!list_push(realmlist, realm)) {
debug(DBG_ERR, "malloc failed"); debug(DBG_ERR, "malloc failed");
pthread_mutex_destroy(&realm->subrealms_mutex); pthread_mutex_destroy(&realm->mutex);
goto errexit; goto errexit;
} }
...@@ -2592,52 +2629,55 @@ struct realm *addrealm(struct list *realmlist, char *value, char **servers, char ...@@ -2592,52 +2629,55 @@ struct realm *addrealm(struct list *realmlist, char *value, char **servers, char
goto exit; goto exit;
errexit: errexit:
while (list_shift(realm->srvconfs));
while (list_shift(realm->accsrvconfs));
freerealm(realm); freerealm(realm);
realm = NULL; realm = NULL;
exit: exit:
free(regex); free(regex);
if (servers) { if (servers) {
if (realm)
for (n = 0; servers[n]; n++)
newrealmref(realm);
for (n = 0; servers[n]; n++) for (n = 0; servers[n]; n++)
free(servers[n]); free(servers[n]);
free(servers); free(servers);
} }
if (accservers) { if (accservers) {
if (realm)
for (n = 0; accservers[n]; n++)
newrealmref(realm);
for (n = 0; accservers[n]; n++) for (n = 0; accservers[n]; n++)
free(accservers[n]); free(accservers[n]);
free(accservers); free(accservers);
} }
return realm; return newrealmref(realm);
} }
void adddynamicrealmserver(struct realm *realm, struct clsrvconf *conf, char *id) { struct realm *adddynamicrealmserver(struct realm *realm, struct clsrvconf *conf, char *id) {
struct clsrvconf *srvconf; struct clsrvconf *srvconf;
struct realm *newrealm = NULL; struct realm *newrealm = NULL;
char *realmname, *s; char *realmname, *s;
pthread_t clientth; pthread_t clientth;
if (!conf->dynamiclookupcommand) if (!conf->dynamiclookupcommand)
return; return NULL;
/* create dynamic for the realm (string after last @, exit if nothing after @ */ /* create dynamic for the realm (string after last @, exit if nothing after @ */
realmname = strrchr(id, '@'); realmname = strrchr(id, '@');
if (!realmname) if (!realmname)
return; return NULL;
realmname++; realmname++;
if (!*realmname) if (!*realmname)
return; return NULL;
for (s = realmname; *s; s++) for (s = realmname; *s; s++)
if (*s != '.' && *s != '-' && !isalnum((int)*s)) if (*s != '.' && *s != '-' && !isalnum((int)*s))
return; return NULL;
pthread_mutex_lock(&realm->subrealms_mutex);
/* exit if we now already got a matching subrealm */
if (id2realm(realm->subrealms, id))
goto exit;
srvconf = malloc(sizeof(struct clsrvconf)); srvconf = malloc(sizeof(struct clsrvconf));
if (!srvconf) { if (!srvconf) {
debug(DBG_ERR, "malloc failed"); debug(DBG_ERR, "malloc failed");
goto exit; return NULL;
} }
*srvconf = *conf; *srvconf = *conf;
if (!addserver(srvconf)) if (!addserver(srvconf))
...@@ -2650,27 +2690,35 @@ void adddynamicrealmserver(struct realm *realm, struct clsrvconf *conf, char *id ...@@ -2650,27 +2690,35 @@ void adddynamicrealmserver(struct realm *realm, struct clsrvconf *conf, char *id
newrealm = addrealm(realm->subrealms, realmname, NULL, NULL, NULL, 0); newrealm = addrealm(realm->subrealms, realmname, NULL, NULL, NULL, 0);
if (!newrealm) if (!newrealm)
goto errexit; goto errexit;
newrealm->parent = newrealmref(realm);
/* add server and accserver to newrealm */ /* add server and accserver to newrealm */
newrealm->srvconfs = list_create(); newrealm->srvconfs = list_create();
if (!newrealm->srvconfs || !list_push(newrealm->srvconfs, srvconf)) { if (!newrealm->srvconfs || !list_push(newrealm->srvconfs, srvconf)) {
debug(DBG_ERR, "malloc failed"); debug(DBG_ERR, "malloc failed");
goto errexit; goto errexit;
} }
newrealmref(newrealm);
newrealm->accsrvconfs = list_create(); newrealm->accsrvconfs = list_create();
if (!newrealm->accsrvconfs || !list_push(newrealm->accsrvconfs, srvconf)) { if (!newrealm->accsrvconfs || !list_push(newrealm->accsrvconfs, srvconf)) {
debug(DBG_ERR, "malloc failed"); debug(DBG_ERR, "malloc failed");
list_shift(realm->srvconfs);
freerealm(newrealm);
goto errexit; goto errexit;
} }
newrealmref(newrealm);
srvconf->servers->dynamiclookuparg = stringcopy(realmname, 0); srvconf->servers->dynamiclookuparg = stringcopy(realmname, 0);
if (pthread_create(&clientth, NULL, clientwr, (void *)(srvconf->servers))) { if (pthread_create(&clientth, NULL, clientwr, (void *)(srvconf->servers))) {
debug(DBG_ERR, "pthread_create failed"); debug(DBG_ERR, "pthread_create failed");
list_shift(realm->srvconfs);
freerealm(newrealm);
list_shift(realm->accsrvconfs);
freerealm(newrealm);
goto errexit; goto errexit;
} }
pthread_detach(clientth); pthread_detach(clientth);
goto exit; return newrealm;
errexit: errexit:
if (newrealm) { if (newrealm) {
...@@ -2684,9 +2732,7 @@ void adddynamicrealmserver(struct realm *realm, struct clsrvconf *conf, char *id ...@@ -2684,9 +2732,7 @@ void adddynamicrealmserver(struct realm *realm, struct clsrvconf *conf, char *id
freeserver(srvconf->servers, 1); freeserver(srvconf->servers, 1);
free(srvconf); free(srvconf);
debug(DBG_ERR, "failed to create dynamic server"); debug(DBG_ERR, "failed to create dynamic server");
return NULL;
exit:
pthread_mutex_unlock(&realm->subrealms_mutex);
} }
int dynamicconfig(struct server *server) { int dynamicconfig(struct server *server) {
......
...@@ -44,7 +44,7 @@ struct options { ...@@ -44,7 +44,7 @@ struct options {
struct request { struct request {
struct timeval created; struct timeval created;
uint8_t refcount; uint32_t refcount;
uint8_t *buf, *replybuf; uint8_t *buf, *replybuf;
struct radmsg *msg; struct radmsg *msg;
struct client *from; struct client *from;
...@@ -138,7 +138,9 @@ struct realm { ...@@ -138,7 +138,9 @@ struct realm {
char *message; char *message;
uint8_t accresp; uint8_t accresp;
regex_t regex; regex_t regex;
pthread_mutex_t subrealms_mutex; uint32_t refcount;
pthread_mutex_t mutex;
struct realm *parent;
struct list *subrealms; struct list *subrealms;
struct list *srvconfs; struct list *srvconfs;
struct list *accsrvconfs; struct list *accsrvconfs;
......
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