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
21 * @brief IAuth client implementation for an IRC server.
27 #include "ircd_alloc.h"
28 #include "ircd_auth.h"
29 #include "ircd_events.h"
30 #include "ircd_features.h"
32 #include "ircd_osdep.h"
33 #include "ircd_snprintf.h"
34 #include "ircd_string.h"
45 /* #include <assert.h> -- Now using assert in ircd_log.h */
50 #include <sys/socket.h>
51 #include <netinet/in.h>
56 /** Describes state of a single pending IAuth request. */
58 struct IAuthRequest *iar_prev; /**< previous request struct */
59 struct IAuthRequest *iar_next; /**< next request struct */
60 struct Client *iar_client; /**< client being authenticated */
61 char iar_timed; /**< if non-zero, using parent i_request_timer */
64 /** Enumeration of IAuth connection flags. */
67 IAUTH_BLOCKED, /**< socket buffer full */
68 IAUTH_CONNECTED, /**< server greeting/handshake done */
69 IAUTH_ABORT, /**< abort connection asap */
70 IAUTH_ICLASS, /**< tell iauth about all local users */
71 IAUTH_CLOSING, /**< candidate to be disposed */
72 IAUTH_LAST_FLAG /**< total number of flags */
74 /** Declare a bitset structure indexed by IAuthFlag. */
75 DECLARE_FLAGSET(IAuthFlags, IAUTH_LAST_FLAG);
77 /** Describes state of an IAuth connection. */
79 struct IAuthRequest i_list_head; /**< doubly linked list of requests */
80 struct MsgQ i_sendQ; /**< messages queued to send */
81 struct Socket i_socket; /**< connection to server */
82 struct Timer i_reconn_timer; /**< when to reconnect the connection */
83 struct Timer i_request_timer; /**< when the current request times out */
84 struct IAuthFlags i_flags; /**< connection state/status/flags */
85 struct DNSQuery i_query; /**< DNS lookup for iauth server */
86 unsigned int i_recvM; /**< messages received */
87 unsigned int i_sendM; /**< messages sent */
88 unsigned int i_recvK; /**< kilobytes received */
89 unsigned int i_sendK; /**< kilobytes sent */
90 unsigned short i_recvB; /**< bytes received modulo 1024 */
91 unsigned short i_sendB; /**< bytes sent modulo 1024 */
92 time_t i_reconnect; /**< seconds to wait before reconnecting */
93 time_t i_timeout; /**< seconds to wait for a request */
94 unsigned int i_count; /**< characters used in i_buffer */
95 char i_buffer[BUFSIZE+1]; /**< partial unprocessed line from server */
96 char i_passwd[PASSWDLEN+1]; /**< password for connection */
97 char i_host[HOSTLEN+1]; /**< iauth server hostname */
98 struct irc_sockaddr i_addr; /**< iauth server ip address and port */
99 struct IAuth *i_next; /**< next connection in list */
102 /** Return flags element of \a iauth. */
103 #define i_flags(iauth) ((iauth)->i_flags)
104 /** Return whether flag \a flag is set on \a iauth. */
105 #define IAuthGet(iauth, flag) FlagHas(&i_flags(iauth), flag)
106 /** Set flag \a flag on \a iauth. */
107 #define IAuthSet(iauth, flag) FlagSet(&i_flags(iauth), flag)
108 /** Clear flag \a flag from \a iauth. */
109 #define IAuthClr(iauth, flag) FlagClr(&i_flags(iauth), flag)
110 /** Get blocked state for \a iauth. */
111 #define i_GetBlocked(iauth) IAuthGet(iauth, IAUTH_BLOCKED)
112 /** Set blocked state for \a iauth. */
113 #define i_SetBlocked(iauth) IAuthSet(iauth, IAUTH_BLOCKED)
114 /** Clear blocked state for \a iauth. */
115 #define i_ClrBlocked(iauth) IAuthClr(iauth, IAUTH_BLOCKED)
116 /** Get connected flag for \a iauth. */
117 #define i_GetConnected(iauth) IAuthGet(iauth, IAUTH_CONNECTED)
118 /** Set connected flag for \a iauth. */
119 #define i_SetConnected(iauth) IAuthSet(iauth, IAUTH_CONNECTED)
120 /** Clear connected flag for \a iauth. */
121 #define i_ClrConnected(iauth) IAuthClr(iauth, IAUTH_CONNECTED)
122 /** Get abort flag for \a iauth. */
123 #define i_GetAbort(iauth) IAuthGet(iauth, IAUTH_ABORT)
124 /** Set abort flag for \a iauth. */
125 #define i_SetAbort(iauth) IAuthSet(iauth, IAUTH_ABORT)
126 /** Clear abort flag for \a iauth. */
127 #define i_ClrAbort(iauth) IAuthClr(iauth, IAUTH_ABORT)
128 /** Get IClass flag for \a iauth. */
129 #define i_GetIClass(iauth) IAuthGet(iauth, IAUTH_ICLASS)
130 /** Set IClass flag for \a iauth. */
131 #define i_SetIClass(iauth) IAuthSet(iauth, IAUTH_ICLASS)
132 /** Clear IClass flag for \a iauth. */
133 #define i_ClrIClass(iauth) IAuthClr(iauth, IAUTH_ICLASS)
134 /** Get closing flag for \a iauth. */
135 #define i_GetClosing(iauth) IAuthGet(iauth, IAUTH_CLOSING)
136 /** Set closing flag for \a iauth. */
137 #define i_SetClosing(iauth) IAuthSet(iauth, IAUTH_CLOSING)
138 /** Clear closing flag for \a iauth. */
139 #define i_ClrClosing(iauth) IAuthClr(iauth, IAUTH_CLOSING)
141 /** Return head of request linked list for \a iauth. */
142 #define i_list_head(iauth) ((iauth)->i_list_head)
143 /** Return socket event generator for \a iauth. */
144 #define i_socket(iauth) ((iauth)->i_socket)
145 /** Return reconnect timer for \a iauth. */
146 #define i_reconn_timer(iauth) ((iauth)->i_reconn_timer)
147 /** Return request timeout timer for \a iauth. */
148 #define i_request_timer(iauth) ((iauth)->i_request_timer)
149 /** Return DNS query for \a iauth. */
150 #define i_query(iauth) ((iauth)->i_query)
151 /** Return received bytes (modulo 1024) for \a iauth. */
152 #define i_recvB(iauth) ((iauth)->i_recvB)
153 /** Return received kilobytes (modulo 1024) for \a iauth. */
154 #define i_recvK(iauth) ((iauth)->i_recvK)
155 /** Return received megabytes for \a iauth. */
156 #define i_recvM(iauth) ((iauth)->i_recvM)
157 /** Return sent bytes (modulo 1024) for \a iauth. */
158 #define i_sendB(iauth) ((iauth)->i_sendB)
159 /** Return sent kilobytes (modulo 1024) for \a iauth. */
160 #define i_sendK(iauth) ((iauth)->i_sendK)
161 /** Return sent megabytes for \a iauth. */
162 #define i_sendM(iauth) ((iauth)->i_sendM)
163 /** Return outbound message queue for \a iauth. */
164 #define i_sendQ(iauth) ((iauth)->i_sendQ)
165 /** Return reconnection interval for \a iauth. */
166 #define i_reconnect(iauth) ((iauth)->i_reconnect)
167 /** Return request timeout interval for \a iauth. */
168 #define i_timeout(iauth) ((iauth)->i_timeout)
169 /** Return length of unprocessed message data for \a iauth. */
170 #define i_count(iauth) ((iauth)->i_count)
171 /** Return start of unprocessed message data for \a iauth. */
172 #define i_buffer(iauth) ((iauth)->i_buffer)
173 /** Return password we send for \a iauth. */
174 #define i_passwd(iauth) ((iauth)->i_passwd)
175 /** Return server hostname for \a iauth. */
176 #define i_host(iauth) ((iauth)->i_host)
177 /** Return address of IAuth server for \a iauth. */
178 #define i_addr(iauth) ((iauth)->i_addr)
179 /** Return server port for \a iauth. */
180 #define i_port(iauth) ((iauth)->i_addr.port)
181 /** Return next IAuth connection after \a iauth. */
182 #define i_next(iauth) ((iauth)->i_next)
184 /** Command table entry. */
186 const char *iac_name; /**< Name of command. */
187 void (*iac_func)(struct IAuth *iauth, int, char *[]); /**< Handler function. */
190 /** Active %IAuth connection(s). */
191 struct IAuth *iauth_active;
193 static void iauth_write(struct IAuth *iauth);
194 static void iauth_reconnect(struct IAuth *iauth);
195 static void iauth_disconnect(struct IAuth *iauth);
196 static void iauth_sock_callback(struct Event *ev);
197 static void iauth_send_request(struct IAuth *iauth, struct IAuthRequest *iar);
198 static void iauth_dispose_request(struct IAuth *iauth, struct IAuthRequest *iar);
199 static void iauth_cmd_doneauth(struct IAuth *iauth, int argc, char *argv[]);
200 static void iauth_cmd_badauth(struct IAuth *iauth, int argc, char *argv[]);
202 /** Table of responses we might get from the IAuth server. */
203 static const struct IAuthCmd iauth_cmdtab[] = {
204 { "DoneAuth", iauth_cmd_doneauth },
205 { "BadAuth", iauth_cmd_badauth },
209 /** Start (or update) a connection to an %IAuth server.
210 * If a connection already exists for the specified server name and
211 * port, update it with the other parameters; otherwise allocate a new
213 * @param[in] host %IAuth server hostname.
214 * @param[in] port %IAuth server port.
215 * @param[in] passwd Password to send.
216 * @param[in] reconnect Reconnect interval.
217 * @param[in] timeout Request timeout interval.
218 * @return IAuth structure for that connection.
220 struct IAuth *iauth_connect(char *host, unsigned short port, char *passwd, time_t reconnect, time_t timeout)
224 for (iauth = iauth_active; iauth; iauth = i_next(iauth)) {
225 if (!ircd_strncmp(i_host(iauth), host, HOSTLEN)
226 && (i_port(iauth) == port)) {
228 i_reconnect(iauth) = reconnect;
229 if (t_active(&i_reconn_timer(iauth)) && (t_expire(&i_reconn_timer(iauth)) > CurrentTime + i_reconnect(iauth)))
230 timer_chg(&i_reconn_timer(iauth), TT_RELATIVE, i_reconnect(iauth));
235 if (iauth_active && !i_GetClosing(iauth_active)) {
236 log_write(LS_CONFIG, L_WARNING, 0, "Creating extra active IAuth connection to %s:%d.", host, port);
238 iauth = MyCalloc(1, sizeof(*iauth));
239 i_list_head(iauth).iar_prev = &i_list_head(iauth);
240 i_list_head(iauth).iar_next = &i_list_head(iauth);
241 msgq_init(&i_sendQ(iauth));
242 ircd_strncpy(i_host(iauth), host, HOSTLEN);
243 memset(&i_addr(iauth), 0, sizeof(i_addr(iauth)));
244 i_port(iauth) = port;
245 iauth_active = iauth;
246 timer_init(&i_reconn_timer(iauth));
247 i_reconnect(iauth) = reconnect;
248 iauth_reconnect(iauth);
251 ircd_strncpy(i_passwd(iauth), passwd, PASSWDLEN);
253 i_passwd(iauth)[0] = '\0';
254 i_timeout(iauth) = timeout;
259 /** Mark all %IAuth connections as closing. */
260 void iauth_mark_closing(void)
263 for (iauth = iauth_active; iauth; iauth = i_next(iauth))
267 /** Close a particular %IAuth connection.
268 * @param[in] iauth %Connection to close.
270 void iauth_close(struct IAuth *iauth)
272 /* Figure out what to do with the closing connection's requests. */
273 if (i_list_head(iauth).iar_next != &i_list_head(iauth)) {
274 struct IAuthRequest *iar;
275 if (iauth_active || i_next(iauth)) {
276 /* If iauth_active != NULL, send requests to it; otherwise if
277 * i_next(iauth) != NULL, we can hope it or some later
278 * connection will be active.
280 struct IAuth *target = iauth_active ? iauth_active : i_next(iauth);
282 /* Append iauth->i_list_head to end of target->i_list_head. */
283 iar = i_list_head(iauth).iar_next;
284 iar->iar_prev = i_list_head(target).iar_prev;
285 i_list_head(target).iar_prev->iar_next = iar;
286 iar = i_list_head(iauth).iar_prev;
287 iar->iar_next = &i_list_head(target);
288 i_list_head(target).iar_prev = iar;
290 /* If the target is not closing, send the requests. */
291 for (iar = i_list_head(iauth).iar_next;
292 iar != &i_list_head(target);
293 iar = iar->iar_next) {
294 if (!i_GetClosing(target))
295 iauth_send_request(target, iar);
298 /* No active connections - approve the requests and drop them. */
299 while ((iar = i_list_head(iauth).iar_next) != &i_list_head(iauth)) {
300 struct Client *client = iar->iar_client;
301 iauth_dispose_request(iauth, iar);
302 register_user(client, client, cli_name(client), cli_username(client));
306 /* Make sure the connection closes with an empty request list. */
307 i_list_head(iauth).iar_prev = &i_list_head(iauth);
308 i_list_head(iauth).iar_next = &i_list_head(iauth);
309 /* Cancel the timer, if it is active. */
310 if (t_active(&i_reconn_timer(iauth)))
311 timer_del(&i_reconn_timer(iauth));
312 if (t_active(&i_request_timer(iauth)))
313 timer_del(&i_request_timer(iauth));
314 /* Disconnect from the server. */
315 if (i_GetConnected(iauth))
316 iauth_disconnect(iauth);
321 /** Close all %IAuth connections marked as closing. */
322 void iauth_close_unused(void)
324 struct IAuth *prev, *iauth, *next;
326 for (prev = NULL, iauth = iauth_active; iauth; iauth = next) {
327 next = i_next(iauth);
328 if (i_GetClosing(iauth)) {
329 /* Update iauth_active linked list. */
334 /* Close and destroy the connection. */
342 /** Send a line to an %IAuth server.
343 * @param[in] iauth %Connection to send on.
344 * @param[in] format Format string for message.
346 static void iauth_send(struct IAuth *iauth, const char *format, ...)
351 va_start(vl, format);
352 mb = msgq_vmake(0, format, vl);
354 msgq_add(&i_sendQ(iauth), mb, 0);
358 /** Report a protocol violation from the %IAuth server.
359 * @param[in] iauth %Connection that experienced the violation.
360 * @param[in] format Format string for message to operators.
362 static void iauth_protocol_violation(struct IAuth *iauth, const char *format, ...)
367 vd.vd_format = format;
368 va_start(vd.vd_args, format);
369 sendwallto_group_butone(&me, WALL_DESYNCH, NULL, "IAuth protocol violation: %v", &vd);
373 /** Send on-connect burst to an %IAuth server.
374 * @param[in] iauth %Connection that has completed.
376 static void iauth_on_connect(struct IAuth *iauth)
378 struct IAuthRequest *iar;
379 if (EmptyString(i_passwd(iauth)))
380 iauth_send(iauth, "Server %s", cli_name(&me));
382 iauth_send(iauth, "Server %s %s", cli_name(&me), i_passwd(iauth));
383 if (i_GetIClass(iauth)) {
384 /* TODO: report local users to iauth */
385 iauth_send(iauth, "EndUsers");
387 i_SetConnected(iauth);
388 for (iar = i_list_head(iauth).iar_next;
389 iar != &i_list_head(iauth);
391 iauth_send_request(iauth, iar);
395 /** Complete disconnection of an %IAuth connection.
396 * @param[in] iauth %Connection to fully close.
398 static void iauth_disconnect(struct IAuth *iauth)
400 close(s_fd(&i_socket(iauth)));
401 socket_del(&i_socket(iauth));
402 i_ClrConnected(iauth);
405 /** DNS completion callback for an %IAuth connection.
406 * @param[in] vptr Pointer to the IAuth struct.
407 * @param[in] he DNS reply parameters.
409 static void iauth_dns_callback(void *vptr, struct DNSReply *he)
411 struct IAuth *iauth = vptr;
413 log_write(LS_IAUTH, L_NOTICE, 0, "IAuth connection to %s failed: host lookup failed", i_host(iauth));
415 memcpy(&i_addr(iauth).addr, &he->addr, sizeof(i_addr(iauth).addr));
416 if (!irc_in_addr_valid(&i_addr(iauth).addr)) {
417 log_write(LS_IAUTH, L_NOTICE, 0, "IAuth connection to %s failed: host came back as unresolved", i_host(iauth));
420 iauth_reconnect(iauth);
424 /** Timer callback for reconnecting to %IAuth.
425 * @param[in] ev Timer event for reconnect.
427 static void iauth_reconnect_ev(struct Event *ev)
429 if (ev_type(ev) == ET_EXPIRE)
430 iauth_reconnect(t_data(ev_timer(ev)));
433 /** Schedule a reconnection for \a iauth.
434 * @param[in] iauth %Connection that needs to be reconnected.
436 static void iauth_schedule_reconnect(struct IAuth *iauth)
439 timer = &i_reconn_timer(iauth);
440 if (t_onqueue(timer))
441 timer_chg(timer, TT_RELATIVE, i_reconnect(iauth));
443 timer_add(&i_reconn_timer(iauth), iauth_reconnect_ev,
444 iauth, TT_RELATIVE, i_reconnect(iauth));
447 /** Initiate a (re-)connection to \a iauth.
448 * @param[in] iauth %Connection that should be initiated.
450 static void iauth_reconnect(struct IAuth *iauth)
452 struct irc_sockaddr *local;
456 if (i_GetConnected(iauth)) {
457 iauth_disconnect(iauth);
458 iauth_schedule_reconnect(iauth);
461 log_write(LS_IAUTH, L_DEBUG, 0, "IAuth attempt connection to %s port %p.", i_host(iauth), i_port(iauth));
462 if (!irc_in_addr_valid(&i_addr(iauth).addr)
463 && !ircd_aton(&i_addr(iauth).addr, i_host(iauth))) {
464 i_query(iauth).vptr = iauth;
465 i_query(iauth).callback = iauth_dns_callback;
466 gethost_byname(i_host(iauth), &i_query(iauth));
469 local = irc_in_addr_is_ipv4(&i_addr(iauth).addr) ? &VirtualHost_v4 : &VirtualHost_v6;
470 fd = os_socket(local, SOCK_STREAM, "IAuth");
472 iauth_schedule_reconnect(iauth);
475 if (!os_set_sockbufs(fd, SERVER_TCP_WINDOW, SERVER_TCP_WINDOW)) {
476 log_write(LS_IAUTH, L_WARNING, 0, "IAuth reconnect unable to set socket buffers: %s", strerror(errno));
479 s_fd(&i_socket(iauth)) = fd;
480 result = os_connect_nonb(fd, &i_addr(iauth));
481 if (result == IO_FAILURE) {
482 log_write(LS_IAUTH, L_NOTICE, 0, "IAuth reconnect unable to initiate connection: %s", strerror(errno));
485 if (!socket_add(&i_socket(iauth), iauth_sock_callback, iauth,
486 (result == IO_SUCCESS) ? SS_CONNECTED : SS_CONNECTING,
487 SOCK_EVENT_READABLE | SOCK_EVENT_WRITABLE, fd)) {
488 log_write(LS_IAUTH, L_WARNING, 0, "IAuth reconnect unable to add socket: %s", strerror(errno));
494 i_ClrConnected(iauth);
495 iauth_schedule_reconnect(iauth);
499 /** Read input from \a iauth.
500 * Reads up to SERVER_TCP_WINDOW bytes per pass.
501 * @param[in] iauth Readable connection.
503 static void iauth_read(struct IAuth *iauth)
505 char *src, *endp, *old_buffer, *argv[MAXPARA + 1];
506 unsigned int length, argc, ii;
507 char readbuf[SERVER_TCP_WINDOW];
510 if (IO_FAILURE == os_recv_nonb(s_fd(&i_socket(iauth)), readbuf, sizeof(readbuf), &length)
512 iauth_reconnect(iauth);
515 i_recvB(iauth) += length;
516 if (i_recvB(iauth) > 1023) {
517 i_recvK(iauth) += i_recvB(iauth) >> 10;
518 i_recvB(iauth) &= 1023;
520 old_buffer = i_buffer(iauth);
521 endp = old_buffer + i_count(iauth);
522 for (src = readbuf; length > 0; --length) {
525 /* Skip blank lines. */
526 if (endp == old_buffer)
528 /* NUL-terminate line and split parameters. */
530 for (argc = 0, endp = old_buffer; *endp && (argc < MAXPARA); ) {
537 argv[argc++] = endp + 1;
541 for (; *endp && *endp != ' '; ++endp) ;
544 /* Count line and reset endp to start of buffer. */
547 /* Look up command and try to dispatch. */
549 for (ii = 0; iauth_cmdtab[ii].iac_name; ++ii) {
550 if (!ircd_strcmp(iauth_cmdtab[ii].iac_name, argv[0])) {
551 iauth_cmdtab[ii].iac_func(iauth, argc, argv);
552 if (i_GetAbort(iauth))
553 iauth_disconnect(iauth);
559 else if (endp < old_buffer + BUFSIZE)
562 i_count(iauth) = endp - old_buffer;
565 /** Send queued output to \a iauth.
566 * @param[in] iauth Writable connection with queued data.
568 static void iauth_write(struct IAuth *iauth)
570 unsigned int bytes_tried, bytes_sent;
573 if (i_GetBlocked(iauth))
575 while (MsgQLength(&i_sendQ(iauth)) > 0) {
576 iores = os_sendv_nonb(s_fd(&i_socket(iauth)), &i_sendQ(iauth), &bytes_tried, &bytes_sent);
579 msgq_delete(&i_sendQ(iauth), bytes_sent);
580 i_sendB(iauth) += bytes_sent;
581 if (i_sendB(iauth) > 1023) {
582 i_sendK(iauth) += i_sendB(iauth) >> 10;
583 i_sendB(iauth) &= 1023;
585 if (bytes_tried == bytes_sent)
587 /* If bytes_sent < bytes_tried, fall through to IO_BLOCKED. */
590 socket_events(&i_socket(iauth), SOCK_ACTION_ADD | SOCK_EVENT_WRITABLE);
593 iauth_disconnect(iauth);
597 /* We were able to flush all events, so remove notification. */
598 socket_events(&i_socket(iauth), SOCK_ACTION_DEL | SOCK_EVENT_WRITABLE);
601 /** Handle socket activity for an %IAuth connection.
602 * @param[in] ev &Socket event; the IAuth connection is the user data pointer for the socket.
604 static void iauth_sock_callback(struct Event *ev)
608 assert(0 != ev_socket(ev));
609 iauth = (struct IAuth*) s_data(ev_socket(ev));
612 switch (ev_type(ev)) {
614 socket_state(ev_socket(ev), SS_CONNECTED);
615 iauth_on_connect(iauth);
618 if (!i_GetClosing(iauth))
619 iauth_schedule_reconnect(iauth);
629 log_write(LS_IAUTH, L_ERROR, 0, "IAuth socket error: %s", strerror(ev_data(ev)));
630 /* and fall through to the ET_EOF case */
632 iauth_disconnect(iauth);
633 iauth_schedule_reconnect(iauth);
636 assert(0 && "Unrecognized event type");
641 /* Functions related to IAuthRequest structs */
643 /** Handle timeout while waiting for a response.
644 * @param[in] ev Timer event that expired.
646 static void iauth_request_ev(struct Event *ev)
648 /* TODO: this could probably be more intelligent */
649 if (ev_type(ev) == ET_EXPIRE) {
650 log_write(LS_IAUTH, L_NOTICE, 0, "IAuth request timed out; reconnecting");
651 iauth_reconnect(t_data(ev_timer(ev)));
655 /** Send a authorization request to an %IAuth server.
656 * @param[in] iauth %Connection to send request on.
657 * @param[in] iar Request to send.
659 static void iauth_send_request(struct IAuth *iauth, struct IAuthRequest *iar)
661 struct Client *client;
663 /* If iauth is not connected, we must defer the request. */
664 if (!i_GetConnected(iauth)) {
665 Debug((DEBUG_SEND, "IAuth deferring request for %s because we are not connected.", cli_name(iar->iar_client)));
669 /* If no timed request, set up expiration timer. */
670 if (!t_active(&i_request_timer(iauth))) {
671 struct Timer *timer = timer_init(&i_request_timer(iauth));
672 timer_add(timer, iauth_request_ev, iauth, TT_RELATIVE, i_timeout(iauth));
677 /* Send the FullAuth request. */
678 client = iar->iar_client;
679 assert(iar->iar_client != NULL);
680 iauth_send(iauth, "FullAuth %x %s %s %s %s %s :%s",
681 client, cli_name(client), cli_username(client),
682 cli_user(client)->host, cli_sock_ip(client),
683 cli_passwd(client), cli_info(client));
685 /* Write to the socket if we can. */
689 /** Start independent authorization check for a client.
690 * @param[in] iauth %Connection to send request on.
691 * @param[in] cptr Client to check.
692 * @return Zero, or CPTR_KILLED in case of memory allocation failure.
694 int iauth_start_client(struct IAuth *iauth, struct Client *cptr)
696 struct IAuthRequest *iar;
698 /* Allocate and initialize IAuthRequest struct. */
699 if (!(iar = MyCalloc(1, sizeof(*iar))))
700 return exit_client(cptr, cptr, &me, "IAuth memory allocation failed");
701 cli_iauth(cptr) = iar;
702 iar->iar_next = &i_list_head(iauth);
703 iar->iar_prev = i_list_head(iauth).iar_prev;
704 iar->iar_client = cptr;
705 iar->iar_prev->iar_next = iar;
706 iar->iar_next->iar_prev = iar;
709 iauth_send_request(iauth, iar);
714 /** Handle a client that is disconnecting.
715 * If there is a pending %IAuth request for the client, close it.
716 * @param[in] cptr Client that is disconnecting.
718 void iauth_exit_client(struct Client *cptr)
720 if (cli_iauth(cptr)) {
721 iauth_dispose_request(iauth_active, cli_iauth(cptr));
722 cli_iauth(cptr) = NULL;
724 if (!i_GetConnected(iauth_active))
726 iauth_send(iauth_active, "ExitUser %x", cptr);
727 iauth_write(iauth_active);
730 /** Find pending request with a particular ID.
731 * @param[in] iauth %Connection context for the ID.
732 * @param[in] id Identifier to look up.
733 * @return IAuthRequest with that ID, or NULL.
735 static struct IAuthRequest *iauth_find_request(struct IAuth *iauth, char *id)
737 struct IAuthRequest *curr;
738 struct Client *target;
739 target = (struct Client*)strtoul(id, NULL, 16);
740 for (curr = i_list_head(iauth).iar_next;
741 curr != &i_list_head(iauth);
742 curr = curr->iar_next) {
743 assert(curr->iar_client != NULL);
744 if (target == curr->iar_client)
750 /** Unlink and free a request.
751 * @param[in] iauth Connection that owns the request.
752 * @param[in] iar Request to free.
754 static void iauth_dispose_request(struct IAuth *iauth, struct IAuthRequest *iar)
756 assert(iar->iar_client != NULL);
758 timer_del(&i_request_timer(iauth));
759 cli_iauth(iar->iar_client) = NULL;
760 iar->iar_prev->iar_next = iar->iar_next;
761 iar->iar_next->iar_prev = iar->iar_prev;
765 /** Handle a DoneAuth response from %IAuth.
766 * This means the client is authorized, so let them in.
767 * @param[in] iauth Connection that sent the message.
768 * @param[in] argc Argument count.
769 * @param[in] argv Argument list.
771 static void iauth_cmd_doneauth(struct IAuth *iauth, int argc, char *argv[])
773 struct IAuthRequest *iar;
774 struct Client *client;
782 iauth_protocol_violation(iauth, "Only %d parameters for DoneAuth (expected >=5)", argc);
789 account = (argc > 5) ? argv[5] : 0;
790 iar = iauth_find_request(iauth, id);
792 iauth_protocol_violation(iauth, "Got unexpected DoneAuth for id %s", id);
795 client = iar->iar_client;
796 ircd_strncpy(cli_username(client), username, USERLEN);
797 ircd_strncpy(cli_user(client)->host, hostname, HOSTLEN);
799 ircd_strncpy(cli_user(client)->account, account, ACCOUNTLEN);
803 iauth_dispose_request(iauth, iar);
804 register_user(client, client, cli_name(client), username);
807 /** Handle a BadAuth response from %IAuth.
808 * This means the client is not authorized, so dump them.
809 * @param[in] iauth Connection that sent the message.
810 * @param[in] argc Argument count.
811 * @param[in] argv Argument list.
813 static void iauth_cmd_badauth(struct IAuth *iauth, int argc, char *argv[])
815 struct IAuthRequest *iar;
816 struct Client *client;
821 iauth_protocol_violation(iauth, "Only %d parameters for BadAuth (expected >=3)", argc);
826 if (EmptyString(reason)) {
827 iauth_protocol_violation(iauth, "Empty BadAuth reason for id %s", id);
830 iar = iauth_find_request(iauth, id);
832 iauth_protocol_violation(iauth, "Got unexpected BadAuth for id %s", id);
835 client = iar->iar_client;
836 iauth_dispose_request(iauth, iar);
837 exit_client(client, client, &me, reason);