2 * IRC - Internet Relay Chat, ircd/ircd_auth.c
3 * Copyright 2004 Michael Poole <mdpoole@troilus.org>
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 2, 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., 59 Temple Place, Suite 330, Boston, MA
25 #include "ircd_alloc.h"
26 #include "ircd_auth.h"
27 #include "ircd_events.h"
28 #include "ircd_features.h"
30 #include "ircd_osdep.h"
31 #include "ircd_snprintf.h"
32 #include "ircd_string.h"
47 #include <sys/socket.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
52 struct IAuthRequest *iar_prev; /* previous request struct */
53 struct IAuthRequest *iar_next; /* next request struct */
54 struct Client *iar_client; /* client being authenticated */
55 char iar_timed; /* if non-zero, using parent i_request_timer */
60 IAUTH_BLOCKED, /* socket buffer full */
61 IAUTH_CONNECTED, /* server greeting/handshake done */
62 IAUTH_ABORT, /* abort connection asap */
63 IAUTH_ICLASS, /* tell iauth about all local users */
64 IAUTH_CLOSING, /* candidate to be disposed */
67 DECLARE_FLAGSET(IAuthFlags, IAUTH_LAST_FLAG);
70 struct IAuthRequest i_list_head; /* doubly linked list of requests */
71 struct MsgQ i_sendQ; /* messages queued to send */
72 struct Socket i_socket; /* connection to server */
73 struct Timer i_reconn_timer; /* when to reconnect the connection */
74 struct Timer i_request_timer; /* when the current request times out */
75 struct IAuthFlags i_flags; /* connection state/status/flags */
76 struct DNSQuery i_query; /* DNS lookup for iauth server */
77 unsigned int i_recvM; /* messages received */
78 unsigned int i_sendM; /* messages sent */
79 unsigned int i_recvK; /* kilobytes received */
80 unsigned int i_sendK; /* kilobytes sent */
81 unsigned short i_recvB; /* bytes received modulo 1024 */
82 unsigned short i_sendB; /* bytes sent modulo 1024 */
83 time_t i_reconnect; /* seconds to wait before reconnecting */
84 time_t i_timeout; /* seconds to wait for a request */
85 unsigned int i_count; /* characters used in i_buffer */
86 char i_buffer[BUFSIZE+1]; /* partial unprocessed line from server */
87 char i_passwd[PASSWDLEN+1]; /* password for connection */
88 char i_host[HOSTLEN+1]; /* iauth server hostname */
89 in_addr_t i_addr; /* iauth server ip address */
90 unsigned short i_port; /* iauth server port */
91 struct IAuth *i_next; /* next connection in list */
94 #define i_flags(iauth) ((iauth)->i_flags)
95 #define IAuthGet(iauth, flag) FlagHas(&i_flags(iauth), flag)
96 #define IAuthSet(iauth, flag) FlagSet(&i_flags(iauth), flag)
97 #define IAuthClr(iauth, flag) FlagClr(&i_flags(iauth), flag)
98 #define i_GetBlocked(iauth) IAuthGet(iauth, IAUTH_BLOCKED)
99 #define i_SetBlocked(iauth) IAuthSet(iauth, IAUTH_BLOCKED)
100 #define i_ClrBlocked(iauth) IAuthClr(iauth, IAUTH_BLOCKED)
101 #define i_GetConnected(iauth) IAuthGet(iauth, IAUTH_CONNECTED)
102 #define i_SetConnected(iauth) IAuthSet(iauth, IAUTH_CONNECTED)
103 #define i_ClrConnected(iauth) IAuthClr(iauth, IAUTH_CONNECTED)
104 #define i_GetAbort(iauth) IAuthGet(iauth, IAUTH_ABORT)
105 #define i_SetAbort(iauth) IAuthSet(iauth, IAUTH_ABORT)
106 #define i_ClrAbort(iauth) IAuthClr(iauth, IAUTH_ABORT)
107 #define i_GetIClass(iauth) IAuthGet(iauth, IAUTH_ICLASS)
108 #define i_SetIClass(iauth) IAuthSet(iauth, IAUTH_ICLASS)
109 #define i_ClrIClass(iauth) IAuthClr(iauth, IAUTH_ICLASS)
110 #define i_GetClosing(iauth) IAuthGet(iauth, IAUTH_CLOSING)
111 #define i_SetClosing(iauth) IAuthSet(iauth, IAUTH_CLOSING)
112 #define i_ClrClosing(iauth) IAuthClr(iauth, IAUTH_CLOSING)
114 #define i_list_head(iauth) ((iauth)->i_list_head)
115 #define i_socket(iauth) ((iauth)->i_socket)
116 #define i_reconn_timer(iauth) ((iauth)->i_reconn_timer)
117 #define i_request_timer(iauth) ((iauth)->i_request_timer)
118 #define i_query(iauth) ((iauth)->i_query)
119 #define i_recvB(iauth) ((iauth)->i_recvB)
120 #define i_recvK(iauth) ((iauth)->i_recvK)
121 #define i_recvM(iauth) ((iauth)->i_recvM)
122 #define i_sendB(iauth) ((iauth)->i_sendB)
123 #define i_sendK(iauth) ((iauth)->i_sendK)
124 #define i_sendM(iauth) ((iauth)->i_sendM)
125 #define i_sendQ(iauth) ((iauth)->i_sendQ)
126 #define i_reconnect(iauth) ((iauth)->i_reconnect)
127 #define i_timeout(iauth) ((iauth)->i_timeout)
128 #define i_count(iauth) ((iauth)->i_count)
129 #define i_buffer(iauth) ((iauth)->i_buffer)
130 #define i_passwd(iauth) ((iauth)->i_passwd)
131 #define i_host(iauth) ((iauth)->i_host)
132 #define i_addr(iauth) ((iauth)->i_addr)
133 #define i_port(iauth) ((iauth)->i_port)
134 #define i_next(iauth) ((iauth)->i_next)
137 const char *iac_name;
138 void (*iac_func)(struct IAuth *iauth, int, char *[]);
141 struct IAuth *iauth_active;
143 static void iauth_write(struct IAuth *iauth);
144 static void iauth_reconnect(struct IAuth *iauth);
145 static void iauth_disconnect(struct IAuth *iauth);
146 static void iauth_sock_callback(struct Event *ev);
147 static void iauth_send_request(struct IAuth *iauth, struct IAuthRequest *iar);
148 static void iauth_dispose_request(struct IAuth *iauth, struct IAuthRequest *iar);
149 static void iauth_cmd_doneauth(struct IAuth *iauth, int argc, char *argv[]);
150 static void iauth_cmd_badauth(struct IAuth *iauth, int argc, char *argv[]);
152 static const struct IAuthCmd iauth_cmdtab[] = {
153 { "DoneAuth", iauth_cmd_doneauth },
154 { "BadAuth", iauth_cmd_badauth },
158 struct IAuth *iauth_connect(char *host, unsigned short port, char *passwd, time_t reconnect, time_t timeout)
162 for (iauth = iauth_active; iauth; iauth = i_next(iauth)) {
163 if (!ircd_strncmp(i_host(iauth), host, HOSTLEN)
164 && (i_port(iauth) == port)) {
166 i_reconnect(iauth) = reconnect;
167 if (t_active(&i_reconn_timer(iauth)) && (t_expire(&i_reconn_timer(iauth)) > CurrentTime + i_reconnect(iauth)))
168 timer_chg(&i_reconn_timer(iauth), TT_RELATIVE, i_reconnect(iauth));
173 if (iauth_active && !i_GetClosing(iauth_active)) {
174 log_write(LS_CONFIG, L_WARNING, 0, "Creating extra active IAuth connection to %s:%d.", host, port);
176 iauth = MyCalloc(1, sizeof(*iauth));
177 i_list_head(iauth).iar_prev = &i_list_head(iauth);
178 i_list_head(iauth).iar_next = &i_list_head(iauth);
179 msgq_init(&i_sendQ(iauth));
180 ircd_strncpy(i_host(iauth), host, HOSTLEN);
181 i_port(iauth) = port;
182 i_addr(iauth) = INADDR_NONE;
183 i_next(iauth) = iauth_active;
184 iauth_active = iauth;
185 i_reconnect(iauth) = reconnect;
186 iauth_reconnect(iauth);
189 ircd_strncpy(i_passwd(iauth), passwd, PASSWDLEN);
191 i_passwd(iauth)[0] = '\0';
192 i_timeout(iauth) = timeout;
196 void iauth_mark_closing(void)
199 for (iauth = iauth_active; iauth; iauth = i_next(iauth))
203 void iauth_close(struct IAuth *iauth)
205 /* Figure out what to do with the closing connection's requests. */
206 if (i_list_head(iauth).iar_next != &i_list_head(iauth)) {
207 struct IAuthRequest *iar;
208 if (iauth_active || i_next(iauth)) {
209 /* If iauth_active != NULL, send requests to it; otherwise if
210 * i_next(iauth) != NULL, we can hope it or some later
211 * connection will be active.
213 struct IAuth *target = iauth_active ? iauth_active : i_next(iauth);
215 /* Append iauth->i_list_head to end of target->i_list_head. */
216 iar = i_list_head(iauth).iar_next;
217 iar->iar_prev = i_list_head(target).iar_prev;
218 i_list_head(target).iar_prev->iar_next = iar;
219 iar = i_list_head(iauth).iar_prev;
220 iar->iar_next = &i_list_head(target);
221 i_list_head(target).iar_prev = iar;
223 /* If the target is not closing, send the requests. */
224 for (iar = i_list_head(iauth).iar_next;
225 iar != &i_list_head(target);
226 iar = iar->iar_next) {
227 if (!i_GetClosing(target))
228 iauth_send_request(target, iar);
231 /* No active connections - approve the requests and drop them. */
232 while ((iar = i_list_head(iauth).iar_next) != &i_list_head(iauth)) {
233 struct Client *client = iar->iar_client;
234 iauth_dispose_request(iauth, iar);
235 register_user(client, client, cli_name(client), cli_username(client));
239 /* Make sure the connection closes with an empty request list. */
240 i_list_head(iauth).iar_prev = &i_list_head(iauth);
241 i_list_head(iauth).iar_next = &i_list_head(iauth);
242 /* Cancel the timer, if it is active. */
243 if (t_active(&i_reconn_timer(iauth)))
244 timer_del(&i_reconn_timer(iauth));
245 if (t_active(&i_request_timer(iauth)))
246 timer_del(&i_request_timer(iauth));
247 /* Disconnect from the server. */
248 if (s_fd(&i_socket(iauth)) != -1)
249 iauth_disconnect(iauth);
254 void iauth_close_unused(void)
256 struct IAuth *prev, *iauth, *next;
258 for (prev = NULL, iauth = iauth_active; iauth; iauth = next) {
259 next = i_next(iauth);
260 if (i_GetClosing(iauth)) {
261 /* Update iauth_active linked list. */
266 /* Close and destroy the connection. */
274 static void iauth_send(struct IAuth *iauth, const char *format, ...)
279 va_start(vl, format);
280 mb = msgq_vmake(0, format, vl);
282 msgq_add(&i_sendQ(iauth), mb, 0);
286 static void iauth_protocol_violation(struct IAuth *iauth, const char *format, ...)
291 vd.vd_format = format;
292 va_start(vd.vd_args, format);
293 sendwallto_group_butone(&me, WALL_DESYNCH, NULL, "IAuth protocol violation: %v", &vd);
297 static void iauth_on_connect(struct IAuth *iauth)
299 struct IAuthRequest *iar;
300 if (EmptyString(i_passwd(iauth)))
301 iauth_send(iauth, "Server %s", cli_name(&me));
303 iauth_send(iauth, "Server %s %s", cli_name(&me), i_passwd(iauth));
304 if (i_GetIClass(iauth)) {
305 /* TODO: report local users to iauth */
306 iauth_send(iauth, "EndUsers");
308 i_SetConnected(iauth);
309 for (iar = i_list_head(iauth).iar_next;
310 iar != &i_list_head(iauth);
312 iauth_send_request(iauth, iar);
316 static void iauth_disconnect(struct IAuth *iauth)
318 close(s_fd(&i_socket(iauth)));
319 socket_del(&i_socket(iauth));
320 s_fd(&i_socket(iauth)) = -1;
323 static void iauth_dns_callback(void *vptr, struct DNSReply *he)
325 struct IAuth *iauth = vptr;
327 sendto_opmask_butone(0, SNO_OLDSNO, "IAuth connection to %s failed: host lookup failed", i_host(iauth));
328 } else if (he->h_addrtype != AF_INET) {
329 sendto_opmask_butone(0, SNO_OLDSNO, "IAuth connection to %s failed: bad host type %d", i_host(iauth), he->h_addrtype);
331 struct sockaddr_in *sin = (struct sockaddr_in*)&he->addr;
332 i_addr(iauth) = sin->sin_addr.s_addr;
333 if (INADDR_NONE == i_addr(iauth)) {
334 sendto_opmask_butone(0, SNO_OLDSNO, "IAuth connection to %s failed: host came back as INADDR_NONE", i_host(iauth));
337 iauth_reconnect(iauth);
341 static void iauth_reconnect_ev(struct Event *ev)
343 if (ev_type(ev) == ET_EXPIRE)
344 iauth_reconnect(t_data(ev_timer(ev)));
347 static void iauth_schedule_reconnect(struct IAuth *iauth)
350 assert(!t_active(&i_reconn_timer(iauth)));
351 timer = timer_init(&i_reconn_timer(iauth));
352 timer_add(timer, iauth_reconnect_ev, iauth, TT_RELATIVE, i_reconnect(iauth));
355 static void iauth_reconnect(struct IAuth *iauth)
357 extern struct sockaddr_in VirtualHost;
358 struct sockaddr_in sin;
362 if (INADDR_NONE == i_addr(iauth)) {
363 i_addr(iauth) = inet_addr(i_host(iauth));
364 if (INADDR_NONE == i_addr(iauth)) {
365 i_query(iauth).vptr = iauth;
366 i_query(iauth).callback = iauth_dns_callback;
367 gethost_byname(i_host(iauth), &i_query(iauth));
371 fd = socket(AF_INET, SOCK_STREAM, 0);
373 sendto_opmask_butone(0, SNO_OLDSNO, "IAuth reconnect unable to allocate socket: %s", strerror(errno));
376 if (feature_bool(FEAT_VIRTUAL_HOST)
377 && bind(fd, (struct sockaddr*)&VirtualHost, sizeof(VirtualHost)) != 0) {
379 sendto_opmask_butone(0, SNO_OLDSNO, "IAuth reconnect unable to bind vhost: %s", strerror(errno));
382 if (!os_set_sockbufs(fd, SERVER_TCP_WINDOW, SERVER_TCP_WINDOW)) {
384 sendto_opmask_butone(0, SNO_OLDSNO, "IAuth reconnect unable to set socket buffers: %s", strerror(errno));
387 if (!os_set_nonblocking(fd)) {
389 sendto_opmask_butone(0, SNO_OLDSNO, "IAuth reconnect unable to make socket non-blocking: %s", strerror(errno));
392 memset(&sin, 0, sizeof(sin));
393 sin.sin_family = AF_INET;
394 sin.sin_addr.s_addr = i_addr(iauth);
395 sin.sin_port = htons(i_port(iauth));
396 result = os_connect_nonb(fd, &sin);
397 if (result == IO_FAILURE) {
399 sendto_opmask_butone(0, SNO_OLDSNO, "IAuth reconnect unable to initiate connection: %s", strerror(errno));
402 if (!socket_add(&i_socket(iauth), iauth_sock_callback, iauth,
403 (result == IO_SUCCESS) ? SS_CONNECTED : SS_CONNECTING,
404 SOCK_EVENT_READABLE | SOCK_EVENT_WRITABLE, fd)) {
406 sendto_opmask_butone(0, SNO_OLDSNO, "IAuth reconnect unable to add socket: %s", strerror(errno));
411 static void iauth_read(struct IAuth *iauth)
413 char *src, *endp, *old_buffer, *argv[MAXPARA + 1];
414 unsigned int length, argc, ii;
415 char readbuf[SERVER_TCP_WINDOW];
418 if (IO_FAILURE == os_recv_nonb(s_fd(&i_socket(iauth)), readbuf, sizeof(readbuf), &length))
420 i_recvB(iauth) += length;
421 if (i_recvB(iauth) > 1023) {
422 i_recvK(iauth) += i_recvB(iauth) >> 10;
423 i_recvB(iauth) &= 1023;
425 old_buffer = i_buffer(iauth);
426 endp = old_buffer + i_count(iauth);
427 for (src = readbuf; length > 0; --length) {
430 /* Skip blank lines. */
431 if (endp == old_buffer)
433 /* NUL-terminate line and split parameters. */
435 for (argc = 0, endp = old_buffer; *endp && (argc < MAXPARA); ) {
442 argv[argc++] = endp + 1;
446 for (; *endp && *endp != ' '; ++endp) ;
449 /* Count line and reset endp to start of buffer. */
452 /* Look up command and try to dispatch. */
454 for (ii = 0; iauth_cmdtab[ii].iac_name; ++ii) {
455 if (!ircd_strcmp(iauth_cmdtab[ii].iac_name, argv[0])) {
456 iauth_cmdtab[ii].iac_func(iauth, argc, argv);
457 if (i_GetAbort(iauth))
458 iauth_disconnect(iauth);
464 else if (endp < old_buffer + BUFSIZE)
467 i_count(iauth) = endp - old_buffer;
470 static void iauth_write(struct IAuth *iauth)
472 unsigned int bytes_tried, bytes_sent;
475 if (i_GetBlocked(iauth))
477 while (MsgQLength(&i_sendQ(iauth)) > 0) {
478 iores = os_sendv_nonb(s_fd(&i_socket(iauth)), &i_sendQ(iauth), &bytes_tried, &bytes_sent);
481 msgq_delete(&i_sendQ(iauth), bytes_sent);
482 i_sendB(iauth) += bytes_sent;
483 if (i_sendB(iauth) > 1023) {
484 i_sendK(iauth) += i_sendB(iauth) >> 10;
485 i_sendB(iauth) &= 1023;
487 if (bytes_tried == bytes_sent)
489 /* If bytes_sent < bytes_tried, fall through to IO_BLOCKED. */
492 socket_events(&i_socket(iauth), SOCK_ACTION_ADD | SOCK_EVENT_WRITABLE);
495 iauth_disconnect(iauth);
499 /* We were able to flush all events, so remove notification. */
500 socket_events(&i_socket(iauth), SOCK_ACTION_DEL | SOCK_EVENT_WRITABLE);
503 static void iauth_sock_callback(struct Event *ev)
507 assert(0 != ev_socket(ev));
508 iauth = (struct IAuth*) s_data(ev_socket(ev));
511 switch (ev_type(ev)) {
513 socket_state(ev_socket(ev), SS_CONNECTED);
514 iauth_on_connect(iauth);
517 if (!i_GetClosing(iauth))
518 iauth_schedule_reconnect(iauth);
528 iauth_disconnect(iauth);
531 sendto_opmask_butone(0, SNO_OLDSNO, "IAuth socket error: %s", strerror(ev_data(ev)));
532 log_write(LS_SOCKET, L_ERROR, 0, "IAuth socket error: %s", strerror(ev_data(ev)));
533 iauth_disconnect(iauth);
536 assert(0 && "Unrecognized event type");
541 /* Functions related to IAuthRequest structs */
543 static void iauth_request_ev(struct Event *ev)
545 /* TODO: this could probably be more intelligent */
546 if (ev_type(ev) == ET_EXPIRE) {
547 sendto_opmask_butone(0, SNO_OLDSNO, "IAuth request timed out; reconnecting");
548 iauth_reconnect(t_data(ev_timer(ev)));
552 static void iauth_send_request(struct IAuth *iauth, struct IAuthRequest *iar)
554 struct Client *client;
556 /* If iauth is not connected, we must defer the request. */
557 if (!i_GetConnected(iauth))
560 /* If no timed request, set up expiration timer. */
561 if (!t_active(&i_request_timer(iauth))) {
562 struct Timer *timer = timer_init(&i_request_timer(iauth));
563 timer_add(timer, iauth_request_ev, iauth, TT_RELATIVE, i_timeout(iauth));
568 /* Send the FullAuth request. */
569 client = iar->iar_client;
570 assert(iar->iar_client != NULL);
571 iauth_send(iauth, "FullAuth %x %s %s %s %s %s :%s",
572 client, cli_name(client), cli_username(client),
573 cli_user(client)->host, cli_sock_ip(client),
574 cli_passwd(client), cli_info(client));
576 /* Write to the socket if we can. */
580 int iauth_start_client(struct IAuth *iauth, struct Client *cptr)
582 struct IAuthRequest *iar;
584 /* Allocate and initialize IAuthRequest struct. */
585 if (!(iar = MyCalloc(1, sizeof(*iar))))
586 return exit_client(cptr, cptr, &me, "IAuth memory allocation failed");
587 iar->iar_next = &i_list_head(iauth);
588 iar->iar_prev = i_list_head(iauth).iar_prev;
589 iar->iar_client = cptr;
590 iar->iar_prev->iar_next = iar;
591 iar->iar_next->iar_prev = iar;
594 iauth_send_request(iauth, iar);
599 void iauth_exit_client(struct Client *cptr)
601 if (cli_iauth(cptr)) {
602 iauth_dispose_request(iauth_active, cli_iauth(cptr));
603 cli_iauth(cptr) = NULL;
604 } else if (IsIAuthed(cptr) && i_GetIClass(iauth_active)) {
605 /* TODO: report quit to iauth */
609 static struct IAuthRequest *iauth_find_request(struct IAuth *iauth, char *id)
611 struct IAuthRequest *curr;
612 struct Client *target;
613 target = (struct Client*)strtoul(id, NULL, 16);
614 for (curr = i_list_head(iauth).iar_next;
615 curr != &i_list_head(iauth);
616 curr = curr->iar_next) {
617 assert(curr->iar_client != NULL);
618 if (target == curr->iar_client)
624 static void iauth_dispose_request(struct IAuth *iauth, struct IAuthRequest *iar)
626 assert(iar->iar_client != NULL);
628 timer_del(&i_request_timer(iauth));
629 cli_iauth(iar->iar_client) = NULL;
630 iar->iar_prev->iar_next = iar->iar_next;
631 iar->iar_next->iar_prev = iar->iar_prev;
635 static void iauth_cmd_doneauth(struct IAuth *iauth, int argc, char *argv[])
637 struct IAuthRequest *iar;
638 struct Client *client;
646 iauth_protocol_violation(iauth, "Only %d parameters for DoneAuth (expected >=5)", argc);
653 account = (argc > 5) ? argv[5] : 0;
654 iar = iauth_find_request(iauth, id);
656 iauth_protocol_violation(iauth, "Got unexpected DoneAuth for id %s", id);
659 client = iar->iar_client;
660 ircd_strncpy(cli_username(client), username, USERLEN);
661 ircd_strncpy(cli_user(client)->host, hostname, HOSTLEN);
663 ircd_strncpy(cli_user(client)->account, account, ACCOUNTLEN);
667 iauth_dispose_request(iauth, iar);
668 register_user(client, client, cli_name(client), username);
671 static void iauth_cmd_badauth(struct IAuth *iauth, int argc, char *argv[])
673 struct IAuthRequest *iar;
674 struct Client *client;
679 iauth_protocol_violation(iauth, "Only %d parameters for BadAuth (expected >=3)", argc);
684 if (EmptyString(reason)) {
685 iauth_protocol_violation(iauth, "Empty BadAuth reason for id %s", id);
688 iar = iauth_find_request(iauth, id);
690 iauth_protocol_violation(iauth, "Got unexpected BadAuth for id %s", id);
693 client = iar->iar_client;
694 iauth_dispose_request(iauth, iar);
695 exit_client(client, client, &me, reason);