]> jfr.im git - irc/rqf/shadowircd.git/blame - src/client.c
s_log.* -> logger.* (s_foo looks ugly, lets try to get rid of it)
[irc/rqf/shadowircd.git] / src / client.c
CommitLineData
212380e3 1/*
b37021a4 2 * charybdis: an advanced ircd.
212380e3 3 * client.c: Controls clients.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
b37021a4 8 * Copyright (C) 2007 William Pitcock
212380e3 9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 * USA
24 *
f80a1823 25 * $Id: client.c 3514 2007-06-06 16:25:21Z nenolod $
212380e3 26 */
27#include "stdinc.h"
28#include "config.h"
29
212380e3 30#include "client.h"
31#include "class.h"
32#include "common.h"
212380e3 33#include "hash.h"
34#include "irc_string.h"
35#include "sprintf_irc.h"
36#include "ircd.h"
37#include "s_gline.h"
38#include "numeric.h"
39#include "packet.h"
40#include "s_auth.h"
212380e3 41#include "s_conf.h"
42#include "s_newconf.h"
d3455e2c 43#include "logger.h"
212380e3 44#include "s_serv.h"
45#include "s_stats.h"
46#include "send.h"
47#include "whowas.h"
48#include "s_user.h"
212380e3 49#include "hash.h"
212380e3 50#include "hostmask.h"
212380e3 51#include "listener.h"
52#include "hook.h"
53#include "msg.h"
54#include "monitor.h"
55#include "blacklist.h"
54015b5f 56#include "reject.h"
994544c2 57#include "scache.h"
b37021a4 58#include "irc_dictionary.h"
212380e3 59
60#define DEBUG_EXITED_CLIENTS
61
af81d5a0
WP
62static void check_pings_list(rb_dlink_list * list);
63static void check_unknowns_list(rb_dlink_list * list);
212380e3 64static void free_exited_clients(void *unused);
65static void exit_aborted_clients(void *unused);
66
67static int exit_remote_client(struct Client *, struct Client *, struct Client *,const char *);
68static int exit_remote_server(struct Client *, struct Client *, struct Client *,const char *);
69static int exit_local_client(struct Client *, struct Client *, struct Client *,const char *);
70static int exit_unknown_client(struct Client *, struct Client *, struct Client *,const char *);
71static int exit_local_server(struct Client *, struct Client *, struct Client *,const char *);
72static int qs_server(struct Client *, struct Client *, struct Client *, const char *comment);
73
74static EVH check_pings;
75
6e9b4415
VY
76extern rb_bh *client_heap;
77extern rb_bh *lclient_heap;
78extern rb_bh *pclient_heap;
784fdac0 79static rb_bh *away_heap = NULL;
212380e3 80
81extern char current_uid[IDLEN];
82
43de0f45
WP
83struct Dictionary *nd_dict = NULL;
84
212380e3 85enum
86{
87 D_LINED,
88 K_LINED,
89 G_LINED
90};
91
af81d5a0 92rb_dlink_list dead_list;
212380e3 93#ifdef DEBUG_EXITED_CLIENTS
af81d5a0 94static rb_dlink_list dead_remote_list;
212380e3 95#endif
96
97struct abort_client
98{
af81d5a0 99 rb_dlink_node node;
212380e3 100 struct Client *client;
101 char notice[REASONLEN];
102};
103
af81d5a0 104static rb_dlink_list abort_list;
212380e3 105
106
107/*
108 * init_client
109 *
110 * inputs - NONE
111 * output - NONE
112 * side effects - initialize client free memory
113 */
114void
115init_client(void)
116{
117 /*
118 * start off the check ping event .. -- adrian
119 * Every 30 seconds is plenty -- db
120 */
ae4091d2 121 client_heap = rb_bh_create(sizeof(struct Client), CLIENT_HEAP_SIZE, "client_heap");
784fdac0
VY
122 lclient_heap = rb_bh_create(sizeof(struct LocalUser), LCLIENT_HEAP_SIZE, "lclient_heap");
123 pclient_heap = rb_bh_create(sizeof(struct PreClient), PCLIENT_HEAP_SIZE, "pclient_heap");
124 away_heap = rb_bh_create(AWAYLEN, AWAY_HEAP_SIZE, "away_heap");
125
780087dc
JT
126 rb_event_addish("check_pings", check_pings, NULL, 30);
127 rb_event_addish("free_exited_clients", &free_exited_clients, NULL, 4);
128 rb_event_addish("exit_aborted_clients", exit_aborted_clients, NULL, 1);
6227ed01 129 rb_event_add("flood_recalc", flood_recalc, NULL, 1);
43de0f45
WP
130
131 nd_dict = irc_dictionary_create(irccmp);
212380e3 132}
133
134
135/*
136 * make_client - create a new Client struct and set it to initial state.
137 *
138 * from == NULL, create local client (a client connected
139 * to a socket).
140 *
141 * from, create remote client (behind a socket
142 * associated with the client defined by
143 * 'from'). ('from' is a local client!!).
144 */
145struct Client *
146make_client(struct Client *from)
147{
148 struct Client *client_p = NULL;
149 struct LocalUser *localClient;
150
6e9b4415 151 client_p = rb_bh_alloc(client_heap);
212380e3 152
153 if(from == NULL)
154 {
155 client_p->from = client_p; /* 'from' of local client is self! */
156
6e9b4415 157 localClient = (struct LocalUser *) rb_bh_alloc(lclient_heap);
212380e3 158 SetMyConnect(client_p);
159 client_p->localClient = localClient;
160
9f6bbe3c 161 client_p->localClient->lasttime = client_p->localClient->firsttime = rb_current_time();
212380e3 162
de057244 163 client_p->localClient->F = NULL;
212380e3 164
6e9b4415 165 client_p->preClient = (struct PreClient *) rb_bh_alloc(pclient_heap);
212380e3 166
167 /* as good a place as any... */
af81d5a0 168 rb_dlinkAdd(client_p, &client_p->localClient->tnode, &unknown_list);
212380e3 169 }
170 else
171 { /* from is not NULL */
172 client_p->localClient = NULL;
173 client_p->preClient = NULL;
174 client_p->from = from; /* 'from' of local client is self! */
175 }
176
177 SetUnknown(client_p);
178 strcpy(client_p->username, "unknown");
179
180 return client_p;
181}
182
183void
184free_pre_client(struct Client *client_p)
185{
186 struct Blacklist *blptr;
187
188 s_assert(NULL != client_p);
189
190 if(client_p->preClient == NULL)
191 return;
192
193 blptr = client_p->preClient->dnsbl_listed;
194 if (blptr != NULL)
195 unref_blacklist(blptr);
196 abort_blacklist_queries(client_p);
6e9b4415 197 rb_bh_free(pclient_heap, client_p->preClient);
212380e3 198 client_p->preClient = NULL;
199}
200
201static void
202free_local_client(struct Client *client_p)
203{
204 s_assert(NULL != client_p);
205 s_assert(&me != client_p);
206
207 if(client_p->localClient == NULL)
208 return;
209
210 /*
211 * clean up extra sockets from P-lines which have been discarded.
212 */
213 if(client_p->localClient->listener)
214 {
215 s_assert(0 < client_p->localClient->listener->ref_count);
216 if(0 == --client_p->localClient->listener->ref_count
217 && !client_p->localClient->listener->active)
218 free_listener(client_p->localClient->listener);
219 client_p->localClient->listener = 0;
220 }
221
24350e62 222 if(client_p->localClient->F)
780087dc 223 rb_close(client_p->localClient->F);
212380e3 224
225 if(client_p->localClient->passwd)
226 {
227 memset(client_p->localClient->passwd, 0,
228 strlen(client_p->localClient->passwd));
90a3c35b 229 rb_free(client_p->localClient->passwd);
212380e3 230 }
231
90a3c35b
VY
232 rb_free(client_p->localClient->challenge);
233 rb_free(client_p->localClient->fullcaps);
234 rb_free(client_p->localClient->opername);
235 rb_free(client_p->localClient->mangledhost);
212380e3 236
6e9b4415 237 rb_bh_free(lclient_heap, client_p->localClient);
212380e3 238 client_p->localClient = NULL;
239}
240
241void
242free_client(struct Client *client_p)
243{
244 s_assert(NULL != client_p);
245 s_assert(&me != client_p);
246 free_local_client(client_p);
247 free_pre_client(client_p);
6e9b4415 248 rb_bh_free(client_heap, client_p);
212380e3 249}
250
251/*
252 * check_pings - go through the local client list and check activity
253 * kill off stuff that should die
254 *
255 * inputs - NOT USED (from event)
256 * output - next time_t when check_pings() should be called again
257 * side effects -
258 *
259 *
260 * A PING can be sent to clients as necessary.
261 *
262 * Client/Server ping outs are handled.
263 */
264
265/*
266 * Addon from adrian. We used to call this after nextping seconds,
267 * however I've changed it to run once a second. This is only for
268 * PING timeouts, not K/etc-line checks (thanks dianora!). Having it
269 * run once a second makes life a lot easier - when a new client connects
270 * and they need a ping in 4 seconds, if nextping was set to 20 seconds
271 * we end up waiting 20 seconds. This is stupid. :-)
272 * I will optimise (hah!) check_pings() once I've finished working on
273 * tidying up other network IO evilnesses.
274 * -- adrian
275 */
276
277static void
278check_pings(void *notused)
279{
280 check_pings_list(&lclient_list);
281 check_pings_list(&serv_list);
282 check_unknowns_list(&unknown_list);
283}
284
285/*
286 * Check_pings_list()
287 *
288 * inputs - pointer to list to check
289 * output - NONE
290 * side effects -
291 */
292static void
af81d5a0 293check_pings_list(rb_dlink_list * list)
212380e3 294{
295 char scratch[32]; /* way too generous but... */
296 struct Client *client_p; /* current local client_p being examined */
297 int ping = 0; /* ping time value from client */
90a3c35b 298 rb_dlink_node *ptr, *next_ptr;
212380e3 299
90a3c35b 300 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
212380e3 301 {
302 client_p = ptr->data;
303
212380e3 304 if(!MyConnect(client_p) || IsDead(client_p))
305 continue;
306
e883cf07 307 ping = get_client_ping(client_p);
212380e3 308
9f6bbe3c 309 if(ping < (rb_current_time() - client_p->localClient->lasttime))
212380e3 310 {
311 /*
312 * If the client/server hasnt talked to us in 2*ping seconds
313 * and it has a ping time, then close its connection.
314 */
9f6bbe3c 315 if(((rb_current_time() - client_p->localClient->lasttime) >= (2 * ping)
212380e3 316 && (client_p->flags & FLAGS_PINGSENT)))
317 {
e883cf07 318 if(IsServer(client_p))
212380e3 319 {
e883cf07 320 sendto_realops_snomask(SNO_GENERAL, L_ALL,
212380e3 321 "No response from %s, closing link",
322 get_server_name(client_p, HIDE_IP));
323 ilog(L_SERVER,
324 "No response from %s, closing link",
325 log_client_name(client_p, HIDE_IP));
326 }
38e6acdd 327 (void) rb_snprintf(scratch, sizeof(scratch),
212380e3 328 "Ping timeout: %d seconds",
9f6bbe3c 329 (int) (rb_current_time() - client_p->localClient->lasttime));
212380e3 330
331 exit_client(client_p, client_p, &me, scratch);
332 continue;
333 }
334 else if((client_p->flags & FLAGS_PINGSENT) == 0)
335 {
336 /*
337 * if we havent PINGed the connection and we havent
338 * heard from it in a while, PING it to make sure
339 * it is still alive.
340 */
341 client_p->flags |= FLAGS_PINGSENT;
342 /* not nice but does the job */
9f6bbe3c 343 client_p->localClient->lasttime = rb_current_time() - ping;
212380e3 344 sendto_one(client_p, "PING :%s", me.name);
345 }
346 }
347 /* ping_timeout: */
348
349 }
350}
351
352/*
353 * check_unknowns_list
354 *
355 * inputs - pointer to list of unknown clients
356 * output - NONE
357 * side effects - unknown clients get marked for termination after n seconds
358 */
359static void
af81d5a0 360check_unknowns_list(rb_dlink_list * list)
212380e3 361{
90a3c35b 362 rb_dlink_node *ptr, *next_ptr;
212380e3 363 struct Client *client_p;
16d59a0d 364 int timeout;
212380e3 365
90a3c35b 366 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
212380e3 367 {
368 client_p = ptr->data;
369
370 if(IsDead(client_p) || IsClosing(client_p))
371 continue;
372
373 /*
374 * Check UNKNOWN connections - if they have been in this state
375 * for > 30s, close them.
376 */
377
16d59a0d 378 timeout = IsAnyServer(client_p) ? ConfigFileEntry.connect_timeout : 30;
9f6bbe3c 379 if((rb_current_time() - client_p->localClient->firsttime) > timeout)
16d59a0d
JT
380 {
381 if(IsAnyServer(client_p))
382 {
383 sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL,
384 "No response from %s, closing link",
385 get_server_name(client_p, HIDE_IP));
386 ilog(L_SERVER,
387 "No response from %s, closing link",
388 log_client_name(client_p, HIDE_IP));
389 }
212380e3 390 exit_client(client_p, client_p, &me, "Connection timed out");
16d59a0d 391 }
212380e3 392 }
393}
394
395static void
396notify_banned_client(struct Client *client_p, struct ConfItem *aconf, int ban)
397{
398 static const char conn_closed[] = "Connection closed";
399 static const char d_lined[] = "D-lined";
400 static const char k_lined[] = "K-lined";
401 static const char g_lined[] = "G-lined";
402 const char *reason = NULL;
403 const char *exit_reason = conn_closed;
404
405 if(ConfigFileEntry.kline_with_reason && !EmptyString(aconf->passwd))
406 {
407 reason = aconf->passwd;
408 exit_reason = aconf->passwd;
409 }
410 else
411 {
412 switch (aconf->status)
413 {
414 case D_LINED:
415 reason = d_lined;
416 break;
417 case G_LINED:
418 reason = g_lined;
419 break;
420 default:
421 reason = k_lined;
422 break;
423 }
424 }
425
426 if(ban == D_LINED && !IsPerson(client_p))
427 sendto_one(client_p, "NOTICE DLINE :*** You have been D-lined");
428 else
429 sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP),
430 me.name, client_p->name, reason);
431
432 exit_client(client_p, client_p, &me,
433 EmptyString(ConfigFileEntry.kline_reason) ? exit_reason :
434 ConfigFileEntry.kline_reason);
435}
436
437/*
438 * check_banned_lines
439 * inputs - NONE
440 * output - NONE
441 * side effects - Check all connections for a pending k/d/gline against the
442 * client, exit the client if found.
443 */
444void
445check_banned_lines(void)
446{
447 struct Client *client_p; /* current local client_p being examined */
448 struct ConfItem *aconf = NULL;
90a3c35b 449 rb_dlink_node *ptr, *next_ptr;
212380e3 450
90a3c35b 451 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, lclient_list.head)
212380e3 452 {
453 client_p = ptr->data;
454
455 if(IsMe(client_p))
456 continue;
457
458 /* if there is a returned struct ConfItem then kill it */
21c9d815 459 if((aconf = find_dline((struct sockaddr *)&client_p->localClient->ip, client_p->localClient->ip.ss_family)))
212380e3 460 {
461 if(aconf->status & CONF_EXEMPTDLINE)
462 continue;
463
464 sendto_realops_snomask(SNO_GENERAL, L_ALL,
465 "DLINE active for %s",
466 get_client_name(client_p, HIDE_IP));
467
468 notify_banned_client(client_p, aconf, D_LINED);
469 continue; /* and go examine next fd/client_p */
470 }
471
472 if(!IsPerson(client_p))
473 continue;
474
475 if((aconf = find_kline(client_p)) != NULL)
476 {
477 if(IsExemptKline(client_p))
478 {
479 sendto_realops_snomask(SNO_GENERAL, L_ALL,
480 "KLINE over-ruled for %s, client is kline_exempt [%s@%s]",
481 get_client_name(client_p, HIDE_IP),
482 aconf->user, aconf->host);
483 continue;
484 }
485
486 sendto_realops_snomask(SNO_GENERAL, L_ALL,
487 "KLINE active for %s",
488 get_client_name(client_p, HIDE_IP));
489 notify_banned_client(client_p, aconf, K_LINED);
490 continue;
491 }
492 else if((aconf = find_gline(client_p)) != NULL)
493 {
494 if(IsExemptKline(client_p))
495 {
496 sendto_realops_snomask(SNO_GENERAL, L_ALL,
497 "GLINE over-ruled for %s, client is kline_exempt [%s@%s]",
498 get_client_name(client_p, HIDE_IP),
499 aconf->user, aconf->host);
500 continue;
501 }
502
503 if(IsExemptGline(client_p))
504 {
505 sendto_realops_snomask(SNO_GENERAL, L_ALL,
506 "GLINE over-ruled for %s, client is gline_exempt [%s@%s]",
507 get_client_name(client_p, HIDE_IP),
508 aconf->user, aconf->host);
509 continue;
510 }
511
512 sendto_realops_snomask(SNO_GENERAL, L_ALL,
513 "GLINE active for %s",
514 get_client_name(client_p, HIDE_IP));
515
516 notify_banned_client(client_p, aconf, G_LINED);
517 continue;
518 }
519 else if((aconf = find_xline(client_p->info, 1)) != NULL)
520 {
521 if(IsExemptKline(client_p))
522 {
523 sendto_realops_snomask(SNO_GENERAL, L_ALL,
524 "XLINE over-ruled for %s, client is kline_exempt [%s]",
525 get_client_name(client_p, HIDE_IP),
526 aconf->name);
527 continue;
528 }
529
530 sendto_realops_snomask(SNO_GENERAL, L_ALL, "XLINE active for %s",
531 get_client_name(client_p, HIDE_IP));
532
533 (void) exit_client(client_p, client_p, &me, "Bad user info");
534 continue;
535 }
536 }
537
538 /* also check the unknowns list for new dlines */
90a3c35b 539 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, unknown_list.head)
212380e3 540 {
541 client_p = ptr->data;
542
21c9d815 543 if((aconf = find_dline((struct sockaddr *)&client_p->localClient->ip,client_p->localClient->ip.ss_family)))
212380e3 544 {
545 if(aconf->status & CONF_EXEMPTDLINE)
546 continue;
547
548 notify_banned_client(client_p, aconf, D_LINED);
549 }
550 }
551
552}
553
554/* check_klines_event()
555 *
556 * inputs -
557 * outputs -
558 * side effects - check_klines() is called, kline_queued unset
559 */
560void
561check_klines_event(void *unused)
562{
563 kline_queued = 0;
564 check_klines();
565}
566
567/* check_klines
568 *
569 * inputs -
570 * outputs -
571 * side effects - all clients will be checked for klines
572 */
573void
574check_klines(void)
575{
576 struct Client *client_p;
577 struct ConfItem *aconf;
af81d5a0 578 rb_dlink_node *ptr;
90a3c35b 579 rb_dlink_node *next_ptr;
212380e3 580
90a3c35b 581 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, lclient_list.head)
212380e3 582 {
583 client_p = ptr->data;
584
585 if(IsMe(client_p) || !IsPerson(client_p))
586 continue;
587
588 if((aconf = find_kline(client_p)) != NULL)
589 {
590 if(IsExemptKline(client_p))
591 {
592 sendto_realops_snomask(SNO_GENERAL, L_ALL,
593 "KLINE over-ruled for %s, client is kline_exempt",
594 get_client_name(client_p, HIDE_IP));
595 continue;
596 }
597
598 sendto_realops_snomask(SNO_GENERAL, L_ALL,
599 "KLINE active for %s",
600 get_client_name(client_p, HIDE_IP));
601
602 notify_banned_client(client_p, aconf, K_LINED);
603 continue;
604 }
605 }
606}
607
608/* check_glines()
609 *
610 * inputs -
611 * outputs -
612 * side effects - all clients will be checked for glines
613 */
614void
615check_glines(void)
616{
617 struct Client *client_p;
618 struct ConfItem *aconf;
af81d5a0 619 rb_dlink_node *ptr;
90a3c35b 620 rb_dlink_node *next_ptr;
212380e3 621
90a3c35b 622 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, lclient_list.head)
212380e3 623 {
624 client_p = ptr->data;
625
626 if(IsMe(client_p) || !IsPerson(client_p))
627 continue;
628
629 if((aconf = find_gline(client_p)) != NULL)
630 {
631 if(IsExemptKline(client_p))
632 {
633 sendto_realops_snomask(SNO_GENERAL, L_ALL,
634 "GLINE over-ruled for %s, client is kline_exempt",
635 get_client_name(client_p, HIDE_IP));
636 continue;
637 }
638
639 if(IsExemptGline(client_p))
640 {
641 sendto_realops_snomask(SNO_GENERAL, L_ALL,
642 "GLINE over-ruled for %s, client is gline_exempt",
643 get_client_name(client_p, HIDE_IP));
644 continue;
645 }
646
647 sendto_realops_snomask(SNO_GENERAL, L_ALL,
648 "GLINE active for %s",
649 get_client_name(client_p, HIDE_IP));
650
651 notify_banned_client(client_p, aconf, K_LINED);
652 continue;
653 }
654 }
655}
656
657/* check_dlines()
658 *
659 * inputs -
660 * outputs -
661 * side effects - all clients will be checked for dlines
662 */
663void
664check_dlines(void)
665{
666 struct Client *client_p;
667 struct ConfItem *aconf;
af81d5a0 668 rb_dlink_node *ptr;
90a3c35b 669 rb_dlink_node *next_ptr;
212380e3 670
90a3c35b 671 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, lclient_list.head)
212380e3 672 {
673 client_p = ptr->data;
674
675 if(IsMe(client_p))
676 continue;
677
21c9d815 678 if((aconf = find_dline((struct sockaddr *)&client_p->localClient->ip,client_p->localClient->ip.ss_family)) != NULL)
212380e3 679 {
680 if(aconf->status & CONF_EXEMPTDLINE)
681 continue;
682
683 sendto_realops_snomask(SNO_GENERAL, L_ALL,
684 "DLINE active for %s",
685 get_client_name(client_p, HIDE_IP));
686
687 notify_banned_client(client_p, aconf, D_LINED);
688 continue;
689 }
690 }
691
692 /* dlines need to be checked against unknowns too */
90a3c35b 693 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, unknown_list.head)
212380e3 694 {
695 client_p = ptr->data;
696
21c9d815 697 if((aconf = find_dline((struct sockaddr *)&client_p->localClient->ip,client_p->localClient->ip.ss_family)) != NULL)
212380e3 698 {
699 if(aconf->status & CONF_EXEMPTDLINE)
700 continue;
701
702 notify_banned_client(client_p, aconf, D_LINED);
703 }
704 }
705}
706
707/* check_xlines
708 *
709 * inputs -
710 * outputs -
711 * side effects - all clients will be checked for xlines
712 */
713void
714check_xlines(void)
715{
716 struct Client *client_p;
717 struct ConfItem *aconf;
af81d5a0 718 rb_dlink_node *ptr;
90a3c35b 719 rb_dlink_node *next_ptr;
212380e3 720
90a3c35b 721 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, lclient_list.head)
212380e3 722 {
723 client_p = ptr->data;
724
725 if(IsMe(client_p) || !IsPerson(client_p))
726 continue;
727
728 if((aconf = find_xline(client_p->info, 1)) != NULL)
729 {
730 if(IsExemptKline(client_p))
731 {
732 sendto_realops_snomask(SNO_GENERAL, L_ALL,
733 "XLINE over-ruled for %s, client is kline_exempt",
734 get_client_name(client_p, HIDE_IP));
735 continue;
736 }
737
738 sendto_realops_snomask(SNO_GENERAL, L_ALL, "XLINE active for %s",
739 get_client_name(client_p, HIDE_IP));
740
741 (void) exit_client(client_p, client_p, &me, "Bad user info");
742 continue;
743 }
744 }
745}
746
747/*
748 * update_client_exit_stats
749 *
750 * input - pointer to client
751 * output - NONE
752 * side effects -
753 */
754static void
755update_client_exit_stats(struct Client *client_p)
756{
757 if(IsServer(client_p))
758 {
759 sendto_realops_snomask(SNO_EXTERNAL, L_ALL,
760 "Server %s split from %s",
761 client_p->name, client_p->servptr->name);
762 if(HasSentEob(client_p))
763 eob_count--;
764 }
765 else if(IsClient(client_p))
766 {
767 --Count.total;
768 if(IsOper(client_p))
769 --Count.oper;
770 if(IsInvisible(client_p))
771 --Count.invisi;
772 }
773
774 if(splitchecking && !splitmode)
775 check_splitmode(NULL);
776}
777
778/*
779 * release_client_state
780 *
781 * input - pointer to client to release
782 * output - NONE
783 * side effects -
784 */
785static void
786release_client_state(struct Client *client_p)
787{
788 if(client_p->user != NULL)
789 {
790 free_user(client_p->user, client_p); /* try this here */
791 }
792 if(client_p->serv)
793 {
794 if(client_p->serv->user != NULL)
795 free_user(client_p->serv->user, client_p);
796 if(client_p->serv->fullcaps)
90a3c35b
VY
797 rb_free(client_p->serv->fullcaps);
798 rb_free(client_p->serv);
212380e3 799 }
800}
801
802/*
803 * remove_client_from_list
804 * inputs - point to client to remove
805 * output - NONE
806 * side effects - taken the code from ExitOneClient() for this
807 * and placed it here. - avalon
808 */
809static void
810remove_client_from_list(struct Client *client_p)
811{
812 s_assert(NULL != client_p);
813
814 if(client_p == NULL)
815 return;
816
817 /* A client made with make_client()
818 * is on the unknown_list until removed.
819 * If it =does= happen to exit before its removed from that list
820 * and its =not= on the global_client_list, it will core here.
821 * short circuit that case now -db
822 */
823 if(client_p->node.prev == NULL && client_p->node.next == NULL)
824 return;
825
af81d5a0 826 rb_dlinkDelete(&client_p->node, &global_client_list);
212380e3 827
828 update_client_exit_stats(client_p);
829}
830
831
832/*
833 * find_person - find person by (nick)name.
834 * inputs - pointer to name
835 * output - return client pointer
836 * side effects -
837 */
838struct Client *
839find_person(const char *name)
840{
841 struct Client *c2ptr;
842
843 c2ptr = find_client(name);
844
845 if(c2ptr && IsPerson(c2ptr))
846 return (c2ptr);
847 return (NULL);
848}
849
850struct Client *
851find_named_person(const char *name)
852{
853 struct Client *c2ptr;
854
855 c2ptr = find_named_client(name);
856
857 if(c2ptr && IsPerson(c2ptr))
858 return (c2ptr);
859 return (NULL);
860}
861
862
863/*
864 * find_chasing - find the client structure for a nick name (user)
865 * using history mechanism if necessary. If the client is not found,
866 * an error message (NO SUCH NICK) is generated. If the client was found
867 * through the history, chasing will be 1 and otherwise 0.
868 */
869struct Client *
870find_chasing(struct Client *source_p, const char *user, int *chasing)
871{
872 struct Client *who;
873
874 if(MyClient(source_p))
875 who = find_named_person(user);
876 else
877 who = find_person(user);
878
879 if(chasing)
880 *chasing = 0;
881
882 if(who || IsDigit(*user))
883 return who;
884
885 if(!(who = get_history(user, (long) KILLCHASETIMELIMIT)))
886 {
887 sendto_one_numeric(source_p, ERR_NOSUCHNICK,
888 form_str(ERR_NOSUCHNICK), user);
889 return (NULL);
890 }
891 if(chasing)
892 *chasing = 1;
893 return who;
894}
895
896/*
897 * get_client_name - Return the name of the client
898 * for various tracking and
899 * admin purposes. The main purpose of this function is to
900 * return the "socket host" name of the client, if that
901 * differs from the advertised name (other than case).
902 * But, this can be used to any client structure.
903 *
904 * NOTE 1:
905 * Watch out the allocation of "nbuf", if either source_p->name
906 * or source_p->sockhost gets changed into pointers instead of
907 * directly allocated within the structure...
908 *
909 * NOTE 2:
910 * Function return either a pointer to the structure (source_p) or
911 * to internal buffer (nbuf). *NEVER* use the returned pointer
912 * to modify what it points!!!
913 */
914
915const char *
916get_client_name(struct Client *client, int showip)
917{
918 static char nbuf[HOSTLEN * 2 + USERLEN + 5];
919
920 s_assert(NULL != client);
921 if(client == NULL)
922 return NULL;
923
924 if(MyConnect(client))
925 {
926 if(!irccmp(client->name, client->host))
927 return client->name;
928
929 if(ConfigFileEntry.hide_spoof_ips &&
930 showip == SHOW_IP && IsIPSpoof(client))
931 showip = MASK_IP;
932#ifdef HIDE_SERVERS_IPS
933 if(IsAnyServer(client))
934 showip = MASK_IP;
935#endif
936
937 /* And finally, let's get the host information, ip or name */
938 switch (showip)
939 {
940 case SHOW_IP:
38e6acdd 941 rb_snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
212380e3 942 client->name, client->username,
943 client->sockhost);
944 break;
945 case MASK_IP:
38e6acdd 946 rb_snprintf(nbuf, sizeof(nbuf), "%s[%s@255.255.255.255]",
212380e3 947 client->name, client->username);
948 break;
949 default:
38e6acdd 950 rb_snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
212380e3 951 client->name, client->username, client->host);
952 }
953 return nbuf;
954 }
955
956 /* As pointed out by Adel Mezibra
957 * Neph|l|m@EFnet. Was missing a return here.
958 */
959 return client->name;
960}
961
962const char *
963get_server_name(struct Client *target_p, int showip)
964{
965 static char nbuf[HOSTLEN * 2 + USERLEN + 5];
966
967 if(target_p == NULL)
968 return NULL;
969
970 if(!MyConnect(target_p) || !irccmp(target_p->name, target_p->host))
971 return target_p->name;
972
973#ifdef HIDE_SERVERS_IPS
974 if(EmptyString(target_p->name))
975 {
38e6acdd 976 rb_snprintf(nbuf, sizeof(nbuf), "[%s@255.255.255.255]",
212380e3 977 target_p->username);
978 return nbuf;
979 }
980 else
981 return target_p->name;
982#endif
983
984 switch (showip)
985 {
986 case SHOW_IP:
38e6acdd 987 rb_snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
212380e3 988 target_p->name, target_p->username,
989 target_p->sockhost);
990 break;
991
992 case MASK_IP:
38e6acdd 993 rb_snprintf(nbuf, sizeof(nbuf), "%s[%s@255.255.255.255]",
212380e3 994 target_p->name, target_p->username);
995
996 default:
38e6acdd 997 rb_snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
212380e3 998 target_p->name, target_p->username,
999 target_p->host);
1000 }
1001
1002 return nbuf;
1003}
1004
1005/* log_client_name()
1006 *
1007 * This version is the same as get_client_name, but doesnt contain the
1008 * code that will hide IPs always. This should be used for logfiles.
1009 */
1010const char *
1011log_client_name(struct Client *target_p, int showip)
1012{
1013 static char nbuf[HOSTLEN * 2 + USERLEN + 5];
1014
1015 if(target_p == NULL)
1016 return NULL;
1017
1018 if(MyConnect(target_p))
1019 {
1020 if(irccmp(target_p->name, target_p->host) == 0)
1021 return target_p->name;
1022
1023 switch (showip)
1024 {
1025 case SHOW_IP:
38e6acdd 1026 rb_snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]", target_p->name,
212380e3 1027 target_p->username, target_p->sockhost);
1028 break;
1029
1030 case MASK_IP:
38e6acdd 1031 rb_snprintf(nbuf, sizeof(nbuf), "%s[%s@255.255.255.255]",
212380e3 1032 target_p->name, target_p->username);
1033
1034 default:
38e6acdd 1035 rb_snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]", target_p->name,
212380e3 1036 target_p->username, target_p->host);
1037 }
1038
1039 return nbuf;
1040 }
1041
1042 return target_p->name;
1043}
1044
1045/* is_remote_connect - Returns whether a server was /connect'ed by a remote
1046 * oper (send notices netwide) */
1047int
1048is_remote_connect(struct Client *client_p)
1049{
1050 struct Client *oper;
1051
1052 if (client_p->serv == NULL)
1053 return FALSE;
1054 oper = find_named_person(client_p->serv->by);
1055 return oper != NULL && IsOper(oper) && !MyConnect(oper);
1056}
1057
1058static void
1059free_exited_clients(void *unused)
1060{
af81d5a0 1061 rb_dlink_node *ptr, *next;
212380e3 1062 struct Client *target_p;
1063
8e69bb4e 1064 RB_DLINK_FOREACH_SAFE(ptr, next, dead_list.head)
212380e3 1065 {
1066 target_p = ptr->data;
1067
1068#ifdef DEBUG_EXITED_CLIENTS
1069 {
1070 struct abort_client *abt;
af81d5a0 1071 rb_dlink_node *aptr;
212380e3 1072 int found = 0;
1073
8e69bb4e 1074 RB_DLINK_FOREACH(aptr, abort_list.head)
212380e3 1075 {
1076 abt = aptr->data;
1077 if(abt->client == target_p)
1078 {
1079 s_assert(0);
1080 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1081 "On abort_list: %s stat: %u flags: %u/%u handler: %c",
1082 target_p->name, (unsigned int) target_p->status,
1083 target_p->flags, target_p->flags2, target_p->handler);
1084 sendto_realops_snomask(SNO_GENERAL, L_ALL,
f80a1823 1085 "Please report this to the charybdis developers!");
212380e3 1086 found++;
1087 }
1088 }
1089
1090 if(found)
1091 {
af81d5a0 1092 rb_dlinkDestroy(ptr, &dead_list);
212380e3 1093 continue;
1094 }
1095 }
1096#endif
1097
1098 if(ptr->data == NULL)
1099 {
1100 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1101 "Warning: null client on dead_list!");
af81d5a0 1102 rb_dlinkDestroy(ptr, &dead_list);
212380e3 1103 continue;
1104 }
1105 release_client_state(target_p);
1106 free_client(target_p);
af81d5a0 1107 rb_dlinkDestroy(ptr, &dead_list);
212380e3 1108 }
1109
1110#ifdef DEBUG_EXITED_CLIENTS
8e69bb4e 1111 RB_DLINK_FOREACH_SAFE(ptr, next, dead_remote_list.head)
212380e3 1112 {
1113 target_p = ptr->data;
1114
1115 if(ptr->data == NULL)
1116 {
1117 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1118 "Warning: null client on dead_list!");
af81d5a0 1119 rb_dlinkDestroy(ptr, &dead_list);
212380e3 1120 continue;
1121 }
1122 release_client_state(target_p);
1123 free_client(target_p);
af81d5a0 1124 rb_dlinkDestroy(ptr, &dead_remote_list);
212380e3 1125 }
1126#endif
1127
1128}
1129
1130/*
1131** Recursively send QUITs and SQUITs for source_p and all its dependent clients
1132** and servers to those servers that need them. A server needs the client
1133** QUITs if it can't figure them out from the SQUIT (ie pre-TS4) or if it
1134** isn't getting the SQUIT because of @#(*&@)# hostmasking. With TS4, once
1135** a link gets a SQUIT, it doesn't need any QUIT/SQUITs for clients depending
1136** on that one -orabidoo
1137*/
1138static void
1139recurse_send_quits(struct Client *client_p, struct Client *source_p,
1140 struct Client *to, const char *comment1,
1141 const char *comment)
1142{
1143 struct Client *target_p;
af81d5a0 1144 rb_dlink_node *ptr, *ptr_next;
212380e3 1145 /* If this server can handle quit storm (QS) removal
1146 * of dependents, just send the SQUIT
1147 */
1148
1149 if(IsCapable(to, CAP_QS))
1150 {
1151 sendto_one(to, "SQUIT %s :%s",
1152 get_id(source_p, to), comment);
1153 }
1154 else
1155 {
8e69bb4e 1156 RB_DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->serv->users.head)
212380e3 1157 {
1158 target_p = ptr->data;
1159 sendto_one(to, ":%s QUIT :%s", target_p->name, comment1);
1160 }
8e69bb4e 1161 RB_DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->serv->servers.head)
212380e3 1162 {
1163 target_p = ptr->data;
1164 recurse_send_quits(client_p, target_p, to, comment1, comment);
1165 }
1166 sendto_one(to, "SQUIT %s :%s", source_p->name, comment);
1167 }
1168}
1169
1170/*
1171** Remove all clients that depend on source_p; assumes all (S)QUITs have
1172** already been sent. we make sure to exit a server's dependent clients
1173** and servers before the server itself; exit_one_client takes care of
1174** actually removing things off llists. tweaked from +CSr31 -orabidoo
1175*/
1176/*
1177 * added sanity test code.... source_p->serv might be NULL...
1178 */
1179static void
1180recurse_remove_clients(struct Client *source_p, const char *comment)
1181{
1182 struct Client *target_p;
af81d5a0 1183 rb_dlink_node *ptr, *ptr_next;
212380e3 1184
1185 if(IsMe(source_p))
1186 return;
1187
1188 if(source_p->serv == NULL) /* oooops. uh this is actually a major bug */
1189 return;
1190
1191 /* this is very ugly, but it saves cpu :P */
1192 if(ConfigFileEntry.nick_delay > 0)
1193 {
8e69bb4e 1194 RB_DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->serv->users.head)
212380e3 1195 {
1196 target_p = ptr->data;
1197 target_p->flags |= FLAGS_KILLED;
1198 add_nd_entry(target_p->name);
1199
1200 if(!IsDead(target_p) && !IsClosing(target_p))
1201 exit_remote_client(NULL, target_p, &me, comment);
1202 }
1203 }
1204 else
1205 {
8e69bb4e 1206 RB_DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->serv->users.head)
212380e3 1207 {
1208 target_p = ptr->data;
1209 target_p->flags |= FLAGS_KILLED;
1210
1211 if(!IsDead(target_p) && !IsClosing(target_p))
1212 exit_remote_client(NULL, target_p, &me, comment);
1213 }
1214 }
1215
8e69bb4e 1216 RB_DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->serv->servers.head)
212380e3 1217 {
1218 target_p = ptr->data;
1219 recurse_remove_clients(target_p, comment);
1220 qs_server(NULL, target_p, &me, comment);
1221 }
1222}
1223
1224/*
1225** Remove *everything* that depends on source_p, from all lists, and sending
1226** all necessary QUITs and SQUITs. source_p itself is still on the lists,
1227** and its SQUITs have been sent except for the upstream one -orabidoo
1228*/
1229static void
1230remove_dependents(struct Client *client_p,
1231 struct Client *source_p,
1232 struct Client *from, const char *comment, const char *comment1)
1233{
1234 struct Client *to;
af81d5a0 1235 rb_dlink_node *ptr, *next;
212380e3 1236
8e69bb4e 1237 RB_DLINK_FOREACH_SAFE(ptr, next, serv_list.head)
212380e3 1238 {
1239 to = ptr->data;
1240
1241 if(IsMe(to) || to == source_p->from ||
1242 (to == client_p && IsCapable(to, CAP_QS)))
1243 continue;
1244
1245 recurse_send_quits(client_p, source_p, to, comment1, comment);
1246 }
1247
1248 recurse_remove_clients(source_p, comment1);
1249}
1250
1251void
1252exit_aborted_clients(void *unused)
1253{
1254 struct abort_client *abt;
af81d5a0 1255 rb_dlink_node *ptr, *next;
8e69bb4e 1256 RB_DLINK_FOREACH_SAFE(ptr, next, abort_list.head)
212380e3 1257 {
1258 abt = ptr->data;
1259
1260#ifdef DEBUG_EXITED_CLIENTS
1261 {
af81d5a0 1262 if(rb_dlinkFind(abt->client, &dead_list))
212380e3 1263 {
1264 s_assert(0);
1265 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1266 "On dead_list: %s stat: %u flags: %u/%u handler: %c",
1267 abt->client->name, (unsigned int) abt->client->status,
1268 abt->client->flags, abt->client->flags2, abt->client->handler);
1269 sendto_realops_snomask(SNO_GENERAL, L_ALL,
f80a1823 1270 "Please report this to the charybdis developers!");
212380e3 1271 continue;
1272 }
1273 }
1274#endif
1275
1276 s_assert(*((unsigned long*)abt->client) != 0xdeadbeef); /* This is lame but its a debug thing */
af81d5a0 1277 rb_dlinkDelete(ptr, &abort_list);
212380e3 1278
1279 if(IsAnyServer(abt->client))
1280 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1281 "Closing link to %s: %s",
1282 get_server_name(abt->client, HIDE_IP), abt->notice);
1283
1284 /* its no longer on abort list - we *must* remove
1285 * FLAGS_CLOSING otherwise exit_client() will not run --fl
1286 */
1287 abt->client->flags &= ~FLAGS_CLOSING;
1288 exit_client(abt->client, abt->client, &me, abt->notice);
90a3c35b 1289 rb_free(abt);
212380e3 1290 }
1291}
1292
1293
1294/*
1295 * dead_link - Adds client to a list of clients that need an exit_client()
1296 *
1297 */
1298void
1299dead_link(struct Client *client_p)
1300{
1301 struct abort_client *abt;
1302
1303 s_assert(!IsMe(client_p));
1304 if(IsDead(client_p) || IsClosing(client_p) || IsMe(client_p))
1305 return;
1306
8e43b0b4 1307 abt = (struct abort_client *) rb_malloc(sizeof(struct abort_client));
212380e3 1308
1309 if(client_p->flags & FLAGS_SENDQEX)
1310 strlcpy(abt->notice, "Max SendQ exceeded", sizeof(abt->notice));
1311 else
38e6acdd 1312 rb_snprintf(abt->notice, sizeof(abt->notice), "Write error: %s", strerror(errno));
212380e3 1313
1314 abt->client = client_p;
1315 SetIOError(client_p);
1316 SetDead(client_p);
1317 SetClosing(client_p);
af81d5a0 1318 rb_dlinkAdd(abt, &abt->node, &abort_list);
212380e3 1319}
1320
1321
1322/* This does the remove of the user from channels..local or remote */
1323static inline void
1324exit_generic_client(struct Client *client_p, struct Client *source_p, struct Client *from,
1325 const char *comment)
1326{
90a3c35b 1327 rb_dlink_node *ptr, *next_ptr;
212380e3 1328
1329 if(IsOper(source_p))
af81d5a0 1330 rb_dlinkFindDestroy(source_p, &oper_list);
212380e3 1331
1332 sendto_common_channels_local(source_p, ":%s!%s@%s QUIT :%s",
1333 source_p->name,
1334 source_p->username, source_p->host, comment);
1335
1336 remove_user_from_channels(source_p);
1337
1338 /* Should not be in any channels now */
1339 s_assert(source_p->user->channel.head == NULL);
1340
1341 /* Clean up invitefield */
90a3c35b 1342 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, source_p->user->invited.head)
212380e3 1343 {
1344 del_invite(ptr->data, source_p);
1345 }
1346
1347 /* Clean up allow lists */
1348 del_all_accepts(source_p);
1349
1350 add_history(source_p, 0);
1351 off_history(source_p);
1352
1353 monitor_signoff(source_p);
1354
1355 if(has_id(source_p))
1356 del_from_id_hash(source_p->id, source_p);
1357
1358 del_from_hostname_hash(source_p->orighost, source_p);
1359 del_from_client_hash(source_p->name, source_p);
1360 remove_client_from_list(source_p);
1361}
1362
1363/*
1364 * Assumes IsPerson(source_p) && !MyConnect(source_p)
1365 */
1366
1367static int
1368exit_remote_client(struct Client *client_p, struct Client *source_p, struct Client *from,
1369 const char *comment)
1370{
1371 exit_generic_client(client_p, source_p, from, comment);
1372
1373 if(source_p->servptr && source_p->servptr->serv)
1374 {
af81d5a0 1375 rb_dlinkDelete(&source_p->lnode, &source_p->servptr->serv->users);
212380e3 1376 }
1377
1378 if((source_p->flags & FLAGS_KILLED) == 0)
1379 {
1380 sendto_server(client_p, NULL, CAP_TS6, NOCAPS,
1381 ":%s QUIT :%s", use_id(source_p), comment);
1382 sendto_server(client_p, NULL, NOCAPS, CAP_TS6,
1383 ":%s QUIT :%s", source_p->name, comment);
1384 }
1385
1386 SetDead(source_p);
1387#ifdef DEBUG_EXITED_CLIENTS
af81d5a0 1388 rb_dlinkAddAlloc(source_p, &dead_remote_list);
212380e3 1389#else
af81d5a0 1390 rb_dlinkAddAlloc(source_p, &dead_list);
212380e3 1391#endif
1392 return(CLIENT_EXITED);
1393}
1394
1395/*
1396 * This assumes IsUnknown(source_p) == TRUE and MyConnect(source_p) == TRUE
1397 */
1398
1399static int
1400exit_unknown_client(struct Client *client_p, struct Client *source_p, struct Client *from,
1401 const char *comment)
1402{
1403 delete_auth_queries(source_p);
21c9d815 1404 del_unknown_ip(source_p);
af81d5a0 1405 rb_dlinkDelete(&source_p->localClient->tnode, &unknown_list);
212380e3 1406
1407 if(!IsIOError(source_p))
dd12a19c 1408 sendto_one(source_p, "ERROR :Closing Link: %s (%s)",
1409 source_p->user != NULL ? source_p->host : "127.0.0.1",
1410 comment);
212380e3 1411
1412 close_connection(source_p);
1413
1414 if(has_id(source_p))
1415 del_from_id_hash(source_p->id, source_p);
1416
1417 del_from_hostname_hash(source_p->host, source_p);
1418 del_from_client_hash(source_p->name, source_p);
1419 remove_client_from_list(source_p);
212380e3 1420 SetDead(source_p);
af81d5a0 1421 rb_dlinkAddAlloc(source_p, &dead_list);
212380e3 1422
1423 /* Note that we don't need to add unknowns to the dead_list */
1424 return(CLIENT_EXITED);
1425}
1426
1427static int
1428exit_remote_server(struct Client *client_p, struct Client *source_p, struct Client *from,
1429 const char *comment)
1430{
1431 static char comment1[(HOSTLEN*2)+2];
1432 static char newcomment[BUFSIZE];
1433 struct Client *target_p;
1434
1435 if(ConfigServerHide.flatten_links)
1436 strcpy(comment1, "*.net *.split");
1437 else
1438 {
66c8fdd2 1439 strcpy(comment1, source_p->servptr->name);
212380e3 1440 strcat(comment1, " ");
1441 strcat(comment1, source_p->name);
1442 }
1443 if (IsPerson(from))
38e6acdd 1444 rb_snprintf(newcomment, sizeof(newcomment), "by %s: %s",
212380e3 1445 from->name, comment);
1446
1447 if(source_p->serv != NULL)
1448 remove_dependents(client_p, source_p, from, IsPerson(from) ? newcomment : comment, comment1);
1449
1450 if(source_p->servptr && source_p->servptr->serv)
af81d5a0 1451 rb_dlinkDelete(&source_p->lnode, &source_p->servptr->serv->servers);
212380e3 1452 else
1453 s_assert(0);
1454
af81d5a0 1455 rb_dlinkFindDestroy(source_p, &global_serv_list);
212380e3 1456 target_p = source_p->from;
1457
1458 if(target_p != NULL && IsServer(target_p) && target_p != client_p &&
1459 !IsMe(target_p) && (source_p->flags & FLAGS_KILLED) == 0)
1460 {
1461 sendto_one(target_p, ":%s SQUIT %s :%s",
1462 get_id(from, target_p), get_id(source_p, target_p),
1463 comment);
1464 }
1465
1466 if(has_id(source_p))
1467 del_from_id_hash(source_p->id, source_p);
1468
1469 del_from_client_hash(source_p->name, source_p);
1470 remove_client_from_list(source_p);
994544c2 1471 scache_split(source_p->serv->nameinfo);
212380e3 1472
1473 SetDead(source_p);
1474#ifdef DEBUG_EXITED_CLIENTS
af81d5a0 1475 rb_dlinkAddAlloc(source_p, &dead_remote_list);
212380e3 1476#else
af81d5a0 1477 rb_dlinkAddAlloc(source_p, &dead_list);
212380e3 1478#endif
1479 return 0;
1480}
1481
1482static int
1483qs_server(struct Client *client_p, struct Client *source_p, struct Client *from,
1484 const char *comment)
1485{
1486 struct Client *target_p;
1487
1488 if(source_p->servptr && source_p->servptr->serv)
af81d5a0 1489 rb_dlinkDelete(&source_p->lnode, &source_p->servptr->serv->servers);
212380e3 1490 else
1491 s_assert(0);
1492
af81d5a0 1493 rb_dlinkFindDestroy(source_p, &global_serv_list);
212380e3 1494 target_p = source_p->from;
1495
1496 if(has_id(source_p))
1497 del_from_id_hash(source_p->id, source_p);
1498
1499 del_from_client_hash(source_p->name, source_p);
1500 remove_client_from_list(source_p);
4f5ec033 1501 scache_split(source_p->serv->nameinfo);
212380e3 1502
1503 SetDead(source_p);
af81d5a0 1504 rb_dlinkAddAlloc(source_p, &dead_list);
212380e3 1505 return 0;
1506}
1507
1508static int
1509exit_local_server(struct Client *client_p, struct Client *source_p, struct Client *from,
1510 const char *comment)
1511{
1512 static char comment1[(HOSTLEN*2)+2];
1513 static char newcomment[BUFSIZE];
1514 unsigned int sendk, recvk;
1515
af81d5a0
WP
1516 rb_dlinkDelete(&source_p->localClient->tnode, &serv_list);
1517 rb_dlinkFindDestroy(source_p, &global_serv_list);
212380e3 1518
1519 unset_chcap_usage_counts(source_p);
1520 sendk = source_p->localClient->sendK;
1521 recvk = source_p->localClient->receiveK;
1522
1523 /* Always show source here, so the server notices show
1524 * which side initiated the split -- jilles
1525 */
38e6acdd 1526 rb_snprintf(newcomment, sizeof(newcomment), "by %s: %s",
212380e3 1527 from == source_p ? me.name : from->name, comment);
1528 if (!IsIOError(source_p))
1529 sendto_one(source_p, "SQUIT %s :%s", use_id(source_p),
1530 newcomment);
1531 if(client_p != NULL && source_p != client_p && !IsIOError(source_p))
1532 {
1533 sendto_one(source_p, "ERROR :Closing Link: 127.0.0.1 %s (%s)",
1534 source_p->name, comment);
1535 }
1536
212380e3 1537 if(source_p->servptr && source_p->servptr->serv)
af81d5a0 1538 rb_dlinkDelete(&source_p->lnode, &source_p->servptr->serv->servers);
212380e3 1539 else
1540 s_assert(0);
1541
1542
1543 close_connection(source_p);
1544
1545 if(ConfigServerHide.flatten_links)
1546 strcpy(comment1, "*.net *.split");
1547 else
1548 {
66c8fdd2 1549 strcpy(comment1, source_p->servptr->name);
212380e3 1550 strcat(comment1, " ");
1551 strcat(comment1, source_p->name);
1552 }
1553
1554 if(source_p->serv != NULL)
1555 remove_dependents(client_p, source_p, from, IsPerson(from) ? newcomment : comment, comment1);
1556
1557 sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s was connected"
1558 " for %ld seconds. %d/%d sendK/recvK.",
784fdac0 1559 source_p->name, (long) rb_current_time() - source_p->localClient->firsttime, sendk, recvk);
212380e3 1560
1561 ilog(L_SERVER, "%s was connected for %ld seconds. %d/%d sendK/recvK.",
784fdac0 1562 source_p->name, (long) rb_current_time() - source_p->localClient->firsttime, sendk, recvk);
212380e3 1563
1564 if(has_id(source_p))
1565 del_from_id_hash(source_p->id, source_p);
1566
1567 del_from_client_hash(source_p->name, source_p);
1568 remove_client_from_list(source_p);
994544c2 1569 scache_split(source_p->serv->nameinfo);
212380e3 1570
1571 SetDead(source_p);
af81d5a0 1572 rb_dlinkAddAlloc(source_p, &dead_list);
212380e3 1573 return 0;
1574}
1575
1576
1577/*
1578 * This assumes IsPerson(source_p) == TRUE && MyConnect(source_p) == TRUE
1579 */
1580
1581static int
1582exit_local_client(struct Client *client_p, struct Client *source_p, struct Client *from,
1583 const char *comment)
1584{
1585 unsigned long on_for;
1586
1587 exit_generic_client(client_p, source_p, from, comment);
1588 clear_monitor(source_p);
1589
1590 s_assert(IsPerson(source_p));
af81d5a0
WP
1591 rb_dlinkDelete(&source_p->localClient->tnode, &lclient_list);
1592 rb_dlinkDelete(&source_p->lnode, &me.serv->users);
212380e3 1593
1594 if(IsOper(source_p))
af81d5a0 1595 rb_dlinkFindDestroy(source_p, &local_oper_list);
212380e3 1596
1597 sendto_realops_snomask(SNO_CCONN, L_ALL,
1598 "Client exiting: %s (%s@%s) [%s] [%s]",
1599 source_p->name,
1600 source_p->username, source_p->host, comment,
1601 show_ip(NULL, source_p) ? source_p->sockhost : "255.255.255.255");
1602
1603 sendto_realops_snomask(SNO_CCONNEXT, L_ALL,
1604 "CLIEXIT %s %s %s %s 0 %s",
1605 source_p->name, source_p->username, source_p->host,
1606 show_ip(NULL, source_p) ? source_p->sockhost : "255.255.255.255",
1607 comment);
1608
9f6bbe3c 1609 on_for = rb_current_time() - source_p->localClient->firsttime;
212380e3 1610
1611 ilog(L_USER, "%s (%3lu:%02lu:%02lu): %s!%s@%s %d/%d",
9f6bbe3c 1612 myctime(rb_current_time()), on_for / 3600,
212380e3 1613 (on_for % 3600) / 60, on_for % 60,
1614 source_p->name, source_p->username, source_p->host,
1615 source_p->localClient->sendK, source_p->localClient->receiveK);
1616
1617 sendto_one(source_p, "ERROR :Closing Link: %s (%s)", source_p->host, comment);
1618 close_connection(source_p);
1619
1620 if((source_p->flags & FLAGS_KILLED) == 0)
1621 {
1622 sendto_server(client_p, NULL, CAP_TS6, NOCAPS,
1623 ":%s QUIT :%s", use_id(source_p), comment);
1624 sendto_server(client_p, NULL, NOCAPS, CAP_TS6,
1625 ":%s QUIT :%s", source_p->name, comment);
1626 }
1627
1628 SetDead(source_p);
af81d5a0 1629 rb_dlinkAddAlloc(source_p, &dead_list);
212380e3 1630 return(CLIENT_EXITED);
1631}
1632
1633
1634/*
1635** exit_client - This is old "m_bye". Name changed, because this is not a
1636** protocol function, but a general server utility function.
1637**
1638** This function exits a client of *any* type (user, server, etc)
1639** from this server. Also, this generates all necessary prototol
1640** messages that this exit may cause.
1641**
1642** 1) If the client is a local client, then this implicitly
1643** exits all other clients depending on this connection (e.g.
1644** remote clients having 'from'-field that points to this.
1645**
1646** 2) If the client is a remote client, then only this is exited.
1647**
1648** For convenience, this function returns a suitable value for
1649** m_function return value:
1650**
1651** CLIENT_EXITED if (client_p == source_p)
1652** 0 if (client_p != source_p)
1653*/
1654int
1655exit_client(struct Client *client_p, /* The local client originating the
1656 * exit or NULL, if this exit is
1657 * generated by this server for
1658 * internal reasons.
1659 * This will not get any of the
1660 * generated messages. */
1661 struct Client *source_p, /* Client exiting */
1662 struct Client *from, /* Client firing off this Exit,
1663 * never NULL! */
1664 const char *comment /* Reason for the exit */
1665 )
1666{
1667 hook_data_client_exit hdata;
1668 if(IsClosing(source_p))
1669 return -1;
1670
1671 /* note, this HAS to be here, when we exit a client we attempt to
1672 * send them data, if this generates a write error we must *not* add
1673 * them to the abort list --fl
1674 */
1675 SetClosing(source_p);
1676
1677 hdata.local_link = client_p;
1678 hdata.target = source_p;
1679 hdata.from = from;
1680 hdata.comment = comment;
1681 call_hook(h_client_exit, &hdata);
1682
1683 if(MyConnect(source_p))
1684 {
1685 /* Local clients of various types */
1686 if(IsPerson(source_p))
1687 return exit_local_client(client_p, source_p, from, comment);
1688 else if(IsServer(source_p))
1689 return exit_local_server(client_p, source_p, from, comment);
1690 /* IsUnknown || IsConnecting || IsHandShake */
1691 else if(!IsReject(source_p))
1692 return exit_unknown_client(client_p, source_p, from, comment);
1693 }
1694 else
1695 {
1696 /* Remotes */
1697 if(IsPerson(source_p))
1698 return exit_remote_client(client_p, source_p, from, comment);
1699 else if(IsServer(source_p))
1700 return exit_remote_server(client_p, source_p, from, comment);
1701 }
1702
1703 return -1;
1704}
1705
1706/*
1707 * Count up local client memory
1708 */
1709
1710/* XXX one common Client list now */
1711void
1712count_local_client_memory(size_t * count, size_t * local_client_memory_used)
1713{
ae4091d2
JT
1714 size_t lusage;
1715 rb_bh_usage(lclient_heap, count, NULL, &lusage, NULL);
784fdac0 1716 *local_client_memory_used = lusage + (*count * (sizeof(void *) + sizeof(struct Client)));
212380e3 1717}
1718
1719/*
1720 * Count up remote client memory
1721 */
1722void
1723count_remote_client_memory(size_t * count, size_t * remote_client_memory_used)
1724{
ae4091d2
JT
1725 size_t lcount, rcount;
1726 rb_bh_usage(lclient_heap, &lcount, NULL, NULL, NULL);
1727 rb_bh_usage(client_heap, &rcount, NULL, NULL, NULL);
1728 *count = rcount - lcount;
784fdac0 1729 *remote_client_memory_used = *count * (sizeof(void *) + sizeof(struct Client));
212380e3 1730}
1731
1732
1733/*
1734 * accept processing, this adds a form of "caller ID" to ircd
1735 *
1736 * If a client puts themselves into "caller ID only" mode,
1737 * only clients that match a client pointer they have put on
1738 * the accept list will be allowed to message them.
1739 *
1740 * [ source.on_allow_list ] -> [ target1 ] -> [ target2 ]
1741 *
1742 * [target.allow_list] -> [ source1 ] -> [source2 ]
1743 *
1744 * i.e. a target will have a link list of source pointers it will allow
1745 * each source client then has a back pointer pointing back
1746 * to the client that has it on its accept list.
1747 * This allows for exit_one_client to remove these now bogus entries
1748 * from any client having an accept on them.
1749 */
1750/*
1751 * del_all_accepts
1752 *
1753 * inputs - pointer to exiting client
1754 * output - NONE
1755 * side effects - Walk through given clients allow_list and on_allow_list
1756 * remove all references to this client
1757 */
1758void
1759del_all_accepts(struct Client *client_p)
1760{
af81d5a0 1761 rb_dlink_node *ptr;
90a3c35b 1762 rb_dlink_node *next_ptr;
212380e3 1763 struct Client *target_p;
1764
1765 if(MyClient(client_p) && client_p->localClient->allow_list.head)
1766 {
1767 /* clear this clients accept list, and remove them from
1768 * everyones on_accept_list
1769 */
90a3c35b 1770 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->localClient->allow_list.head)
212380e3 1771 {
1772 target_p = ptr->data;
af81d5a0
WP
1773 rb_dlinkFindDestroy(client_p, &target_p->on_allow_list);
1774 rb_dlinkDestroy(ptr, &client_p->localClient->allow_list);
212380e3 1775 }
1776 }
1777
1778 /* remove this client from everyones accept list */
90a3c35b 1779 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->on_allow_list.head)
212380e3 1780 {
1781 target_p = ptr->data;
af81d5a0
WP
1782 rb_dlinkFindDestroy(client_p, &target_p->localClient->allow_list);
1783 rb_dlinkDestroy(ptr, &client_p->on_allow_list);
212380e3 1784 }
1785}
1786
1787/*
1788 * show_ip() - asks if the true IP shoudl be shown when source is
1789 * askin for info about target
1790 *
1791 * Inputs - source_p who is asking
1792 * - target_p who do we want the info on
1793 * Output - returns 1 if clear IP can be showed, otherwise 0
1794 * Side Effects - none
1795 */
1796
1797int
1798show_ip(struct Client *source_p, struct Client *target_p)
1799{
1800 if(IsAnyServer(target_p))
1801 {
1802#ifndef HIDE_SERVERS_IPS
1803 if(source_p == NULL || IsOper(source_p))
1804 return 1;
1805#endif
1806 return 0;
1807 }
1808 else if(IsIPSpoof(target_p))
1809 {
1810 /* source == NULL indicates message is being sent
1811 * to local opers.
1812 */
1813 if(!ConfigFileEntry.hide_spoof_ips &&
1814 (source_p == NULL || MyOper(source_p)))
1815 return 1;
1816 return 0;
1817 }
1818 else if(IsDynSpoof(target_p) && (source_p != NULL && !IsOper(source_p)))
1819 return 0;
1820 else
1821 return 1;
1822}
1823
1824int
1825show_ip_conf(struct ConfItem *aconf, struct Client *source_p)
1826{
1827 if(IsConfDoSpoofIp(aconf))
1828 {
1829 if(!ConfigFileEntry.hide_spoof_ips && MyOper(source_p))
1830 return 1;
1831
1832 return 0;
1833 }
1834 else
1835 return 1;
1836}
1837
1838/*
1839 * initUser
1840 *
1841 * inputs - none
1842 * outputs - none
1843 *
1844 * side effects - Creates a block heap for struct Users
1845 *
1846 */
6e9b4415 1847static rb_bh *user_heap;
212380e3 1848void
1849initUser(void)
1850{
784fdac0 1851 user_heap = rb_bh_create(sizeof(struct User), USER_HEAP_SIZE, "user_heap");
212380e3 1852 if(!user_heap)
784fdac0 1853 rb_outofmemory();
212380e3 1854}
1855
1856/*
1857 * make_user
1858 *
1859 * inputs - pointer to client struct
1860 * output - pointer to struct User
1861 * side effects - add's an User information block to a client
1862 * if it was not previously allocated.
1863 */
1864struct User *
1865make_user(struct Client *client_p)
1866{
1867 struct User *user;
1868
1869 user = client_p->user;
1870 if(!user)
1871 {
6e9b4415 1872 user = (struct User *) rb_bh_alloc(user_heap);
212380e3 1873 user->refcnt = 1;
1874 client_p->user = user;
1875 }
1876 return user;
1877}
1878
1879/*
1880 * make_server
1881 *
1882 * inputs - pointer to client struct
1883 * output - pointer to server_t
1884 * side effects - add's an Server information block to a client
1885 * if it was not previously allocated.
1886 */
1887server_t *
1888make_server(struct Client *client_p)
1889{
1890 server_t *serv = client_p->serv;
1891
1892 if(!serv)
1893 {
8e43b0b4 1894 serv = (server_t *) rb_malloc(sizeof(server_t));
212380e3 1895 client_p->serv = serv;
1896 }
1897 return client_p->serv;
1898}
1899
1900/*
1901 * free_user
1902 *
1903 * inputs - pointer to user struct
1904 * - pointer to client struct
1905 * output - none
1906 * side effects - Decrease user reference count by one and release block,
1907 * if count reaches 0
1908 */
1909void
1910free_user(struct User *user, struct Client *client_p)
1911{
784fdac0
VY
1912 free_away(client_p);
1913
212380e3 1914 if(--user->refcnt <= 0)
1915 {
1916 if(user->away)
90a3c35b 1917 rb_free((char *) user->away);
212380e3 1918 /*
1919 * sanity check
1920 */
1921 if(user->refcnt < 0 || user->invited.head || user->channel.head)
1922 {
1923 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1924 "* %#lx user (%s!%s@%s) %#lx %#lx %#lx %lu %d *",
1925 (unsigned long) client_p,
1926 client_p ? client_p->
1927 name : "<noname>",
1928 client_p->username,
1929 client_p->host,
1930 (unsigned long) user,
1931 (unsigned long) user->invited.head,
1932 (unsigned long) user->channel.head,
af81d5a0 1933 rb_dlink_list_length(&user->channel),
212380e3 1934 user->refcnt);
1935 s_assert(!user->refcnt);
1936 s_assert(!user->invited.head);
1937 s_assert(!user->channel.head);
1938 }
1939
6e9b4415 1940 rb_bh_free(user_heap, user);
212380e3 1941 }
1942}
1943
784fdac0
VY
1944void
1945allocate_away(struct Client *client_p)
1946{
1947 if(client_p->user->away == NULL)
1948 client_p->user->away = rb_bh_alloc(away_heap);
1949}
1950
1951
1952void
1953free_away(struct Client *client_p)
1954{
1955 if(client_p->user->away != NULL) {
1956 rb_bh_free(away_heap, client_p->user->away);
1957 client_p->user->away = NULL;
1958 }
ece36b7b
VY
1959}
1960
212380e3 1961void
1962init_uid(void)
1963{
1964 int i;
1965
1966 for(i = 0; i < 3; i++)
1967 current_uid[i] = me.id[i];
1968
1969 for(i = 3; i < 9; i++)
1970 current_uid[i] = 'A';
1971
1972 current_uid[9] = '\0';
1973}
1974
1975
1976char *
1977generate_uid(void)
1978{
1979 int i;
1980
1981 for(i = 8; i > 3; i--)
1982 {
1983 if(current_uid[i] == 'Z')
1984 {
1985 current_uid[i] = '0';
1986 return current_uid;
1987 }
1988 else if(current_uid[i] != '9')
1989 {
1990 current_uid[i]++;
1991 return current_uid;
1992 }
1993 else
1994 current_uid[i] = 'A';
1995 }
1996
1997 /* if this next if() triggers, we're fucked. */
1998 if(current_uid[3] == 'Z')
1999 {
2000 current_uid[i] = 'A';
2001 s_assert(0);
2002 }
2003 else
2004 current_uid[i]++;
2005
2006 return current_uid;
2007}
2008
2009/*
2010 * close_connection
2011 * Close the physical connection. This function must make
2012 * MyConnect(client_p) == FALSE, and set client_p->from == NULL.
2013 */
2014void
2015close_connection(struct Client *client_p)
2016{
2017 s_assert(client_p != NULL);
2018 if(client_p == NULL)
2019 return;
2020
2021 s_assert(MyConnect(client_p));
2022 if(!MyConnect(client_p))
2023 return;
2024
2025 if(IsServer(client_p))
2026 {
2027 struct server_conf *server_p;
2028
21c9d815
VY
2029 ServerStats->is_sv++;
2030 ServerStats->is_sbs += client_p->localClient->sendB;
2031 ServerStats->is_sbr += client_p->localClient->receiveB;
2032 ServerStats->is_sks += client_p->localClient->sendK;
2033 ServerStats->is_skr += client_p->localClient->receiveK;
2034 ServerStats->is_sti += rb_current_time() - client_p->localClient->firsttime;
2035 if(ServerStats->is_sbs > 2047)
212380e3 2036 {
21c9d815
VY
2037 ServerStats->is_sks += (ServerStats->is_sbs >> 10);
2038 ServerStats->is_sbs &= 0x3ff;
212380e3 2039 }
21c9d815 2040 if(ServerStats->is_sbr > 2047)
212380e3 2041 {
21c9d815
VY
2042 ServerStats->is_skr += (ServerStats->is_sbr >> 10);
2043 ServerStats->is_sbr &= 0x3ff;
212380e3 2044 }
2045
2046 /*
2047 * If the connection has been up for a long amount of time, schedule
2048 * a 'quick' reconnect, else reset the next-connect cycle.
2049 */
2050 if((server_p = find_server_conf(client_p->name)) != NULL)
2051 {
2052 /*
2053 * Reschedule a faster reconnect, if this was a automatically
2054 * connected configuration entry. (Note that if we have had
2055 * a rehash in between, the status has been changed to
2056 * CONF_ILLEGAL). But only do this if it was a "good" link.
2057 */
2058 server_p->hold = time(NULL);
2059 server_p->hold +=
2060 (server_p->hold - client_p->localClient->lasttime >
2061 HANGONGOODLINK) ? HANGONRETRYDELAY : ConFreq(server_p->class);
2062 }
2063
2064 }
2065 else if(IsClient(client_p))
2066 {
21c9d815
VY
2067 ServerStats->is_cl++;
2068 ServerStats->is_cbs += client_p->localClient->sendB;
2069 ServerStats->is_cbr += client_p->localClient->receiveB;
2070 ServerStats->is_cks += client_p->localClient->sendK;
2071 ServerStats->is_ckr += client_p->localClient->receiveK;
2072 ServerStats->is_cti += rb_current_time() - client_p->localClient->firsttime;
2073 if(ServerStats->is_cbs > 2047)
212380e3 2074 {
21c9d815
VY
2075 ServerStats->is_cks += (ServerStats->is_cbs >> 10);
2076 ServerStats->is_cbs &= 0x3ff;
212380e3 2077 }
21c9d815 2078 if(ServerStats->is_cbr > 2047)
212380e3 2079 {
21c9d815
VY
2080 ServerStats->is_ckr += (ServerStats->is_cbr >> 10);
2081 ServerStats->is_cbr &= 0x3ff;
212380e3 2082 }
2083 }
2084 else
21c9d815
VY
2085 ServerStats->is_ni++;
2086
2087 if(client_p->localClient->F)
2088 {
2089 /* attempt to flush any pending dbufs. Evil, but .. -- adrian */
2090 if(!IsIOError(client_p))
2091 send_queued(client_p);
2092
2093 rb_close(client_p->localClient->F);
2094 client_p->localClient->F = NULL;
2095 }
2096
527ec911
JT
2097 rb_linebuf_donebuf(&client_p->localClient->buf_sendq);
2098 rb_linebuf_donebuf(&client_p->localClient->buf_recvq);
212380e3 2099 detach_conf(client_p);
2100
2101 /* XXX shouldnt really be done here. */
2102 detach_server_conf(client_p);
2103
2104 client_p->from = NULL; /* ...this should catch them! >:) --msa */
2105 ClearMyConnect(client_p);
2106 SetIOError(client_p);
2107}
2108
2109
2110
2111void
2112error_exit_client(struct Client *client_p, int error)
2113{
2114 /*
2115 * ...hmm, with non-blocking sockets we might get
2116 * here from quite valid reasons, although.. why
2117 * would select report "data available" when there
2118 * wasn't... so, this must be an error anyway... --msa
2119 * actually, EOF occurs when read() returns 0 and
2120 * in due course, select() returns that fd as ready
2121 * for reading even though it ends up being an EOF. -avalon
2122 */
2123 char errmsg[255];
527ec911 2124 int current_error = rb_get_sockerr(client_p->localClient->F);
212380e3 2125
2126 SetIOError(client_p);
2127
2128 if(IsServer(client_p) || IsHandshake(client_p))
2129 {
212380e3 2130 if(error == 0)
2131 {
2132 sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) && !IsServer(client_p) ? L_NETWIDE : L_ALL,
2133 "Server %s closed the connection",
2134 get_server_name(client_p, SHOW_IP));
2135
2136 ilog(L_SERVER, "Server %s closed the connection",
2137 log_client_name(client_p, SHOW_IP));
2138 }
2139 else
2140 {
2141 sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) && !IsServer(client_p) ? L_NETWIDE : L_ALL,
2142 "Lost connection to %s: %s",
2143 client_p->name, strerror(current_error));
2144 ilog(L_SERVER, "Lost connection to %s: %s",
2145 log_client_name(client_p, SHOW_IP), strerror(current_error));
2146 }
212380e3 2147 }
2148
2149 if(error == 0)
2150 strlcpy(errmsg, "Remote host closed the connection", sizeof(errmsg));
2151 else
38e6acdd 2152 rb_snprintf(errmsg, sizeof(errmsg), "Read error: %s", strerror(current_error));
212380e3 2153
2154 exit_client(client_p, client_p, &me, errmsg);
2155}