]>
jfr.im git - irc/quakenet/snircd.git/blob - ircd/ircd_auth.c
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.
22 * @version $Id: ircd_auth.c,v 1.18 2005/07/12 02:58:49 entrope Exp $
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 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 */
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)
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)
183 /** Command table entry. */
185 const char *iac_name
; /**< Name of command. */
186 void (*iac_func
)(struct IAuth
*iauth
, int, char *[]); /**< Handler function. */
189 /** Active %IAuth connection(s). */
190 struct IAuth
*iauth_active
;
192 static void iauth_write(struct IAuth
*iauth
);
193 static void iauth_reconnect(struct IAuth
*iauth
);
194 static void iauth_disconnect(struct IAuth
*iauth
);
195 static void iauth_sock_callback(struct Event
*ev
);
196 static void iauth_send_request(struct IAuth
*iauth
, struct IAuthRequest
*iar
);
197 static void iauth_dispose_request(struct IAuth
*iauth
, struct IAuthRequest
*iar
);
198 static void iauth_cmd_doneauth(struct IAuth
*iauth
, int argc
, char *argv
[]);
199 static void iauth_cmd_badauth(struct IAuth
*iauth
, int argc
, char *argv
[]);
201 /** Table of responses we might get from the IAuth server. */
202 static const struct IAuthCmd iauth_cmdtab
[] = {
203 { "DoneAuth", iauth_cmd_doneauth
},
204 { "BadAuth", iauth_cmd_badauth
},
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
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.
219 struct IAuth
*iauth_connect(char *host
, unsigned short port
, char *passwd
, time_t reconnect
, time_t timeout
)
223 for (iauth
= iauth_active
; iauth
; iauth
= i_next(iauth
)) {
224 if (!ircd_strncmp(i_host(iauth
), host
, HOSTLEN
)
225 && (i_port(iauth
) == port
)) {
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
));
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
);
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
);
250 ircd_strncpy(i_passwd(iauth
), passwd
, PASSWDLEN
);
252 i_passwd(iauth
)[0] = '\0';
253 i_timeout(iauth
) = timeout
;
258 /** Mark all %IAuth connections as closing. */
259 void iauth_mark_closing(void)
262 for (iauth
= iauth_active
; iauth
; iauth
= i_next(iauth
))
266 /** Close a particular %IAuth connection.
267 * @param[in] iauth %Connection to close.
269 void iauth_close(struct IAuth
*iauth
)
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.
279 struct IAuth
*target
= iauth_active
? iauth_active
: i_next(iauth
);
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
;
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
);
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
;
300 iauth_dispose_request(iauth
, iar
);
301 register_user(client
, client
, cli_name(client
), cli_username(client
));
305 /* Make sure the connection closes with an empty request list. */
306 i_list_head(iauth
).iar_prev
= &i_list_head(iauth
);
307 i_list_head(iauth
).iar_next
= &i_list_head(iauth
);
308 /* Cancel the timer, if it is active. */
309 if (t_active(&i_reconn_timer(iauth
)))
310 timer_del(&i_reconn_timer(iauth
));
311 if (t_active(&i_request_timer(iauth
)))
312 timer_del(&i_request_timer(iauth
));
313 /* Disconnect from the server. */
314 if (i_GetConnected(iauth
))
315 iauth_disconnect(iauth
);
320 /** Close all %IAuth connections marked as closing. */
321 void iauth_close_unused(void)
323 struct IAuth
*prev
, *iauth
, *next
;
325 for (prev
= NULL
, iauth
= iauth_active
; iauth
; iauth
= next
) {
326 next
= i_next(iauth
);
327 if (i_GetClosing(iauth
)) {
328 /* Update iauth_active linked list. */
333 /* Close and destroy the connection. */
341 /** Send a line to an %IAuth server.
342 * @param[in] iauth %Connection to send on.
343 * @param[in] format Format string for message.
345 static void iauth_send(struct IAuth
*iauth
, const char *format
, ...)
350 va_start(vl
, format
);
351 mb
= msgq_vmake(0, format
, vl
);
353 msgq_add(&i_sendQ(iauth
), mb
, 0);
357 /** Report a protocol violation from the %IAuth server.
358 * @param[in] iauth %Connection that experienced the violation.
359 * @param[in] format Format string for message to operators.
361 static void iauth_protocol_violation(struct IAuth
*iauth
, const char *format
, ...)
366 vd
.vd_format
= format
;
367 va_start(vd
.vd_args
, format
);
368 sendto_opmask_butone(NULL
, SNO_CONNEXIT
, "IAuth protocol violation: %v", &vd
);
372 /** Send on-connect burst to an %IAuth server.
373 * @param[in] iauth %Connection that has completed.
375 static void iauth_on_connect(struct IAuth
*iauth
)
377 struct IAuthRequest
*iar
;
378 if (EmptyString(i_passwd(iauth
)))
379 iauth_send(iauth
, "Server %s", cli_name(&me
));
381 iauth_send(iauth
, "Server %s %s", cli_name(&me
), i_passwd(iauth
));
382 if (i_GetIClass(iauth
)) {
383 /* TODO: report local users to iauth */
384 iauth_send(iauth
, "EndUsers");
386 i_SetConnected(iauth
);
387 for (iar
= i_list_head(iauth
).iar_next
;
388 iar
!= &i_list_head(iauth
);
390 iauth_send_request(iauth
, iar
);
394 /** Complete disconnection of an %IAuth connection.
395 * @param[in] iauth %Connection to fully close.
397 static void iauth_disconnect(struct IAuth
*iauth
)
399 close(s_fd(&i_socket(iauth
)));
400 socket_del(&i_socket(iauth
));
401 i_ClrConnected(iauth
);
404 /** DNS completion callback for an %IAuth connection.
405 * @param[in] vptr Pointer to the IAuth struct.
406 * @param[in] he DNS reply parameters.
408 static void iauth_dns_callback(void *vptr
, const struct irc_in_addr
*addr
, const char *h_name
)
410 struct IAuth
*iauth
= vptr
;
412 log_write(LS_IAUTH
, L_NOTICE
, 0, "IAuth connection to %s failed: host lookup failed", i_host(iauth
));
414 memcpy(&i_addr(iauth
).addr
, addr
, sizeof(i_addr(iauth
).addr
));
415 if (!irc_in_addr_valid(&i_addr(iauth
).addr
)) {
416 log_write(LS_IAUTH
, L_NOTICE
, 0, "IAuth connection to %s failed: host came back as unresolved", i_host(iauth
));
419 iauth_reconnect(iauth
);
423 /** Timer callback for reconnecting to %IAuth.
424 * @param[in] ev Timer event for reconnect.
426 static void iauth_reconnect_ev(struct Event
*ev
)
428 if (ev_type(ev
) == ET_EXPIRE
)
429 iauth_reconnect(t_data(ev_timer(ev
)));
432 /** Schedule a reconnection for \a iauth.
433 * @param[in] iauth %Connection that needs to be reconnected.
435 static void iauth_schedule_reconnect(struct IAuth
*iauth
)
438 timer
= &i_reconn_timer(iauth
);
439 if (t_onqueue(timer
))
440 timer_chg(timer
, TT_RELATIVE
, i_reconnect(iauth
));
442 timer_add(&i_reconn_timer(iauth
), iauth_reconnect_ev
,
443 iauth
, TT_RELATIVE
, i_reconnect(iauth
));
446 /** Initiate a (re-)connection to \a iauth.
447 * @param[in] iauth %Connection that should be initiated.
449 static void iauth_reconnect(struct IAuth
*iauth
)
451 struct irc_sockaddr
*local
;
455 if (i_GetConnected(iauth
)) {
456 iauth_disconnect(iauth
);
457 iauth_schedule_reconnect(iauth
);
460 log_write(LS_IAUTH
, L_DEBUG
, 0, "IAuth attempt connection to %s port %p.", i_host(iauth
), i_port(iauth
));
461 if (!irc_in_addr_valid(&i_addr(iauth
).addr
)
462 && !ircd_aton(&i_addr(iauth
).addr
, i_host(iauth
))) {
463 gethost_byname(i_host(iauth
), iauth_dns_callback
, iauth
);
466 local
= irc_in_addr_is_ipv4(&i_addr(iauth
).addr
) ? &VirtualHost_v4
: &VirtualHost_v6
;
467 fd
= os_socket(local
, SOCK_STREAM
, "IAuth");
469 iauth_schedule_reconnect(iauth
);
472 if (!os_set_sockbufs(fd
, SERVER_TCP_WINDOW
, SERVER_TCP_WINDOW
)) {
473 log_write(LS_IAUTH
, L_WARNING
, 0, "IAuth reconnect unable to set socket buffers: %s", strerror(errno
));
476 s_fd(&i_socket(iauth
)) = fd
;
477 result
= os_connect_nonb(fd
, &i_addr(iauth
));
478 if (result
== IO_FAILURE
) {
479 log_write(LS_IAUTH
, L_NOTICE
, 0, "IAuth reconnect unable to initiate connection: %s", strerror(errno
));
482 if (!socket_add(&i_socket(iauth
), iauth_sock_callback
, iauth
,
483 (result
== IO_SUCCESS
) ? SS_CONNECTED
: SS_CONNECTING
,
484 SOCK_EVENT_READABLE
| SOCK_EVENT_WRITABLE
, fd
)) {
485 log_write(LS_IAUTH
, L_WARNING
, 0, "IAuth reconnect unable to add socket: %s", strerror(errno
));
491 i_ClrConnected(iauth
);
492 iauth_schedule_reconnect(iauth
);
496 /** Read input from \a iauth.
497 * Reads up to SERVER_TCP_WINDOW bytes per pass.
498 * @param[in] iauth Readable connection.
500 static void iauth_read(struct IAuth
*iauth
)
502 char *src
, *endp
, *old_buffer
, *argv
[MAXPARA
+ 1];
503 unsigned int length
, argc
, ii
;
504 char readbuf
[SERVER_TCP_WINDOW
];
507 if (IO_FAILURE
== os_recv_nonb(s_fd(&i_socket(iauth
)), readbuf
, sizeof(readbuf
), &length
)
509 iauth_reconnect(iauth
);
512 i_recvB(iauth
) += length
;
513 if (i_recvB(iauth
) > 1023) {
514 i_recvK(iauth
) += i_recvB(iauth
) >> 10;
515 i_recvB(iauth
) &= 1023;
517 old_buffer
= i_buffer(iauth
);
518 endp
= old_buffer
+ i_count(iauth
);
519 for (src
= readbuf
; length
> 0; --length
) {
522 /* Skip blank lines. */
523 if (endp
== old_buffer
)
525 /* NUL-terminate line and split parameters. */
527 for (argc
= 0, endp
= old_buffer
; *endp
&& (argc
< MAXPARA
); ) {
534 argv
[argc
++] = endp
+ 1;
538 for (; *endp
&& *endp
!= ' '; ++endp
) ;
541 /* Count line and reset endp to start of buffer. */
544 /* Look up command and try to dispatch. */
546 for (ii
= 0; iauth_cmdtab
[ii
].iac_name
; ++ii
) {
547 if (!ircd_strcmp(iauth_cmdtab
[ii
].iac_name
, argv
[0])) {
548 iauth_cmdtab
[ii
].iac_func(iauth
, argc
, argv
);
549 if (i_GetAbort(iauth
))
550 iauth_disconnect(iauth
);
556 else if (endp
< old_buffer
+ BUFSIZE
)
559 i_count(iauth
) = endp
- old_buffer
;
562 /** Send queued output to \a iauth.
563 * @param[in] iauth Writable connection with queued data.
565 static void iauth_write(struct IAuth
*iauth
)
567 unsigned int bytes_tried
, bytes_sent
;
570 if (i_GetBlocked(iauth
))
572 while (MsgQLength(&i_sendQ(iauth
)) > 0) {
573 iores
= os_sendv_nonb(s_fd(&i_socket(iauth
)), &i_sendQ(iauth
), &bytes_tried
, &bytes_sent
);
576 msgq_delete(&i_sendQ(iauth
), bytes_sent
);
577 i_sendB(iauth
) += bytes_sent
;
578 if (i_sendB(iauth
) > 1023) {
579 i_sendK(iauth
) += i_sendB(iauth
) >> 10;
580 i_sendB(iauth
) &= 1023;
582 if (bytes_tried
== bytes_sent
)
584 /* If bytes_sent < bytes_tried, fall through to IO_BLOCKED. */
587 socket_events(&i_socket(iauth
), SOCK_ACTION_ADD
| SOCK_EVENT_WRITABLE
);
590 iauth_disconnect(iauth
);
594 /* We were able to flush all events, so remove notification. */
595 socket_events(&i_socket(iauth
), SOCK_ACTION_DEL
| SOCK_EVENT_WRITABLE
);
598 /** Handle socket activity for an %IAuth connection.
599 * @param[in] ev &Socket event; the IAuth connection is the user data pointer for the socket.
601 static void iauth_sock_callback(struct Event
*ev
)
605 assert(0 != ev_socket(ev
));
606 iauth
= (struct IAuth
*) s_data(ev_socket(ev
));
609 switch (ev_type(ev
)) {
611 socket_state(ev_socket(ev
), SS_CONNECTED
);
612 iauth_on_connect(iauth
);
615 if (!i_GetClosing(iauth
))
616 iauth_schedule_reconnect(iauth
);
626 log_write(LS_IAUTH
, L_ERROR
, 0, "IAuth socket error: %s", strerror(ev_data(ev
)));
627 /* and fall through to the ET_EOF case */
629 iauth_disconnect(iauth
);
630 iauth_schedule_reconnect(iauth
);
633 assert(0 && "Unrecognized event type");
638 /* Functions related to IAuthRequest structs */
640 /** Handle timeout while waiting for a response.
641 * @param[in] ev Timer event that expired.
643 static void iauth_request_ev(struct Event
*ev
)
645 /* TODO: this could probably be more intelligent */
646 if (ev_type(ev
) == ET_EXPIRE
) {
647 log_write(LS_IAUTH
, L_NOTICE
, 0, "IAuth request timed out; reconnecting");
648 iauth_reconnect(t_data(ev_timer(ev
)));
652 /** Send a authorization request to an %IAuth server.
653 * @param[in] iauth %Connection to send request on.
654 * @param[in] iar Request to send.
656 static void iauth_send_request(struct IAuth
*iauth
, struct IAuthRequest
*iar
)
658 struct Client
*client
;
660 /* If iauth is not connected, we must defer the request. */
661 if (!i_GetConnected(iauth
)) {
662 Debug((DEBUG_SEND
, "IAuth deferring request for %s because we are not connected.", cli_name(iar
->iar_client
)));
666 /* If no timed request, set up expiration timer. */
667 if (!t_active(&i_request_timer(iauth
))) {
668 struct Timer
*timer
= timer_init(&i_request_timer(iauth
));
669 timer_add(timer
, iauth_request_ev
, iauth
, TT_RELATIVE
, i_timeout(iauth
));
674 /* Send the FullAuth request. */
675 client
= iar
->iar_client
;
676 assert(iar
->iar_client
!= NULL
);
677 iauth_send(iauth
, "FullAuth %x %s %s %s %s %s :%s",
678 client
, cli_name(client
), cli_username(client
),
679 cli_user(client
)->host
, cli_sock_ip(client
),
680 cli_passwd(client
), cli_info(client
));
682 /* Write to the socket if we can. */
686 /** Start independent authorization check for a client.
687 * @param[in] iauth %Connection to send request on.
688 * @param[in] cptr Client to check.
689 * @return Zero, or CPTR_KILLED in case of memory allocation failure.
691 int iauth_start_client(struct IAuth
*iauth
, struct Client
*cptr
)
693 struct IAuthRequest
*iar
;
695 /* Allocate and initialize IAuthRequest struct. */
696 if (!(iar
= MyCalloc(1, sizeof(*iar
))))
697 return exit_client(cptr
, cptr
, &me
, "IAuth memory allocation failed");
698 cli_iauth(cptr
) = iar
;
699 iar
->iar_next
= &i_list_head(iauth
);
700 iar
->iar_prev
= i_list_head(iauth
).iar_prev
;
701 iar
->iar_client
= cptr
;
702 iar
->iar_prev
->iar_next
= iar
;
703 iar
->iar_next
->iar_prev
= iar
;
706 iauth_send_request(iauth
, iar
);
711 /** Handle a client that is disconnecting.
712 * If there is a pending %IAuth request for the client, close it.
713 * @param[in] cptr Client that is disconnecting.
715 void iauth_exit_client(struct Client
*cptr
)
717 if (cli_iauth(cptr
)) {
718 iauth_dispose_request(iauth_active
, cli_iauth(cptr
));
719 cli_iauth(cptr
) = NULL
;
721 if (iauth_active
&& i_GetConnected(iauth_active
)) {
722 iauth_send(iauth_active
, "ExitUser %x", cptr
);
723 iauth_write(iauth_active
);
727 /** Find pending request with a particular ID.
728 * @param[in] iauth %Connection context for the ID.
729 * @param[in] id Identifier to look up.
730 * @return IAuthRequest with that ID, or NULL.
732 static struct IAuthRequest
*iauth_find_request(struct IAuth
*iauth
, char *id
)
734 struct IAuthRequest
*curr
;
735 struct Client
*target
;
736 target
= (struct Client
*)strtoul(id
, NULL
, 16);
737 for (curr
= i_list_head(iauth
).iar_next
;
738 curr
!= &i_list_head(iauth
);
739 curr
= curr
->iar_next
) {
740 assert(curr
->iar_client
!= NULL
);
741 if (target
== curr
->iar_client
)
747 /** Unlink and free a request.
748 * @param[in] iauth Connection that owns the request.
749 * @param[in] iar Request to free.
751 static void iauth_dispose_request(struct IAuth
*iauth
, struct IAuthRequest
*iar
)
753 assert(iar
->iar_client
!= NULL
);
754 if (iar
->iar_timed
&& t_active(&i_request_timer(iauth
)))
755 timer_del(&i_request_timer(iauth
));
756 cli_iauth(iar
->iar_client
) = NULL
;
757 iar
->iar_prev
->iar_next
= iar
->iar_next
;
758 iar
->iar_next
->iar_prev
= iar
->iar_prev
;
762 /** Handle a DoneAuth response from %IAuth.
763 * This means the client is authorized, so let them in.
764 * @param[in] iauth Connection that sent the message.
765 * @param[in] argc Argument count.
766 * @param[in] argv Argument list.
768 static void iauth_cmd_doneauth(struct IAuth
*iauth
, int argc
, char *argv
[])
770 struct IAuthRequest
*iar
;
771 struct Client
*client
;
779 iauth_protocol_violation(iauth
, "Only %d parameters for DoneAuth (expected >=5)", argc
);
786 account
= (argc
> 5) ? argv
[5] : 0;
787 iar
= iauth_find_request(iauth
, id
);
789 iauth_protocol_violation(iauth
, "Got unexpected DoneAuth for id %s", id
);
792 client
= iar
->iar_client
;
793 ircd_strncpy(cli_username(client
), username
, USERLEN
);
794 ircd_strncpy(cli_user(client
)->host
, hostname
, HOSTLEN
);
796 ircd_strncpy(cli_user(client
)->account
, account
, ACCOUNTLEN
);
800 iauth_dispose_request(iauth
, iar
);
801 register_user(client
, client
, cli_name(client
), username
);
804 /** Handle a BadAuth response from %IAuth.
805 * This means the client is not authorized, so dump them.
806 * @param[in] iauth Connection that sent the message.
807 * @param[in] argc Argument count.
808 * @param[in] argv Argument list.
810 static void iauth_cmd_badauth(struct IAuth
*iauth
, int argc
, char *argv
[])
812 struct IAuthRequest
*iar
;
813 struct Client
*client
;
818 iauth_protocol_violation(iauth
, "Only %d parameters for BadAuth (expected >=3)", argc
);
823 if (EmptyString(reason
)) {
824 iauth_protocol_violation(iauth
, "Empty BadAuth reason for id %s", id
);
827 iar
= iauth_find_request(iauth
, id
);
829 iauth_protocol_violation(iauth
, "Got unexpected BadAuth for id %s", id
);
832 client
= iar
->iar_client
;
833 iauth_dispose_request(iauth
, iar
);
834 exit_client(client
, client
, &me
, reason
);