]> jfr.im git - solanum.git/blame - authd/providers/rdns.c
authd: add rdns provider (compile-tested)
[solanum.git] / authd / providers / rdns.c
CommitLineData
18764319
EM
1/* authd/providers/rdns.c - rDNS lookup provider for authd
2 * Copyright (c) 2016 Elizabeth Myers <elizabeth@interlinked.me>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice is present in all copies.
7 *
8 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
9 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
11 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
12 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
13 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
14 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
15 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
16 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
17 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
18 * POSSIBILITY OF SUCH DAMAGE.
19 */
20
21#include "stdinc.h"
22#include "rb_commio.h"
23#include "authd.h"
24#include "provider.h"
25#include "res.h"
26#include "dns.h"
27
28struct dns_query
29{
30 rb_dlink_node node;
31
32 struct auth_client *auth; /* Our client */
33 struct DNSQuery query; /* DNS query */
34 time_t timeout; /* When the request times out */
35};
36
37/* Goinked from old s_auth.c --Elizabeth */
38static const char *messages[] =
39{
40 "*** Looking up your hostname...",
41 "*** Found your hostname",
42 "*** Couldn't look up your hostname",
43 "*** Your hostname is too long, ignoring hostname",
44};
45
46typedef enum
47{
48 REPORT_LOOKUP,
49 REPORT_FOUND,
50 REPORT_FAIL,
51 REPORT_TOOLONG,
52} dns_message;
53
54static EVH timeout_dns_queries_event;
55static void client_fail(struct dns_query *query, dns_message message);
56static void client_success(struct dns_query *query);
57static void get_dns_answer(void *userdata, struct DNSReply *reply);
58
59rb_dlink_list queries;
60static struct ev_entry *timeout_ev;
61int timeout = 30;
62
63
64bool client_dns_init(void)
65{
66 timeout_ev = rb_event_addish("timeout_dns_queries_event", timeout_dns_queries_event, NULL, 1);
67 return (timeout_ev != NULL);
68}
69
70void client_dns_destroy(void)
71{
72 rb_dlink_node *ptr, *nptr;
73 struct dns_query *query;
74
75 RB_DLINK_FOREACH_SAFE(ptr, nptr, queries.head)
76 {
77 client_fail(ptr->data, REPORT_FAIL);
78 rb_dlinkDelete(ptr, &queries);
79 rb_free(ptr);
80 }
81
82 rb_event_delete(timeout_ev);
83}
84
85bool client_dns_start(struct auth_client *auth)
86{
87 struct dns_query *query = rb_malloc(sizeof(struct dns_query));
88
89 query->auth = auth;
90 query->timeout = rb_current_time() + timeout;
91
92 query->query.ptr = query;
93 query->query.callback = get_dns_answer;
94
95 gethost_byaddr(&auth->c_addr, &query->query);
96 notice_client(auth, messages[REPORT_LOOKUP]);
97 return true;
98}
99
100void client_dns_cancel(struct auth_client *auth)
101{
102 rb_dlink_node *ptr;
103
104 /* Bah, the stupid DNS resolver code doesn't have a cancellation
105 * func... */
106 RB_DLINK_FOREACH(ptr, queries.head)
107 {
108 struct dns_query *query = ptr->data;
109
110 if(query->auth == auth)
111 {
112 /* This will get cleaned up later by the DNS stuff */
113 client_fail(query, REPORT_FAIL);
114 return;
115 }
116 }
117}
118
119static void
120get_dns_answer(void *userdata, struct DNSReply *reply)
121{
122 struct dns_query *query = userdata;
123 struct auth_client *auth = query->auth;
124 rb_dlink_node *ptr, *nptr;
125 bool fail = false;
126 dns_message response;
127
128 if(reply == NULL || auth == NULL)
129 {
130 response = REPORT_FAIL;
131 fail = true;
132 goto cleanup;
133 }
134
135 if(!sockcmp(&auth->c_addr, &reply->addr, GET_SS_FAMILY(&auth->c_addr)))
136 {
137 response = REPORT_FAIL;
138 fail = true;
139 goto cleanup;
140 }
141
142 if(strlen(reply->h_name) > HOSTLEN)
143 {
144 /* Ah well. */
145 response = REPORT_TOOLONG;
146 fail = true;
147 goto cleanup;
148 }
149
150 rb_strlcpy(auth->hostname, reply->h_name, HOSTLEN + 1);
151
152cleanup:
153 /* Clean us up off the pending queries list */
154 RB_DLINK_FOREACH_SAFE(ptr, nptr, queries.head)
155 {
156 struct dns_query *query_l = ptr->data;
157
158 if(query == query_l)
159 {
160 /* Found */
161 if(fail)
162 client_fail(query, response);
163 else
164 client_success(query);
165
166 rb_dlinkDelete(ptr, &queries);
167 rb_free(query);
168 return;
169 }
170 }
171}
172
173/* Timeout outstanding queries */
174static void timeout_dns_queries_event(void *notused)
175{
176 rb_dlink_node *ptr;
177
178 /* NOTE - we do not delete queries from the list from a timeout, when
179 * the query times out later it will be deleted.
180 */
181 RB_DLINK_FOREACH(ptr, queries.head)
182 {
183 struct dns_query *query = ptr->data;
184
185 if(query->auth && query->timeout < rb_current_time())
186 {
187 client_fail(query, REPORT_FAIL);
188 return;
189 }
190 }
191}
192
193static void client_fail(struct dns_query *query, dns_message report)
194{
195 struct auth_client *auth = query->auth;
196
197 if(auth)
198 {
199 rb_strlcpy(auth->hostname, "*", sizeof(auth->hostname));
200 notice_client(auth, messages[report]);
201 provider_done(auth, PROVIDER_RDNS);
202 query->auth = NULL;
203 }
204}
205
206static void client_success(struct dns_query *query)
207{
208 struct auth_client *auth = query->auth;
209
210 if(auth)
211 {
212 notice_client(auth, messages[REPORT_FOUND]);
213 provider_done(auth, PROVIDER_RDNS);
214 query->auth = NULL;
215 }
216}
217
218struct auth_provider rdns_provider =
219{
220 .id = PROVIDER_RDNS,
221 .init = client_dns_init,
222 .destroy = client_dns_destroy,
223 .start = client_dns_start,
224 .cancel = client_dns_cancel,
225 .completed = NULL,
226};