authd: clean up refcounting stuff

This commit is contained in:
Elizabeth Myers 2016-04-06 11:43:05 -05:00
parent 45e6c74631
commit 4434f37513

View file

@ -88,7 +88,8 @@ destroy_providers(void)
RB_DICTIONARY_FOREACH(auth, &iter, auth_clients) RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
{ {
/* TBD - is this the right thing? */ /* TBD - is this the right thing? */
reject_client(auth, -1, "destroy", "Authentication system is down... try reconnecting in a few seconds"); reject_client(auth, UINT32_MAX, "destroy",
"Authentication system is down... try reconnecting in a few seconds");
} }
RB_DICTIONARY_FOREACH(provider, &iter, auth_providers) RB_DICTIONARY_FOREACH(provider, &iter, auth_providers)
@ -114,7 +115,17 @@ load_provider(struct auth_provider *provider)
rb_dlinkDestroy(free_pids.head, &free_pids); rb_dlinkDestroy(free_pids.head, &free_pids);
} }
else else
{
if(pid == UINT32_MAX)
{
/* If this happens, well, I don't know what to say. Probably a bug.
* In any case, UINT32_MAX is a special sentinel. */
warn_opers(L_WARN, "Cannot load additional provider, max reached!");
return;
}
provider->id = pid++; provider->id = pid++;
}
if(provider->opt_handlers != NULL) if(provider->opt_handlers != NULL)
{ {
@ -157,9 +168,12 @@ unload_provider(struct auth_provider *provider)
} }
/* Cancel outstanding providers for a client */ /* Cancel outstanding providers for a client (if any) and free the auth instance
* WARNING: do not use auth instance after calling! */
void void
cancel_providers(struct auth_client *auth) cancel_providers(struct auth_client *auth)
{
if(auth->refcount > 0)
{ {
rb_dictionary_iter iter; rb_dictionary_iter iter;
struct auth_provider *provider; struct auth_provider *provider;
@ -170,8 +184,8 @@ cancel_providers(struct auth_client *auth)
/* Cancel if required */ /* Cancel if required */
provider->cancel(auth); provider->cancel(auth);
} }
}
auth->refcount = 0;
rb_dictionary_delete(auth_clients, RB_UINT_TO_POINTER(auth->cid)); rb_dictionary_delete(auth_clients, RB_UINT_TO_POINTER(auth->cid));
rb_free(auth->data); rb_free(auth->data);
rb_free(auth); rb_free(auth);
@ -185,17 +199,19 @@ provider_done(struct auth_client *auth, uint32_t id)
rb_dictionary_iter iter; rb_dictionary_iter iter;
struct auth_provider *provider; struct auth_provider *provider;
if(auth->refcount == 1 && !auth->providers_starting) lrb_assert(is_provider_running(auth, id));
lrb_assert(id != UINT32_MAX);
lrb_assert(id <= pid);
set_provider_done(auth, id);
if(auth->refcount == 0 && !auth->providers_starting)
{ {
/* Providers aren't being executed and refcount is 1 (last provider), accept */ /* All done */
accept_client(auth, id); accept_client(auth, id);
return; return;
} }
set_provider_done(auth, id);
/* It's safe to use auth below, since refcount will be > 0, per above
* Thus the object will still be live */
RB_DICTIONARY_FOREACH(provider, &iter, auth_providers) RB_DICTIONARY_FOREACH(provider, &iter, auth_providers)
{ {
if(provider->completed != NULL && is_provider_running(auth, provider->id)) if(provider->completed != NULL && is_provider_running(auth, provider->id))
@ -204,7 +220,7 @@ provider_done(struct auth_client *auth, uint32_t id)
} }
} }
/* Reject a client /* Reject a client and cancel any outstanding providers
* WARNING: do not use auth instance after calling! */ * WARNING: do not use auth instance after calling! */
void void
reject_client(struct auth_client *auth, uint32_t id, const char *data, const char *fmt, ...) reject_client(struct auth_client *auth, uint32_t id, const char *data, const char *fmt, ...)
@ -213,9 +229,6 @@ reject_client(struct auth_client *auth, uint32_t id, const char *data, const cha
char buf[BUFSIZE]; char buf[BUFSIZE];
va_list args; va_list args;
if(data == NULL)
data = "*";
va_start(args, fmt); va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args); vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args); va_end(args);
@ -227,15 +240,15 @@ reject_client(struct auth_client *auth, uint32_t id, const char *data, const cha
rb_helper_write(authd_helper, "R %x %c %s %s %s :%s", rb_helper_write(authd_helper, "R %x %c %s %s %s :%s",
auth->cid, auth->data[id].provider->letter, auth->cid, auth->data[id].provider->letter,
auth->username, auth->hostname, auth->username, auth->hostname,
data, buf); data == NULL ? "*" : data, buf);
if(id != UINT32_MAX)
set_provider_done(auth, id); set_provider_done(auth, id);
if(--refcount > 0)
/* We have providers remaining, let them clean up */
cancel_providers(auth); cancel_providers(auth);
} }
/* Accept a client, cancel outstanding providers if any /* Accept a client and cancel outstanding providers if any
* WARNING: do not use auth instance after calling! */ * WARNING: do not use auth instance after calling! */
void void
accept_client(struct auth_client *auth, uint32_t id) accept_client(struct auth_client *auth, uint32_t id)
@ -244,9 +257,9 @@ accept_client(struct auth_client *auth, uint32_t id)
rb_helper_write(authd_helper, "A %x %s %s", auth->cid, auth->username, auth->hostname); rb_helper_write(authd_helper, "A %x %s %s", auth->cid, auth->username, auth->hostname);
if(id != UINT32_MAX)
set_provider_done(auth, id); set_provider_done(auth, id);
if(--refcount > 0)
/* We have providers remaining, let them clean up */
cancel_providers(auth); cancel_providers(auth);
} }
@ -297,17 +310,14 @@ start_auth(const char *cid, const char *l_ip, const char *l_port, const char *c_
/* Execute providers */ /* Execute providers */
if(!provider->start(auth)) if(!provider->start(auth))
{
/* Rejected immediately */ /* Rejected immediately */
cancel_providers(auth);
return; return;
} }
}
auth->providers_starting = false; auth->providers_starting = false;
/* If no providers are running, accept the client */ /* If no providers are running, accept the client */
if(!auth->refcount) if(auth->refcount == 0)
accept_client(auth, -1); accept_client(auth, UINT32_MAX);
} }
/* Callback for the initiation */ /* Callback for the initiation */