]> jfr.im git - irc/rqf/shadowircd.git/blob - src/s_auth.c
irc_string.h -> match.h, irc_string.h; includes changed
[irc/rqf/shadowircd.git] / src / s_auth.c
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * s_auth.c: Functions for querying a users ident.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
23 *
24 * $Id: s_auth.c 3354 2007-04-03 09:21:31Z nenolod $ */
25
26 /*
27 * Changes:
28 * July 6, 1999 - Rewrote most of the code here. When a client connects
29 * to the server and passes initial socket validation checks, it
30 * is owned by this module (auth) which returns it to the rest of the
31 * server when dns and auth queries are finished. Until the client is
32 * released, the server does not know it exists and does not process
33 * any messages from it.
34 * --Bleep Thomas Helvey <tomh@inxpress.net>
35 */
36 #include "stdinc.h"
37 #include "config.h"
38 #include "s_auth.h"
39 #include "s_conf.h"
40 #include "client.h"
41 #include "common.h"
42 #include "match.h"
43 #include "ircd.h"
44 #include "numeric.h"
45 #include "packet.h"
46 #include "res.h"
47 #include "logger.h"
48 #include "s_stats.h"
49 #include "send.h"
50 #include "hook.h"
51 #include "blacklist.h"
52
53 /*
54 * a bit different approach
55 * this replaces the original sendheader macros
56 */
57
58 static const char *HeaderMessages[] =
59 {
60 ":*** Looking up your hostname...",
61 ":*** Found your hostname",
62 ":*** Couldn't look up your hostname",
63 ":*** Checking Ident",
64 ":*** Got Ident response",
65 ":*** No Ident response",
66 ":*** Your hostname is too long, ignoring hostname",
67 ":*** Your forward and reverse DNS do not match, ignoring hostname",
68 ":*** Cannot verify hostname validity, ignoring hostname",
69 };
70
71 typedef enum
72 {
73 REPORT_DO_DNS,
74 REPORT_FIN_DNS,
75 REPORT_FAIL_DNS,
76 REPORT_DO_ID,
77 REPORT_FIN_ID,
78 REPORT_FAIL_ID,
79 REPORT_HOST_TOOLONG,
80 REPORT_HOST_MISMATCH,
81 REPORT_HOST_UNKNOWN
82 }
83 ReportType;
84
85 #define sendheader(c, r) sendto_one_notice(c, HeaderMessages[(r)])
86
87 static rb_dlink_list auth_poll_list;
88 static rb_bh *auth_heap;
89 static EVH timeout_auth_queries_event;
90
91 static PF read_auth_reply;
92 static CNCB auth_connect_callback;
93
94 /*
95 * init_auth()
96 *
97 * Initialise the auth code
98 */
99 void
100 init_auth(void)
101 {
102 /* This hook takes a struct Client for its argument */
103 memset(&auth_poll_list, 0, sizeof(auth_poll_list));
104 rb_event_addish("timeout_auth_queries_event", timeout_auth_queries_event, NULL, 1);
105 auth_heap = rb_bh_create(sizeof(struct AuthRequest), LCLIENT_HEAP_SIZE, "auth_heap");
106 }
107
108 /*
109 * make_auth_request - allocate a new auth request
110 */
111 static struct AuthRequest *
112 make_auth_request(struct Client *client)
113 {
114 struct AuthRequest *request = rb_bh_alloc(auth_heap);
115 client->localClient->auth_request = request;
116 request->F = NULL;
117 request->client = client;
118 request->timeout = rb_current_time() + ConfigFileEntry.connect_timeout;
119 return request;
120 }
121
122 /*
123 * free_auth_request - cleanup auth request allocations
124 */
125 static void
126 free_auth_request(struct AuthRequest *request)
127 {
128 rb_bh_free(auth_heap, request);
129 }
130
131 /*
132 * release_auth_client - release auth client from auth system
133 * this adds the client into the local client lists so it can be read by
134 * the main io processing loop
135 */
136 static void
137 release_auth_client(struct AuthRequest *auth)
138 {
139 struct Client *client = auth->client;
140
141 if(IsDNSPending(auth) || IsDoingAuth(auth))
142 return;
143
144 client->localClient->auth_request = NULL;
145 rb_dlinkDelete(&auth->node, &auth_poll_list);
146 free_auth_request(auth);
147
148 /*
149 * When a client has auth'ed, we want to start reading what it sends
150 * us. This is what read_packet() does.
151 * -- adrian
152 */
153 client->localClient->allow_read = MAX_FLOOD;
154 rb_dlinkAddTail(client, &client->node, &global_client_list);
155 read_packet(client->localClient->F, client);
156 }
157
158 /*
159 * auth_dns_callback - called when resolver query finishes
160 * if the query resulted in a successful search, hp will contain
161 * a non-null pointer, otherwise hp will be null.
162 * set the client on it's way to a connection completion, regardless
163 * of success of failure
164 */
165 static void
166 auth_dns_callback(void *vptr, struct DNSReply *reply)
167 {
168 struct AuthRequest *auth = (struct AuthRequest *) vptr;
169 ClearDNSPending(auth);
170
171 /* XXX: this shouldn't happen, but it does. -nenolod */
172 if(auth->client->localClient == NULL)
173 {
174 sendto_realops_snomask(SNO_GENERAL, L_ALL,
175 "auth_dns_callback(): auth->client->localClient (%s) is NULL", get_client_name(auth->client, HIDE_IP));
176
177 rb_dlinkDelete(&auth->node, &auth_poll_list);
178 free_auth_request(auth);
179
180 /* and they will silently drop through and all will hopefully be ok... -nenolod */
181 return;
182 }
183
184 if(reply)
185 {
186 int good = 1;
187
188 if(auth->client->localClient->ip.ss_family == AF_INET)
189 {
190 struct sockaddr_in *ip, *ip_fwd;
191
192 ip = (struct sockaddr_in *) &auth->client->localClient->ip;
193 ip_fwd = (struct sockaddr_in *) &reply->addr;
194
195 if(ip->sin_addr.s_addr != ip_fwd->sin_addr.s_addr)
196 {
197 sendheader(auth->client, REPORT_HOST_MISMATCH);
198 good = 0;
199 }
200 }
201 #ifdef RB_IPV6
202 else if(auth->client->localClient->ip.ss_family == AF_INET6)
203 {
204 struct sockaddr_in6 *ip, *ip_fwd;
205
206 ip = (struct sockaddr_in6 *) &auth->client->localClient->ip;
207 ip_fwd = (struct sockaddr_in6 *) &reply->addr;
208
209 if(memcmp(&ip->sin6_addr, &ip_fwd->sin6_addr, sizeof(struct in6_addr)) != 0)
210 {
211 sendheader(auth->client, REPORT_HOST_MISMATCH);
212 good = 0;
213 }
214 }
215 #endif
216 else /* can't verify it, don't know how. reject it. */
217 {
218 sendheader(auth->client, REPORT_HOST_UNKNOWN);
219 good = 0;
220 }
221
222 if(good && strlen(reply->h_name) <= HOSTLEN)
223 {
224 rb_strlcpy(auth->client->host, reply->h_name, sizeof(auth->client->host));
225 sendheader(auth->client, REPORT_FIN_DNS);
226 }
227 else if (strlen(reply->h_name) > HOSTLEN)
228 sendheader(auth->client, REPORT_HOST_TOOLONG);
229 }
230 else
231 sendheader(auth->client, REPORT_FAIL_DNS);
232
233 release_auth_client(auth);
234 }
235
236 /*
237 * authsenderr - handle auth send errors
238 */
239 static void
240 auth_error(struct AuthRequest *auth)
241 {
242 ++ServerStats.is_abad;
243
244 rb_close(auth->F);
245 auth->F = NULL;
246
247 ClearAuth(auth);
248 sendheader(auth->client, REPORT_FAIL_ID);
249
250 release_auth_client(auth);
251 }
252
253 /*
254 * start_auth_query - Flag the client to show that an attempt to
255 * contact the ident server on
256 * the client's host. The connect and subsequently the socket are all put
257 * into 'non-blocking' mode. Should the connect or any later phase of the
258 * identifing process fail, it is aborted and the user is given a username
259 * of "unknown".
260 */
261 static int
262 start_auth_query(struct AuthRequest *auth)
263 {
264 struct rb_sockaddr_storage localaddr, destaddr;
265 socklen_t locallen = sizeof(struct rb_sockaddr_storage);
266 rb_fde_t *F;
267 int family;
268
269 if(IsAnyDead(auth->client))
270 return 0;
271
272 family = auth->client->localClient->ip.ss_family;
273 if((F = rb_socket(family, SOCK_STREAM, 0, "ident")) == NULL)
274 {
275 ilog_error("creating auth stream socket");
276 ++ServerStats.is_abad;
277 return 0;
278 }
279
280 /*
281 * TBD: this is a pointless arbitrary limit .. we either have a socket or not. -nenolod
282 */
283 if((maxconnections - 10) < rb_get_fd(F))
284 {
285 sendto_realops_snomask(SNO_GENERAL, L_ALL,
286 "Can't allocate fd for auth on %s",
287 get_client_name(auth->client, SHOW_IP));
288 rb_close(F);
289 return 0;
290 }
291
292 sendheader(auth->client, REPORT_DO_ID);
293
294 /*
295 * get the local address of the client and bind to that to
296 * make the auth request. This used to be done only for
297 * ifdef VIRTUAL_HOST, but needs to be done for all clients
298 * since the ident request must originate from that same address--
299 * and machines with multiple IP addresses are common now
300 */
301 memset(&localaddr, 0, locallen);
302 getsockname(rb_get_fd(auth->client->localClient->F),
303 (struct sockaddr *) &localaddr, &locallen);
304
305 /* XXX mangle_mapped_sockaddr((struct sockaddr *)&localaddr); */
306 #ifdef RB_IPV6
307 if(localaddr.ss_family == AF_INET6)
308 {
309 ((struct sockaddr_in6 *)&localaddr)->sin6_port = 0;
310 } else
311 #endif
312 ((struct sockaddr_in *)&localaddr)->sin_port = 0;
313
314 destaddr = auth->client->localClient->ip;
315 #ifdef RB_IPV6
316 if(localaddr.ss_family == AF_INET6)
317 {
318 ((struct sockaddr_in6 *)&destaddr)->sin6_port = htons(113);
319 } else
320 #endif
321 ((struct sockaddr_in *)&destaddr)->sin_port = htons(113);
322
323 auth->F = F;
324 SetAuthConnect(auth);
325
326 rb_connect_tcp(F, (struct sockaddr *)&destaddr,
327 (struct sockaddr *) &localaddr, GET_SS_LEN(&localaddr),
328 auth_connect_callback, auth,
329 GlobalSetOptions.ident_timeout);
330 return 1; /* We suceed here for now */
331 }
332
333 /*
334 * GetValidIdent - parse ident query reply from identd server
335 *
336 * Inputs - pointer to ident buf
337 * Output - NULL if no valid ident found, otherwise pointer to name
338 * Side effects -
339 */
340 static char *
341 GetValidIdent(char *buf)
342 {
343 int remp = 0;
344 int locp = 0;
345 char *colon1Ptr;
346 char *colon2Ptr;
347 char *colon3Ptr;
348 char *commaPtr;
349 char *remotePortString;
350
351 /* All this to get rid of a sscanf() fun. */
352 remotePortString = buf;
353
354 colon1Ptr = strchr(remotePortString, ':');
355 if(!colon1Ptr)
356 return 0;
357
358 *colon1Ptr = '\0';
359 colon1Ptr++;
360 colon2Ptr = strchr(colon1Ptr, ':');
361 if(!colon2Ptr)
362 return 0;
363
364 *colon2Ptr = '\0';
365 colon2Ptr++;
366 commaPtr = strchr(remotePortString, ',');
367
368 if(!commaPtr)
369 return 0;
370
371 *commaPtr = '\0';
372 commaPtr++;
373
374 remp = atoi(remotePortString);
375 if(!remp)
376 return 0;
377
378 locp = atoi(commaPtr);
379 if(!locp)
380 return 0;
381
382 /* look for USERID bordered by first pair of colons */
383 if(!strstr(colon1Ptr, "USERID"))
384 return 0;
385
386 colon3Ptr = strchr(colon2Ptr, ':');
387 if(!colon3Ptr)
388 return 0;
389
390 *colon3Ptr = '\0';
391 colon3Ptr++;
392 return (colon3Ptr);
393 }
394
395 /*
396 * start_auth - starts auth (identd) and dns queries for a client
397 */
398 void
399 start_auth(struct Client *client)
400 {
401 struct AuthRequest *auth = 0;
402 s_assert(0 != client);
403 if(client == NULL)
404 return;
405
406 auth = make_auth_request(client);
407
408 auth->dns_query.ptr = auth;
409 auth->dns_query.callback = auth_dns_callback;
410
411 sendheader(client, REPORT_DO_DNS);
412
413 /* No DNS cache now, remember? -- adrian */
414 gethost_byaddr(&client->localClient->ip, &auth->dns_query);
415
416 SetDNSPending(auth);
417
418 if(ConfigFileEntry.disable_auth == 0)
419 start_auth_query(auth);
420
421 rb_dlinkAdd(auth, &auth->node, &auth_poll_list);
422 }
423
424 /*
425 * timeout_auth_queries - timeout resolver and identd requests
426 * allow clients through if requests failed
427 */
428 static void
429 timeout_auth_queries_event(void *notused)
430 {
431 rb_dlink_node *ptr;
432 rb_dlink_node *next_ptr;
433 struct AuthRequest *auth;
434
435 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, auth_poll_list.head)
436 {
437 auth = ptr->data;
438
439 if(auth->timeout < rb_current_time())
440 {
441 if(auth->F != NULL)
442 rb_close(auth->F);
443
444 if(IsDoingAuth(auth))
445 {
446 ClearAuth(auth);
447 ++ServerStats.is_abad;
448 sendheader(auth->client, REPORT_FAIL_ID);
449 auth->client->localClient->auth_request = NULL;
450 }
451 if(IsDNSPending(auth))
452 {
453 ClearDNSPending(auth);
454 delete_resolver_queries(&auth->dns_query);
455 sendheader(auth->client, REPORT_FAIL_DNS);
456 }
457
458 auth->client->localClient->lasttime = rb_current_time();
459 release_auth_client(auth);
460 }
461 }
462 }
463
464 /*
465 * auth_connect_callback() - deal with the result of rb_connect_tcp()
466 *
467 * If the connection failed, we simply close the auth fd and report
468 * a failure. If the connection suceeded send the ident server a query
469 * giving "theirport , ourport". The write is only attempted *once* so
470 * it is deemed to be a fail if the entire write doesn't write all the
471 * data given. This shouldnt be a problem since the socket should have
472 * a write buffer far greater than this message to store it in should
473 * problems arise. -avalon
474 */
475 static void
476 auth_connect_callback(rb_fde_t *F, int error, void *data)
477 {
478 struct AuthRequest *auth = data;
479 struct sockaddr_in us;
480 struct sockaddr_in them;
481 char authbuf[32];
482 socklen_t ulen = sizeof(struct sockaddr_in);
483 socklen_t tlen = sizeof(struct sockaddr_in);
484
485 /* Check the error */
486 if(error != RB_OK)
487 {
488 /* We had an error during connection :( */
489 auth_error(auth);
490 return;
491 }
492
493 if(getsockname
494 (rb_get_fd(auth->client->localClient->F), (struct sockaddr *) &us,
495 (socklen_t *) & ulen)
496 || getpeername(rb_get_fd(auth->client->localClient->F),
497 (struct sockaddr *) &them, (socklen_t *) & tlen))
498 {
499 ilog(L_IOERROR, "auth get{sock,peer}name error for %s:%m",
500 log_client_name(auth->client, SHOW_IP));
501 auth_error(auth);
502 return;
503 }
504 rb_snprintf(authbuf, sizeof(authbuf), "%u , %u\r\n",
505 (unsigned int) ntohs(them.sin_port), (unsigned int) ntohs(us.sin_port));
506
507 if(write(rb_get_fd(auth->F), authbuf, strlen(authbuf)) == -1)
508 {
509 auth_error(auth);
510 return;
511 }
512 ClearAuthConnect(auth);
513 SetAuthPending(auth);
514 read_auth_reply(auth->F, auth);
515 }
516
517
518 /*
519 * read_auth_reply - read the reply (if any) from the ident server
520 * we connected to.
521 * We only give it one shot, if the reply isn't good the first time
522 * fail the authentication entirely. --Bleep
523 */
524 #define AUTH_BUFSIZ 128
525
526 static void
527 read_auth_reply(rb_fde_t *F, void *data)
528 {
529 struct AuthRequest *auth = data;
530 char *s = NULL;
531 char *t = NULL;
532 int len;
533 int count;
534 char buf[AUTH_BUFSIZ + 1]; /* buffer to read auth reply into */
535
536 len = read(rb_get_fd(F), buf, AUTH_BUFSIZ);
537
538 if(len < 0 && rb_ignore_errno(errno))
539 {
540 rb_setselect(F, RB_SELECT_READ, read_auth_reply, auth);
541 return;
542 }
543
544 if(len > 0)
545 {
546 buf[len] = '\0';
547
548 if((s = GetValidIdent(buf)))
549 {
550 t = auth->client->username;
551
552 while (*s == '~' || *s == '^')
553 s++;
554
555 for (count = USERLEN; *s && count; s++)
556 {
557 if(*s == '@')
558 {
559 break;
560 }
561 if(!IsSpace(*s) && *s != ':' && *s != '[')
562 {
563 *t++ = *s;
564 count--;
565 }
566 }
567 *t = '\0';
568 }
569 }
570
571 rb_close(auth->F);
572 auth->F = NULL;
573 ClearAuth(auth);
574
575 if(s == NULL)
576 {
577 ++ServerStats.is_abad;
578 strcpy(auth->client->username, "unknown");
579 sendheader(auth->client, REPORT_FAIL_ID);
580 }
581 else
582 {
583 sendheader(auth->client, REPORT_FIN_ID);
584 ++ServerStats.is_asuc;
585 SetGotId(auth->client);
586 }
587
588 release_auth_client(auth);
589 }
590
591
592
593 /*
594 * delete_auth_queries()
595 *
596 */
597 void
598 delete_auth_queries(struct Client *target_p)
599 {
600 struct AuthRequest *auth;
601
602 if(target_p == NULL || target_p->localClient == NULL ||
603 target_p->localClient->auth_request == NULL)
604 return;
605
606 auth = target_p->localClient->auth_request;
607 target_p->localClient->auth_request = NULL;
608
609 if(IsDNSPending(auth))
610 delete_resolver_queries(&auth->dns_query);
611
612 if(auth->F != NULL)
613 rb_close(auth->F);
614
615 rb_dlinkDelete(&auth->node, &auth_poll_list);
616 free_auth_request(auth);
617 }