Clean up s_auth.c in preparation for Doxygenation.
[ircu2.10.12-pk.git] / ircd / s_auth.c
1 /************************************************************************
2  *   IRC - Internet Relay Chat, src/s_auth.c
3  *   Copyright (C) 1992 Darren Reed
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 1, or (at your option)
8  *   any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *   GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program; if not, write to the Free Software
17  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  *   $Id$
20  *
21  * Changes:
22  *   July 6, 1999 - Rewrote most of the code here. When a client connects
23  *     to the server and passes initial socket validation checks, it
24  *     is owned by this module (auth) which returns it to the rest of the
25  *     server when dns and auth queries are finished. Until the client is
26  *     released, the server does not know it exists and does not process
27  *     any messages from it.
28  *     --Bleep  Thomas Helvey <tomh@inxpress.net>
29  */
30 #include "config.h"
31
32 #include "s_auth.h"
33 #include "client.h"
34 #include "IPcheck.h"
35 #include "ircd.h"
36 #include "ircd_alloc.h"
37 #include "ircd_chattr.h"
38 #include "ircd_events.h"
39 #include "ircd_features.h"
40 #include "ircd_log.h"
41 #include "ircd_osdep.h"
42 #include "ircd_snprintf.h"
43 #include "ircd_string.h"
44 #include "list.h"
45 #include "numeric.h"
46 #include "querycmds.h"
47 #include "res.h"
48 #include "s_bsd.h"
49 #include "s_debug.h"
50 #include "s_misc.h"
51 #include "send.h"
52 #include "struct.h"
53 #include "sys.h"               /* TRUE bleah */
54
55 #include <arpa/inet.h>         /* inet_netof */
56 #include <netdb.h>             /* struct hostent */
57 #include <string.h>
58 #include <stdlib.h>
59 #include <unistd.h>
60 #include <errno.h>
61 #include <fcntl.h>
62 #include <assert.h>
63 #include <sys/socket.h>
64 #include <sys/file.h>
65 #include <sys/ioctl.h>
66
67 /*
68  * a bit different approach
69  * this replaces the original sendheader macros
70  */
71 static struct {
72   const char*  message;
73   unsigned int length;
74 } HeaderMessages [] = {
75 #define MSG(STR) { STR, sizeof(STR) - 1 }
76   MSG("NOTICE AUTH :*** Looking up your hostname\r\n"),
77   MSG("NOTICE AUTH :*** Found your hostname\r\n"),
78   MSG("NOTICE AUTH :*** Found your hostname, cached\r\n"),
79   MSG("NOTICE AUTH :*** Couldn't look up your hostname\r\n"),
80   MSG("NOTICE AUTH :*** Checking Ident\r\n"),
81   MSG("NOTICE AUTH :*** Got ident response\r\n"),
82   MSG("NOTICE AUTH :*** No ident response\r\n"),
83   MSG("NOTICE AUTH :*** Your forward and reverse DNS do not match, "
84     "ignoring hostname.\r\n"),
85   MSG("NOTICE AUTH :*** Invalid hostname\r\n")
86 #undef MSG
87 };
88
89 typedef enum {
90   REPORT_DO_DNS,
91   REPORT_FIN_DNS,
92   REPORT_FIN_DNSC,
93   REPORT_FAIL_DNS,
94   REPORT_DO_ID,
95   REPORT_FIN_ID,
96   REPORT_FAIL_ID,
97   REPORT_IP_MISMATCH,
98   REPORT_INVAL_DNS
99 } ReportType;
100
101 #define sendheader(c, r) \
102    send(cli_fd(c), HeaderMessages[(r)].message, HeaderMessages[(r)].length, 0)
103
104 static void release_auth_client(struct Client* client);
105 static void unlink_auth_request(struct AuthRequest* request,
106                                 struct AuthRequest** list);
107 void free_auth_request(struct AuthRequest* auth);
108
109 /* auth_verify_hostname - verify that a hostname is valid, i.e., only
110  * contains characters valid for a hostname and that a hostname is not
111  * too long.
112  */
113 static int
114 auth_verify_hostname(char *host, int maxlen)
115 {
116   int i;
117
118   /* Walk through the host name */
119   for (i = 0; host[i]; i++)
120     /* If it's not a hostname character or if it's too long, return false */
121     if (!IsHostChar(host[i]) || i >= maxlen)
122       return 0;
123
124   return 1; /* it's a valid hostname */
125 }
126
127 /*
128  * auth_timeout - timeout a given auth request
129  */
130 static void auth_timeout_callback(struct Event* ev)
131 {
132   struct AuthRequest* auth;
133
134   assert(0 != ev_timer(ev));
135   assert(0 != t_data(ev_timer(ev)));
136
137   auth = (struct AuthRequest*) t_data(ev_timer(ev));
138
139   if (ev_type(ev) == ET_DESTROY) { /* being destroyed */
140     auth->flags &= ~AM_TIMEOUT;
141
142     if (!(auth->flags & AM_FREE_MASK)) {
143       Debug((DEBUG_LIST, "Freeing auth from timeout callback; %p [%p]", auth,
144              ev_timer(ev)));
145       MyFree(auth); /* done with it, finally */
146     }
147   } else {
148     assert(ev_type(ev) == ET_EXPIRE);
149
150     destroy_auth_request(auth, 1);
151   }
152 }
153
154 /*
155  * auth_sock_callback - called when an event occurs on the socket
156  */
157 static void auth_sock_callback(struct Event* ev)
158 {
159   struct AuthRequest* auth;
160
161   assert(0 != ev_socket(ev));
162   assert(0 != s_data(ev_socket(ev)));
163
164   auth = (struct AuthRequest*) s_data(ev_socket(ev));
165
166   switch (ev_type(ev)) {
167   case ET_DESTROY: /* being destroyed */
168     auth->flags &= ~AM_SOCKET;
169
170     if (!(auth->flags & AM_FREE_MASK)) {
171       Debug((DEBUG_LIST, "Freeing auth from sock callback; %p [%p]", auth,
172              ev_socket(ev)));
173       MyFree(auth); /* done with it finally */
174     }
175     break;
176
177   case ET_CONNECT: /* socket connection completed */
178     Debug((DEBUG_LIST, "Connection completed for auth %p [%p]; sending query",
179            auth, ev_socket(ev)));
180     socket_state(&auth->socket, SS_CONNECTED);
181     send_auth_query(auth);
182     break;
183
184   case ET_READ: /* socket is readable */
185   case ET_EOF: /* end of file on socket */
186   case ET_ERROR: /* error on socket */
187     Debug((DEBUG_LIST, "Auth socket %p [%p] readable", auth, ev_socket(ev)));
188     read_auth_reply(auth);
189     break;
190
191   default:
192 #ifndef NDEBUG
193     abort(); /* unrecognized event */
194 #endif
195     break;
196   }
197 }
198
199 /*
200  * destroy_auth_request - stop an auth request completely
201  */
202 void destroy_auth_request(struct AuthRequest* auth, int send_reports)
203 {
204   if (IsDoingAuth(auth)) {
205     if (-1 < auth->fd) {
206       close(auth->fd);
207       auth->fd = -1;
208       socket_del(&auth->socket);
209     }
210
211     if (send_reports && IsUserPort(auth->client))
212       sendheader(auth->client, REPORT_FAIL_ID);
213   }
214
215   if (IsDNSPending(auth)) {
216     delete_resolver_queries(auth);
217     if (send_reports && IsUserPort(auth->client))
218       sendheader(auth->client, REPORT_FAIL_DNS);
219   }
220
221   if (send_reports) {
222     log_write(LS_RESOLVER, L_INFO, 0, "DNS/AUTH timeout %s",
223               get_client_name(auth->client, HIDE_IP));
224     release_auth_client(auth->client);
225   }
226
227   free_auth_request(auth);
228 }
229
230 /*
231  * make_auth_request - allocate a new auth request
232  */
233 static struct AuthRequest* make_auth_request(struct Client* client)
234 {
235   struct AuthRequest* auth = 
236                (struct AuthRequest*) MyMalloc(sizeof(struct AuthRequest));
237   assert(0 != auth);
238   memset(auth, 0, sizeof(struct AuthRequest));
239   auth->flags   = AM_TIMEOUT;
240   auth->fd      = -1;
241   auth->client  = client;
242   cli_auth(client) = auth;
243   timer_add(timer_init(&auth->timeout), auth_timeout_callback, (void*) auth,
244             TT_RELATIVE, feature_int(FEAT_AUTH_TIMEOUT));
245   return auth;
246 }
247
248 /*
249  * free_auth_request - cleanup auth request allocations
250  */
251 void free_auth_request(struct AuthRequest* auth)
252 {
253   if (-1 < auth->fd) {
254     close(auth->fd);
255     Debug((DEBUG_LIST, "Deleting auth socket for %p", auth->client));
256     socket_del(&auth->socket);
257   }
258   Debug((DEBUG_LIST, "Deleting auth timeout timer for %p", auth->client));
259   timer_del(&auth->timeout);
260 }
261
262 /*
263  * unlink_auth_request - remove auth request from a list
264  */
265 static void unlink_auth_request(struct AuthRequest* request,
266                                 struct AuthRequest** list)
267 {
268   if (request->next)
269     request->next->prev = request->prev;
270   if (request->prev)
271     request->prev->next = request->next;
272   else
273     *list = request->next;
274 }
275
276 /*
277  * link_auth_request - add auth request to a list
278  */
279 static void link_auth_request(struct AuthRequest* request,
280                               struct AuthRequest** list)
281 {
282   request->prev = 0;
283   request->next = *list;
284   if (*list)
285     (*list)->prev = request;
286   *list = request;
287 }
288
289 /*
290  * release_auth_client - release auth client from auth system
291  * this adds the client into the local client lists so it can be read by
292  * the main io processing loop
293  */
294 static void release_auth_client(struct Client* client)
295 {
296   assert(0 != client);
297   cli_auth(client) = 0;
298   cli_lasttime(client) = cli_since(client) = CurrentTime;
299   if (cli_fd(client) > HighestFd)
300     HighestFd = cli_fd(client);
301   LocalClientArray[cli_fd(client)] = client;
302
303   add_client_to_list(client);
304   socket_events(&(cli_socket(client)), SOCK_ACTION_SET | SOCK_EVENT_READABLE);
305   Debug((DEBUG_INFO, "Auth: release_auth_client %s@%s[%s]",
306          cli_username(client), cli_sockhost(client), cli_sock_ip(client)));
307 }
308
309 static void auth_kill_client(struct AuthRequest* auth)
310 {
311   assert(0 != auth);
312
313   if (IsDNSPending(auth))
314     delete_resolver_queries(auth);
315   IPcheck_disconnect(auth->client);
316   Count_unknowndisconnects(UserStats);
317   cli_auth(auth->client) = 0;
318   free_client(auth->client);
319   free_auth_request(auth);
320 }
321
322 /*
323  * auth_dns_callback - called when resolver query finishes
324  * if the query resulted in a successful search, hp will contain
325  * a non-null pointer, otherwise hp will be null.
326  * set the client on it's way to a connection completion, regardless
327  * of success of failure
328  */
329 static void auth_dns_callback(void* vptr, struct DNSReply* hp)
330 {
331   struct AuthRequest* auth = (struct AuthRequest*) vptr;
332   assert(auth);
333   /*
334    * need to do this here so auth_kill_client doesn't
335    * try have the resolver delete the query it's about
336    * to delete anyways. --Bleep
337    */
338   ClearDNSPending(auth);
339
340   if (hp) {
341     /*
342      * Verify that the host to ip mapping is correct both ways and that
343      * the ip#(s) for the socket is listed for the host.
344      */
345     if (irc_in_addr_cmp(&hp->addr, &cli_ip(auth->client))) {
346       if (IsUserPort(auth->client))
347         sendheader(auth->client, REPORT_IP_MISMATCH);
348       sendto_opmask_butone(0, SNO_IPMISMATCH, "IP# Mismatch: %s != %s[%s]",
349                            cli_sock_ip(auth->client), hp->h_name,
350                            ircd_ntoa(&hp->addr));
351       if (feature_bool(FEAT_KILL_IPMISMATCH)) {
352         auth_kill_client(auth);
353         return;
354       }
355     }
356     else if (!auth_verify_hostname(hp->h_name, HOSTLEN))
357     {
358       if (IsUserPort(auth->client))
359         sendheader(auth->client, REPORT_INVAL_DNS);
360     }
361     else
362     {
363       cli_dns_reply(auth->client) = hp;
364       ircd_strncpy(cli_sockhost(auth->client), hp->h_name, HOSTLEN);
365       if (IsUserPort(auth->client))
366         sendheader(auth->client, REPORT_FIN_DNS);
367     }
368   }
369   else {
370     /*
371      * this should have already been done by s_bsd.c in add_connection
372      *
373      * strcpy(auth->client->sockhost, auth->client->sock_ip);
374      */
375     if (IsUserPort(auth->client))
376       sendheader(auth->client, REPORT_FAIL_DNS);
377   }
378   if (!IsDoingAuth(auth)) {
379     release_auth_client(auth->client);
380     free_auth_request(auth);
381   }
382 }
383
384 /*
385  * authsenderr - handle auth send errors
386  */
387 static void auth_error(struct AuthRequest* auth, int kill)
388 {
389   ++ServerStats->is_abad;
390
391   assert(0 != auth);
392   close(auth->fd);
393   auth->fd = -1;
394   socket_del(&auth->socket);
395
396   if (IsUserPort(auth->client))
397     sendheader(auth->client, REPORT_FAIL_ID);
398
399   if (kill) {
400     /*
401      * we can't read the client info from the client socket,
402      * close the client connection and free the client
403      * Need to do this before we ClearAuth(auth) so we know
404      * which list to remove the query from. --Bleep
405      */
406     auth_kill_client(auth);
407     return;
408   }
409
410   ClearAuth(auth);
411
412   if (!IsDNSPending(auth)) {
413     release_auth_client(auth->client);
414     free_auth_request(auth);
415   }
416 }
417
418 /*
419  * start_auth_query - Flag the client to show that an attempt to
420  * contact the ident server on the client's host.  The connect and
421  * subsequently the socket are all put into 'non-blocking' mode.
422  * Should the connect or any later phase of the identifing process fail,
423  * it is aborted and the user is given a username of "unknown".
424  */
425 static int start_auth_query(struct AuthRequest* auth)
426 {
427   struct irc_sockaddr remote_addr;
428   struct irc_sockaddr local_addr;
429   int                fd;
430   IOResult           result;
431
432   assert(0 != auth);
433   assert(0 != auth->client);
434
435   /*
436    * get the local address of the client and bind to that to
437    * make the auth request.  This used to be done only for
438    * ifdef VIRTTUAL_HOST, but needs to be done for all clients
439    * since the ident request must originate from that same address--
440    * and machines with multiple IP addresses are common now
441    */
442   memset(&local_addr, 0, sizeof(local_addr));
443   os_get_sockname(cli_fd(auth->client), &local_addr);
444   local_addr.port = 0;
445   fd = os_socket(&local_addr, SOCK_STREAM, "auth query");
446   if (fd < 0)
447     return 0;
448   if (IsUserPort(auth->client))
449     sendheader(auth->client, REPORT_DO_ID);
450   memcpy(&remote_addr.addr, &cli_ip(auth->client), sizeof(remote_addr.addr));
451   remote_addr.port = 113;
452
453   if ((result = os_connect_nonb(fd, &remote_addr)) == IO_FAILURE ||
454       !socket_add(&auth->socket, auth_sock_callback, (void*) auth,
455                   result == IO_SUCCESS ? SS_CONNECTED : SS_CONNECTING,
456                   SOCK_EVENT_READABLE, fd)) {
457     ServerStats->is_abad++;
458     /*
459      * No error report from this...
460      */
461     close(fd);
462     if (IsUserPort(auth->client))
463       sendheader(auth->client, REPORT_FAIL_ID);
464     return 0;
465   }
466
467   auth->flags |= AM_SOCKET;
468   auth->fd = fd;
469
470   SetAuthConnect(auth);
471   if (result == IO_SUCCESS)
472     send_auth_query(auth); /* this does a SetAuthPending(auth) for us */
473
474   return 1;
475 }
476
477
478 enum IdentReplyFields {
479   IDENT_PORT_NUMBERS,
480   IDENT_REPLY_TYPE,
481   IDENT_OS_TYPE,
482   IDENT_INFO,
483   USERID_TOKEN_COUNT
484 };
485
486 static char* check_ident_reply(char* reply)
487 {
488   char* token;
489   char* end;
490   char* vector[USERID_TOKEN_COUNT];
491   int count = token_vector(reply, ':', vector, USERID_TOKEN_COUNT);
492
493   if (USERID_TOKEN_COUNT != count)
494     return 0;
495   /*
496    * second token is the reply type
497    */
498   token = vector[IDENT_REPLY_TYPE];
499   if (EmptyString(token))
500     return 0;
501
502   while (IsSpace(*token))
503     ++token;
504
505   if (0 != strncmp(token, "USERID", 6))
506     return 0;
507
508   /*
509    * third token is the os type
510    */
511   token = vector[IDENT_OS_TYPE];
512   if (EmptyString(token))
513     return 0;
514   while (IsSpace(*token))
515    ++token;
516
517   /*
518    * Unless "OTHER" is specified as the operating system
519    * type, the server is expected to return the "normal"
520    * user identification of the owner of this connection.
521    * "Normal" in this context may be taken to mean a string
522    * of characters which uniquely identifies the connection
523    * owner such as a user identifier assigned by the system
524    * administrator and used by such user as a mail
525    * identifier, or as the "user" part of a user/password
526    * pair used to gain access to system resources.  When an
527    * operating system is specified (e.g., anything but
528    * "OTHER"), the user identifier is expected to be in a
529    * more or less immediately useful form - e.g., something
530    * that could be used as an argument to "finger" or as a
531    * mail address.
532    */
533   if (0 == strncmp(token, "OTHER", 5))
534     return 0;
535   /*
536    * fourth token is the username
537    */
538   token = vector[IDENT_INFO];
539   if (EmptyString(token))
540     return 0;
541   while (IsSpace(*token))
542     ++token;
543   /*
544    * look for the end of the username, terminators are '\0, @, <SPACE>, :'
545    */
546   for (end = token; *end; ++end) {
547     if (IsSpace(*end) || '@' == *end || ':' == *end)
548       break;
549   }
550   *end = '\0'; 
551   return token;
552 }
553
554 /*
555  * start_auth - starts auth (identd) and dns queries for a client
556  */
557 enum { LOOPBACK = 127 };
558
559 void start_auth(struct Client* client)
560 {
561   struct AuthRequest* auth = 0;
562
563   assert(0 != client);
564
565   auth = make_auth_request(client);
566   assert(0 != auth);
567
568   Debug((DEBUG_INFO, "Beginning auth request on client %p", client));
569
570   if (!feature_bool(FEAT_NODNS)) {
571     if (irc_in_addr_is_loopback(&cli_ip(client)))
572       strcpy(cli_sockhost(client), cli_name(&me));
573     else {
574       struct DNSQuery query;
575
576       query.vptr     = auth;
577       query.callback = auth_dns_callback;
578
579       if (IsUserPort(auth->client))
580         sendheader(client, REPORT_DO_DNS);
581
582       gethost_byaddr(&cli_ip(client), &query);
583       SetDNSPending(auth);
584     }
585   }
586
587   if (start_auth_query(auth)) {
588     Debug((DEBUG_LIST, "identd query for %p initiated successfully",
589            auth->client));
590   } else if (IsDNSPending(auth)) {
591     Debug((DEBUG_LIST, "identd query for %p not initiated successfully; "
592            "waiting on DNS", auth->client));
593   } else {
594     Debug((DEBUG_LIST, "identd query for %p not initiated successfully; "
595            "no DNS pending; releasing immediately", auth->client));
596     free_auth_request(auth);
597     release_auth_client(client);
598   }
599 }
600
601 /*
602  * send_auth_query - send the ident server a query giving "theirport , ourport"
603  * The write is only attempted *once* so it is deemed to be a fail if the
604  * entire write doesn't write all the data given.  This shouldnt be a
605  * problem since the socket should have a write buffer far greater than
606  * this message to store it in should problems arise. -avalon
607  */
608 void send_auth_query(struct AuthRequest* auth)
609 {
610   struct irc_sockaddr us;
611   struct irc_sockaddr them;
612   char               authbuf[32];
613   unsigned int       count;
614
615   assert(0 != auth);
616   assert(0 != auth->client);
617
618   if (!os_get_sockname(cli_fd(auth->client), &us) ||
619       !os_get_peername(cli_fd(auth->client), &them)) {
620     auth_error(auth, 1);
621     return;
622   }
623   ircd_snprintf(0, authbuf, sizeof(authbuf), "%u , %u\r\n",
624                 (unsigned int) them.port,
625                 (unsigned int) us.port);
626
627   if (IO_SUCCESS == os_send_nonb(auth->fd, authbuf, strlen(authbuf), &count)) {
628     ClearAuthConnect(auth);
629     SetAuthPending(auth);
630   }
631   else
632     auth_error(auth, 0);
633 }
634
635
636 /*
637  * read_auth_reply - read the reply (if any) from the ident server 
638  * we connected to.
639  * We only give it one shot, if the reply isn't good the first time
640  * fail the authentication entirely. --Bleep
641  */
642 void read_auth_reply(struct AuthRequest* auth)
643 {
644   char*        username = 0;
645   unsigned int len;
646   /*
647    * rfc1453 sez we MUST accept 512 bytes
648    */
649   char   buf[BUFSIZE + 1];
650
651   assert(0 != auth);
652   assert(0 != auth->client);
653   assert(auth == cli_auth(auth->client));
654
655   if (IO_SUCCESS == os_recv_nonb(auth->fd, buf, BUFSIZE, &len)) {
656     buf[len] = '\0';
657     Debug((DEBUG_LIST, "Auth %p [%p] reply: %s", auth, &auth->socket, buf));
658     username = check_ident_reply(buf);
659     Debug((DEBUG_LIST, "Username: %s", username));
660   }
661
662   close(auth->fd);
663   auth->fd = -1;
664   Debug((DEBUG_LIST, "Deleting auth [%p] socket %p", auth, &auth->socket));
665   socket_del(&auth->socket);
666   ClearAuth(auth);
667
668   if (!EmptyString(username)) {
669     ircd_strncpy(cli_username(auth->client), username, USERLEN);
670     /*
671      * Not needed, struct is zeroed by memset
672      * auth->client->username[USERLEN] = '\0';
673      */
674     SetGotId(auth->client);
675     ++ServerStats->is_asuc;
676     if (IsUserPort(auth->client))
677       sendheader(auth->client, REPORT_FIN_ID);
678   }
679   else {
680     ++ServerStats->is_abad;
681   }
682
683   if (!IsDNSPending(auth)) {
684     release_auth_client(auth->client);
685     free_auth_request(auth);
686   }
687 }