ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/auth.c
Revision: 3274
Committed: Sun Apr 6 12:22:23 2014 UTC (11 years, 4 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/src/s_auth.c
File size: 15100 byte(s)
Log Message:
- Clean up redundant/unused header includes

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

Properties

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