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