]> jfr.im git - irc/quakenet/snircd.git/blame - ircd/ircd_auth.c
Update my e-mail address.
[irc/quakenet/snircd.git] / ircd / ircd_auth.c
CommitLineData
189935b1 1/*
2 * IRC - Internet Relay Chat, ircd/ircd_auth.c
3 * Copyright 2004 Michael Poole <mdpoole@troilus.org>
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 2, 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., 59 Temple Place, Suite 330, Boston, MA
18 * 02111-1307, USA.
19 */
20/** @file
21 * @brief IAuth client implementation for an IRC server.
22 * @version $Id: ircd_auth.c,v 1.18 2005/07/12 02:58:49 entrope Exp $
23 */
24
25#include "config.h"
26#include "client.h"
27#include "ircd_alloc.h"
28#include "ircd_auth.h"
29#include "ircd_events.h"
30#include "ircd_features.h"
31#include "ircd_log.h"
32#include "ircd_osdep.h"
33#include "ircd_snprintf.h"
34#include "ircd_string.h"
35#include "ircd.h"
36#include "msg.h"
37#include "msgq.h"
38#include "res.h"
39#include "s_bsd.h"
40#include "s_debug.h"
41#include "s_misc.h"
42#include "s_user.h"
43#include "send.h"
44
45/* #include <assert.h> -- Now using assert in ircd_log.h */
46#include <errno.h>
47#include <netdb.h>
48#include <string.h>
49#include <unistd.h>
50#include <sys/socket.h>
51#include <netinet/in.h>
52#ifdef HAVE_STDINT_H
53#include <stdint.h>
54#endif
55
56/** Describes state of a single pending IAuth request. */
57struct IAuthRequest {
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 */
62};
63
64/** Enumeration of IAuth connection flags. */
65enum IAuthFlag
66{
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 */
73};
74/** Declare a bitset structure indexed by IAuthFlag. */
75DECLARE_FLAGSET(IAuthFlags, IAUTH_LAST_FLAG);
76
77/** Describes state of an IAuth connection. */
78struct IAuth {
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 unsigned int i_recvM; /**< messages received */
86 unsigned int i_sendM; /**< messages sent */
87 unsigned int i_recvK; /**< kilobytes received */
88 unsigned int i_sendK; /**< kilobytes sent */
89 unsigned short i_recvB; /**< bytes received modulo 1024 */
90 unsigned short i_sendB; /**< bytes sent modulo 1024 */
91 time_t i_reconnect; /**< seconds to wait before reconnecting */
92 time_t i_timeout; /**< seconds to wait for a request */
93 unsigned int i_count; /**< characters used in i_buffer */
94 char i_buffer[BUFSIZE+1]; /**< partial unprocessed line from server */
95 char i_passwd[PASSWDLEN+1]; /**< password for connection */
96 char i_host[HOSTLEN+1]; /**< iauth server hostname */
97 struct irc_sockaddr i_addr; /**< iauth server ip address and port */
98 struct IAuth *i_next; /**< next connection in list */
99};
100
101/** Return flags element of \a iauth. */
102#define i_flags(iauth) ((iauth)->i_flags)
103/** Return whether flag \a flag is set on \a iauth. */
104#define IAuthGet(iauth, flag) FlagHas(&i_flags(iauth), flag)
105/** Set flag \a flag on \a iauth. */
106#define IAuthSet(iauth, flag) FlagSet(&i_flags(iauth), flag)
107/** Clear flag \a flag from \a iauth. */
108#define IAuthClr(iauth, flag) FlagClr(&i_flags(iauth), flag)
109/** Get blocked state for \a iauth. */
110#define i_GetBlocked(iauth) IAuthGet(iauth, IAUTH_BLOCKED)
111/** Set blocked state for \a iauth. */
112#define i_SetBlocked(iauth) IAuthSet(iauth, IAUTH_BLOCKED)
113/** Clear blocked state for \a iauth. */
114#define i_ClrBlocked(iauth) IAuthClr(iauth, IAUTH_BLOCKED)
115/** Get connected flag for \a iauth. */
116#define i_GetConnected(iauth) IAuthGet(iauth, IAUTH_CONNECTED)
117/** Set connected flag for \a iauth. */
118#define i_SetConnected(iauth) IAuthSet(iauth, IAUTH_CONNECTED)
119/** Clear connected flag for \a iauth. */
120#define i_ClrConnected(iauth) IAuthClr(iauth, IAUTH_CONNECTED)
121/** Get abort flag for \a iauth. */
122#define i_GetAbort(iauth) IAuthGet(iauth, IAUTH_ABORT)
123/** Set abort flag for \a iauth. */
124#define i_SetAbort(iauth) IAuthSet(iauth, IAUTH_ABORT)
125/** Clear abort flag for \a iauth. */
126#define i_ClrAbort(iauth) IAuthClr(iauth, IAUTH_ABORT)
127/** Get IClass flag for \a iauth. */
128#define i_GetIClass(iauth) IAuthGet(iauth, IAUTH_ICLASS)
129/** Set IClass flag for \a iauth. */
130#define i_SetIClass(iauth) IAuthSet(iauth, IAUTH_ICLASS)
131/** Clear IClass flag for \a iauth. */
132#define i_ClrIClass(iauth) IAuthClr(iauth, IAUTH_ICLASS)
133/** Get closing flag for \a iauth. */
134#define i_GetClosing(iauth) IAuthGet(iauth, IAUTH_CLOSING)
135/** Set closing flag for \a iauth. */
136#define i_SetClosing(iauth) IAuthSet(iauth, IAUTH_CLOSING)
137/** Clear closing flag for \a iauth. */
138#define i_ClrClosing(iauth) IAuthClr(iauth, IAUTH_CLOSING)
139
140/** Return head of request linked list for \a iauth. */
141#define i_list_head(iauth) ((iauth)->i_list_head)
142/** Return socket event generator for \a iauth. */
143#define i_socket(iauth) ((iauth)->i_socket)
144/** Return reconnect timer for \a iauth. */
145#define i_reconn_timer(iauth) ((iauth)->i_reconn_timer)
146/** Return request timeout timer for \a iauth. */
147#define i_request_timer(iauth) ((iauth)->i_request_timer)
148/** Return DNS query for \a iauth. */
149#define i_query(iauth) ((iauth)->i_query)
150/** Return received bytes (modulo 1024) for \a iauth. */
151#define i_recvB(iauth) ((iauth)->i_recvB)
152/** Return received kilobytes (modulo 1024) for \a iauth. */
153#define i_recvK(iauth) ((iauth)->i_recvK)
154/** Return received megabytes for \a iauth. */
155#define i_recvM(iauth) ((iauth)->i_recvM)
156/** Return sent bytes (modulo 1024) for \a iauth. */
157#define i_sendB(iauth) ((iauth)->i_sendB)
158/** Return sent kilobytes (modulo 1024) for \a iauth. */
159#define i_sendK(iauth) ((iauth)->i_sendK)
160/** Return sent megabytes for \a iauth. */
161#define i_sendM(iauth) ((iauth)->i_sendM)
162/** Return outbound message queue for \a iauth. */
163#define i_sendQ(iauth) ((iauth)->i_sendQ)
164/** Return reconnection interval for \a iauth. */
165#define i_reconnect(iauth) ((iauth)->i_reconnect)
166/** Return request timeout interval for \a iauth. */
167#define i_timeout(iauth) ((iauth)->i_timeout)
168/** Return length of unprocessed message data for \a iauth. */
169#define i_count(iauth) ((iauth)->i_count)
170/** Return start of unprocessed message data for \a iauth. */
171#define i_buffer(iauth) ((iauth)->i_buffer)
172/** Return password we send for \a iauth. */
173#define i_passwd(iauth) ((iauth)->i_passwd)
174/** Return server hostname for \a iauth. */
175#define i_host(iauth) ((iauth)->i_host)
176/** Return address of IAuth server for \a iauth. */
177#define i_addr(iauth) ((iauth)->i_addr)
178/** Return server port for \a iauth. */
179#define i_port(iauth) ((iauth)->i_addr.port)
180/** Return next IAuth connection after \a iauth. */
181#define i_next(iauth) ((iauth)->i_next)
182
183/** Command table entry. */
184struct IAuthCmd {
185 const char *iac_name; /**< Name of command. */
186 void (*iac_func)(struct IAuth *iauth, int, char *[]); /**< Handler function. */
187};
188
189/** Active %IAuth connection(s). */
190struct IAuth *iauth_active;
191
192static void iauth_write(struct IAuth *iauth);
193static void iauth_reconnect(struct IAuth *iauth);
194static void iauth_disconnect(struct IAuth *iauth);
195static void iauth_sock_callback(struct Event *ev);
196static void iauth_send_request(struct IAuth *iauth, struct IAuthRequest *iar);
197static void iauth_dispose_request(struct IAuth *iauth, struct IAuthRequest *iar);
198static void iauth_cmd_doneauth(struct IAuth *iauth, int argc, char *argv[]);
199static void iauth_cmd_badauth(struct IAuth *iauth, int argc, char *argv[]);
200
201/** Table of responses we might get from the IAuth server. */
202static const struct IAuthCmd iauth_cmdtab[] = {
203 { "DoneAuth", iauth_cmd_doneauth },
204 { "BadAuth", iauth_cmd_badauth },
205 { NULL, NULL }
206};
207
208/** Start (or update) a connection to an %IAuth server.
209 * If a connection already exists for the specified server name and
210 * port, update it with the other parameters; otherwise allocate a new
211 * IAuth record.
212 * @param[in] host %IAuth server hostname.
213 * @param[in] port %IAuth server port.
214 * @param[in] passwd Password to send.
215 * @param[in] reconnect Reconnect interval.
216 * @param[in] timeout Request timeout interval.
217 * @return IAuth structure for that connection.
218 */
219struct IAuth *iauth_connect(char *host, unsigned short port, char *passwd, time_t reconnect, time_t timeout)
220{
221 struct IAuth *iauth;
222
223 for (iauth = iauth_active; iauth; iauth = i_next(iauth)) {
224 if (!ircd_strncmp(i_host(iauth), host, HOSTLEN)
225 && (i_port(iauth) == port)) {
226 i_ClrClosing(iauth);
227 i_reconnect(iauth) = reconnect;
228 if (t_active(&i_reconn_timer(iauth)) && (t_expire(&i_reconn_timer(iauth)) > CurrentTime + i_reconnect(iauth)))
229 timer_chg(&i_reconn_timer(iauth), TT_RELATIVE, i_reconnect(iauth));
230 break;
231 }
232 }
233 if (NULL == iauth) {
234 if (iauth_active && !i_GetClosing(iauth_active)) {
235 log_write(LS_CONFIG, L_WARNING, 0, "Creating extra active IAuth connection to %s:%d.", host, port);
236 }
237 iauth = MyCalloc(1, sizeof(*iauth));
238 i_list_head(iauth).iar_prev = &i_list_head(iauth);
239 i_list_head(iauth).iar_next = &i_list_head(iauth);
240 msgq_init(&i_sendQ(iauth));
241 ircd_strncpy(i_host(iauth), host, HOSTLEN);
242 memset(&i_addr(iauth), 0, sizeof(i_addr(iauth)));
243 i_port(iauth) = port;
244 iauth_active = iauth;
245 timer_init(&i_reconn_timer(iauth));
246 i_reconnect(iauth) = reconnect;
247 iauth_reconnect(iauth);
248 }
249 if (passwd)
250 ircd_strncpy(i_passwd(iauth), passwd, PASSWDLEN);
251 else
252 i_passwd(iauth)[0] = '\0';
253 i_timeout(iauth) = timeout;
254 i_SetIClass(iauth);
255 return iauth;
256}
257
258/** Mark all %IAuth connections as closing. */
259void iauth_mark_closing(void)
260{
261 struct IAuth *iauth;
262 for (iauth = iauth_active; iauth; iauth = i_next(iauth))
263 i_SetClosing(iauth);
264}
265
266/** Close a particular %IAuth connection.
267 * @param[in] iauth %Connection to close.
268 */
269void iauth_close(struct IAuth *iauth)
270{
271 /* Figure out what to do with the closing connection's requests. */
272 if (i_list_head(iauth).iar_next != &i_list_head(iauth)) {
273 struct IAuthRequest *iar;
274 if (iauth_active || i_next(iauth)) {
275 /* If iauth_active != NULL, send requests to it; otherwise if
276 * i_next(iauth) != NULL, we can hope it or some later
277 * connection will be active.
278 */
279 struct IAuth *target = iauth_active ? iauth_active : i_next(iauth);
280
281 /* Append iauth->i_list_head to end of target->i_list_head. */
282 iar = i_list_head(iauth).iar_next;
283 iar->iar_prev = i_list_head(target).iar_prev;
284 i_list_head(target).iar_prev->iar_next = iar;
285 iar = i_list_head(iauth).iar_prev;
286 iar->iar_next = &i_list_head(target);
287 i_list_head(target).iar_prev = iar;
288
289 /* If the target is not closing, send the requests. */
290 for (iar = i_list_head(iauth).iar_next;
291 iar != &i_list_head(target);
292 iar = iar->iar_next) {
293 if (!i_GetClosing(target))
294 iauth_send_request(target, iar);
295 }
296 } else {
297 /* No active connections - approve the requests and drop them. */
298 while ((iar = i_list_head(iauth).iar_next) != &i_list_head(iauth)) {
299 struct Client *client = iar->iar_client;
4d36340a 300 ircd_strncpy(cli_user(client)->realusername, cli_username(client), USERLEN);
189935b1 301 iauth_dispose_request(iauth, iar);
302 register_user(client, client, cli_name(client), cli_username(client));
303 }
304 }
305 }
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);
317 /* Free memory. */
318 MyFree(iauth);
319}
320
321/** Close all %IAuth connections marked as closing. */
322void iauth_close_unused(void)
323{
324 struct IAuth *prev, *iauth, *next;
325
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. */
330 if (prev)
331 i_next(prev) = next;
332 else
333 iauth_active = next;
334 /* Close and destroy the connection. */
335 iauth_close(iauth);
336 } else {
337 prev = iauth;
338 }
339 }
340}
341
342/** Send a line to an %IAuth server.
343 * @param[in] iauth %Connection to send on.
344 * @param[in] format Format string for message.
345 */
346static void iauth_send(struct IAuth *iauth, const char *format, ...)
347{
348 va_list vl;
349 struct MsgBuf *mb;
350
351 va_start(vl, format);
352 mb = msgq_vmake(0, format, vl);
353 va_end(vl);
354 msgq_add(&i_sendQ(iauth), mb, 0);
355 msgq_clean(mb);
356}
357
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.
361 */
362static void iauth_protocol_violation(struct IAuth *iauth, const char *format, ...)
363{
364 struct VarData vd;
365 assert(iauth != 0);
366 assert(format != 0);
367 vd.vd_format = format;
368 va_start(vd.vd_args, format);
369 sendto_opmask_butone(NULL, SNO_CONNEXIT, "IAuth protocol violation: %v", &vd);
370 va_end(vd.vd_args);
371}
372
373/** Send on-connect burst to an %IAuth server.
374 * @param[in] iauth %Connection that has completed.
375 */
376static void iauth_on_connect(struct IAuth *iauth)
377{
378 struct IAuthRequest *iar;
379 if (EmptyString(i_passwd(iauth)))
380 iauth_send(iauth, "Server %s", cli_name(&me));
381 else
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");
386 }
387 i_SetConnected(iauth);
388 for (iar = i_list_head(iauth).iar_next;
389 iar != &i_list_head(iauth);
390 iar = iar->iar_next)
391 iauth_send_request(iauth, iar);
392 iauth_write(iauth);
393}
394
395/** Complete disconnection of an %IAuth connection.
396 * @param[in] iauth %Connection to fully close.
397 */
398static void iauth_disconnect(struct IAuth *iauth)
399{
400 close(s_fd(&i_socket(iauth)));
401 socket_del(&i_socket(iauth));
402 i_ClrConnected(iauth);
403}
404
405/** DNS completion callback for an %IAuth connection.
406 * @param[in] vptr Pointer to the IAuth struct.
407 * @param[in] he DNS reply parameters.
408 */
409static void iauth_dns_callback(void *vptr, const struct irc_in_addr *addr, const char *h_name)
410{
411 struct IAuth *iauth = vptr;
412 if (!addr) {
413 log_write(LS_IAUTH, L_NOTICE, 0, "IAuth connection to %s failed: host lookup failed", i_host(iauth));
414 } else {
415 memcpy(&i_addr(iauth).addr, 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));
418 return;
419 }
420 iauth_reconnect(iauth);
421 }
422}
423
424/** Timer callback for reconnecting to %IAuth.
425 * @param[in] ev Timer event for reconnect.
426 */
427static void iauth_reconnect_ev(struct Event *ev)
428{
429 if (ev_type(ev) == ET_EXPIRE)
430 iauth_reconnect(t_data(ev_timer(ev)));
431}
432
433/** Schedule a reconnection for \a iauth.
434 * @param[in] iauth %Connection that needs to be reconnected.
435 */
436static void iauth_schedule_reconnect(struct IAuth *iauth)
437{
438 struct Timer *timer;
439 timer = &i_reconn_timer(iauth);
440 if (t_onqueue(timer))
441 timer_chg(timer, TT_RELATIVE, i_reconnect(iauth));
442 else
443 timer_add(&i_reconn_timer(iauth), iauth_reconnect_ev,
444 iauth, TT_RELATIVE, i_reconnect(iauth));
445}
446
447/** Initiate a (re-)connection to \a iauth.
448 * @param[in] iauth %Connection that should be initiated.
449 */
450static void iauth_reconnect(struct IAuth *iauth)
451{
452 struct irc_sockaddr *local;
453 IOResult result;
454 int fd;
455
456 if (i_GetConnected(iauth)) {
457 iauth_disconnect(iauth);
458 iauth_schedule_reconnect(iauth);
459 return;
460 }
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 gethost_byname(i_host(iauth), iauth_dns_callback, iauth);
465 return;
466 }
467 local = irc_in_addr_is_ipv4(&i_addr(iauth).addr) ? &VirtualHost_v4 : &VirtualHost_v6;
468 fd = os_socket(local, SOCK_STREAM, "IAuth");
469 if (fd < 0) {
470 iauth_schedule_reconnect(iauth);
471 return;
472 }
473 if (!os_set_sockbufs(fd, SERVER_TCP_WINDOW, SERVER_TCP_WINDOW)) {
474 log_write(LS_IAUTH, L_WARNING, 0, "IAuth reconnect unable to set socket buffers: %s", strerror(errno));
475 goto failure;
476 }
477 s_fd(&i_socket(iauth)) = fd;
478 result = os_connect_nonb(fd, &i_addr(iauth));
479 if (result == IO_FAILURE) {
480 log_write(LS_IAUTH, L_NOTICE, 0, "IAuth reconnect unable to initiate connection: %s", strerror(errno));
481 goto failure;
482 }
483 if (!socket_add(&i_socket(iauth), iauth_sock_callback, iauth,
484 (result == IO_SUCCESS) ? SS_CONNECTED : SS_CONNECTING,
485 SOCK_EVENT_READABLE | SOCK_EVENT_WRITABLE, fd)) {
486 log_write(LS_IAUTH, L_WARNING, 0, "IAuth reconnect unable to add socket: %s", strerror(errno));
487 goto failure;
488 }
489 return;
490failure:
491 close(fd);
492 i_ClrConnected(iauth);
493 iauth_schedule_reconnect(iauth);
494 return;
495}
496
497/** Read input from \a iauth.
498 * Reads up to SERVER_TCP_WINDOW bytes per pass.
499 * @param[in] iauth Readable connection.
500 */
501static void iauth_read(struct IAuth *iauth)
502{
503 char *src, *endp, *old_buffer, *argv[MAXPARA + 1];
504 unsigned int length, argc, ii;
505 char readbuf[SERVER_TCP_WINDOW];
506
507 length = 0;
508 if (IO_FAILURE == os_recv_nonb(s_fd(&i_socket(iauth)), readbuf, sizeof(readbuf), &length)
509 || length == 0) {
510 iauth_reconnect(iauth);
511 return;
512 }
513 i_recvB(iauth) += length;
514 if (i_recvB(iauth) > 1023) {
515 i_recvK(iauth) += i_recvB(iauth) >> 10;
516 i_recvB(iauth) &= 1023;
517 }
518 old_buffer = i_buffer(iauth);
519 endp = old_buffer + i_count(iauth);
520 for (src = readbuf; length > 0; --length) {
521 *endp = *src++;
522 if (IsEol(*endp)) {
523 /* Skip blank lines. */
524 if (endp == old_buffer)
525 continue;
526 /* NUL-terminate line and split parameters. */
527 *endp = '\0';
528 for (argc = 0, endp = old_buffer; *endp && (argc < MAXPARA); ) {
529 while (*endp == ' ')
530 *endp++ = '\0';
531 if (*endp == '\0')
532 break;
533 if (*endp == ':')
534 {
535 argv[argc++] = endp + 1;
536 break;
537 }
538 argv[argc++] = endp;
539 for (; *endp && *endp != ' '; ++endp) ;
540 }
541 argv[argc] = NULL;
542 /* Count line and reset endp to start of buffer. */
543 i_recvM(iauth)++;
544 endp = old_buffer;
545 /* Look up command and try to dispatch. */
546 if (argc > 0) {
547 for (ii = 0; iauth_cmdtab[ii].iac_name; ++ii) {
548 if (!ircd_strcmp(iauth_cmdtab[ii].iac_name, argv[0])) {
549 iauth_cmdtab[ii].iac_func(iauth, argc, argv);
550 if (i_GetAbort(iauth))
551 iauth_disconnect(iauth);
552 break;
553 }
554 }
555 }
556 }
557 else if (endp < old_buffer + BUFSIZE)
558 endp++;
559 }
560 i_count(iauth) = endp - old_buffer;
561}
562
563/** Send queued output to \a iauth.
564 * @param[in] iauth Writable connection with queued data.
565 */
566static void iauth_write(struct IAuth *iauth)
567{
568 unsigned int bytes_tried, bytes_sent;
569 IOResult iores;
570
571 if (i_GetBlocked(iauth))
572 return;
573 while (MsgQLength(&i_sendQ(iauth)) > 0) {
574 iores = os_sendv_nonb(s_fd(&i_socket(iauth)), &i_sendQ(iauth), &bytes_tried, &bytes_sent);
575 switch (iores) {
576 case IO_SUCCESS:
577 msgq_delete(&i_sendQ(iauth), bytes_sent);
578 i_sendB(iauth) += bytes_sent;
579 if (i_sendB(iauth) > 1023) {
580 i_sendK(iauth) += i_sendB(iauth) >> 10;
581 i_sendB(iauth) &= 1023;
582 }
583 if (bytes_tried == bytes_sent)
584 break;
585 /* If bytes_sent < bytes_tried, fall through to IO_BLOCKED. */
586 case IO_BLOCKED:
587 i_SetBlocked(iauth);
588 socket_events(&i_socket(iauth), SOCK_ACTION_ADD | SOCK_EVENT_WRITABLE);
589 return;
590 case IO_FAILURE:
591 iauth_disconnect(iauth);
592 return;
593 }
594 }
595 /* We were able to flush all events, so remove notification. */
596 socket_events(&i_socket(iauth), SOCK_ACTION_DEL | SOCK_EVENT_WRITABLE);
597}
598
599/** Handle socket activity for an %IAuth connection.
600 * @param[in] ev &Socket event; the IAuth connection is the user data pointer for the socket.
601 */
602static void iauth_sock_callback(struct Event *ev)
603{
604 struct IAuth *iauth;
605
606 assert(0 != ev_socket(ev));
607 iauth = (struct IAuth*) s_data(ev_socket(ev));
608 assert(0 != iauth);
609
610 switch (ev_type(ev)) {
611 case ET_CONNECT:
612 socket_state(ev_socket(ev), SS_CONNECTED);
613 iauth_on_connect(iauth);
614 break;
615 case ET_DESTROY:
616 if (!i_GetClosing(iauth))
617 iauth_schedule_reconnect(iauth);
618 break;
619 case ET_READ:
620 iauth_read(iauth);
621 break;
622 case ET_WRITE:
623 i_ClrBlocked(iauth);
624 iauth_write(iauth);
625 break;
626 case ET_ERROR:
627 log_write(LS_IAUTH, L_ERROR, 0, "IAuth socket error: %s", strerror(ev_data(ev)));
628 /* and fall through to the ET_EOF case */
629 case ET_EOF:
630 iauth_disconnect(iauth);
631 iauth_schedule_reconnect(iauth);
632 break;
633 default:
634 assert(0 && "Unrecognized event type");
635 break;
636 }
637}
638
639/* Functions related to IAuthRequest structs */
640
641/** Handle timeout while waiting for a response.
642 * @param[in] ev Timer event that expired.
643 */
644static void iauth_request_ev(struct Event *ev)
645{
646 /* TODO: this could probably be more intelligent */
647 if (ev_type(ev) == ET_EXPIRE) {
648 log_write(LS_IAUTH, L_NOTICE, 0, "IAuth request timed out; reconnecting");
649 iauth_reconnect(t_data(ev_timer(ev)));
650 }
651}
652
653/** Send a authorization request to an %IAuth server.
654 * @param[in] iauth %Connection to send request on.
655 * @param[in] iar Request to send.
656 */
657static void iauth_send_request(struct IAuth *iauth, struct IAuthRequest *iar)
658{
659 struct Client *client;
660
661 /* If iauth is not connected, we must defer the request. */
662 if (!i_GetConnected(iauth)) {
663 Debug((DEBUG_SEND, "IAuth deferring request for %s because we are not connected.", cli_name(iar->iar_client)));
664 return;
665 }
666
667 /* If no timed request, set up expiration timer. */
668 if (!t_active(&i_request_timer(iauth))) {
669 struct Timer *timer = timer_init(&i_request_timer(iauth));
670 timer_add(timer, iauth_request_ev, iauth, TT_RELATIVE, i_timeout(iauth));
671 iar->iar_timed = 1;
672 } else
673 iar->iar_timed = 0;
674
675 /* Send the FullAuth request. */
676 client = iar->iar_client;
677 assert(iar->iar_client != NULL);
678 iauth_send(iauth, "FullAuth %x %s %s %s %s %s :%s",
679 client, cli_name(client), cli_username(client),
680 cli_user(client)->host, cli_sock_ip(client),
681 cli_passwd(client), cli_info(client));
682
683 /* Write to the socket if we can. */
684 iauth_write(iauth);
685}
686
687/** Start independent authorization check for a client.
688 * @param[in] iauth %Connection to send request on.
689 * @param[in] cptr Client to check.
690 * @return Zero, or CPTR_KILLED in case of memory allocation failure.
691 */
692int iauth_start_client(struct IAuth *iauth, struct Client *cptr)
693{
694 struct IAuthRequest *iar;
695
696 /* Allocate and initialize IAuthRequest struct. */
697 if (!(iar = MyCalloc(1, sizeof(*iar))))
698 return exit_client(cptr, cptr, &me, "IAuth memory allocation failed");
699 cli_iauth(cptr) = iar;
700 iar->iar_next = &i_list_head(iauth);
701 iar->iar_prev = i_list_head(iauth).iar_prev;
702 iar->iar_client = cptr;
703 iar->iar_prev->iar_next = iar;
704 iar->iar_next->iar_prev = iar;
705
706 /* Send request. */
707 iauth_send_request(iauth, iar);
708
709 return 0;
710}
711
712/** Handle a client that is disconnecting.
713 * If there is a pending %IAuth request for the client, close it.
714 * @param[in] cptr Client that is disconnecting.
715 */
716void iauth_exit_client(struct Client *cptr)
717{
718 if (cli_iauth(cptr)) {
719 iauth_dispose_request(iauth_active, cli_iauth(cptr));
720 cli_iauth(cptr) = NULL;
721 }
722 if (iauth_active && i_GetConnected(iauth_active)) {
723 iauth_send(iauth_active, "ExitUser %x", cptr);
724 iauth_write(iauth_active);
725 }
726}
727
728/** Find pending request with a particular ID.
729 * @param[in] iauth %Connection context for the ID.
730 * @param[in] id Identifier to look up.
731 * @return IAuthRequest with that ID, or NULL.
732 */
733static struct IAuthRequest *iauth_find_request(struct IAuth *iauth, char *id)
734{
735 struct IAuthRequest *curr;
736 struct Client *target;
737 target = (struct Client*)strtoul(id, NULL, 16);
738 for (curr = i_list_head(iauth).iar_next;
739 curr != &i_list_head(iauth);
740 curr = curr->iar_next) {
741 assert(curr->iar_client != NULL);
742 if (target == curr->iar_client)
743 return curr;
744 }
745 return NULL;
746}
747
748/** Unlink and free a request.
749 * @param[in] iauth Connection that owns the request.
750 * @param[in] iar Request to free.
751 */
752static void iauth_dispose_request(struct IAuth *iauth, struct IAuthRequest *iar)
753{
754 assert(iar->iar_client != NULL);
755 if (iar->iar_timed && t_active(&i_request_timer(iauth)))
756 timer_del(&i_request_timer(iauth));
757 cli_iauth(iar->iar_client) = NULL;
758 iar->iar_prev->iar_next = iar->iar_next;
759 iar->iar_next->iar_prev = iar->iar_prev;
760 MyFree(iar);
761}
762
763/** Handle a DoneAuth response from %IAuth.
764 * This means the client is authorized, so let them in.
765 * @param[in] iauth Connection that sent the message.
766 * @param[in] argc Argument count.
767 * @param[in] argv Argument list.
768 */
769static void iauth_cmd_doneauth(struct IAuth *iauth, int argc, char *argv[])
770{
771 struct IAuthRequest *iar;
772 struct Client *client;
773 char *id;
774 char *username;
775 char *hostname;
776 char *c_class;
777 char *account;
778
779 if (argc < 5) {
780 iauth_protocol_violation(iauth, "Only %d parameters for DoneAuth (expected >=5)", argc);
781 return;
782 }
783 id = argv[1];
784 username = argv[2];
785 hostname = argv[3];
786 c_class = argv[4];
787 account = (argc > 5) ? argv[5] : 0;
788 iar = iauth_find_request(iauth, id);
789 if (!iar) {
790 iauth_protocol_violation(iauth, "Got unexpected DoneAuth for id %s", id);
791 return;
792 }
793 client = iar->iar_client;
794 ircd_strncpy(cli_username(client), username, USERLEN);
4d36340a 795 ircd_strncpy(cli_user(client)->realusername, username, USERLEN);
189935b1 796 ircd_strncpy(cli_user(client)->host, hostname, HOSTLEN);
797 if (account) {
798 ircd_strncpy(cli_user(client)->account, account, ACCOUNTLEN);
799 SetAccount(client);
800 }
801 SetIAuthed(client);
802 iauth_dispose_request(iauth, iar);
803 register_user(client, client, cli_name(client), username);
804}
805
806/** Handle a BadAuth response from %IAuth.
807 * This means the client is not authorized, so dump them.
808 * @param[in] iauth Connection that sent the message.
809 * @param[in] argc Argument count.
810 * @param[in] argv Argument list.
811 */
812static void iauth_cmd_badauth(struct IAuth *iauth, int argc, char *argv[])
813{
814 struct IAuthRequest *iar;
815 struct Client *client;
816 char *id;
817 char *reason;
818
819 if (argc < 3) {
820 iauth_protocol_violation(iauth, "Only %d parameters for BadAuth (expected >=3)", argc);
821 return;
822 }
823 id = argv[1];
824 reason = argv[2];
825 if (EmptyString(reason)) {
826 iauth_protocol_violation(iauth, "Empty BadAuth reason for id %s", id);
827 return;
828 }
829 iar = iauth_find_request(iauth, id);
830 if (!iar) {
831 iauth_protocol_violation(iauth, "Got unexpected BadAuth for id %s", id);
832 return;
833 }
834 client = iar->iar_client;
835 iauth_dispose_request(iauth, iar);
836 exit_client(client, client, &me, reason);
837}