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