From 187643195c6c3b429f79c6d55828c06051e8bc88 Mon Sep 17 00:00:00 2001 From: Elizabeth Myers Date: Thu, 10 Mar 2016 08:04:17 -0600 Subject: [PATCH] authd: add rdns provider (compile-tested) --- authd/Makefile.am | 8 +- authd/provider.c | 16 +-- authd/provider.h | 3 +- authd/providers/rdns.c | 226 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 238 insertions(+), 15 deletions(-) create mode 100644 authd/providers/rdns.c diff --git a/authd/Makefile.am b/authd/Makefile.am index b394aacf..8848b761 100644 --- a/authd/Makefile.am +++ b/authd/Makefile.am @@ -3,5 +3,11 @@ AM_CFLAGS=$(WARNFLAGS) AM_CPPFLAGS = -I../include -I../librb/include -authd_SOURCES = provider.c authd.c res.c reslib.c dns.c +authd_SOURCES = provider.c \ + authd.c \ + res.c \ + reslib.c \ + dns.c \ + providers/rdns.c + authd_LDADD = ../librb/src/librb.la diff --git a/authd/provider.c b/authd/provider.c index f63b9be8..c83e5761 100644 --- a/authd/provider.c +++ b/authd/provider.c @@ -66,17 +66,7 @@ void unload_provider(struct auth_provider *provider) /* Initalise all providers */ void init_providers(void) { - rb_dlink_node *ptr; - struct auth_provider *provider; - - RB_DLINK_FOREACH(ptr, auth_providers.head) - { - provider = ptr->data; - - if(provider->init && !provider->init()) - /* Provider failed to init, time to go */ - exit(1); - } + load_provider(&rdns_provider); } /* Terminate all providers */ @@ -184,7 +174,7 @@ void notice_client(struct auth_client *auth, const char *notice) } /* Begin authenticating user */ -static void start_auth(const char *cid, const char *l_ip, const char *l_port, const char *c_ip, const char *c_port) +static void start_auth(const char *cid, const char *l_ip, const char *l_port, const char *c_addr, const char *c_port) { rb_dlink_node *ptr; struct auth_provider *provider; @@ -204,7 +194,7 @@ static void start_auth(const char *cid, const char *l_ip, const char *l_port, co (void)rb_inet_pton_sock(l_ip, (struct sockaddr *)&auth->l_ip); auth->l_port = (uint16_t)atoi(l_port); /* Safe cast, port shouldn't exceed 16 bits */ - (void)rb_inet_pton_sock(c_ip, (struct sockaddr *)&auth->c_ip); + (void)rb_inet_pton_sock(c_addr, (struct sockaddr *)&auth->c_addr); auth->c_port = (uint16_t)atoi(c_port); RB_DLINK_FOREACH(ptr, auth_providers.head) diff --git a/authd/provider.h b/authd/provider.h index 60aefd77..8bd4d18f 100644 --- a/authd/provider.h +++ b/authd/provider.h @@ -42,7 +42,7 @@ struct auth_client struct rb_sockaddr_storage l_ip; /* Listener IP address */ uint16_t l_port; /* Listener port */ - struct rb_sockaddr_storage c_ip; /* Client IP address */ + struct rb_sockaddr_storage c_addr; /* Client IP address */ uint16_t c_port; /* Client port */ char hostname[HOSTLEN + 1]; /* Used for DNS lookup */ @@ -73,6 +73,7 @@ struct auth_provider }; extern rb_dlink_list auth_providers; +extern struct auth_provider rdns_provider; extern struct auth_client auth_clients[MAX_CLIENTS]; diff --git a/authd/providers/rdns.c b/authd/providers/rdns.c new file mode 100644 index 00000000..92f53822 --- /dev/null +++ b/authd/providers/rdns.c @@ -0,0 +1,226 @@ +/* authd/providers/rdns.c - rDNS lookup provider for authd + * Copyright (c) 2016 Elizabeth Myers + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "stdinc.h" +#include "rb_commio.h" +#include "authd.h" +#include "provider.h" +#include "res.h" +#include "dns.h" + +struct dns_query +{ + rb_dlink_node node; + + struct auth_client *auth; /* Our client */ + struct DNSQuery query; /* DNS query */ + time_t timeout; /* When the request times out */ +}; + +/* Goinked from old s_auth.c --Elizabeth */ +static const char *messages[] = +{ + "*** Looking up your hostname...", + "*** Found your hostname", + "*** Couldn't look up your hostname", + "*** Your hostname is too long, ignoring hostname", +}; + +typedef enum +{ + REPORT_LOOKUP, + REPORT_FOUND, + REPORT_FAIL, + REPORT_TOOLONG, +} dns_message; + +static EVH timeout_dns_queries_event; +static void client_fail(struct dns_query *query, dns_message message); +static void client_success(struct dns_query *query); +static void get_dns_answer(void *userdata, struct DNSReply *reply); + +rb_dlink_list queries; +static struct ev_entry *timeout_ev; +int timeout = 30; + + +bool client_dns_init(void) +{ + timeout_ev = rb_event_addish("timeout_dns_queries_event", timeout_dns_queries_event, NULL, 1); + return (timeout_ev != NULL); +} + +void client_dns_destroy(void) +{ + rb_dlink_node *ptr, *nptr; + struct dns_query *query; + + RB_DLINK_FOREACH_SAFE(ptr, nptr, queries.head) + { + client_fail(ptr->data, REPORT_FAIL); + rb_dlinkDelete(ptr, &queries); + rb_free(ptr); + } + + rb_event_delete(timeout_ev); +} + +bool client_dns_start(struct auth_client *auth) +{ + struct dns_query *query = rb_malloc(sizeof(struct dns_query)); + + query->auth = auth; + query->timeout = rb_current_time() + timeout; + + query->query.ptr = query; + query->query.callback = get_dns_answer; + + gethost_byaddr(&auth->c_addr, &query->query); + notice_client(auth, messages[REPORT_LOOKUP]); + return true; +} + +void client_dns_cancel(struct auth_client *auth) +{ + rb_dlink_node *ptr; + + /* Bah, the stupid DNS resolver code doesn't have a cancellation + * func... */ + RB_DLINK_FOREACH(ptr, queries.head) + { + struct dns_query *query = ptr->data; + + if(query->auth == auth) + { + /* This will get cleaned up later by the DNS stuff */ + client_fail(query, REPORT_FAIL); + return; + } + } +} + +static void +get_dns_answer(void *userdata, struct DNSReply *reply) +{ + struct dns_query *query = userdata; + struct auth_client *auth = query->auth; + rb_dlink_node *ptr, *nptr; + bool fail = false; + dns_message response; + + if(reply == NULL || auth == NULL) + { + response = REPORT_FAIL; + fail = true; + goto cleanup; + } + + if(!sockcmp(&auth->c_addr, &reply->addr, GET_SS_FAMILY(&auth->c_addr))) + { + response = REPORT_FAIL; + fail = true; + goto cleanup; + } + + if(strlen(reply->h_name) > HOSTLEN) + { + /* Ah well. */ + response = REPORT_TOOLONG; + fail = true; + goto cleanup; + } + + rb_strlcpy(auth->hostname, reply->h_name, HOSTLEN + 1); + +cleanup: + /* Clean us up off the pending queries list */ + RB_DLINK_FOREACH_SAFE(ptr, nptr, queries.head) + { + struct dns_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; + } + } +} + +/* Timeout outstanding queries */ +static void timeout_dns_queries_event(void *notused) +{ + rb_dlink_node *ptr; + + /* NOTE - we do not delete queries from the list from a timeout, when + * the query times out later it will be deleted. + */ + RB_DLINK_FOREACH(ptr, queries.head) + { + struct dns_query *query = ptr->data; + + if(query->auth && query->timeout < rb_current_time()) + { + client_fail(query, REPORT_FAIL); + return; + } + } +} + +static void client_fail(struct dns_query *query, dns_message report) +{ + struct auth_client *auth = query->auth; + + if(auth) + { + rb_strlcpy(auth->hostname, "*", sizeof(auth->hostname)); + notice_client(auth, messages[report]); + provider_done(auth, PROVIDER_RDNS); + query->auth = NULL; + } +} + +static void client_success(struct dns_query *query) +{ + struct auth_client *auth = query->auth; + + if(auth) + { + notice_client(auth, messages[REPORT_FOUND]); + provider_done(auth, PROVIDER_RDNS); + query->auth = NULL; + } +} + +struct auth_provider rdns_provider = +{ + .id = PROVIDER_RDNS, + .init = client_dns_init, + .destroy = client_dns_destroy, + .start = client_dns_start, + .cancel = client_dns_cancel, + .completed = NULL, +};