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