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