X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fs_auth.c;h=acb2663caf94ec10142a6c9a49086dc4d7c25b79;hb=ae91ef6320f611af74e70a0db2620c338fbaa7d5;hp=44f45eaa9779724240f39bddd6e7235e7e335d1d;hpb=eeff5dd006459c6c56f025f13852fdafb2961339;p=ircu2.10.12-pk.git diff --git a/ircd/s_auth.c b/ircd/s_auth.c index 44f45ea..acb2663 100644 --- a/ircd/s_auth.c +++ b/ircd/s_auth.c @@ -1,268 +1,684 @@ -/* - * IRC - Internet Relay Chat, ircd/s_auth.c - * Copyright (C) 1992 Darren Reed +/************************************************************************ + * IRC - Internet Relay Chat, src/s_auth.c + * Copyright (C) 1992 Darren Reed + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 1, or (at your option) - * any later version. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * $Id$ * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Changes: + * July 6, 1999 - Rewrote most of the code here. When a client connects + * to the server and passes initial socket validation checks, it + * is owned by this module (auth) which returns it to the rest of the + * server when dns and auth queries are finished. Until the client is + * released, the server does not know it exists and does not process + * any messages from it. + * --Bleep Thomas Helvey */ - -#include "sys.h" -#include -#if HAVE_SYS_FILE_H -#include -#endif -#if HAVE_SYS_IOCTL_H -#include -#endif -#ifdef UNIXPORT -#include -#endif -#if HAVE_UNISTD_H -#include -#endif -#ifdef HPUX -#include -#endif /* HPUX */ -#if HAVE_FCNTL_H -#include -#endif -#ifdef USE_SYSLOG -#include -#endif -#include "h.h" +#include "s_auth.h" +#include "client.h" +#include "IPcheck.h" +#include "ircd.h" +#include "ircd_alloc.h" +#include "ircd_chattr.h" +#include "ircd_log.h" +#include "ircd_osdep.h" +#include "ircd_string.h" +#include "list.h" +#include "numeric.h" +#include "querycmds.h" #include "res.h" -#include "struct.h" -#include "common.h" -#include "send.h" #include "s_bsd.h" +#include "s_debug.h" #include "s_misc.h" -#include "support.h" -#include "ircd.h" -#include "s_auth.h" +#include "send.h" #include "sprintf_irc.h" +#include "struct.h" +#include "sys.h" /* TRUE bleah */ -RCSTAG_CC("$Id$"); +#include /* struct hostent */ +#include +#include +#include +#include +#include +#include +#include +#include +#include /* - * start_auth - * - * Flag the client to show that an attempt to contact the ident server on - * the client's host. The connect and subsequently the socket are all put - * into 'non-blocking' mode. Should the connect or any later phase of the - * identifing process fail, it is aborted and the user is given a username - * of "unknown". + * a bit different approach + * this replaces the original sendheader macros + */ +static struct { + const char* message; + size_t length; +} HeaderMessages [] = { + /* 123456789012345678901234567890123456789012345678901234567890 */ + { "NOTICE AUTH :*** Looking up your hostname\r\n", 43 }, + { "NOTICE AUTH :*** Found your hostname\r\n", 38 }, + { "NOTICE AUTH :*** Found your hostname, cached\r\n", 46 }, + { "NOTICE AUTH :*** Couldn't look up your hostname\r\n", 49 }, + { "NOTICE AUTH :*** Checking Ident\r\n", 33 }, + { "NOTICE AUTH :*** Got ident response\r\n", 37 }, + { "NOTICE AUTH :*** No ident response\r\n", 36 }, + { "NOTICE AUTH :*** Your forward and reverse DNS do not match, " \ + "ignoring hostname.\r\n", 80 } +}; + +typedef enum { + REPORT_DO_DNS, + REPORT_FIN_DNS, + REPORT_FIN_DNSC, + REPORT_FAIL_DNS, + REPORT_DO_ID, + REPORT_FIN_ID, + REPORT_FAIL_ID, + REPORT_IP_MISMATCH +} ReportType; + +#define sendheader(c, r) \ + send((c)->fd, HeaderMessages[(r)].message, HeaderMessages[(r)].length, 0) + +struct AuthRequest* AuthPollList = 0; /* GLOBAL - auth queries pending io */ +static struct AuthRequest* AuthIncompleteList = 0; + +/* + * make_auth_request - allocate a new auth request + */ +static struct AuthRequest* make_auth_request(struct Client* client) +{ + struct AuthRequest* auth = + (struct AuthRequest*) MyMalloc(sizeof(struct AuthRequest)); + assert(0 != auth); + memset(auth, 0, sizeof(struct AuthRequest)); + auth->fd = -1; + auth->client = client; + auth->timeout = CurrentTime + CONNECTTIMEOUT; + return auth; +} + +/* + * free_auth_request - cleanup auth request allocations + */ +void free_auth_request(struct AuthRequest* auth) +{ + if (-1 < auth->fd) + close(auth->fd); + MyFree(auth); +} + +/* + * unlink_auth_request - remove auth request from a list + */ +static void unlink_auth_request(struct AuthRequest* request, + struct AuthRequest** list) +{ + if (request->next) + request->next->prev = request->prev; + if (request->prev) + request->prev->next = request->next; + else + *list = request->next; +} + +/* + * link_auth_request - add auth request to a list + */ +static void link_auth_request(struct AuthRequest* request, + struct AuthRequest** list) +{ + request->prev = 0; + request->next = *list; + if (*list) + (*list)->prev = request; + *list = request; +} + +/* + * release_auth_client - release auth client from auth system + * this adds the client into the local client lists so it can be read by + * the main io processing loop */ -void start_auth(aClient *cptr) +static void release_auth_client(struct Client* client) +{ + assert(0 != client); + client->lasttime = client->since = CurrentTime; + if (client->fd > HighestFd) + HighestFd = client->fd; + LocalClientArray[client->fd] = client; + + add_client_to_list(client); + Debug((DEBUG_INFO, "Auth: release_auth_client %s@%s[%s]", + client->username, client->sockhost, client->sock_ip)); +} + +static void auth_kill_client(struct AuthRequest* auth) { - struct sockaddr_in sock; - int err; - - Debug((DEBUG_NOTICE, "start_auth(%p) fd %d status %d", - cptr, cptr->fd, cptr->status)); - - alarm(2); - cptr->authfd = socket(AF_INET, SOCK_STREAM, 0); - err = errno; - alarm(0); - - if (cptr->authfd < 0) - { -#ifdef USE_SYSLOG - syslog(LOG_ERR, "Unable to create auth socket for %s:%m", - get_client_name(cptr, FALSE)); + assert(0 != auth); + + unlink_auth_request(auth, (IsDoingAuth(auth)) ? &AuthPollList : &AuthIncompleteList); + + if (IsDNSPending(auth)) + delete_resolver_queries(auth); + IPcheck_disconnect(auth->client); + Count_unknowndisconnects(UserStats); + free_client(auth->client); + free_auth_request(auth); +} + +/* + * auth_dns_callback - called when resolver query finishes + * if the query resulted in a successful search, hp will contain + * a non-null pointer, otherwise hp will be null. + * set the client on it's way to a connection completion, regardless + * of success of failure + */ +static void auth_dns_callback(void* vptr, struct DNSReply* reply) +{ + struct AuthRequest* auth = (struct AuthRequest*) vptr; + + assert(0 != auth); + /* + * need to do this here so auth_kill_client doesn't + * try have the resolver delete the query it's about + * to delete anyways. --Bleep + */ + ClearDNSPending(auth); + + if (reply) { + const struct hostent* hp = reply->hp; + int i; + assert(0 != hp); + /* + * Verify that the host to ip mapping is correct both ways and that + * the ip#(s) for the socket is listed for the host. + */ + for (i = 0; hp->h_addr_list[i]; ++i) { + if (0 == memcmp(hp->h_addr_list[i], &auth->client->ip, + sizeof(struct in_addr))) + break; + } + if (!hp->h_addr_list[i]) { + if (IsUserPort(auth->client)) + sendheader(auth->client, REPORT_IP_MISMATCH); + sendto_op_mask(SNO_IPMISMATCH, "IP# Mismatch: %s != %s[%s]", + auth->client->sock_ip, hp->h_name, + ircd_ntoa(hp->h_addr_list[0])); +#if defined(KILL_IPMISMATCH) + auth_kill_client(auth); + return; #endif - Debug((DEBUG_ERROR, "Unable to create auth socket for %s:%s", - get_client_name(cptr, FALSE), strerror(get_sockerr(cptr)))); - if (!DoingDNS(cptr)) - SetAccess(cptr); - ircstp->is_abad++; - return; + } + else { + ++reply->ref_count; + auth->client->dns_reply = reply; + ircd_strncpy(auth->client->sockhost, hp->h_name, HOSTLEN); + if (IsUserPort(auth->client)) + sendheader(auth->client, REPORT_FIN_DNS); + } } - if (cptr->authfd >= (MAXCONNECTIONS - 2)) - { - close(cptr->authfd); - cptr->authfd = -1; - return; + else { + /* + * this should have already been done by s_bsd.c in add_connection + * + * strcpy(auth->client->sockhost, auth->client->sock_ip); + */ + if (IsUserPort(auth->client)) + sendheader(auth->client, REPORT_FAIL_DNS); + } + if (!IsDoingAuth(auth)) { + release_auth_client(auth->client); + unlink_auth_request(auth, &AuthIncompleteList); + free_auth_request(auth); } +} - set_non_blocking(cptr->authfd, cptr); +/* + * authsenderr - handle auth send errors + */ +static void auth_error(struct AuthRequest* auth, int kill) +{ + ++ServerStats->is_abad; -#ifdef VIRTUAL_HOST - if (bind(cptr->authfd, (struct sockaddr *)&vserv, sizeof(vserv)) == -1) - { - report_error("binding auth stream socket %s: %s", cptr); - close(cptr->authfd); - cptr->authfd = -1; + assert(0 != auth); + close(auth->fd); + auth->fd = -1; + + if (IsUserPort(auth->client)) + sendheader(auth->client, REPORT_FAIL_ID); + + if (kill) { + /* + * we can't read the client info from the client socket, + * close the client connection and free the client + * Need to do this before we ClearAuth(auth) so we know + * which list to remove the query from. --Bleep + */ + auth_kill_client(auth); return; } + + ClearAuth(auth); + unlink_auth_request(auth, &AuthPollList); + + if (IsDNSPending(auth)) + link_auth_request(auth, &AuthIncompleteList); + else { + release_auth_client(auth->client); + free_auth_request(auth); + } +} + +/* + * start_auth_query - Flag the client to show that an attempt to + * contact the ident server on the client's host. The connect and + * subsequently the socket are all put into 'non-blocking' mode. + * Should the connect or any later phase of the identifing process fail, + * it is aborted and the user is given a username of "unknown". + */ +static int start_auth_query(struct AuthRequest* auth) +{ + struct sockaddr_in remote_addr; + struct sockaddr_in local_addr; + int fd; + + assert(0 != auth); + assert(0 != auth->client); + + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { +#if 0 + report_error(SOCKET_ERROR_MSG, get_client_name(auth->client, HIDE_IP), errno); +#endif + ++ServerStats->is_abad; + return 0; + } + if ((MAXCONNECTIONS - 10) < fd) { +#if 0 + report_error(CONNLIMIT_ERROR_MSG, + get_client_name(auth->client, HIDE_IP), errno); +#endif + close(fd); + return 0; + } + if (!os_set_nonblocking(fd)) { +#if 0 + report_error(NONB_ERROR_MSG, get_client_name(auth->client, HIDE_IP), errno); +#endif + close(fd); + return 0; + } + if (IsUserPort(auth->client)) + sendheader(auth->client, REPORT_DO_ID); + /* + * get the local address of the client and bind to that to + * make the auth request. This used to be done only for + * ifdef VIRTTUAL_HOST, but needs to be done for all clients + * since the ident request must originate from that same address-- + * and machines with multiple IP addresses are common now + */ + memset(&local_addr, 0, sizeof(struct sockaddr_in)); + os_get_sockname(auth->client->fd, &local_addr); + local_addr.sin_port = htons(0); + + if (bind(fd, (struct sockaddr*) &local_addr, sizeof(struct sockaddr_in))) { +#if 0 + report_error(BIND_ERROR_MSG, + get_client_name(auth->client, HIDE_IP), errno); #endif - memcpy(&sock.sin_addr, &cptr->ip, sizeof(struct in_addr)); + close(fd); + return 0; + } - sock.sin_port = htons(113); - sock.sin_family = AF_INET; + remote_addr.sin_addr.s_addr = auth->client->ip.s_addr; + remote_addr.sin_port = htons(113); + remote_addr.sin_family = AF_INET; - alarm((unsigned)4); - if (connect(cptr->authfd, (struct sockaddr *)&sock, - sizeof(sock)) == -1 && errno != EINPROGRESS) - { - ircstp->is_abad++; + if (!os_connect_nonb(fd, &remote_addr)) { + ServerStats->is_abad++; /* * No error report from this... */ - alarm((unsigned)0); - close(cptr->authfd); - cptr->authfd = -1; - if (!DoingDNS(cptr)) - SetAccess(cptr); - return; + close(fd); + if (IsUserPort(auth->client)) + sendheader(auth->client, REPORT_FAIL_ID); + return 0; + } + + auth->fd = fd; + + SetAuthConnect(auth); + return 1; +} + + +enum IdentReplyFields { + IDENT_PORT_NUMBERS, + IDENT_REPLY_TYPE, + IDENT_OS_TYPE, + IDENT_INFO, + USERID_TOKEN_COUNT +}; + +static char* check_ident_reply(char* reply) +{ + char* token; + char* end; + char* vector[USERID_TOKEN_COUNT]; + int count = token_vector(reply, ':', vector, USERID_TOKEN_COUNT); + + if (USERID_TOKEN_COUNT != count) + return 0; + /* + * second token is the reply type + */ + token = vector[IDENT_REPLY_TYPE]; + if (EmptyString(token)) + return 0; + + while (IsSpace(*token)) + ++token; + + if (0 != strncmp(token, "USERID", 6)) + return 0; + + /* + * third token is the os type + */ + token = vector[IDENT_OS_TYPE]; + if (EmptyString(token)) + return 0; + while (IsSpace(*token)) + ++token; + + /* + * Unless "OTHER" is specified as the operating system + * type, the server is expected to return the "normal" + * user identification of the owner of this connection. + * "Normal" in this context may be taken to mean a string + * of characters which uniquely identifies the connection + * owner such as a user identifier assigned by the system + * administrator and used by such user as a mail + * identifier, or as the "user" part of a user/password + * pair used to gain access to system resources. When an + * operating system is specified (e.g., anything but + * "OTHER"), the user identifier is expected to be in a + * more or less immediately useful form - e.g., something + * that could be used as an argument to "finger" or as a + * mail address. + */ + if (0 == strncmp(token, "OTHER", 5)) + return 0; + /* + * fourth token is the username + */ + token = vector[IDENT_INFO]; + if (EmptyString(token)) + return 0; + while (IsSpace(*token)) + ++token; + /* + * look for the end of the username, terminators are '\0, @, , :' + */ + for (end = token; *end; ++end) { + if (IsSpace(*end) || '@' == *end || ':' == *end) + break; } - alarm((unsigned)0); - cptr->flags |= (FLAGS_WRAUTH | FLAGS_AUTH); - if (cptr->authfd > highest_fd) - highest_fd = cptr->authfd; - return; + *end = '\0'; + return token; } +#if 0 /* - * send_authports - * - * Send the ident server a query giving "theirport , ourport". + * GetValidIdent - parse ident query reply from identd server + * + * Inputs - pointer to ident buf + * Output - NULL if no valid ident found, otherwise pointer to name + * Side effects - + */ +static char* GetValidIdent(char *buf) +{ + int remp = 0; + int locp = 0; + char* colon1Ptr; + char* colon2Ptr; + char* colon3Ptr; + char* commaPtr; + char* remotePortString; + + /* All this to get rid of a sscanf() fun. */ + remotePortString = buf; + + colon1Ptr = strchr(remotePortString,':'); + if(!colon1Ptr) + return 0; + + *colon1Ptr = '\0'; + colon1Ptr++; + colon2Ptr = strchr(colon1Ptr,':'); + if(!colon2Ptr) + return 0; + + *colon2Ptr = '\0'; + colon2Ptr++; + commaPtr = strchr(remotePortString, ','); + + if(!commaPtr) + return 0; + + *commaPtr = '\0'; + commaPtr++; + + remp = atoi(remotePortString); + if(!remp) + return 0; + + locp = atoi(commaPtr); + if(!locp) + return 0; + + /* look for USERID bordered by first pair of colons */ + if(!strstr(colon1Ptr, "USERID")) + return 0; + + colon3Ptr = strchr(colon2Ptr,':'); + if(!colon3Ptr) + return 0; + + *colon3Ptr = '\0'; + colon3Ptr++; + return(colon3Ptr); +} +#endif + +/* + * start_auth - starts auth (identd) and dns queries for a client + */ +void start_auth(struct Client* client) +{ + struct DNSQuery query; + struct AuthRequest* auth = 0; + + assert(0 != client); + + auth = make_auth_request(client); + assert(0 != auth); + + query.vptr = auth; + query.callback = auth_dns_callback; + + if (IsUserPort(auth->client)) + sendheader(client, REPORT_DO_DNS); + +#if !defined(NODNS) + client->dns_reply = gethost_byaddr((const char*) &client->ip, &query); + if (client->dns_reply) { + ++client->dns_reply->ref_count; + ircd_strncpy(client->sockhost, client->dns_reply->hp->h_name, HOSTLEN); + if (IsUserPort(auth->client)) + sendheader(client, REPORT_FIN_DNSC); + } + else + SetDNSPending(auth); +#endif + + if (start_auth_query(auth)) + link_auth_request(auth, &AuthPollList); + else if (IsDNSPending(auth)) + link_auth_request(auth, &AuthIncompleteList); + else { + free_auth_request(auth); + release_auth_client(client); + } +} + +/* + * timeout_auth_queries - timeout resolver and identd requests + * allow clients through if requests failed + */ +void timeout_auth_queries(time_t now) +{ + struct AuthRequest* auth; + struct AuthRequest* auth_next = 0; + + for (auth = AuthPollList; auth; auth = auth_next) { + auth_next = auth->next; + if (auth->timeout < CurrentTime) { + if (-1 < auth->fd) { + close(auth->fd); + auth->fd = -1; + } + + if (IsUserPort(auth->client)) + sendheader(auth->client, REPORT_FAIL_ID); + if (IsDNSPending(auth)) { + delete_resolver_queries(auth); + if (IsUserPort(auth->client)) + sendheader(auth->client, REPORT_FAIL_DNS); + } + ircd_log(L_INFO, "DNS/AUTH timeout %s", + get_client_name(auth->client, HIDE_IP)); + + release_auth_client(auth->client); + unlink_auth_request(auth, &AuthPollList); + free_auth_request(auth); + } + } + for (auth = AuthIncompleteList; auth; auth = auth_next) { + auth_next = auth->next; + if (auth->timeout < CurrentTime) { + delete_resolver_queries(auth); + if (IsUserPort(auth->client)) + sendheader(auth->client, REPORT_FAIL_DNS); + ircd_log(L_INFO, "DNS timeout %s", get_client_name(auth->client, HIDE_IP)); + + release_auth_client(auth->client); + unlink_auth_request(auth, &AuthIncompleteList); + free_auth_request(auth); + } + } +} + +/* + * send_auth_query - send the ident server a query giving "theirport , ourport" * The write is only attempted *once* so it is deemed to be a fail if the * entire write doesn't write all the data given. This shouldnt be a * problem since the socket should have a write buffer far greater than * this message to store it in should problems arise. -avalon */ -void send_authports(aClient *cptr) +void send_auth_query(struct AuthRequest* auth) { - struct sockaddr_in us, them; - char authbuf[32]; - size_t ulen, tlen; - - Debug((DEBUG_NOTICE, "write_authports(%p) fd %d authfd %d stat %d", - cptr, cptr->fd, cptr->authfd, cptr->status)); - tlen = ulen = sizeof(us); - if (getsockname(cptr->fd, (struct sockaddr *)&us, &ulen) || - getpeername(cptr->fd, (struct sockaddr *)&them, &tlen)) - { -#ifdef USE_SYSLOG - syslog(LOG_ERR, "auth get{sock,peer}name error for %s:%m", - get_client_name(cptr, FALSE)); -#endif - goto authsenderr; + struct sockaddr_in us; + struct sockaddr_in them; + char authbuf[32]; + size_t count; + + assert(0 != auth); + assert(0 != auth->client); + + if (!os_get_sockname(auth->client->fd, &us) || + !os_get_peername(auth->client->fd, &them)) { + auth_error(auth, 1); + return; } + sprintf_irc(authbuf, "%u , %u\r\n", + (unsigned int) ntohs(them.sin_port), + (unsigned int) ntohs(us.sin_port)); - sprintf_irc(authbuf, "%u , %u\r\n", (unsigned int)ntohs(them.sin_port), - (unsigned int)ntohs(us.sin_port)); - - Debug((DEBUG_SEND, "sending [%s] to auth port %s.113", - authbuf, inetntoa(them.sin_addr))); - if (write(cptr->authfd, authbuf, strlen(authbuf)) != (int)strlen(authbuf)) - { - authsenderr: - ircstp->is_abad++; - close(cptr->authfd); - if (cptr->authfd == highest_fd) - while (!loc_clients[highest_fd]) - highest_fd--; - cptr->authfd = -1; - cptr->flags &= ~FLAGS_AUTH; - if (!DoingDNS(cptr)) - SetAccess(cptr); + if (IO_SUCCESS == os_send_nonb(auth->fd, authbuf, strlen(authbuf), &count)) { + ClearAuthConnect(auth); + SetAuthPending(auth); } - cptr->flags &= ~FLAGS_WRAUTH; - return; + else + auth_error(auth, 0); } + /* - * read_authports - * - * read the reply (if any) from the ident server we connected to. - * The actual read processijng here is pretty weak - no handling of the reply - * if it is fragmented by IP. + * read_auth_reply - read the reply (if any) from the ident server + * we connected to. + * We only give it one shot, if the reply isn't good the first time + * fail the authentication entirely. --Bleep */ -void read_authports(aClient *cptr) +void read_auth_reply(struct AuthRequest* auth) { - Reg1 char *s, *t; - Reg2 int len; - char ruser[USERLEN + 1], system[8]; - unsigned short int remp = 0, locp = 0; - - *system = *ruser = '\0'; - Debug((DEBUG_NOTICE, "read_authports(%p) fd %d authfd %d stat %d", - cptr, cptr->fd, cptr->authfd, cptr->status)); + char* username = 0; + size_t len; /* - * Nasty. Cant allow any other reads from client fd while we're - * waiting on the authfd to return a full valid string. Use the - * client's input buffer to buffer the authd reply. - * Oh. this is needed because an authd reply may come back in more - * than 1 read! -avalon + * rfc1453 sez we MUST accept 512 bytes */ - if ((len = read(cptr->authfd, cptr->buffer + cptr->count, - sizeof(cptr->buffer) - 1 - cptr->count)) >= 0) - { - cptr->count += len; - cptr->buffer[cptr->count] = '\0'; + char buf[BUFSIZE + 1]; + + assert(0 != auth); + assert(0 != auth->client); + + if (IO_SUCCESS == os_recv_nonb(auth->fd, buf, BUFSIZE, &len)) { + buf[len] = '\0'; + username = check_ident_reply(buf); } - cptr->lasttime = now; - if ((len > 0) && (cptr->count != (sizeof(cptr->buffer) - 1)) && - (sscanf(cptr->buffer, "%hd , %hd : USERID : %*[^:]: %10s", - &remp, &locp, ruser) == 3)) - { - s = strrchr(cptr->buffer, ':'); - *s++ = '\0'; - for (t = (strrchr(cptr->buffer, ':') + 1); *t; t++) - if (!isSpace(*t)) - break; - strncpy(system, t, sizeof(system) - 1); - system[sizeof(system) - 1] = 0; - for (t = ruser; *s && (t < ruser + sizeof(ruser)); s++) - if (!isSpace(*s) && *s != ':' && *s != '@') - *t++ = *s; - *t = '\0'; - Debug((DEBUG_INFO, "auth reply ok [%s] [%s]", system, ruser)); + close(auth->fd); + auth->fd = -1; + ClearAuth(auth); + + if (!EmptyString(username)) { + ircd_strncpy(auth->client->username, username, USERLEN); + /* + * Not needed, struct is zeroed by memset + * auth->client->username[USERLEN] = '\0'; + */ + SetGotId(auth->client); + ++ServerStats->is_asuc; + if (IsUserPort(auth->client)) + sendheader(auth->client, REPORT_FIN_ID); } - else if (len != 0) - { - if (!strchr(cptr->buffer, '\n') && !strchr(cptr->buffer, '\r')) - return; - Debug((DEBUG_ERROR, "local %d remote %d", locp, remp)); - Debug((DEBUG_ERROR, "bad auth reply in [%s]", cptr->buffer)); - *ruser = '\0'; + else { + ++ServerStats->is_abad; +#if 0 + strcpy(auth->client->username, "unknown"); +#endif } - close(cptr->authfd); - if (cptr->authfd == highest_fd) - while (!loc_clients[highest_fd]) - highest_fd--; - cptr->count = 0; - cptr->authfd = -1; - ClearAuth(cptr); - if (!DoingDNS(cptr)) - SetAccess(cptr); - if (len > 0) - Debug((DEBUG_INFO, "ident reply: [%s]", cptr->buffer)); - - if (!locp || !remp || !*ruser) - { - ircstp->is_abad++; - return; + unlink_auth_request(auth, &AuthPollList); + + if (IsDNSPending(auth)) + link_auth_request(auth, &AuthIncompleteList); + else { + release_auth_client(auth->client); + free_auth_request(auth); } - ircstp->is_asuc++; - strncpy(cptr->username, ruser, USERLEN); - cptr->username[USERLEN] = 0; /* This is the LA bug --Run */ - if (strncmp(system, "OTHER", 5)) - cptr->flags |= FLAGS_GOTID; - Debug((DEBUG_INFO, "got username [%s]", ruser)); - return; } + +