/[svn]/branches/newio/src/s_auth.c
ViewVC logotype

Contents of /branches/newio/src/s_auth.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2415 - (show annotations)
Sun Jul 21 14:33:22 2013 UTC (6 years, 11 months ago) by michael
File MIME type: text/x-chdr
File size: 16886 byte(s)
- ioengine changes as of 21JUL13

1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 *
4 * Copyright (C) 1999-2013 by the Hybrid Development Team.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 * USA
20 */
21
22 /*! \file s_auth.c
23 * \brief Interface for DNS and ident lookups.
24 * \version $Id$
25 */
26
27 /*
28 * Changes:
29 * July 6, 1999 - Rewrote most of the code here. When a client connects
30 * to the server and passes initial socket validation checks, it
31 * is owned by this module (auth) which returns it to the rest of the
32 * server when dns and auth queries are finished. Until the client is
33 * released, the server does not know it exists and does not process
34 * any messages from it.
35 * --Bleep Thomas Helvey <tomh@inxpress.net>
36 */
37
38 #include "stdinc.h"
39 #include "list.h"
40 #include "ircd_defs.h"
41 #include "ioengine.h"
42 #include "s_auth.h"
43 #include "conf.h"
44 #include "client.h"
45 #include "hook.h"
46 #include "irc_string.h"
47 #include "ircd.h"
48 #include "packet.h"
49 #include "irc_res.h"
50 #include "s_bsd.h"
51 #include "log.h"
52 #include "send.h"
53 #include "mempool.h"
54 #include "memory.h"
55 #include "s_user.h"
56
57
58 static void auth_timeout_callback(struct Event *);
59
60 static const char *HeaderMessages[] =
61 {
62 ":%s NOTICE AUTH :*** Looking up your hostname...",
63 ":%s NOTICE AUTH :*** Found your hostname",
64 ":%s NOTICE AUTH :*** Couldn't look up your hostname",
65 ":%s NOTICE AUTH :*** Checking Ident",
66 ":%s NOTICE AUTH :*** Got Ident response",
67 ":%s NOTICE AUTH :*** No Ident response",
68 ":%s NOTICE AUTH :*** Your forward and reverse DNS do not match, ignoring hostname.",
69 ":%s NOTICE AUTH :*** Invalid hostname"
70 };
71
72 enum
73 {
74 REPORT_DO_DNS,
75 REPORT_FIN_DNS,
76 REPORT_FAIL_DNS,
77 REPORT_DO_ID,
78 REPORT_FIN_ID,
79 REPORT_FAIL_ID,
80 REPORT_IP_MISMATCH,
81 REPORT_INVAL_DNS
82 };
83
84 #define sendheader(c, i) sendto_one((c), HeaderMessages[(i)], me.name)
85
86
87 /*
88 * make_auth_request - allocate a new auth request
89 */
90 static struct AuthRequest *
91 make_auth_request(struct Client *client)
92 {
93 struct AuthRequest *auth = MyMalloc(sizeof(struct AuthRequest)); /* XXX MEMPOOL */
94
95 auth->flags = AM_TIMEOUT;
96 auth->fd = -1;
97 auth->client = client;
98 client->localClient->auth = auth;
99 timer_add(timer_init(&auth->timeout), auth_timeout_callback, auth,
100 TT_RELATIVE, CONNECTTIMEOUT);
101
102 return auth;
103 }
104
105 /** Clean up auth request allocations (event loop objects, etc).
106 * @param auth The request to clean up.
107 */
108 static void
109 free_auth_request(struct AuthRequest *auth)
110 {
111 if (auth->fd > -1)
112 {
113 close(auth->fd);
114 ilog(LOG_TYPE_DEBUG, "Deleting auth socket for %p", auth->client);
115 socket_del(&auth->socket);
116 }
117
118 ilog(LOG_TYPE_DEBUG, "Deleting auth timeout timer for %p", auth->client);
119 timer_del(&auth->timeout);
120 }
121
122 /** Stop an auth request completely.
123 * @param auth The struct AuthRequest to cancel.
124 * @param send_reports If non-zero, report the failure to the user and
125 * resolver log.
126 */
127 void
128 destroy_auth_request(struct AuthRequest *auth, int send_reports)
129 {
130 if (IsDoingAuth(auth))
131 {
132 if (auth->fd > -1)
133 {
134 close(auth->fd);
135 auth->fd = -1;
136 socket_del(&auth->socket);
137 }
138
139 if (send_reports)
140 sendheader(auth->client, REPORT_FAIL_ID);
141 }
142
143 if (IsDNSPending(auth))
144 {
145 delete_resolver_queries(auth);
146
147 if (send_reports)
148 sendheader(auth->client, REPORT_FAIL_DNS);
149 }
150
151 if (send_reports)
152 {
153 ilog(LOG_TYPE_DEBUG, "DNS/AUTH timeout %s",
154 get_client_name(auth->client, HIDE_IP));
155 release_auth_client(auth->client);
156 }
157
158 free_auth_request(auth);
159 }
160
161 /*
162 * release_auth_client - release auth client from auth system
163 * this adds the client into the local client lists so it can be read by
164 * the main io processing loop
165 */
166 void
167 release_auth_client(struct Client *client)
168 {
169 client->localClient->auth = NULL;
170 client->localClient->since = CurrentTime;
171 client->localClient->lasttime = CurrentTime;
172 client->localClient->firsttime = CurrentTime; /* TBV */
173 client->flags |= FLAGS_FINISHED_AUTH; /* XXX No longer required */
174
175 dlinkAdd(client, &client->localClient->node, &connection_list);
176 add_client_to_list(client);
177
178 socket_events(&client->localClient->socket, SOCK_ACTION_SET | SOCK_EVENT_READABLE);
179 }
180
181 /*
182 * auth_dns_callback - called when resolver query finishes
183 * if the query resulted in a successful search, name will contain
184 * a non-NULL pointer, otherwise name will be NULL.
185 * set the client on it's way to a connection completion, regardless
186 * of success of failure
187 */
188 static void
189 auth_dns_callback(void *vptr, const struct irc_ssaddr *addr, const char *name)
190 {
191 struct AuthRequest *auth = vptr;
192
193 assert(auth);
194
195 ClearDNSPending(auth);
196
197 if (name != NULL)
198 {
199 const struct sockaddr_in *v4, *v4dns;
200 const struct sockaddr_in6 *v6, *v6dns;
201 int good = 1;
202
203 if (auth->client->localClient->ip.ss.ss_family == AF_INET6)
204 {
205 v6 = (const struct sockaddr_in6 *)&auth->client->localClient->ip;
206 v6dns = (const struct sockaddr_in6 *)addr;
207 if (memcmp(&v6->sin6_addr, &v6dns->sin6_addr, sizeof(struct in6_addr)) != 0)
208 {
209 sendheader(auth->client, REPORT_IP_MISMATCH);
210 good = 0;
211 }
212 }
213 else
214 {
215 v4 = (const struct sockaddr_in *)&auth->client->localClient->ip;
216 v4dns = (const struct sockaddr_in *)addr;
217 if (v4->sin_addr.s_addr != v4dns->sin_addr.s_addr)
218 {
219 sendheader(auth->client, REPORT_IP_MISMATCH);
220 good = 0;
221 }
222 }
223
224 if (good)
225 {
226 if (!valid_hostname(name))
227 sendheader(auth->client, REPORT_INVAL_DNS);
228 else
229 {
230 strlcpy(auth->client->host, name,
231 sizeof(auth->client->host));
232 sendheader(auth->client, REPORT_FIN_DNS);
233 }
234 }
235 }
236 else
237 sendheader(auth->client, REPORT_FAIL_DNS);
238
239 if (!IsDoingAuth(auth))
240 {
241 release_auth_client(auth->client);
242 free_auth_request(auth);
243 }
244 }
245
246 /** Handle auth send errors.
247 * @param auth The request that saw the failure.
248 * @param kill If non-zero, a critical error; close the client's connection.
249 */
250 static void
251 auth_error(struct AuthRequest *auth)
252 {
253 ++ServerStats.is_abad;
254
255 assert(auth);
256
257 close(auth->fd);
258 auth->fd = -1;
259 socket_del(&auth->socket);
260
261 sendheader(auth->client, REPORT_FAIL_ID);
262
263 ClearAuth(auth);
264
265 if (!IsDNSPending(auth))
266 {
267 release_auth_client(auth->client);
268 free_auth_request(auth);
269 }
270 }
271
272 /*
273 * start_auth_query - Flag the client to show that an attempt to
274 * contact the ident server on
275 * the client's host. The connect and subsequently the socket are all put
276 * into 'non-blocking' mode. Should the connect or any later phase of the
277 * identifing process fail, it is aborted and the user is given a username
278 * of "unknown".
279 */
280 static int
281 start_auth_query(struct AuthRequest *auth)
282 {
283 struct irc_ssaddr localaddr;
284 socklen_t locallen = sizeof(struct irc_ssaddr);
285 struct sockaddr_in6 *v6;
286
287 #ifdef XXX__
288 /* open a socket of the same type as the client socket */
289 if (comm_open(&auth->fd, auth->client->localClient->ip.ss.ss_family,
290 SOCK_STREAM, 0, "ident") == -1)
291 {
292 report_error(L_ALL, "creating auth stream socket %s:%s",
293 get_client_name(auth->client, SHOW_IP), errno);
294 ilog(LOG_TYPE_IRCD, "Unable to create auth socket for %s",
295 get_client_name(auth->client, SHOW_IP));
296 ++ServerStats.is_abad;
297 return 0;
298 }
299 #endif
300 sendheader(auth->client, REPORT_DO_ID);
301
302 /*
303 * get the local address of the client and bind to that to
304 * make the auth request. This used to be done only for
305 * ifdef VIRTUAL_HOST, but needs to be done for all clients
306 * since the ident request must originate from that same address--
307 * and machines with multiple IP addresses are common now
308 */
309 memset(&localaddr, 0, locallen);
310 getsockname(s_fd(&auth->client->localClient->socket), (struct sockaddr *)&localaddr,
311 &locallen);
312
313 remove_ipv6_mapping(&localaddr);
314 v6 = (struct sockaddr_in6 *)&localaddr;
315 v6->sin6_port = htons(0);
316 localaddr.ss_port = htons(0);
317
318 #ifdef XXX__
319 comm_connect_tcp(&auth->fd, auth->client->sockhost, 113,
320 (struct sockaddr *)&localaddr, localaddr.ss_len, auth_connect_callback,
321 auth, auth->client->localClient->ip.ss.ss_family,
322 GlobalSetOptions.ident_timeout);
323 #endif
324 return 1; /* We suceed here for now */
325 }
326
327 /** Enum used to index ident reply fields in a human-readable way. */
328 enum IdentReplyFields
329 {
330 IDENT_PORT_NUMBERS,
331 IDENT_REPLY_TYPE,
332 IDENT_OS_TYPE,
333 IDENT_INFO,
334 USERID_TOKEN_COUNT
335 };
336
337 /** Parse an ident reply line and extract the userid from it.
338 * @param reply The ident reply line.
339 * @return The userid, or NULL on parse failure.
340 */
341 static char *
342 check_ident_reply(char *reply)
343 {
344 char *token;
345 char *end;
346 char *vector[USERID_TOKEN_COUNT];
347 int count = token_vector(reply, ':', vector, USERID_TOKEN_COUNT);
348
349 if (USERID_TOKEN_COUNT != count)
350 return 0;
351
352 /*
353 * Second token is the reply type
354 */
355 token = vector[IDENT_REPLY_TYPE];
356
357 if (EmptyString(token))
358 return 0;
359
360 while (IsSpace(*token))
361 ++token;
362
363 if (strncmp(token, "USERID", 6))
364 return 0;
365
366 /*
367 * Third token is the os type
368 */
369 token = vector[IDENT_OS_TYPE];
370
371 if (EmptyString(token))
372 return 0;
373 while (IsSpace(*token))
374 ++token;
375
376 /*
377 * Unless "OTHER" is specified as the operating system
378 * type, the server is expected to return the "normal"
379 * user identification of the owner of this connection.
380 * "Normal" in this context may be taken to mean a string
381 * of characters which uniquely identifies the connection
382 * owner such as a user identifier assigned by the system
383 * administrator and used by such user as a mail
384 * identifier, or as the "user" part of a user/password
385 * pair used to gain access to system resources. When an
386 * operating system is specified (e.g., anything but
387 * "OTHER"), the user identifier is expected to be in a
388 * more or less immediately useful form - e.g., something
389 * that could be used as an argument to "finger" or as a
390 * mail address.
391 */
392 if (!strncmp(token, "OTHER", 5))
393 return 0;
394
395 /*
396 * Fourth token is the username
397 */
398 token = vector[IDENT_INFO];
399
400 if (EmptyString(token))
401 return 0;
402 while (IsSpace(*token))
403 ++token;
404
405 #if 0
406 while (*token == '~' || *token == '^')
407 ++s;
408 #endif
409
410 /*
411 * Look for the end of the username, terminators are '\0, @, <SPACE>, :'
412 */
413 for (end = token; *end; ++end)
414 if (IsSpace(*end) || '@' == *end || ':' == *end)
415 break;
416 *end = '\0';
417
418 return token;
419 }
420
421 /** Starts auth (identd) and dns queries for a client.
422 * @param client The client for which to start queries.
423 */
424 void
425 start_auth(struct Client *client)
426 {
427 struct AuthRequest *auth = NULL;
428
429 assert(client);
430
431 auth = make_auth_request(client);
432 assert(auth);
433
434 sendheader(client, REPORT_DO_DNS);
435 gethost_byaddr(auth_dns_callback, auth, &client->localClient->ip);
436 SetDNSPending(auth);
437
438 if (start_auth_query(auth))
439 ilog(LOG_TYPE_DEBUG, "identd query for %p initiated successfully",
440 auth->client);
441 else if (IsDNSPending(auth))
442 ilog(LOG_TYPE_DEBUG, "identd query for %p not initiated successfully; "
443 "waiting on DNS", auth->client);
444 else
445 {
446 ilog(LOG_TYPE_DEBUG, "identd query for %p not initiated successfully; "
447 "no DNS pending; releasing immediately", auth->client);
448 free_auth_request(auth);
449 release_auth_client(client);
450 }
451 }
452
453 /** Send the ident server a query giving "theirport , ourport". The
454 * write is only attempted *once* so it is deemed to be a fail if the
455 * entire write doesn't write all the data given. This shouldn't be a
456 * problem since the socket should have a write buffer far greater
457 * than this message to store it in should problems arise. -avalon
458 * @param auth The request to send.
459 */
460 static void
461 send_auth_query(struct AuthRequest *auth)
462 {
463 struct irc_ssaddr us;
464 struct irc_ssaddr them;
465 char authbuf[32];
466 socklen_t ulen = sizeof(struct irc_ssaddr);
467 socklen_t tlen = sizeof(struct irc_ssaddr);
468 uint16_t uport, tport;
469 struct sockaddr_in6 *v6;
470 unsigned int count = 0;
471
472 if (getsockname(s_fd(&auth->client->localClient->socket), (struct sockaddr *)&us, &ulen) ||
473 getpeername(s_fd(&auth->client->localClient->socket), (struct sockaddr *)&them, &tlen))
474 {
475 ilog(LOG_TYPE_IRCD, "auth get{sock,peer}name error for %s",
476 get_client_name(auth->client, SHOW_IP));
477 auth_error(auth);
478 return;
479 }
480
481 v6 = (struct sockaddr_in6 *)&us;
482 uport = ntohs(v6->sin6_port);
483
484 v6 = (struct sockaddr_in6 *)&them;
485 tport = ntohs(v6->sin6_port);
486
487 remove_ipv6_mapping(&us);
488 remove_ipv6_mapping(&them);
489
490 snprintf(authbuf, sizeof(authbuf), "%u , %u\r\n", tport, uport);
491
492 if (os_send_nonb(auth->fd, authbuf, strlen(authbuf), &count) == IO_SUCCESS)
493 {
494 ClearAuthConnect(auth);
495 SetAuthPending(auth);
496 }
497 else
498 auth_error(auth);
499 }
500
501 /** Read the reply (if any) from the ident server we connected to. We
502 * only give it one shot, if the reply isn't good the first time fail
503 * the authentication entirely. --Bleep
504 * @param auth The request to read.
505 */
506 static void
507 read_auth_reply(struct AuthRequest *auth)
508 {
509 /*
510 * rfc1453 sez we MUST accept 512 bytes
511 */
512 char buf[IRCD_BUFSIZE + 1];
513 const char *username = NULL;
514 unsigned int len;
515
516 assert(auth);
517 assert(auth->client);
518 assert(auth == auth->client->localClient->auth);
519
520 if (IO_SUCCESS == os_recv_nonb(auth->fd, buf, IRCD_BUFSIZE, &len))
521 {
522 buf[len] = '\0';
523 ilog(LOG_TYPE_DEBUG, "Auth %p [%p] reply: %s", auth, &auth->socket, buf);
524 username = check_ident_reply(buf);
525 ilog(LOG_TYPE_DEBUG, "Username: %s", username);
526 }
527
528 close(auth->fd);
529 auth->fd = -1;
530 ilog(LOG_TYPE_DEBUG, "Deleting auth [%p] socket %p", auth, &auth->socket);
531 socket_del(&auth->socket);
532 ClearAuth(auth);
533
534 if (!EmptyString(username))
535 {
536 strlcpy(auth->client->username, username, sizeof(auth->client->username));
537 SetGotId(auth->client);
538 ++ServerStats.is_asuc;
539
540 sendheader(auth->client, REPORT_FIN_ID);
541 }
542 else
543 {
544 ++ServerStats.is_abad;
545 sendheader(auth->client, REPORT_FAIL_ID);
546 }
547
548 if (!IsDNSPending(auth))
549 {
550 release_auth_client(auth->client);
551 free_auth_request(auth);
552 }
553 }
554
555 /** Timeout a given auth request.
556 * @param ev A timer event whose associated data is the expired struct
557 * AuthRequest.
558 */
559 static void
560 auth_timeout_callback(struct Event *ev)
561 {
562 struct AuthRequest *auth = NULL;
563
564 assert(ev_timer(ev));
565 assert(t_data(ev_timer(ev)));
566
567 auth = t_data(ev_timer(ev));
568
569 if (ev_type(ev) == ET_DESTROY)
570 {
571 /* Being destroyed */
572 auth->flags &= ~AM_TIMEOUT;
573
574 if (!(auth->flags & AM_FREE_MASK))
575 {
576 ilog(LOG_TYPE_DEBUG, "Freeing auth from timeout callback; %p [%p]", auth,
577 ev_timer(ev));
578 MyFree(auth); /* Done with it, finally */
579 }
580 }
581 else
582 {
583 assert(ev_type(ev) == ET_EXPIRE);
584 destroy_auth_request(auth, 1);
585 }
586 }
587
588 /** Handle socket I/O activity.
589 * @param ev A socket event whos associated data is the active struct
590 * AuthRequest.
591 */
592 static void
593 auth_socket_callback(struct Event *ev)
594 {
595 struct AuthRequest *auth = NULL;
596
597 assert(ev_socket(ev));
598 assert(s_data(ev_socket(ev)));
599
600 auth = s_data(ev_socket(ev));
601
602 switch (ev_type(ev))
603 {
604 case ET_DESTROY: /* Being destroyed */
605 auth->flags &= ~AM_SOCKET;
606
607 if (!(auth->flags & AM_FREE_MASK))
608 {
609 ilog(LOG_TYPE_DEBUG, "Freeing auth from sock callback; %p [%p]", auth,
610 ev_socket(ev));
611 MyFree(auth); /* Done with it finally */
612 }
613
614 break;
615
616 case ET_CONNECT: /* Socket connection completed */
617 ilog(LOG_TYPE_DEBUG, "Connection completed for auth %p [%p]; sending query",
618 auth, ev_socket(ev));
619 socket_state(&auth->socket, SS_CONNECTED);
620 send_auth_query(auth);
621 break;
622
623 case ET_READ: /* Socket is readable */
624 case ET_EOF: /* End of file on socket */
625 case ET_ERROR: /* Error on socket */
626 ilog(LOG_TYPE_DEBUG, "Auth socket %p [%p] readable", auth, ev_socket(ev));
627 read_auth_reply(auth);
628 break;
629
630 default:
631 assert(0 && "Unrecognized event in auth_socket_callback().");
632 break;
633 }
634 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28