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