1 /************************************************************************
2 * IRC - Internet Relay Chat, src/s_auth.c
3 * Copyright (C) 1992 Darren Reed
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)
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.
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.
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>
36 #include "ircd_alloc.h"
37 #include "ircd_chattr.h"
38 #include "ircd_events.h"
39 #include "ircd_features.h"
41 #include "ircd_osdep.h"
42 #include "ircd_string.h"
45 #include "querycmds.h"
51 #include "sprintf_irc.h"
53 #include "sys.h" /* TRUE bleah */
55 #include <arpa/inet.h> /* inet_netof */
56 #include <netdb.h> /* struct hostent */
63 #include <sys/socket.h>
65 #include <sys/ioctl.h>
68 * a bit different approach
69 * this replaces the original sendheader macros
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 }
98 #define sendheader(c, r) \
99 send(cli_fd(c), HeaderMessages[(r)].message, HeaderMessages[(r)].length, 0)
101 struct AuthRequest* AuthPollList = 0; /* GLOBAL - auth queries pending io */
102 static struct AuthRequest* AuthIncompleteList = 0;
104 enum { AUTH_TIMEOUT = 60 };
106 static void release_auth_client(struct Client* client);
107 static void unlink_auth_request(struct AuthRequest* request,
108 struct AuthRequest** list);
109 void free_auth_request(struct AuthRequest* auth);
112 * auth_timeout - timeout a given auth request
114 static void auth_timeout_callback(struct Event* ev)
116 struct AuthRequest* auth;
118 assert(0 != ev_timer(ev));
119 assert(0 != t_data(ev_timer(ev)));
121 auth = t_data(ev_timer(ev));
123 if (ev_type(ev) == ET_DESTROY) { /* being destroyed */
124 auth->flags &= ~AM_TIMEOUT;
126 if (!(auth->flags & AM_FREE_MASK)) {
127 Debug((DEBUG_LIST, "Freeing auth from timeout callback; %p [%p]", auth,
129 MyFree(auth); /* done with it, finally */
132 assert(ev_type(ev) == ET_EXPIRE);
134 destroy_auth_request(auth, 1);
139 * auth_sock_callback - called when an event occurs on the socket
141 static void auth_sock_callback(struct Event* ev)
143 struct AuthRequest* auth;
145 assert(0 != ev_socket(ev));
146 assert(0 != s_data(ev_socket(ev)));
148 auth = s_data(ev_socket(ev));
150 switch (ev_type(ev)) {
151 case ET_DESTROY: /* being destroyed */
152 auth->flags &= ~AM_SOCKET;
154 if (!(auth->flags & AM_FREE_MASK)) {
155 Debug((DEBUG_LIST, "Freeing auth from sock callback; %p [%p]", auth,
157 MyFree(auth); /* done with it finally */
161 case ET_CONNECT: /* socket connection completed */
162 Debug((DEBUG_LIST, "Connection completed for auth %p [%p]; sending query",
163 auth, ev_socket(ev)));
164 socket_state(&auth->socket, SS_CONNECTED);
165 send_auth_query(auth);
168 case ET_READ: /* socket is readable */
169 case ET_EOF: /* end of file on socket */
170 case ET_ERROR: /* error on socket */
171 Debug((DEBUG_LIST, "Auth socket %p [%p] readable", auth, ev_socket(ev)));
172 read_auth_reply(auth);
177 abort(); /* unrecognized event */
184 * destroy_auth_request - stop an auth request completely
186 void destroy_auth_request(struct AuthRequest* auth, int send_reports)
188 struct AuthRequest** authList;
190 if (IsDoingAuth(auth)) {
191 authList = &AuthPollList;
195 socket_del(&auth->socket);
198 if (send_reports && IsUserPort(auth->client))
199 sendheader(auth->client, REPORT_FAIL_ID);
201 authList = &AuthIncompleteList;
203 if (IsDNSPending(auth)) {
204 delete_resolver_queries(auth);
205 if (send_reports && IsUserPort(auth->client))
206 sendheader(auth->client, REPORT_FAIL_DNS);
210 log_write(LS_RESOLVER, L_INFO, 0, "DNS/AUTH timeout %s",
211 get_client_name(auth->client, HIDE_IP));
213 release_auth_client(auth->client);
214 unlink_auth_request(auth, authList);
215 free_auth_request(auth);
219 * make_auth_request - allocate a new auth request
221 static struct AuthRequest* make_auth_request(struct Client* client)
223 struct AuthRequest* auth =
224 (struct AuthRequest*) MyMalloc(sizeof(struct AuthRequest));
226 memset(auth, 0, sizeof(struct AuthRequest));
227 auth->flags = AM_TIMEOUT;
229 auth->client = client;
230 cli_auth(client) = auth;
231 timer_add(&auth->timeout, auth_timeout_callback, (void*) auth, TT_RELATIVE,
237 * free_auth_request - cleanup auth request allocations
239 void free_auth_request(struct AuthRequest* auth)
243 Debug((DEBUG_LIST, "Deleting auth socket for %p", auth->client));
244 socket_del(&auth->socket);
246 Debug((DEBUG_LIST, "Deleting auth timeout timer for %p", auth->client));
247 timer_del(&auth->timeout);
251 * unlink_auth_request - remove auth request from a list
253 static void unlink_auth_request(struct AuthRequest* request,
254 struct AuthRequest** list)
257 request->next->prev = request->prev;
259 request->prev->next = request->next;
261 *list = request->next;
265 * link_auth_request - add auth request to a list
267 static void link_auth_request(struct AuthRequest* request,
268 struct AuthRequest** list)
271 request->next = *list;
273 (*list)->prev = request;
278 * release_auth_client - release auth client from auth system
279 * this adds the client into the local client lists so it can be read by
280 * the main io processing loop
282 static void release_auth_client(struct Client* client)
285 cli_auth(client) = 0;
286 cli_lasttime(client) = cli_since(client) = CurrentTime;
287 if (cli_fd(client) > HighestFd)
288 HighestFd = cli_fd(client);
289 LocalClientArray[cli_fd(client)] = client;
291 add_client_to_list(client);
292 socket_events(&(cli_socket(client)), SOCK_ACTION_SET | SOCK_EVENT_READABLE);
293 Debug((DEBUG_INFO, "Auth: release_auth_client %s@%s[%s]",
294 cli_username(client), cli_sockhost(client), cli_sock_ip(client)));
297 static void auth_kill_client(struct AuthRequest* auth)
301 unlink_auth_request(auth, (IsDoingAuth(auth)) ? &AuthPollList : &AuthIncompleteList);
303 if (IsDNSPending(auth))
304 delete_resolver_queries(auth);
305 IPcheck_disconnect(auth->client);
306 Count_unknowndisconnects(UserStats);
307 free_client(auth->client);
308 free_auth_request(auth);
312 * auth_dns_callback - called when resolver query finishes
313 * if the query resulted in a successful search, hp will contain
314 * a non-null pointer, otherwise hp will be null.
315 * set the client on it's way to a connection completion, regardless
316 * of success of failure
318 static void auth_dns_callback(void* vptr, struct DNSReply* reply)
320 struct AuthRequest* auth = (struct AuthRequest*) vptr;
324 * need to do this here so auth_kill_client doesn't
325 * try have the resolver delete the query it's about
326 * to delete anyways. --Bleep
328 ClearDNSPending(auth);
331 const struct hostent* hp = reply->hp;
335 * Verify that the host to ip mapping is correct both ways and that
336 * the ip#(s) for the socket is listed for the host.
338 for (i = 0; hp->h_addr_list[i]; ++i) {
339 if (0 == memcmp(hp->h_addr_list[i], &(cli_ip(auth->client)),
340 sizeof(struct in_addr)))
343 if (!hp->h_addr_list[i]) {
344 if (IsUserPort(auth->client))
345 sendheader(auth->client, REPORT_IP_MISMATCH);
346 sendto_opmask_butone(0, SNO_IPMISMATCH, "IP# Mismatch: %s != %s[%s]",
347 cli_sock_ip(auth->client), hp->h_name,
348 ircd_ntoa(hp->h_addr_list[0]));
349 if (feature_bool(FEAT_KILL_IPMISMATCH)) {
350 auth_kill_client(auth);
356 cli_dns_reply(auth->client) = reply;
357 ircd_strncpy(cli_sockhost(auth->client), hp->h_name, HOSTLEN);
358 if (IsUserPort(auth->client))
359 sendheader(auth->client, REPORT_FIN_DNS);
364 * this should have already been done by s_bsd.c in add_connection
366 * strcpy(auth->client->sockhost, auth->client->sock_ip);
368 if (IsUserPort(auth->client))
369 sendheader(auth->client, REPORT_FAIL_DNS);
371 if (!IsDoingAuth(auth)) {
372 release_auth_client(auth->client);
373 unlink_auth_request(auth, &AuthIncompleteList);
374 free_auth_request(auth);
379 * authsenderr - handle auth send errors
381 static void auth_error(struct AuthRequest* auth, int kill)
383 ++ServerStats->is_abad;
388 socket_del(&auth->socket);
390 if (IsUserPort(auth->client))
391 sendheader(auth->client, REPORT_FAIL_ID);
395 * we can't read the client info from the client socket,
396 * close the client connection and free the client
397 * Need to do this before we ClearAuth(auth) so we know
398 * which list to remove the query from. --Bleep
400 auth_kill_client(auth);
405 unlink_auth_request(auth, &AuthPollList);
407 if (IsDNSPending(auth))
408 link_auth_request(auth, &AuthIncompleteList);
410 release_auth_client(auth->client);
411 free_auth_request(auth);
416 * start_auth_query - Flag the client to show that an attempt to
417 * contact the ident server on the client's host. The connect and
418 * subsequently the socket are all put into 'non-blocking' mode.
419 * Should the connect or any later phase of the identifing process fail,
420 * it is aborted and the user is given a username of "unknown".
422 static int start_auth_query(struct AuthRequest* auth)
424 struct sockaddr_in remote_addr;
425 struct sockaddr_in local_addr;
430 assert(0 != auth->client);
432 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
434 report_error(SOCKET_ERROR_MSG, get_client_name(auth->client, HIDE_IP), errno);
436 ++ServerStats->is_abad;
439 if ((MAXCONNECTIONS - 10) < fd) {
441 report_error(CONNLIMIT_ERROR_MSG,
442 get_client_name(auth->client, HIDE_IP), errno);
447 if (!os_set_nonblocking(fd)) {
449 report_error(NONB_ERROR_MSG, get_client_name(auth->client, HIDE_IP), errno);
454 if (IsUserPort(auth->client))
455 sendheader(auth->client, REPORT_DO_ID);
457 * get the local address of the client and bind to that to
458 * make the auth request. This used to be done only for
459 * ifdef VIRTTUAL_HOST, but needs to be done for all clients
460 * since the ident request must originate from that same address--
461 * and machines with multiple IP addresses are common now
463 memset(&local_addr, 0, sizeof(struct sockaddr_in));
464 os_get_sockname(cli_fd(auth->client), &local_addr);
465 local_addr.sin_port = htons(0);
467 if (bind(fd, (struct sockaddr*) &local_addr, sizeof(struct sockaddr_in))) {
469 report_error(BIND_ERROR_MSG,
470 get_client_name(auth->client, HIDE_IP), errno);
476 remote_addr.sin_addr.s_addr = (cli_ip(auth->client)).s_addr;
477 remote_addr.sin_port = htons(113);
478 remote_addr.sin_family = AF_INET;
480 if ((result = os_connect_nonb(fd, &remote_addr)) == IO_FAILURE ||
481 !socket_add(&auth->socket, auth_sock_callback, (void*) auth,
482 result == IO_SUCCESS ? SS_CONNECTED : SS_CONNECTING,
483 SOCK_EVENT_READABLE, fd)) {
484 ServerStats->is_abad++;
486 * No error report from this...
489 if (IsUserPort(auth->client))
490 sendheader(auth->client, REPORT_FAIL_ID);
494 auth->flags |= AM_SOCKET;
497 SetAuthConnect(auth);
498 if (result == IO_SUCCESS)
499 send_auth_query(auth); /* this does a SetAuthPending(auth) for us */
505 enum IdentReplyFields {
513 static char* check_ident_reply(char* reply)
517 char* vector[USERID_TOKEN_COUNT];
518 int count = token_vector(reply, ':', vector, USERID_TOKEN_COUNT);
520 if (USERID_TOKEN_COUNT != count)
523 * second token is the reply type
525 token = vector[IDENT_REPLY_TYPE];
526 if (EmptyString(token))
529 while (IsSpace(*token))
532 if (0 != strncmp(token, "USERID", 6))
536 * third token is the os type
538 token = vector[IDENT_OS_TYPE];
539 if (EmptyString(token))
541 while (IsSpace(*token))
545 * Unless "OTHER" is specified as the operating system
546 * type, the server is expected to return the "normal"
547 * user identification of the owner of this connection.
548 * "Normal" in this context may be taken to mean a string
549 * of characters which uniquely identifies the connection
550 * owner such as a user identifier assigned by the system
551 * administrator and used by such user as a mail
552 * identifier, or as the "user" part of a user/password
553 * pair used to gain access to system resources. When an
554 * operating system is specified (e.g., anything but
555 * "OTHER"), the user identifier is expected to be in a
556 * more or less immediately useful form - e.g., something
557 * that could be used as an argument to "finger" or as a
560 if (0 == strncmp(token, "OTHER", 5))
563 * fourth token is the username
565 token = vector[IDENT_INFO];
566 if (EmptyString(token))
568 while (IsSpace(*token))
571 * look for the end of the username, terminators are '\0, @, <SPACE>, :'
573 for (end = token; *end; ++end) {
574 if (IsSpace(*end) || '@' == *end || ':' == *end)
583 * GetValidIdent - parse ident query reply from identd server
585 * Inputs - pointer to ident buf
586 * Output - NULL if no valid ident found, otherwise pointer to name
589 static char* GetValidIdent(char *buf)
597 char* remotePortString;
599 /* All this to get rid of a sscanf() fun. */
600 remotePortString = buf;
602 colon1Ptr = strchr(remotePortString,':');
608 colon2Ptr = strchr(colon1Ptr,':');
614 commaPtr = strchr(remotePortString, ',');
622 remp = atoi(remotePortString);
626 locp = atoi(commaPtr);
630 /* look for USERID bordered by first pair of colons */
631 if(!strstr(colon1Ptr, "USERID"))
634 colon3Ptr = strchr(colon2Ptr,':');
645 * start_auth - starts auth (identd) and dns queries for a client
647 enum { LOOPBACK = 127 };
649 void start_auth(struct Client* client)
651 struct AuthRequest* auth = 0;
655 auth = make_auth_request(client);
658 Debug((DEBUG_INFO, "Beginning auth request on client %p", client));
660 if (!feature_bool(FEAT_NODNS)) {
661 if (LOOPBACK == inet_netof(cli_ip(client)))
662 strcpy(cli_sockhost(client), cli_name(&me));
664 struct DNSQuery query;
667 query.callback = auth_dns_callback;
669 if (IsUserPort(auth->client))
670 sendheader(client, REPORT_DO_DNS);
672 cli_dns_reply(client) = gethost_byaddr((const char*) &(cli_ip(client)),
675 if (cli_dns_reply(client)) {
676 ++(cli_dns_reply(client))->ref_count;
677 ircd_strncpy(cli_sockhost(client), cli_dns_reply(client)->hp->h_name,
679 if (IsUserPort(auth->client))
680 sendheader(client, REPORT_FIN_DNSC);
681 Debug((DEBUG_LIST, "DNS entry for %p was cached", auth->client));
687 if (start_auth_query(auth)) {
688 Debug((DEBUG_LIST, "identd query for %p initiated successfully",
690 link_auth_request(auth, &AuthPollList);
691 } else if (IsDNSPending(auth)) {
692 Debug((DEBUG_LIST, "identd query for %p not initiated successfully; "
693 "waiting on DNS", auth->client));
694 link_auth_request(auth, &AuthIncompleteList);
696 Debug((DEBUG_LIST, "identd query for %p not initiated successfully; "
697 "no DNS pending; releasing immediately", auth->client));
698 free_auth_request(auth);
699 release_auth_client(client);
704 * send_auth_query - send the ident server a query giving "theirport , ourport"
705 * The write is only attempted *once* so it is deemed to be a fail if the
706 * entire write doesn't write all the data given. This shouldnt be a
707 * problem since the socket should have a write buffer far greater than
708 * this message to store it in should problems arise. -avalon
710 void send_auth_query(struct AuthRequest* auth)
712 struct sockaddr_in us;
713 struct sockaddr_in them;
718 assert(0 != auth->client);
720 if (!os_get_sockname(cli_fd(auth->client), &us) ||
721 !os_get_peername(cli_fd(auth->client), &them)) {
725 sprintf_irc(authbuf, "%u , %u\r\n",
726 (unsigned int) ntohs(them.sin_port),
727 (unsigned int) ntohs(us.sin_port));
729 if (IO_SUCCESS == os_send_nonb(auth->fd, authbuf, strlen(authbuf), &count)) {
730 ClearAuthConnect(auth);
731 SetAuthPending(auth);
739 * read_auth_reply - read the reply (if any) from the ident server
741 * We only give it one shot, if the reply isn't good the first time
742 * fail the authentication entirely. --Bleep
744 void read_auth_reply(struct AuthRequest* auth)
749 * rfc1453 sez we MUST accept 512 bytes
751 char buf[BUFSIZE + 1];
754 assert(0 != auth->client);
755 assert(auth = cli_auth(auth->client));
757 if (IO_SUCCESS == os_recv_nonb(auth->fd, buf, BUFSIZE, &len)) {
759 Debug((DEBUG_LIST, "Auth %p [%p] reply: %s", auth, &auth->socket, buf));
760 username = check_ident_reply(buf);
761 Debug((DEBUG_LIST, "Username: %s", username));
766 Debug((DEBUG_LIST, "Deleting auth [%p] socket %p", auth, &auth->socket));
767 socket_del(&auth->socket);
770 if (!EmptyString(username)) {
771 ircd_strncpy(cli_username(auth->client), username, USERLEN);
773 * Not needed, struct is zeroed by memset
774 * auth->client->username[USERLEN] = '\0';
776 SetGotId(auth->client);
777 ++ServerStats->is_asuc;
778 if (IsUserPort(auth->client))
779 sendheader(auth->client, REPORT_FIN_ID);
782 ++ServerStats->is_abad;
784 strcpy(cli_username(auth->client), "unknown");
787 unlink_auth_request(auth, &AuthPollList);
789 if (IsDNSPending(auth))
790 link_auth_request(auth, &AuthIncompleteList);
792 release_auth_client(auth->client);
793 free_auth_request(auth);