ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/auth.c
Revision: 4189
Committed: Mon Jul 7 18:30:34 2014 UTC (11 years, 1 month ago) by michael
Content type: text/x-csrc
File size: 15151 byte(s)
Log Message:
- Don't add/remove unregistered connections to/from global_client_list

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

Properties

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