diff --git a/authd/provider.c b/authd/provider.c index 81c8dfc06..ecbb45c5c 100644 --- a/authd/provider.c +++ b/authd/provider.c @@ -27,7 +27,8 @@ * Providers can either return failure immediately, immediate acceptance, or * do work in the background (calling set_provider to signal this). * - * A dictionary is provided in auth_client for storage of provider-specific data. + * Provider-specific data for each client can be kept in an index of the data + * struct member (using the provider's ID). * * All providers must implement at a minimum a perform_provider function. You * don't have to implement the others if you don't need them. @@ -49,11 +50,15 @@ rb_dlink_list auth_providers; /* Clients waiting */ -struct auth_client auth_clients[MAX_CLIENTS]; +struct Dictionary *auth_clients; /* Load a provider */ void load_provider(struct auth_provider *provider) { + if(rb_dlink_list_length(&auth_providers) >= MAX_PROVIDERS) + /* XXX should probably warn here */ + return; + provider->init(); rb_dlinkAdd(provider, &provider->node, &auth_providers); } @@ -67,6 +72,7 @@ void unload_provider(struct auth_provider *provider) /* Initalise all providers */ void init_providers(void) { + auth_clients = rb_dictionary_create("pending auth clients", rb_uint32cmp); load_provider(&rdns_provider); load_provider(&ident_provider); } @@ -75,17 +81,15 @@ void init_providers(void) void destroy_providers(void) { rb_dlink_node *ptr; + struct DictionaryIter iter; + struct auth_client *auth; struct auth_provider *provider; /* Cancel outstanding connections */ - for (size_t i = 0; i < MAX_CLIENTS; i++) + DICTIONARY_FOREACH(auth, &iter, auth_clients) { - if(auth_clients[i].cid) - { - /* TBD - is this the right thing? */ - reject_client(&auth_clients[i], 0, - "Authentication system is down... try reconnecting in a few seconds"); - } + /* TBD - is this the right thing? */ + reject_client(auth, 0, "Authentication system is down... try reconnecting in a few seconds"); } RB_DLINK_FOREACH(ptr, auth_providers.head) @@ -112,9 +116,8 @@ void cancel_providers(struct auth_client *auth) provider->cancel(auth); } - /* All data should be already destroyed */ - rb_dictionary_destroy(auth->data, NULL, NULL); - auth->data = NULL; + rb_dictionary_delete(auth_clients, RB_UINT_TO_POINTER(auth->cid)); + rb_free(auth); } /* Provider is done */ @@ -145,7 +148,6 @@ void provider_done(struct auth_client *auth, provider_t id) /* Reject a client */ void reject_client(struct auth_client *auth, provider_t id, const char *reason) { - uint16_t cid = auth->cid; char reject; switch(id) @@ -159,7 +161,6 @@ void reject_client(struct auth_client *auth, provider_t id, const char *reason) case PROVIDER_BLACKLIST: reject = 'B'; break; - case PROVIDER_NULL: default: reject = 'N'; break; @@ -170,19 +171,17 @@ void reject_client(struct auth_client *auth, provider_t id, const char *reason) unset_provider(auth, id); cancel_providers(auth); - memset(&auth_clients[cid], 0, sizeof(struct auth_client)); } /* Accept a client, cancel outstanding providers if any */ void accept_client(struct auth_client *auth, provider_t id) { - uint16_t cid = auth->cid; + uint32_t cid = auth->cid; rb_helper_write(authd_helper, "A %x %s %s", auth->cid, auth->username, auth->hostname); unset_provider(auth, id); cancel_providers(auth); - memset(&auth_clients[cid], 0, sizeof(struct auth_client)); } /* Send a notice to a client */ @@ -195,20 +194,14 @@ void notice_client(struct auth_client *auth, const char *notice) static void start_auth(const char *cid, const char *l_ip, const char *l_port, const char *c_ip, const char *c_port) { struct auth_provider *provider; - struct auth_client *auth; + struct auth_client *auth = rb_malloc(sizeof(struct auth_client)); long lcid = strtol(cid, NULL, 16); - char name[20]; rb_dlink_node *ptr; - if(lcid >= MAX_CLIENTS) + if(lcid >= UINT32_MAX) return; - auth = &auth_clients[lcid]; - if(auth->cid != 0) - /* Shouldn't get here */ - return; - - auth->cid = (uint16_t)lcid; + auth->cid = (uint32_t)lcid; rb_strlcpy(auth->l_ip, l_ip, sizeof(auth->l_ip)); auth->l_port = (uint16_t)atoi(l_port); /* should be safe */ @@ -216,8 +209,7 @@ static void start_auth(const char *cid, const char *l_ip, const char *l_port, co rb_strlcpy(auth->c_ip, c_ip, sizeof(auth->c_ip)); auth->c_port = (uint16_t)atoi(c_port); - snprintf(name, sizeof(name), "%d provider data", auth->cid); - auth->data = rb_dictionary_create(name, rb_uint32cmp); + rb_dictionary_add(auth_clients, RB_UINT_TO_POINTER(auth->cid), auth); RB_DLINK_FOREACH(ptr, auth_providers.head) { diff --git a/authd/provider.h b/authd/provider.h index d443c0bbe..f9cb12f71 100644 --- a/authd/provider.h +++ b/authd/provider.h @@ -22,17 +22,16 @@ #define __CHARYBDIS_AUTHD_PROVIDER_H__ #include "stdinc.h" +#include "rb_dictionary.h" -/* Arbitrary limit */ -#define MAX_CLIENTS 4096 +#define MAX_PROVIDERS 32 /* This should be enough */ /* Registered providers */ typedef enum { - PROVIDER_NULL = 0x0, /* Dummy value */ - PROVIDER_RDNS = 0x1, - PROVIDER_IDENT = 0x2, - PROVIDER_BLACKLIST = 0x4, + PROVIDER_RDNS, + PROVIDER_IDENT, + PROVIDER_BLACKLIST, } provider_t; struct auth_client @@ -48,10 +47,10 @@ struct auth_client char hostname[HOSTLEN + 1]; /* Used for DNS lookup */ char username[USERLEN + 1]; /* Used for ident lookup */ - unsigned int providers; /* Providers at work, + uint32_t providers; /* Providers at work, * none left when set to 0 */ - struct Dictionary *data; /* Provider-specific data */ + void *data[MAX_PROVIDERS]; /* Provider-specific data slots */ }; typedef bool (*provider_init_t)(void); @@ -75,11 +74,11 @@ struct auth_provider }; extern rb_dlink_list auth_providers; +extern struct Dictionary *auth_clients; + extern struct auth_provider rdns_provider; extern struct auth_provider ident_provider; -extern struct auth_client auth_clients[MAX_CLIENTS]; - void load_provider(struct auth_provider *provider); void unload_provider(struct auth_provider *provider); @@ -98,19 +97,19 @@ void handle_new_connection(int parc, char *parv[]); /* Provider is operating on this auth_client (set this if you have async work to do) */ static inline void set_provider(struct auth_client *auth, provider_t provider) { - auth->providers |= provider; + auth->providers |= (1 << provider); } /* Provider is no longer operating on this auth client (you should use provider_done) */ static inline void unset_provider(struct auth_client *auth, provider_t provider) { - auth->providers &= ~provider; + auth->providers &= ~(1 << provider); } /* Check if provider is operating on this auth client */ static inline bool is_provider(struct auth_client *auth, provider_t provider) { - return auth->providers & provider; + return auth->providers & (1 << provider); } #endif /* __CHARYBDIS_AUTHD_PROVIDER_H__ */ diff --git a/authd/providers/ident.c b/authd/providers/ident.c index d633d1726..5a9376cc3 100644 --- a/authd/providers/ident.c +++ b/authd/providers/ident.c @@ -28,9 +28,6 @@ struct ident_query { - rb_dlink_node node; - - struct auth_client *auth; /* Our client */ time_t timeout; /* Timeout interval */ rb_fde_t *F; /* Our FD */ }; @@ -54,12 +51,10 @@ static EVH timeout_ident_queries_event; static CNCB ident_connected; static PF read_ident_reply; -static void client_fail(struct ident_query *query, ident_message message); -static void client_success(struct ident_query *query); -static void cleanup_query(struct ident_query *query); +static void client_fail(struct auth_client *auth, ident_message message); +static void client_success(struct auth_client *auth); static char * get_valid_ident(char *buf); -static rb_dlink_list queries; static struct ev_entry *timeout_ev; static int ident_timeout = 5; @@ -72,18 +67,14 @@ bool ident_init(void) void ident_destroy(void) { - rb_dlink_node *ptr, *nptr; + struct auth_client *auth; + struct DictionaryIter iter; /* Nuke all ident queries */ - RB_DLINK_FOREACH_SAFE(ptr, nptr, queries.head) + DICTIONARY_FOREACH(auth, &iter, auth_clients) { - struct ident_query *query = ptr->data; - - notice_client(query->auth, messages[REPORT_FAIL]); - - rb_close(query->F); - rb_free(query); - rb_dlinkDelete(ptr, &queries); + if(auth->data[PROVIDER_IDENT] != NULL) + client_fail(auth, REPORT_FAIL); } } @@ -94,12 +85,12 @@ bool ident_start(struct auth_client *auth) int family; rb_fde_t *F; - query->auth = auth; + auth->data[PROVIDER_IDENT] = query; query->timeout = rb_current_time() + ident_timeout; if((F = rb_socket(family, SOCK_STREAM, 0, "ident")) == NULL) { - client_fail(query, REPORT_FAIL); + client_fail(auth, REPORT_FAIL); return true; /* Not a fatal error */ } @@ -109,7 +100,7 @@ bool ident_start(struct auth_client *auth) if(!rb_inet_ntop_sock((struct sockaddr *)&l_addr, auth->l_ip, sizeof(l_addr)) || !rb_inet_ntop_sock((struct sockaddr *)&c_addr, auth->c_ip, sizeof(c_addr))) { - client_fail(query, REPORT_FAIL); + client_fail(auth, REPORT_FAIL); return true; } @@ -133,52 +124,32 @@ bool ident_start(struct auth_client *auth) GET_SS_LEN(&l_addr), ident_connected, query, ident_timeout); - rb_dlinkAdd(query, &query->node, &queries); - - set_provider(auth, PROVIDER_IDENT); notice_client(auth, messages[REPORT_LOOKUP]); + set_provider(auth, PROVIDER_IDENT); return true; } void ident_cancel(struct auth_client *auth) { - rb_dlink_node *ptr, *nptr; + struct ident_query *query = auth->data[PROVIDER_IDENT]; - RB_DLINK_FOREACH_SAFE(ptr, nptr, queries.head) - { - struct ident_query *query = ptr->data; - - if(query->auth == auth) - { - client_fail(query, REPORT_FAIL); - - rb_close(query->F); - rb_free(query); - rb_dlinkDelete(ptr, &queries); - - return; - } - } + if(query != NULL) + client_fail(auth, REPORT_FAIL); } /* Timeout outstanding queries */ static void timeout_ident_queries_event(void *notused) { - rb_dlink_node *ptr, *nptr; + struct auth_client *auth; + struct DictionaryIter iter; - RB_DLINK_FOREACH_SAFE(ptr, nptr, queries.head) + DICTIONARY_FOREACH(auth, &iter, auth_clients) { - struct ident_query *query = ptr->data; + struct ident_query *query = auth->data[PROVIDER_IDENT]; - if(query->timeout < rb_current_time()) - { - client_fail(query, REPORT_FAIL); - - rb_close(query->F); - rb_free(query); - rb_dlinkDelete(ptr, &queries); - } + if(query != NULL && query->timeout < rb_current_time()) + client_fail(auth, REPORT_FAIL); } } @@ -195,8 +166,8 @@ static void timeout_ident_queries_event(void *notused) */ static void ident_connected(rb_fde_t *F, int error, void *data) { - struct ident_query *query = data; - struct auth_client *auth = query->auth; + struct auth_client *auth = data; + struct ident_query *query = auth->data[PROVIDER_IDENT]; char authbuf[32]; int authlen; @@ -204,8 +175,7 @@ static void ident_connected(rb_fde_t *F, int error, void *data) if(error != RB_OK) { /* We had an error during connection :( */ - client_fail(query, REPORT_FAIL); - cleanup_query(query); + client_fail(auth, REPORT_FAIL); return; } @@ -215,18 +185,18 @@ static void ident_connected(rb_fde_t *F, int error, void *data) if(rb_write(query->F, authbuf, authlen) != authlen) { - client_fail(query, REPORT_FAIL); + client_fail(auth, REPORT_FAIL); return; } - read_ident_reply(query->F, query); + read_ident_reply(query->F, auth); } static void read_ident_reply(rb_fde_t *F, void *data) { - struct ident_query *query = data; - struct auth_client *auth = query->auth; + struct auth_client *auth = data; + struct ident_query *query = auth->data[PROVIDER_IDENT]; char *s = NULL; char *t = NULL; int len; @@ -268,51 +238,35 @@ read_ident_reply(rb_fde_t *F, void *data) } if(s == NULL) - client_fail(query, REPORT_FAIL); + client_fail(auth, REPORT_FAIL); else - client_success(query); - - cleanup_query(query); + client_success(auth); } -static void client_fail(struct ident_query *query, ident_message report) +static void client_fail(struct auth_client *auth, ident_message report) { - struct auth_client *auth = query->auth; + struct ident_query *query = auth->data[PROVIDER_IDENT]; - if(auth) - { - rb_strlcpy(auth->username, "*", sizeof(auth->username)); - notice_client(auth, messages[report]); - provider_done(auth, PROVIDER_IDENT); - } + rb_strlcpy(auth->username, "*", sizeof(auth->username)); + + rb_close(query->F); + rb_free(query); + auth->data[PROVIDER_IDENT] = NULL; + + notice_client(auth, messages[report]); + provider_done(auth, PROVIDER_IDENT); } -static void client_success(struct ident_query *query) +static void client_success(struct auth_client *auth) { - struct auth_client *auth = query->auth; + struct ident_query *query = auth->data[PROVIDER_IDENT]; - if(auth) - { - notice_client(auth, messages[REPORT_FOUND]); - provider_done(auth, PROVIDER_IDENT); - } -} + rb_close(query->F); + rb_free(query); + auth->data[PROVIDER_IDENT] = NULL; -static void cleanup_query(struct ident_query *query) -{ - rb_dlink_node *ptr, *nptr; - - RB_DLINK_FOREACH_SAFE(ptr, nptr, queries.head) - { - struct ident_query *query_l = ptr->data; - - if(query_l == query) - { - rb_close(query->F); - rb_free(query); - rb_dlinkDelete(ptr, &queries); - } - } + notice_client(auth, messages[REPORT_FOUND]); + provider_done(auth, PROVIDER_IDENT); } /* get_valid_ident diff --git a/authd/providers/rdns.c b/authd/providers/rdns.c index 0a3c2e5e0..163be7961 100644 --- a/authd/providers/rdns.c +++ b/authd/providers/rdns.c @@ -29,7 +29,6 @@ struct user_query { rb_dlink_node node; - struct auth_client *auth; /* Our client */ struct dns_query *query; /* Pending DNS query */ time_t timeout; /* When the request times out */ }; @@ -51,14 +50,13 @@ typedef enum REPORT_TOOLONG, } dns_message; -static void client_fail(struct user_query *query, dns_message message); -static void client_success(struct user_query *query); +static void client_fail(struct auth_client *auth, dns_message message); +static void client_success(struct auth_client *auth); static void get_dns_answer(const char *res, bool status, query_type type, void *data); static struct ev_entry *timeout_ev; static EVH timeout_dns_queries_event; static int rdns_timeout = 30; -static rb_dlink_list queries; /* Stored here for easy timeout */ bool client_dns_init(void) @@ -69,14 +67,13 @@ bool client_dns_init(void) void client_dns_destroy(void) { - rb_dlink_node *ptr, *nptr; - struct user_query *query; + struct auth_client *auth; + struct DictionaryIter iter; - RB_DLINK_FOREACH_SAFE(ptr, nptr, queries.head) + DICTIONARY_FOREACH(auth, &iter, auth_clients) { - client_fail(ptr->data, REPORT_FAIL); - rb_dlinkDelete(ptr, &queries); - rb_free(ptr); + if(auth->data[PROVIDER_RDNS] != NULL) + client_fail(auth, REPORT_FAIL); } rb_event_delete(timeout_ev); @@ -86,10 +83,11 @@ bool client_dns_start(struct auth_client *auth) { struct user_query *query = rb_malloc(sizeof(struct user_query)); - query->auth = auth; query->timeout = rb_current_time() + rdns_timeout; - query->query = lookup_hostname(auth->c_ip, get_dns_answer, query); + auth->data[PROVIDER_RDNS] = query; + + query->query = lookup_hostname(auth->c_ip, get_dns_answer, auth); notice_client(auth, messages[REPORT_LOOKUP]); set_provider(auth, PROVIDER_RDNS); @@ -98,104 +96,75 @@ bool client_dns_start(struct auth_client *auth) void client_dns_cancel(struct auth_client *auth) { - rb_dlink_node *ptr, *nptr; + struct user_query *query = auth->data[PROVIDER_RDNS]; - RB_DLINK_FOREACH_SAFE(ptr, nptr, queries.head) - { - struct user_query *query = ptr->data; - - if(query->auth == auth) - { - /* Victim found */ - client_fail(query, REPORT_FAIL); - rb_dlinkDelete(ptr, &queries); - rb_free(query); - return; - } - } + if(query != NULL) + client_fail(auth, REPORT_FAIL); } static void get_dns_answer(const char *res, bool status, query_type type, void *data) { - struct user_query *query = data; - struct auth_client *auth = query->auth; - bool fail = false; - dns_message response; - rb_dlink_node *ptr, *nptr; + struct auth_client *auth = data; + struct user_query *query = auth->data[PROVIDER_RDNS]; - if(res == NULL || status == false) - { - response = REPORT_FAIL; - fail = true; - goto cleanup; - } + if(query == NULL || res == NULL || status == false) + client_fail(auth, REPORT_FAIL); else if(strlen(res) > HOSTLEN) + client_fail(auth, REPORT_TOOLONG); + else { - /* Ah well. */ - response = REPORT_TOOLONG; - fail = true; - goto cleanup; - } - - rb_strlcpy(auth->hostname, res, HOSTLEN + 1); - -cleanup: - /* Clean us up off the pending queries list */ - RB_DLINK_FOREACH_SAFE(ptr, nptr, queries.head) - { - struct user_query *query_l = ptr->data; - - if(query == query_l) - { - /* Found */ - if(fail) - client_fail(query, response); - else - client_success(query); - - rb_dlinkDelete(ptr, &queries); - rb_free(query); - return; - } + rb_strlcpy(auth->hostname, res, HOSTLEN + 1); + client_success(auth); } } /* Timeout outstanding queries */ static void timeout_dns_queries_event(void *notused) { - rb_dlink_node *ptr, *nptr; + struct auth_client *auth; + struct DictionaryIter iter; - RB_DLINK_FOREACH_SAFE(ptr, nptr, queries.head) + DICTIONARY_FOREACH(auth, &iter, auth_clients) { - struct user_query *query = ptr->data; + struct user_query *query = auth->data[PROVIDER_RDNS]; - if(query->auth && query->timeout < rb_current_time()) + if(query != NULL && query->timeout < rb_current_time()) { - client_fail(query, REPORT_FAIL); - rb_dlinkDelete(ptr, &queries); - rb_free(query); + client_fail(auth, REPORT_FAIL); return; } } } -static void client_fail(struct user_query *query, dns_message report) +static void client_fail(struct auth_client *auth, dns_message report) { - struct auth_client *auth = query->auth; + struct user_query *query = auth->data[PROVIDER_RDNS]; + + if(query == NULL) + return; rb_strlcpy(auth->hostname, "*", sizeof(auth->hostname)); + notice_client(auth, messages[report]); cancel_query(query->query); + + rb_free(query); + auth->data[PROVIDER_RDNS] = NULL; + provider_done(auth, PROVIDER_RDNS); } -static void client_success(struct user_query *query) +static void client_success(struct auth_client *auth) { - struct auth_client *auth = query->auth; + struct user_query *query = auth->data[PROVIDER_RDNS]; notice_client(auth, messages[REPORT_FOUND]); cancel_query(query->query); + + rb_free(query); + auth->data[PROVIDER_RDNS] = NULL; + provider_done(auth, PROVIDER_RDNS); }