]>
Commit | Line | Data |
---|---|---|
2b0cc3d3 EM |
1 | /* authd/providers/ident.c - ident 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 | ||
06f3496a EM |
21 | /* Largely adapted from old s_auth.c, but reworked for authd. rDNS code |
22 | * moved to its own provider. | |
23 | * | |
24 | * --Elizafox 13 March 2016 | |
25 | */ | |
26 | ||
2b0cc3d3 | 27 | #include "stdinc.h" |
9057170c | 28 | #include "defaults.h" |
2b0cc3d3 EM |
29 | #include "match.h" |
30 | #include "authd.h" | |
db821ee9 | 31 | #include "notice.h" |
2b0cc3d3 EM |
32 | #include "provider.h" |
33 | #include "res.h" | |
34 | ||
731d1289 EM |
35 | #define SELF_PID (ident_provider.id) |
36 | ||
2b0cc3d3 EM |
37 | #define IDENT_BUFSIZE 128 |
38 | ||
39 | struct ident_query | |
40 | { | |
2b0cc3d3 EM |
41 | rb_fde_t *F; /* Our FD */ |
42 | }; | |
43 | ||
44 | /* Goinked from old s_auth.c --Elizafox */ | |
45 | static const char *messages[] = | |
46 | { | |
f875cb84 EM |
47 | "*** Checking Ident", |
48 | "*** Got Ident response", | |
49 | "*** No Ident response", | |
22946d30 | 50 | "*** Cannot verify ident validity, ignoring ident", |
1345a41d | 51 | "*** Ident disabled, not checking ident", |
2b0cc3d3 EM |
52 | }; |
53 | ||
54 | typedef enum | |
55 | { | |
56 | REPORT_LOOKUP, | |
57 | REPORT_FOUND, | |
58 | REPORT_FAIL, | |
22946d30 | 59 | REPORT_INVALID, |
1345a41d | 60 | REPORT_DISABLED, |
2b0cc3d3 EM |
61 | } ident_message; |
62 | ||
2b0cc3d3 EM |
63 | static CNCB ident_connected; |
64 | static PF read_ident_reply; | |
65 | ||
3e875f62 EM |
66 | static void client_fail(struct auth_client *auth, ident_message message); |
67 | static void client_success(struct auth_client *auth); | |
2b0cc3d3 EM |
68 | static char * get_valid_ident(char *buf); |
69 | ||
9057170c | 70 | static int ident_timeout = IDENT_TIMEOUT_DEFAULT; |
54fb109d | 71 | static bool ident_enable = true; |
2b0cc3d3 EM |
72 | |
73 | ||
2b0cc3d3 EM |
74 | /* |
75 | * ident_connected() - deal with the result of rb_connect_tcp() | |
76 | * | |
77 | * If the connection failed, we simply close the auth fd and report | |
78 | * a failure. If the connection suceeded send the ident server a query | |
79 | * giving "theirport , ourport". The write is only attempted *once* so | |
80 | * it is deemed to be a fail if the entire write doesn't write all the | |
81 | * data given. This shouldnt be a problem since the socket should have | |
82 | * a write buffer far greater than this message to store it in should | |
83 | * problems arise. -avalon | |
84 | */ | |
06f3496a | 85 | static void |
d1b70e35 | 86 | ident_connected(rb_fde_t *F __unused, int error, void *data) |
2b0cc3d3 | 87 | { |
3e875f62 | 88 | struct auth_client *auth = data; |
d1b70e35 | 89 | struct ident_query *query; |
2b0cc3d3 EM |
90 | char authbuf[32]; |
91 | int authlen; | |
92 | ||
9155a948 | 93 | lrb_assert(auth != NULL); |
731d1289 | 94 | query = get_provider_data(auth, SELF_PID); |
9155a948 | 95 | lrb_assert(query != NULL); |
f875cb84 | 96 | |
2b0cc3d3 EM |
97 | /* Check the error */ |
98 | if(error != RB_OK) | |
99 | { | |
100 | /* We had an error during connection :( */ | |
3e875f62 | 101 | client_fail(auth, REPORT_FAIL); |
2b0cc3d3 EM |
102 | return; |
103 | } | |
104 | ||
105 | snprintf(authbuf, sizeof(authbuf), "%u , %u\r\n", | |
106 | auth->c_port, auth->l_port); | |
107 | authlen = strlen(authbuf); | |
108 | ||
109 | if(rb_write(query->F, authbuf, authlen) != authlen) | |
110 | { | |
3e875f62 | 111 | client_fail(auth, REPORT_FAIL); |
2b0cc3d3 EM |
112 | return; |
113 | } | |
114 | ||
3e875f62 | 115 | read_ident_reply(query->F, auth); |
2b0cc3d3 EM |
116 | } |
117 | ||
118 | static void | |
119 | read_ident_reply(rb_fde_t *F, void *data) | |
120 | { | |
3e875f62 | 121 | struct auth_client *auth = data; |
244f6259 | 122 | char buf[IDENT_BUFSIZE + 1] = { 0 }; /* buffer to read auth reply into */ |
22946d30 | 123 | ident_message message = REPORT_FAIL; |
2b0cc3d3 EM |
124 | char *s = NULL; |
125 | char *t = NULL; | |
22946d30 | 126 | ssize_t len; |
2b0cc3d3 | 127 | int count; |
2b0cc3d3 EM |
128 | |
129 | len = rb_read(F, buf, IDENT_BUFSIZE); | |
130 | if(len < 0 && rb_ignore_errno(errno)) | |
131 | { | |
d1b70e35 | 132 | rb_setselect(F, RB_SELECT_READ, read_ident_reply, auth); |
2b0cc3d3 EM |
133 | return; |
134 | } | |
135 | ||
136 | if(len > 0) | |
137 | { | |
22946d30 | 138 | if((s = get_valid_ident(buf)) != NULL) |
2b0cc3d3 EM |
139 | { |
140 | t = auth->username; | |
141 | ||
142 | while (*s == '~' || *s == '^') | |
143 | s++; | |
144 | ||
145 | for (count = USERLEN; *s && count; s++) | |
146 | { | |
22946d30 | 147 | if(*s == '@' || *s == '\r' || *s == '\n') |
2b0cc3d3 | 148 | break; |
22946d30 | 149 | |
2b0cc3d3 EM |
150 | if(*s != ' ' && *s != ':' && *s != '[') |
151 | { | |
152 | *t++ = *s; | |
153 | count--; | |
154 | } | |
155 | } | |
156 | *t = '\0'; | |
157 | } | |
22946d30 EM |
158 | else |
159 | message = REPORT_INVALID; | |
2b0cc3d3 EM |
160 | } |
161 | ||
162 | if(s == NULL) | |
22946d30 | 163 | client_fail(auth, message); |
2b0cc3d3 | 164 | else |
3e875f62 | 165 | client_success(auth); |
2b0cc3d3 EM |
166 | } |
167 | ||
06f3496a EM |
168 | static void |
169 | client_fail(struct auth_client *auth, ident_message report) | |
2b0cc3d3 | 170 | { |
731d1289 | 171 | struct ident_query *query = get_provider_data(auth, SELF_PID); |
2b0cc3d3 | 172 | |
9155a948 | 173 | lrb_assert(query != NULL); |
f875cb84 | 174 | |
3e875f62 | 175 | rb_strlcpy(auth->username, "*", sizeof(auth->username)); |
2b0cc3d3 | 176 | |
f875cb84 EM |
177 | if(query->F != NULL) |
178 | rb_close(query->F); | |
179 | ||
3e875f62 | 180 | rb_free(query); |
731d1289 EM |
181 | set_provider_data(auth, SELF_PID, NULL); |
182 | set_provider_timeout_absolute(auth, SELF_PID, 0); | |
2b0cc3d3 | 183 | |
db821ee9 | 184 | notice_client(auth->cid, messages[report]); |
731d1289 | 185 | provider_done(auth, SELF_PID); |
a5f52774 SA |
186 | |
187 | auth_client_unref(auth); | |
2b0cc3d3 EM |
188 | } |
189 | ||
06f3496a EM |
190 | static void |
191 | client_success(struct auth_client *auth) | |
2b0cc3d3 | 192 | { |
731d1289 | 193 | struct ident_query *query = get_provider_data(auth, SELF_PID); |
2b0cc3d3 | 194 | |
9155a948 | 195 | lrb_assert(query != NULL); |
f875cb84 EM |
196 | |
197 | if(query->F != NULL) | |
198 | rb_close(query->F); | |
199 | ||
3e875f62 | 200 | rb_free(query); |
731d1289 EM |
201 | set_provider_data(auth, SELF_PID, NULL); |
202 | set_provider_timeout_absolute(auth, SELF_PID, 0); | |
2b0cc3d3 | 203 | |
db821ee9 | 204 | notice_client(auth->cid, messages[REPORT_FOUND]); |
731d1289 | 205 | provider_done(auth, SELF_PID); |
a5f52774 SA |
206 | |
207 | auth_client_unref(auth); | |
2b0cc3d3 EM |
208 | } |
209 | ||
210 | /* get_valid_ident | |
211 | * parse ident query reply from identd server | |
212 | * | |
06f3496a | 213 | * Taken from old s_auth.c --Elizafox |
2b0cc3d3 EM |
214 | * |
215 | * Inputs - pointer to ident buf | |
216 | * Outputs - NULL if no valid ident found, otherwise pointer to name | |
217 | * Side effects - None | |
218 | */ | |
219 | static char * | |
220 | get_valid_ident(char *buf) | |
221 | { | |
222 | int remp = 0; | |
223 | int locp = 0; | |
224 | char *colon1Ptr; | |
225 | char *colon2Ptr; | |
226 | char *colon3Ptr; | |
227 | char *commaPtr; | |
228 | char *remotePortString; | |
229 | ||
230 | /* All this to get rid of a sscanf() fun. */ | |
231 | remotePortString = buf; | |
232 | ||
233 | colon1Ptr = strchr(remotePortString, ':'); | |
234 | if(!colon1Ptr) | |
22946d30 | 235 | return NULL; |
2b0cc3d3 EM |
236 | |
237 | *colon1Ptr = '\0'; | |
238 | colon1Ptr++; | |
239 | colon2Ptr = strchr(colon1Ptr, ':'); | |
240 | if(!colon2Ptr) | |
22946d30 | 241 | return NULL; |
2b0cc3d3 EM |
242 | |
243 | *colon2Ptr = '\0'; | |
244 | colon2Ptr++; | |
245 | commaPtr = strchr(remotePortString, ','); | |
246 | ||
247 | if(!commaPtr) | |
22946d30 | 248 | return NULL; |
2b0cc3d3 EM |
249 | |
250 | *commaPtr = '\0'; | |
251 | commaPtr++; | |
252 | ||
253 | remp = atoi(remotePortString); | |
254 | if(!remp) | |
22946d30 | 255 | return NULL; |
2b0cc3d3 EM |
256 | |
257 | locp = atoi(commaPtr); | |
258 | if(!locp) | |
22946d30 | 259 | return NULL; |
2b0cc3d3 EM |
260 | |
261 | /* look for USERID bordered by first pair of colons */ | |
262 | if(!strstr(colon1Ptr, "USERID")) | |
22946d30 | 263 | return NULL; |
2b0cc3d3 EM |
264 | |
265 | colon3Ptr = strchr(colon2Ptr, ':'); | |
266 | if(!colon3Ptr) | |
22946d30 | 267 | return NULL; |
2b0cc3d3 EM |
268 | |
269 | *colon3Ptr = '\0'; | |
270 | colon3Ptr++; | |
271 | return (colon3Ptr); | |
272 | } | |
273 | ||
06f3496a EM |
274 | static void |
275 | ident_destroy(void) | |
276 | { | |
a71b65b1 AC |
277 | struct auth_client *auth; |
278 | rb_dictionary_iter iter; | |
06f3496a EM |
279 | |
280 | /* Nuke all ident queries */ | |
a71b65b1 | 281 | RB_DICTIONARY_FOREACH(auth, &iter, auth_clients) |
06f3496a | 282 | { |
731d1289 | 283 | if(get_provider_data(auth, SELF_PID) != NULL) |
06f3496a | 284 | client_fail(auth, REPORT_FAIL); |
a5f52774 | 285 | /* auth is now invalid as we have no reference */ |
06f3496a EM |
286 | } |
287 | } | |
288 | ||
1e89fb5f EM |
289 | static bool |
290 | ident_start(struct auth_client *auth) | |
06f3496a EM |
291 | { |
292 | struct ident_query *query = rb_malloc(sizeof(struct ident_query)); | |
293 | struct rb_sockaddr_storage l_addr, c_addr; | |
47ab6f6e EM |
294 | int family = GET_SS_FAMILY(&auth->c_addr); |
295 | ||
731d1289 | 296 | lrb_assert(get_provider_data(auth, SELF_PID) == NULL); |
751d39cc EM |
297 | |
298 | if(!ident_enable) | |
1345a41d | 299 | { |
751d39cc | 300 | rb_free(query); |
1345a41d | 301 | notice_client(auth->cid, messages[REPORT_DISABLED]); |
f21ef0ce | 302 | provider_done(auth, SELF_PID); |
1345a41d EM |
303 | return true; |
304 | } | |
f681e277 | 305 | |
a5f52774 SA |
306 | auth_client_ref(auth); |
307 | ||
47ab6f6e | 308 | notice_client(auth->cid, messages[REPORT_LOOKUP]); |
06f3496a | 309 | |
731d1289 EM |
310 | set_provider_data(auth, SELF_PID, query); |
311 | set_provider_timeout_relative(auth, SELF_PID, ident_timeout); | |
06f3496a | 312 | |
c6ad9b0c | 313 | if((query->F = rb_socket(family, SOCK_STREAM, auth->protocol, "ident")) == NULL) |
06f3496a | 314 | { |
47ab6f6e | 315 | warn_opers(L_DEBUG, "Could not create ident socket: %s", strerror(errno)); |
06f3496a EM |
316 | client_fail(auth, REPORT_FAIL); |
317 | return true; /* Not a fatal error */ | |
318 | } | |
319 | ||
06f3496a | 320 | /* Build sockaddr_storages for rb_connect_tcp below */ |
367b1a39 EM |
321 | l_addr = auth->l_addr; |
322 | c_addr = auth->c_addr; | |
06f3496a | 323 | |
d86692fa EM |
324 | SET_SS_PORT(&l_addr, 0); |
325 | SET_SS_PORT(&c_addr, htons(113)); | |
06f3496a | 326 | |
47ab6f6e | 327 | rb_connect_tcp(query->F, (struct sockaddr *)&c_addr, |
06f3496a | 328 | (struct sockaddr *)&l_addr, |
5ad62c80 | 329 | ident_connected, |
d1b70e35 | 330 | auth, ident_timeout); |
06f3496a | 331 | |
06f3496a EM |
332 | return true; |
333 | } | |
334 | ||
335 | static void | |
336 | ident_cancel(struct auth_client *auth) | |
337 | { | |
731d1289 | 338 | struct ident_query *query = get_provider_data(auth, SELF_PID); |
06f3496a EM |
339 | |
340 | if(query != NULL) | |
341 | client_fail(auth, REPORT_FAIL); | |
342 | } | |
343 | ||
67acafca | 344 | static void |
d1b70e35 | 345 | add_conf_ident_timeout(const char *key __unused, int parc __unused, const char **parv) |
67acafca EM |
346 | { |
347 | int timeout = atoi(parv[0]); | |
348 | ||
349 | if(timeout < 0) | |
350 | { | |
34b96d7f EM |
351 | warn_opers(L_CRIT, "Ident: ident timeout < 0 (value: %d)", timeout); |
352 | exit(EX_PROVIDER_ERROR); | |
67acafca EM |
353 | } |
354 | ||
355 | ident_timeout = timeout; | |
356 | } | |
357 | ||
54fb109d EM |
358 | static void |
359 | set_ident_enabled(const char *key __unused, int parc __unused, const char **parv) | |
360 | { | |
1345a41d | 361 | ident_enable = (*parv[0] == '1'); |
54fb109d EM |
362 | } |
363 | ||
67acafca EM |
364 | struct auth_opts_handler ident_options[] = |
365 | { | |
366 | { "ident_timeout", 1, add_conf_ident_timeout }, | |
54fb109d | 367 | { "ident_enabled", 1, set_ident_enabled }, |
67acafca EM |
368 | { NULL, 0, NULL }, |
369 | }; | |
370 | ||
2b0cc3d3 EM |
371 | |
372 | struct auth_provider ident_provider = | |
373 | { | |
731d1289 EM |
374 | .name = "ident", |
375 | .letter = 'I', | |
1e89fb5f | 376 | .start = ident_start, |
2b0cc3d3 | 377 | .destroy = ident_destroy, |
2b0cc3d3 | 378 | .cancel = ident_cancel, |
15c49abb | 379 | .timeout = ident_cancel, |
67acafca | 380 | .opt_handlers = ident_options, |
2b0cc3d3 | 381 | }; |