ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/auth.c
Revision: 3250
Committed: Sun Mar 30 20:47:30 2014 UTC (11 years, 5 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/src/s_auth.c
File size: 15118 byte(s)
Log Message:
- Fixed inconsistent style in several places

File Contents

# User Rev Content
1 adx 30 /*
2 michael 2916 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 adx 30 *
4 michael 2916 * Copyright (c) 1997-2014 ircd-hybrid development team
5 adx 30 *
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 michael 2916 /*! \file s_auth.c
23     * \brief Functions for querying a users ident.
24     * \version $Id$
25     */
26    
27 adx 30 /*
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 michael 1309
38 adx 30 #include "stdinc.h"
39     #include "list.h"
40 michael 1011 #include "ircd_defs.h"
41     #include "fdlist.h"
42 adx 30 #include "s_auth.h"
43 michael 1309 #include "conf.h"
44 adx 30 #include "client.h"
45     #include "event.h"
46     #include "hook.h"
47     #include "irc_string.h"
48     #include "ircd.h"
49     #include "packet.h"
50     #include "irc_res.h"
51     #include "s_bsd.h"
52 michael 1309 #include "log.h"
53 adx 30 #include "send.h"
54 michael 1654 #include "mempool.h"
55 adx 30
56 michael 1011
57 michael 2916 static const char *HeaderMessages[] =
58     {
59 michael 3168 ":*** Looking up your hostname...",
60     ":*** Found your hostname",
61     ":*** Couldn't look up your hostname",
62     ":*** Checking Ident",
63     ":*** Got Ident response",
64     ":*** No Ident response",
65     ":*** Your forward and reverse DNS do not match, ignoring hostname.",
66     ":*** Your hostname is too long, ignoring hostname"
67 adx 30 };
68    
69 michael 2916 enum
70     {
71 adx 30 REPORT_DO_DNS,
72     REPORT_FIN_DNS,
73     REPORT_FAIL_DNS,
74     REPORT_DO_ID,
75     REPORT_FIN_ID,
76     REPORT_FAIL_ID,
77     REPORT_IP_MISMATCH,
78     REPORT_HOST_TOOLONG
79     };
80    
81 michael 3168 #define sendheader(c, i) sendto_one_notice((c), &me, HeaderMessages[(i)])
82 adx 30
83 michael 992 static dlink_list auth_doing_list = { NULL, NULL, 0 };
84 adx 30
85     static EVH timeout_auth_queries_event;
86    
87     static PF read_auth_reply;
88     static CNCB auth_connect_callback;
89    
90 michael 1798 /* auth_init
91 adx 30 *
92     * Initialise the auth code
93     */
94     void
95 michael 1798 auth_init(void)
96 adx 30 {
97     eventAddIsh("timeout_auth_queries_event", timeout_auth_queries_event, NULL, 1);
98     }
99    
100     /*
101     * make_auth_request - allocate a new auth request
102     */
103     static struct AuthRequest *
104     make_auth_request(struct Client *client)
105     {
106 michael 2181 struct AuthRequest *request = &client->localClient->auth;
107 adx 30
108 michael 1654 memset(request, 0, sizeof(*request));
109 adx 30
110 michael 2181 request->client = client;
111     request->timeout = CurrentTime + CONNECTTIMEOUT;
112    
113 michael 650 return request;
114 adx 30 }
115    
116     /*
117     * release_auth_client - release auth client from auth system
118     * this adds the client into the local client lists so it can be read by
119     * the main io processing loop
120     */
121     void
122 michael 992 release_auth_client(struct AuthRequest *auth)
123 adx 30 {
124 michael 992 struct Client *client = auth->client;
125    
126     if (IsDoingAuth(auth) || IsDNSPending(auth))
127     return;
128    
129 michael 2929 if (IsInAuth(auth))
130     {
131 michael 2181 dlinkDelete(&auth->node, &auth_doing_list);
132 michael 2929 ClearInAuth(auth);
133     }
134 michael 992
135 adx 30 /*
136     * When a client has auth'ed, we want to start reading what it sends
137     * us. This is what read_packet() does.
138     * -- adrian
139     */
140     client->localClient->allow_read = MAX_FLOOD;
141     comm_setflush(&client->localClient->fd, 1000, flood_recalc, client);
142 michael 650
143 michael 992 dlinkAdd(client, &client->node, &global_client_list);
144 michael 650
145 michael 1241 client->localClient->since = CurrentTime;
146     client->localClient->lasttime = CurrentTime;
147     client->localClient->firsttime = CurrentTime;
148 michael 664 client->flags |= FLAGS_FINISHED_AUTH;
149 michael 650
150 adx 30 read_packet(&client->localClient->fd, client);
151     }
152 michael 2916
153 adx 30 /*
154     * auth_dns_callback - called when resolver query finishes
155 michael 998 * if the query resulted in a successful search, name will contain
156     * a non-NULL pointer, otherwise name will be NULL.
157 adx 30 * set the client on it's way to a connection completion, regardless
158     * of success of failure
159     */
160     static void
161 michael 992 auth_dns_callback(void *vptr, const struct irc_ssaddr *addr, const char *name)
162 adx 30 {
163 michael 992 struct AuthRequest *auth = vptr;
164 adx 30
165     ClearDNSPending(auth);
166    
167 michael 3250 if (name)
168 adx 30 {
169 michael 992 const struct sockaddr_in *v4, *v4dns;
170 adx 30 #ifdef IPV6
171 michael 992 const struct sockaddr_in6 *v6, *v6dns;
172 adx 30 #endif
173     int good = 1;
174    
175     #ifdef IPV6
176     if (auth->client->localClient->ip.ss.ss_family == AF_INET6)
177     {
178 michael 992 v6 = (const struct sockaddr_in6 *)&auth->client->localClient->ip;
179     v6dns = (const struct sockaddr_in6 *)addr;
180 michael 3250
181 adx 30 if (memcmp(&v6->sin6_addr, &v6dns->sin6_addr, sizeof(struct in6_addr)) != 0)
182     {
183     sendheader(auth->client, REPORT_IP_MISMATCH);
184     good = 0;
185     }
186     }
187     else
188     #endif
189     {
190 michael 992 v4 = (const struct sockaddr_in *)&auth->client->localClient->ip;
191     v4dns = (const struct sockaddr_in *)addr;
192 michael 3250
193     if (v4->sin_addr.s_addr != v4dns->sin_addr.s_addr)
194 adx 30 {
195     sendheader(auth->client, REPORT_IP_MISMATCH);
196     good = 0;
197     }
198     }
199 michael 3250
200 michael 992 if (good && strlen(name) <= HOSTLEN)
201 adx 30 {
202 michael 992 strlcpy(auth->client->host, name,
203 michael 2916 sizeof(auth->client->host));
204 adx 30 sendheader(auth->client, REPORT_FIN_DNS);
205     }
206 michael 992 else if (strlen(name) > HOSTLEN)
207 adx 30 sendheader(auth->client, REPORT_HOST_TOOLONG);
208     }
209     else
210 michael 992 sendheader(auth->client, REPORT_FAIL_DNS);
211 adx 30
212 michael 992 release_auth_client(auth);
213 adx 30 }
214    
215     /*
216     * authsenderr - handle auth send errors
217     */
218     static void
219     auth_error(struct AuthRequest *auth)
220     {
221 michael 896 ++ServerStats.is_abad;
222 adx 30
223     fd_close(&auth->fd);
224    
225     ClearAuth(auth);
226    
227     sendheader(auth->client, REPORT_FAIL_ID);
228    
229 michael 992 release_auth_client(auth);
230 adx 30 }
231    
232     /*
233 michael 2916 * start_auth_query - Flag the client to show that an attempt to
234 adx 30 * contact the ident server on
235     * the client's host. The connect and subsequently the socket are all put
236     * into 'non-blocking' mode. Should the connect or any later phase of the
237     * identifing process fail, it is aborted and the user is given a username
238     * of "unknown".
239     */
240     static int
241     start_auth_query(struct AuthRequest *auth)
242     {
243     struct irc_ssaddr localaddr;
244     socklen_t locallen = sizeof(struct irc_ssaddr);
245     #ifdef IPV6
246     struct sockaddr_in6 *v6;
247     #else
248     struct sockaddr_in *v4;
249     #endif
250    
251     /* open a socket of the same type as the client socket */
252     if (comm_open(&auth->fd, auth->client->localClient->ip.ss.ss_family,
253     SOCK_STREAM, 0, "ident") == -1)
254     {
255 michael 2916 report_error(L_ALL, "creating auth stream socket %s:%s",
256     get_client_name(auth->client, SHOW_IP), errno);
257 michael 1247 ilog(LOG_TYPE_IRCD, "Unable to create auth socket for %s",
258 adx 30 get_client_name(auth->client, SHOW_IP));
259 michael 896 ++ServerStats.is_abad;
260 adx 30 return 0;
261     }
262    
263     sendheader(auth->client, REPORT_DO_ID);
264    
265 michael 2916 /*
266 adx 30 * get the local address of the client and bind to that to
267     * make the auth request. This used to be done only for
268     * ifdef VIRTUAL_HOST, but needs to be done for all clients
269     * since the ident request must originate from that same address--
270     * and machines with multiple IP addresses are common now
271     */
272     memset(&localaddr, 0, locallen);
273     getsockname(auth->client->localClient->fd.fd, (struct sockaddr*)&localaddr,
274     &locallen);
275    
276     #ifdef IPV6
277     remove_ipv6_mapping(&localaddr);
278     v6 = (struct sockaddr_in6 *)&localaddr;
279     v6->sin6_port = htons(0);
280     #else
281     localaddr.ss_len = locallen;
282     v4 = (struct sockaddr_in *)&localaddr;
283     v4->sin_port = htons(0);
284     #endif
285     localaddr.ss_port = htons(0);
286    
287 michael 2916 comm_connect_tcp(&auth->fd, auth->client->sockhost, 113,
288     (struct sockaddr *)&localaddr, localaddr.ss_len, auth_connect_callback,
289     auth, auth->client->localClient->ip.ss.ss_family,
290 adx 30 GlobalSetOptions.ident_timeout);
291     return 1; /* We suceed here for now */
292     }
293    
294     /*
295     * GetValidIdent - parse ident query reply from identd server
296 michael 2916 *
297 adx 30 * Inputs - pointer to ident buf
298     * Output - NULL if no valid ident found, otherwise pointer to name
299     * Side effects -
300     */
301     /*
302     * A few questions have been asked about this mess, obviously
303     * it should have been commented better the first time.
304     * The original idea was to remove all references to libc from ircd-hybrid.
305     * Instead of having to write a replacement for sscanf(), I did a
306     * rather gruseome parser here so we could remove this function call.
307     * Note, that I had also removed a few floating point printfs as well (though
308     * now we are still stuck with a few...)
309     * Remember, we have a replacement ircd sprintf, we have bleeps fputs lib
310     * it would have been nice to remove some unneeded code.
311     * Oh well. If we don't remove libc stuff totally, then it would be
312     * far cleaner to use sscanf()
313     *
314     * - Dianora
315     */
316     static char *
317     GetValidIdent(char *buf)
318     {
319     int remp = 0;
320     int locp = 0;
321     char* colon1Ptr;
322     char* colon2Ptr;
323     char* colon3Ptr;
324     char* commaPtr;
325     char* remotePortString;
326    
327     /* All this to get rid of a sscanf() fun. */
328     remotePortString = buf;
329 michael 2916
330 adx 30 if ((colon1Ptr = strchr(remotePortString,':')) == NULL)
331     return 0;
332     *colon1Ptr = '\0';
333     colon1Ptr++;
334    
335     if ((colon2Ptr = strchr(colon1Ptr,':')) == NULL)
336     return 0;
337     *colon2Ptr = '\0';
338     colon2Ptr++;
339 michael 2916
340 adx 30 if ((commaPtr = strchr(remotePortString, ',')) == NULL)
341     return 0;
342     *commaPtr = '\0';
343     commaPtr++;
344    
345     if ((remp = atoi(remotePortString)) == 0)
346     return 0;
347 michael 2916
348 adx 30 if ((locp = atoi(commaPtr)) == 0)
349     return 0;
350    
351     /* look for USERID bordered by first pair of colons */
352     if (strstr(colon1Ptr, "USERID") == NULL)
353     return 0;
354    
355     if ((colon3Ptr = strchr(colon2Ptr,':')) == NULL)
356     return 0;
357     *colon3Ptr = '\0';
358     colon3Ptr++;
359     return (colon3Ptr);
360     }
361    
362     /*
363 michael 2916 * start_auth
364 adx 30 *
365     * inputs - pointer to client to auth
366     * output - NONE
367     * side effects - starts auth (identd) and dns queries for a client
368     */
369 michael 2916 void
370 michael 3250 start_auth(struct Client *client_p)
371 adx 30 {
372     struct AuthRequest *auth = NULL;
373    
374 michael 3250 assert(client_p);
375 adx 30
376 michael 3250 auth = make_auth_request(client_p);
377 michael 2929 SetInAuth(auth);
378     dlinkAddTail(auth, &auth->node, &auth_doing_list);
379 adx 30
380 michael 3250 sendheader(client_p, REPORT_DO_DNS);
381 adx 30
382 michael 992 SetDNSPending(auth);
383    
384 adx 30 if (ConfigFileEntry.disable_auth == 0)
385 michael 992 {
386     SetDoingAuth(auth);
387 adx 30 start_auth_query(auth);
388 michael 992 }
389 adx 30
390 michael 3250 gethost_byaddr(auth_dns_callback, auth, &client_p->localClient->ip);
391 adx 30 }
392    
393     /*
394     * timeout_auth_queries - timeout resolver and identd requests
395     * allow clients through if requests failed
396     */
397     static void
398     timeout_auth_queries_event(void *notused)
399     {
400 michael 3250 dlink_node *ptr = NULL, *ptr_next = NULL;
401 adx 30
402 michael 3250 DLINK_FOREACH_SAFE(ptr, ptr_next, auth_doing_list.head)
403 adx 30 {
404 michael 992 struct AuthRequest *auth = ptr->data;
405 adx 30
406 michael 992 if (auth->timeout > CurrentTime)
407 michael 2929 break;
408 adx 30
409 michael 992 if (IsDoingAuth(auth))
410 michael 2916 {
411 michael 896 ++ServerStats.is_abad;
412 michael 1000 fd_close(&auth->fd);
413 michael 998 ClearAuth(auth);
414 adx 30 sendheader(auth->client, REPORT_FAIL_ID);
415 michael 992 }
416 adx 30
417 michael 992 if (IsDNSPending(auth))
418     {
419     delete_resolver_queries(auth);
420 michael 998 ClearDNSPending(auth);
421 michael 992 sendheader(auth->client, REPORT_FAIL_DNS);
422     }
423 adx 30
424 michael 1247 ilog(LOG_TYPE_IRCD, "DNS/AUTH timeout %s",
425 michael 992 get_client_name(auth->client, SHOW_IP));
426     release_auth_client(auth);
427 adx 30 }
428     }
429    
430     /*
431     * auth_connect_callback() - deal with the result of comm_connect_tcp()
432     *
433     * If the connection failed, we simply close the auth fd and report
434     * a failure. If the connection suceeded send the ident server a query
435     * giving "theirport , ourport". The write is only attempted *once* so
436     * it is deemed to be a fail if the entire write doesn't write all the
437     * data given. This shouldnt be a problem since the socket should have
438     * a write buffer far greater than this message to store it in should
439     * problems arise. -avalon
440     */
441     static void
442     auth_connect_callback(fde_t *fd, int error, void *data)
443     {
444     struct AuthRequest *auth = data;
445     struct irc_ssaddr us;
446     struct irc_ssaddr them;
447     char authbuf[32];
448     socklen_t ulen = sizeof(struct irc_ssaddr);
449     socklen_t tlen = sizeof(struct irc_ssaddr);
450 michael 1032 uint16_t uport, tport;
451 adx 30 #ifdef IPV6
452     struct sockaddr_in6 *v6;
453     #else
454     struct sockaddr_in *v4;
455     #endif
456    
457     if (error != COMM_OK)
458     {
459     auth_error(auth);
460     return;
461     }
462    
463 michael 3250 if (getsockname(auth->client->localClient->fd.fd, (struct sockaddr *)&us, &ulen) ||
464     getpeername(auth->client->localClient->fd.fd, (struct sockaddr *)&them, &tlen))
465 adx 30 {
466 michael 1247 ilog(LOG_TYPE_IRCD, "auth get{sock,peer}name error for %s",
467 michael 3250 get_client_name(auth->client, SHOW_IP));
468 adx 30 auth_error(auth);
469     return;
470     }
471    
472     #ifdef IPV6
473     v6 = (struct sockaddr_in6 *)&us;
474     uport = ntohs(v6->sin6_port);
475     v6 = (struct sockaddr_in6 *)&them;
476     tport = ntohs(v6->sin6_port);
477     remove_ipv6_mapping(&us);
478     remove_ipv6_mapping(&them);
479     #else
480     v4 = (struct sockaddr_in *)&us;
481     uport = ntohs(v4->sin_port);
482     v4 = (struct sockaddr_in *)&them;
483     tport = ntohs(v4->sin_port);
484     us.ss_len = ulen;
485     them.ss_len = tlen;
486     #endif
487 michael 2916
488 michael 1124 snprintf(authbuf, sizeof(authbuf), "%u , %u\r\n", tport, uport);
489 adx 30
490     if (send(fd->fd, authbuf, strlen(authbuf), 0) == -1)
491     {
492     auth_error(auth);
493     return;
494     }
495 michael 696
496 adx 30 read_auth_reply(&auth->fd, auth);
497     }
498    
499     /*
500 michael 2916 * read_auth_reply - read the reply (if any) from the ident server
501 adx 30 * we connected to.
502     * We only give it one shot, if the reply isn't good the first time
503     * fail the authentication entirely. --Bleep
504     */
505     #define AUTH_BUFSIZ 128
506    
507     static void
508     read_auth_reply(fde_t *fd, void *data)
509     {
510     struct AuthRequest *auth = data;
511     char *s = NULL;
512     char *t = NULL;
513     int len;
514     int count;
515     char buf[AUTH_BUFSIZ + 1]; /* buffer to read auth reply into */
516    
517 nenolod 397 /* Why?
518     * Well, recv() on many POSIX systems is a per-packet operation,
519     * and we do not necessarily want this, because on lowspec machines,
520     * the ident response may come back fragmented, thus resulting in an
521     * invalid ident response, even if the ident response was really OK.
522     *
523     * So PLEASE do not change this code to recv without being aware of the
524     * consequences.
525     *
526     * --nenolod
527     */
528     len = read(fd->fd, buf, AUTH_BUFSIZ);
529 michael 1001
530 adx 30 if (len < 0)
531     {
532     if (ignoreErrno(errno))
533     comm_setselect(fd, COMM_SELECT_READ, read_auth_reply, auth, 0);
534     else
535     auth_error(auth);
536     return;
537     }
538    
539     if (len > 0)
540     {
541     buf[len] = '\0';
542    
543     if ((s = GetValidIdent(buf)))
544     {
545     t = auth->client->username;
546    
547     while (*s == '~' || *s == '^')
548     s++;
549    
550     for (count = USERLEN; *s && count; s++)
551     {
552     if (*s == '@')
553     break;
554     if (!IsSpace(*s) && *s != ':' && *s != '[')
555     {
556     *t++ = *s;
557     count--;
558     }
559     }
560    
561     *t = '\0';
562     }
563     }
564    
565     fd_close(fd);
566    
567     ClearAuth(auth);
568    
569     if (s == NULL)
570     {
571     sendheader(auth->client, REPORT_FAIL_ID);
572 michael 896 ++ServerStats.is_abad;
573 adx 30 }
574     else
575     {
576     sendheader(auth->client, REPORT_FIN_ID);
577 michael 896 ++ServerStats.is_asuc;
578 adx 30 SetGotId(auth->client);
579     }
580    
581 michael 992 release_auth_client(auth);
582 adx 30 }
583    
584     /*
585     * delete_auth()
586     */
587 michael 2916 void
588 michael 992 delete_auth(struct AuthRequest *auth)
589 adx 30 {
590 michael 992 if (IsDNSPending(auth))
591     delete_resolver_queries(auth);
592 adx 30
593 michael 1000 if (IsDoingAuth(auth))
594     fd_close(&auth->fd);
595    
596 michael 2929 if (IsInAuth(auth))
597     {
598 michael 2181 dlinkDelete(&auth->node, &auth_doing_list);
599 michael 2929 ClearInAuth(auth);
600     }
601 adx 30 }

Properties

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