ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/src/auth.c
Revision: 4409
Committed: Wed Aug 6 21:20:45 2014 UTC (9 years, 8 months ago) by michael
Content type: text/x-csrc
File size: 14655 byte(s)
Log Message:
- Fixed resolver/auth issues with too long hostnames

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 3564 static const char *const HeaderMessages[] =
57 michael 2916 {
58 michael 4310 ":*** Looking up your hostname",
59 michael 3168 ":*** Found your hostname",
60     ":*** Couldn't look up your hostname",
61     ":*** Checking Ident",
62     ":*** Got Ident response",
63     ":*** No Ident response",
64 michael 4310 ":*** Your forward and reverse DNS do not match, ignoring hostname",
65 michael 3168 ":*** 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 4310 static dlink_list auth_pending_list;
83 adx 30 static PF read_auth_reply;
84     static CNCB auth_connect_callback;
85    
86 michael 4095
87 adx 30 /*
88     * make_auth_request - allocate a new auth request
89     */
90     static struct AuthRequest *
91     make_auth_request(struct Client *client)
92     {
93 michael 2181 struct AuthRequest *request = &client->localClient->auth;
94 adx 30
95 michael 1654 memset(request, 0, sizeof(*request));
96 adx 30
97 michael 2181 request->client = client;
98     request->timeout = CurrentTime + CONNECTTIMEOUT;
99    
100 michael 650 return request;
101 adx 30 }
102    
103     /*
104     * release_auth_client - release auth client from auth system
105     * this adds the client into the local client lists so it can be read by
106     * the main io processing loop
107     */
108     void
109 michael 992 release_auth_client(struct AuthRequest *auth)
110 adx 30 {
111 michael 992 struct Client *client = auth->client;
112    
113     if (IsDoingAuth(auth) || IsDNSPending(auth))
114     return;
115    
116 michael 2929 if (IsInAuth(auth))
117     {
118 michael 4310 dlinkDelete(&auth->node, &auth_pending_list);
119 michael 2929 ClearInAuth(auth);
120     }
121 michael 992
122 adx 30 /*
123     * When a client has auth'ed, we want to start reading what it sends
124     * us. This is what read_packet() does.
125     * -- adrian
126     */
127     client->localClient->allow_read = MAX_FLOOD;
128     comm_setflush(&client->localClient->fd, 1000, flood_recalc, client);
129 michael 650
130 michael 1241 client->localClient->since = CurrentTime;
131     client->localClient->lasttime = CurrentTime;
132     client->localClient->firsttime = CurrentTime;
133 michael 664 client->flags |= FLAGS_FINISHED_AUTH;
134 michael 650
135 adx 30 read_packet(&client->localClient->fd, client);
136     }
137 michael 2916
138 adx 30 /*
139     * auth_dns_callback - called when resolver query finishes
140 michael 998 * if the query resulted in a successful search, name will contain
141     * a non-NULL pointer, otherwise name will be NULL.
142 adx 30 * set the client on it's way to a connection completion, regardless
143     * of success of failure
144     */
145     static void
146 michael 4409 auth_dns_callback(void *vptr, const struct irc_ssaddr *addr, const char *name, size_t namelength)
147 adx 30 {
148 michael 992 struct AuthRequest *auth = vptr;
149 adx 30
150     ClearDNSPending(auth);
151    
152 michael 4409 if (!EmptyString(name))
153 adx 30 {
154 michael 992 const struct sockaddr_in *v4, *v4dns;
155 adx 30 #ifdef IPV6
156 michael 992 const struct sockaddr_in6 *v6, *v6dns;
157 adx 30
158     if (auth->client->localClient->ip.ss.ss_family == AF_INET6)
159     {
160 michael 992 v6 = (const struct sockaddr_in6 *)&auth->client->localClient->ip;
161     v6dns = (const struct sockaddr_in6 *)addr;
162 michael 3250
163 adx 30 if (memcmp(&v6->sin6_addr, &v6dns->sin6_addr, sizeof(struct in6_addr)) != 0)
164     {
165     sendheader(auth->client, REPORT_IP_MISMATCH);
166 michael 4409 release_auth_client(auth);
167     return;
168 adx 30 }
169     }
170     else
171     #endif
172     {
173 michael 992 v4 = (const struct sockaddr_in *)&auth->client->localClient->ip;
174     v4dns = (const struct sockaddr_in *)addr;
175 michael 3250
176     if (v4->sin_addr.s_addr != v4dns->sin_addr.s_addr)
177 adx 30 {
178     sendheader(auth->client, REPORT_IP_MISMATCH);
179 michael 4409 release_auth_client(auth);
180     return;
181 adx 30 }
182     }
183 michael 3250
184 michael 4409 if (namelength > HOSTLEN)
185     sendheader(auth->client, REPORT_HOST_TOOLONG);
186     else
187 adx 30 {
188 michael 4409 strlcpy(auth->client->host, name, sizeof(auth->client->host));
189 adx 30 sendheader(auth->client, REPORT_FIN_DNS);
190     }
191     }
192     else
193 michael 992 sendheader(auth->client, REPORT_FAIL_DNS);
194 adx 30
195 michael 992 release_auth_client(auth);
196 adx 30 }
197    
198     /*
199     * authsenderr - handle auth send errors
200     */
201     static void
202     auth_error(struct AuthRequest *auth)
203     {
204 michael 896 ++ServerStats.is_abad;
205 adx 30
206     fd_close(&auth->fd);
207    
208     ClearAuth(auth);
209    
210     sendheader(auth->client, REPORT_FAIL_ID);
211    
212 michael 992 release_auth_client(auth);
213 adx 30 }
214    
215     /*
216 michael 2916 * start_auth_query - Flag the client to show that an attempt to
217 adx 30 * contact the ident server on
218     * the client's host. The connect and subsequently the socket are all put
219     * into 'non-blocking' mode. Should the connect or any later phase of the
220     * identifing process fail, it is aborted and the user is given a username
221     * of "unknown".
222     */
223     static int
224     start_auth_query(struct AuthRequest *auth)
225     {
226     struct irc_ssaddr localaddr;
227     socklen_t locallen = sizeof(struct irc_ssaddr);
228     #ifdef IPV6
229     struct sockaddr_in6 *v6;
230     #else
231     struct sockaddr_in *v4;
232     #endif
233    
234     /* open a socket of the same type as the client socket */
235     if (comm_open(&auth->fd, auth->client->localClient->ip.ss.ss_family,
236     SOCK_STREAM, 0, "ident") == -1)
237     {
238 michael 2916 report_error(L_ALL, "creating auth stream socket %s:%s",
239     get_client_name(auth->client, SHOW_IP), errno);
240 michael 1247 ilog(LOG_TYPE_IRCD, "Unable to create auth socket for %s",
241 adx 30 get_client_name(auth->client, SHOW_IP));
242 michael 896 ++ServerStats.is_abad;
243 adx 30 return 0;
244     }
245    
246     sendheader(auth->client, REPORT_DO_ID);
247    
248 michael 2916 /*
249 adx 30 * get the local address of the client and bind to that to
250     * make the auth request. This used to be done only for
251     * ifdef VIRTUAL_HOST, but needs to be done for all clients
252     * since the ident request must originate from that same address--
253     * and machines with multiple IP addresses are common now
254     */
255     memset(&localaddr, 0, locallen);
256     getsockname(auth->client->localClient->fd.fd, (struct sockaddr*)&localaddr,
257     &locallen);
258    
259     #ifdef IPV6
260     remove_ipv6_mapping(&localaddr);
261     v6 = (struct sockaddr_in6 *)&localaddr;
262     v6->sin6_port = htons(0);
263     #else
264     localaddr.ss_len = locallen;
265     v4 = (struct sockaddr_in *)&localaddr;
266     v4->sin_port = htons(0);
267     #endif
268     localaddr.ss_port = htons(0);
269    
270 michael 4310 comm_connect_tcp(&auth->fd, auth->client->sockhost, RFC1413_PORT,
271 michael 2916 (struct sockaddr *)&localaddr, localaddr.ss_len, auth_connect_callback,
272     auth, auth->client->localClient->ip.ss.ss_family,
273 adx 30 GlobalSetOptions.ident_timeout);
274     return 1; /* We suceed here for now */
275     }
276    
277     /*
278 michael 2916 * start_auth
279 adx 30 *
280     * inputs - pointer to client to auth
281     * output - NONE
282     * side effects - starts auth (identd) and dns queries for a client
283     */
284 michael 2916 void
285 michael 3250 start_auth(struct Client *client_p)
286 adx 30 {
287     struct AuthRequest *auth = NULL;
288    
289 michael 3250 assert(client_p);
290 adx 30
291 michael 3250 auth = make_auth_request(client_p);
292 michael 2929 SetInAuth(auth);
293 michael 4310 dlinkAddTail(auth, &auth->node, &auth_pending_list);
294 adx 30
295 michael 3250 sendheader(client_p, REPORT_DO_DNS);
296 adx 30
297 michael 992 SetDNSPending(auth);
298    
299 michael 4341 if (ConfigGeneral.disable_auth == 0)
300 michael 992 {
301     SetDoingAuth(auth);
302 adx 30 start_auth_query(auth);
303 michael 992 }
304 adx 30
305 michael 3250 gethost_byaddr(auth_dns_callback, auth, &client_p->localClient->ip);
306 adx 30 }
307    
308     /*
309     * timeout_auth_queries - timeout resolver and identd requests
310     * allow clients through if requests failed
311     */
312     static void
313     timeout_auth_queries_event(void *notused)
314     {
315 michael 3250 dlink_node *ptr = NULL, *ptr_next = NULL;
316 adx 30
317 michael 4310 DLINK_FOREACH_SAFE(ptr, ptr_next, auth_pending_list.head)
318 adx 30 {
319 michael 992 struct AuthRequest *auth = ptr->data;
320 adx 30
321 michael 992 if (auth->timeout > CurrentTime)
322 michael 2929 break;
323 adx 30
324 michael 992 if (IsDoingAuth(auth))
325 michael 2916 {
326 michael 896 ++ServerStats.is_abad;
327 michael 1000 fd_close(&auth->fd);
328 michael 998 ClearAuth(auth);
329 adx 30 sendheader(auth->client, REPORT_FAIL_ID);
330 michael 992 }
331 adx 30
332 michael 992 if (IsDNSPending(auth))
333     {
334     delete_resolver_queries(auth);
335 michael 998 ClearDNSPending(auth);
336 michael 992 sendheader(auth->client, REPORT_FAIL_DNS);
337     }
338 adx 30
339 michael 1247 ilog(LOG_TYPE_IRCD, "DNS/AUTH timeout %s",
340 michael 992 get_client_name(auth->client, SHOW_IP));
341     release_auth_client(auth);
342 adx 30 }
343     }
344    
345     /*
346     * auth_connect_callback() - deal with the result of comm_connect_tcp()
347     *
348     * If the connection failed, we simply close the auth fd and report
349     * a failure. If the connection suceeded send the ident server a query
350     * giving "theirport , ourport". The write is only attempted *once* so
351     * it is deemed to be a fail if the entire write doesn't write all the
352     * data given. This shouldnt be a problem since the socket should have
353     * a write buffer far greater than this message to store it in should
354     * problems arise. -avalon
355     */
356     static void
357     auth_connect_callback(fde_t *fd, int error, void *data)
358     {
359     struct AuthRequest *auth = data;
360     struct irc_ssaddr us;
361     struct irc_ssaddr them;
362     char authbuf[32];
363     socklen_t ulen = sizeof(struct irc_ssaddr);
364     socklen_t tlen = sizeof(struct irc_ssaddr);
365 michael 1032 uint16_t uport, tport;
366 adx 30 #ifdef IPV6
367     struct sockaddr_in6 *v6;
368     #else
369     struct sockaddr_in *v4;
370     #endif
371    
372     if (error != COMM_OK)
373     {
374     auth_error(auth);
375     return;
376     }
377    
378 michael 3250 if (getsockname(auth->client->localClient->fd.fd, (struct sockaddr *)&us, &ulen) ||
379     getpeername(auth->client->localClient->fd.fd, (struct sockaddr *)&them, &tlen))
380 adx 30 {
381 michael 1247 ilog(LOG_TYPE_IRCD, "auth get{sock,peer}name error for %s",
382 michael 3250 get_client_name(auth->client, SHOW_IP));
383 adx 30 auth_error(auth);
384     return;
385     }
386    
387     #ifdef IPV6
388     v6 = (struct sockaddr_in6 *)&us;
389     uport = ntohs(v6->sin6_port);
390     v6 = (struct sockaddr_in6 *)&them;
391     tport = ntohs(v6->sin6_port);
392     remove_ipv6_mapping(&us);
393     remove_ipv6_mapping(&them);
394     #else
395     v4 = (struct sockaddr_in *)&us;
396     uport = ntohs(v4->sin_port);
397     v4 = (struct sockaddr_in *)&them;
398     tport = ntohs(v4->sin_port);
399     us.ss_len = ulen;
400     them.ss_len = tlen;
401     #endif
402 michael 2916
403 michael 4310 snprintf(authbuf, sizeof(authbuf), "%u, %u\r\n", tport, uport);
404 adx 30
405     if (send(fd->fd, authbuf, strlen(authbuf), 0) == -1)
406     {
407     auth_error(auth);
408     return;
409     }
410 michael 696
411 michael 4310 comm_setselect(fd, COMM_SELECT_READ, read_auth_reply, auth, 0);
412 adx 30 }
413    
414 michael 4310 /** Enum used to index ident reply fields in a human-readable way. */
415     enum IdentReplyFields
416     {
417     IDENT_PORT_NUMBERS,
418     IDENT_REPLY_TYPE,
419     IDENT_OS_TYPE,
420     IDENT_INFO,
421     USERID_TOKEN_COUNT
422     };
423    
424     /** Parse an ident reply line and extract the userid from it.
425     * \param reply The ident reply line.
426     * \return The userid, or NULL on parse failure.
427     */
428     static const char *
429     check_ident_reply(char *reply)
430     {
431     char *token = NULL, *end = NULL;
432     char *vector[USERID_TOKEN_COUNT];
433     int count = token_vector(reply, ':', vector, USERID_TOKEN_COUNT);
434    
435     if (USERID_TOKEN_COUNT != count)
436     return NULL;
437    
438     /*
439     * Second token is the reply type
440     */
441     token = vector[IDENT_REPLY_TYPE];
442    
443     if (EmptyString(token))
444     return NULL;
445    
446     while (IsSpace(*token))
447     ++token;
448    
449     if (strncmp(token, "USERID", 6))
450     return NULL;
451    
452     /*
453     * Third token is the os type
454     */
455     token = vector[IDENT_OS_TYPE];
456    
457     if (EmptyString(token))
458     return NULL;
459    
460     while (IsSpace(*token))
461     ++token;
462    
463     /*
464     * Unless "OTHER" is specified as the operating system type, the server
465     * is expected to return the "normal" user identification of the owner
466     * of this connection. "Normal" in this context may be taken to mean a
467     * string of characters which uniquely identifies the connection owner
468     * such as a user identifier assigned by the system administrator and
469     * used by such user as a mail identifier, or as the "user" part of a
470     * user/password pair used to gain access to system resources. When an
471     * operating system is specified (e.g., anything but "OTHER"), the user
472     * identifier is expected to be in a more or less immediately useful
473     * form - e.g., something that could be used as an argument to "finger"
474     * or as a mail address.
475     */
476     if (!strncmp(token, "OTHER", 5))
477     return NULL;
478    
479     /*
480     * Fourth token is the username
481     */
482     token = vector[IDENT_INFO];
483    
484     if (EmptyString(token))
485     return NULL;
486    
487     while (IsSpace(*token))
488     ++token;
489    
490     while (*token == '~' || *token == '^')
491     ++token;
492    
493     /*
494     * Look for the end of the username, terminators are '\0, @, <SPACE>, :'
495     */
496     for (end = token; *end; ++end)
497     if (IsSpace(*end) || '@' == *end || ':' == *end)
498     break;
499     *end = '\0';
500    
501     return token;
502     }
503    
504 adx 30 /*
505 michael 2916 * read_auth_reply - read the reply (if any) from the ident server
506 adx 30 * we connected to.
507     * We only give it one shot, if the reply isn't good the first time
508     * fail the authentication entirely. --Bleep
509     */
510     static void
511     read_auth_reply(fde_t *fd, void *data)
512     {
513     struct AuthRequest *auth = data;
514 michael 4310 const char *username = NULL;
515     ssize_t len = 0;
516     char buf[RFC1413_BUFSIZ + 1];
517 adx 30
518 michael 4310 if ((len = recv(fd->fd, buf, RFC1413_BUFSIZ, 0)) > 0)
519 adx 30 {
520     buf[len] = '\0';
521 michael 4310 username = check_ident_reply(buf);
522 adx 30 }
523    
524     fd_close(fd);
525    
526     ClearAuth(auth);
527    
528 michael 4310 if (EmptyString(username))
529 adx 30 {
530     sendheader(auth->client, REPORT_FAIL_ID);
531 michael 896 ++ServerStats.is_abad;
532 adx 30 }
533     else
534     {
535 michael 4310 strlcpy(auth->client->username, username, sizeof(auth->client->username));
536 adx 30 sendheader(auth->client, REPORT_FIN_ID);
537 michael 896 ++ServerStats.is_asuc;
538 adx 30 SetGotId(auth->client);
539     }
540    
541 michael 992 release_auth_client(auth);
542 adx 30 }
543    
544     /*
545     * delete_auth()
546     */
547 michael 2916 void
548 michael 992 delete_auth(struct AuthRequest *auth)
549 adx 30 {
550 michael 992 if (IsDNSPending(auth))
551     delete_resolver_queries(auth);
552 adx 30
553 michael 1000 if (IsDoingAuth(auth))
554     fd_close(&auth->fd);
555    
556 michael 2929 if (IsInAuth(auth))
557     {
558 michael 4310 dlinkDelete(&auth->node, &auth_pending_list);
559 michael 2929 ClearInAuth(auth);
560     }
561 adx 30 }
562 michael 4310
563     /* auth_init
564     *
565     * Initialise the auth code
566     */
567     void
568     auth_init(void)
569     {
570     static struct event timeout_auth_queries =
571     {
572     .name = "timeout_auth_queries_event",
573     .handler = timeout_auth_queries_event,
574     .when = 1
575     };
576    
577     event_add(&timeout_auth_queries, NULL);
578     }

Properties

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