]> jfr.im git - irc/rqf/shadowircd.git/blame - src/client.c
Remove Server.up and Server.upid.
[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 {
66c8fdd2 1458 strcpy(comment1, source_p->servptr->name);
212380e3 1459 strcat(comment1, " ");
1460 strcat(comment1, source_p->name);
1461 }
1462 if (IsPerson(from))
1463 ircsnprintf(newcomment, sizeof(newcomment), "by %s: %s",
1464 from->name, comment);
1465
1466 if(source_p->serv != NULL)
1467 remove_dependents(client_p, source_p, from, IsPerson(from) ? newcomment : comment, comment1);
1468
1469 if(source_p->servptr && source_p->servptr->serv)
1470 dlinkDelete(&source_p->lnode, &source_p->servptr->serv->servers);
1471 else
1472 s_assert(0);
1473
1474 dlinkFindDestroy(source_p, &global_serv_list);
1475 target_p = source_p->from;
1476
1477 if(target_p != NULL && IsServer(target_p) && target_p != client_p &&
1478 !IsMe(target_p) && (source_p->flags & FLAGS_KILLED) == 0)
1479 {
1480 sendto_one(target_p, ":%s SQUIT %s :%s",
1481 get_id(from, target_p), get_id(source_p, target_p),
1482 comment);
1483 }
1484
1485 if(has_id(source_p))
1486 del_from_id_hash(source_p->id, source_p);
1487
1488 del_from_client_hash(source_p->name, source_p);
1489 remove_client_from_list(source_p);
1490
1491 SetDead(source_p);
1492#ifdef DEBUG_EXITED_CLIENTS
1493 dlinkAddAlloc(source_p, &dead_remote_list);
1494#else
1495 dlinkAddAlloc(source_p, &dead_list);
1496#endif
1497 return 0;
1498}
1499
1500static int
1501qs_server(struct Client *client_p, struct Client *source_p, struct Client *from,
1502 const char *comment)
1503{
1504 struct Client *target_p;
1505
1506 if(source_p->servptr && source_p->servptr->serv)
1507 dlinkDelete(&source_p->lnode, &source_p->servptr->serv->servers);
1508 else
1509 s_assert(0);
1510
1511 dlinkFindDestroy(source_p, &global_serv_list);
1512 target_p = source_p->from;
1513
1514 if(has_id(source_p))
1515 del_from_id_hash(source_p->id, source_p);
1516
1517 del_from_client_hash(source_p->name, source_p);
1518 remove_client_from_list(source_p);
1519
1520 SetDead(source_p);
1521 dlinkAddAlloc(source_p, &dead_list);
1522 return 0;
1523}
1524
1525static int
1526exit_local_server(struct Client *client_p, struct Client *source_p, struct Client *from,
1527 const char *comment)
1528{
1529 static char comment1[(HOSTLEN*2)+2];
1530 static char newcomment[BUFSIZE];
1531 unsigned int sendk, recvk;
1532
1533 dlinkDelete(&source_p->localClient->tnode, &serv_list);
1534 dlinkFindDestroy(source_p, &global_serv_list);
1535
1536 unset_chcap_usage_counts(source_p);
1537 sendk = source_p->localClient->sendK;
1538 recvk = source_p->localClient->receiveK;
1539
1540 /* Always show source here, so the server notices show
1541 * which side initiated the split -- jilles
1542 */
1543 ircsnprintf(newcomment, sizeof(newcomment), "by %s: %s",
1544 from == source_p ? me.name : from->name, comment);
1545 if (!IsIOError(source_p))
1546 sendto_one(source_p, "SQUIT %s :%s", use_id(source_p),
1547 newcomment);
1548 if(client_p != NULL && source_p != client_p && !IsIOError(source_p))
1549 {
1550 sendto_one(source_p, "ERROR :Closing Link: 127.0.0.1 %s (%s)",
1551 source_p->name, comment);
1552 }
1553
212380e3 1554 if(source_p->servptr && source_p->servptr->serv)
1555 dlinkDelete(&source_p->lnode, &source_p->servptr->serv->servers);
1556 else
1557 s_assert(0);
1558
1559
1560 close_connection(source_p);
1561
1562 if(ConfigServerHide.flatten_links)
1563 strcpy(comment1, "*.net *.split");
1564 else
1565 {
66c8fdd2 1566 strcpy(comment1, source_p->servptr->name);
212380e3 1567 strcat(comment1, " ");
1568 strcat(comment1, source_p->name);
1569 }
1570
1571 if(source_p->serv != NULL)
1572 remove_dependents(client_p, source_p, from, IsPerson(from) ? newcomment : comment, comment1);
1573
1574 sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s was connected"
1575 " for %ld seconds. %d/%d sendK/recvK.",
1576 source_p->name, CurrentTime - source_p->localClient->firsttime, sendk, recvk);
1577
1578 ilog(L_SERVER, "%s was connected for %ld seconds. %d/%d sendK/recvK.",
1579 source_p->name, CurrentTime - source_p->localClient->firsttime, sendk, recvk);
1580
1581 if(has_id(source_p))
1582 del_from_id_hash(source_p->id, source_p);
1583
1584 del_from_client_hash(source_p->name, source_p);
1585 remove_client_from_list(source_p);
1586
1587 SetDead(source_p);
1588 dlinkAddAlloc(source_p, &dead_list);
1589 return 0;
1590}
1591
1592
1593/*
1594 * This assumes IsPerson(source_p) == TRUE && MyConnect(source_p) == TRUE
1595 */
1596
1597static int
1598exit_local_client(struct Client *client_p, struct Client *source_p, struct Client *from,
1599 const char *comment)
1600{
1601 unsigned long on_for;
1602
1603 exit_generic_client(client_p, source_p, from, comment);
1604 clear_monitor(source_p);
1605
1606 s_assert(IsPerson(source_p));
1607 client_flush_input(source_p);
1608 dlinkDelete(&source_p->localClient->tnode, &lclient_list);
1609 dlinkDelete(&source_p->lnode, &me.serv->users);
1610
1611 if(IsOper(source_p))
1612 dlinkFindDestroy(source_p, &local_oper_list);
1613
1614 sendto_realops_snomask(SNO_CCONN, L_ALL,
1615 "Client exiting: %s (%s@%s) [%s] [%s]",
1616 source_p->name,
1617 source_p->username, source_p->host, comment,
1618 show_ip(NULL, source_p) ? source_p->sockhost : "255.255.255.255");
1619
1620 sendto_realops_snomask(SNO_CCONNEXT, L_ALL,
1621 "CLIEXIT %s %s %s %s 0 %s",
1622 source_p->name, source_p->username, source_p->host,
1623 show_ip(NULL, source_p) ? source_p->sockhost : "255.255.255.255",
1624 comment);
1625
1626 on_for = CurrentTime - source_p->localClient->firsttime;
1627
1628 ilog(L_USER, "%s (%3lu:%02lu:%02lu): %s!%s@%s %d/%d",
1629 myctime(CurrentTime), on_for / 3600,
1630 (on_for % 3600) / 60, on_for % 60,
1631 source_p->name, source_p->username, source_p->host,
1632 source_p->localClient->sendK, source_p->localClient->receiveK);
1633
1634 sendto_one(source_p, "ERROR :Closing Link: %s (%s)", source_p->host, comment);
1635 close_connection(source_p);
1636
1637 if((source_p->flags & FLAGS_KILLED) == 0)
1638 {
1639 sendto_server(client_p, NULL, CAP_TS6, NOCAPS,
1640 ":%s QUIT :%s", use_id(source_p), comment);
1641 sendto_server(client_p, NULL, NOCAPS, CAP_TS6,
1642 ":%s QUIT :%s", source_p->name, comment);
1643 }
1644
1645 SetDead(source_p);
1646 dlinkAddAlloc(source_p, &dead_list);
1647 return(CLIENT_EXITED);
1648}
1649
1650
1651/*
1652** exit_client - This is old "m_bye". Name changed, because this is not a
1653** protocol function, but a general server utility function.
1654**
1655** This function exits a client of *any* type (user, server, etc)
1656** from this server. Also, this generates all necessary prototol
1657** messages that this exit may cause.
1658**
1659** 1) If the client is a local client, then this implicitly
1660** exits all other clients depending on this connection (e.g.
1661** remote clients having 'from'-field that points to this.
1662**
1663** 2) If the client is a remote client, then only this is exited.
1664**
1665** For convenience, this function returns a suitable value for
1666** m_function return value:
1667**
1668** CLIENT_EXITED if (client_p == source_p)
1669** 0 if (client_p != source_p)
1670*/
1671int
1672exit_client(struct Client *client_p, /* The local client originating the
1673 * exit or NULL, if this exit is
1674 * generated by this server for
1675 * internal reasons.
1676 * This will not get any of the
1677 * generated messages. */
1678 struct Client *source_p, /* Client exiting */
1679 struct Client *from, /* Client firing off this Exit,
1680 * never NULL! */
1681 const char *comment /* Reason for the exit */
1682 )
1683{
1684 hook_data_client_exit hdata;
1685 if(IsClosing(source_p))
1686 return -1;
1687
1688 /* note, this HAS to be here, when we exit a client we attempt to
1689 * send them data, if this generates a write error we must *not* add
1690 * them to the abort list --fl
1691 */
1692 SetClosing(source_p);
1693
1694 hdata.local_link = client_p;
1695 hdata.target = source_p;
1696 hdata.from = from;
1697 hdata.comment = comment;
1698 call_hook(h_client_exit, &hdata);
1699
1700 if(MyConnect(source_p))
1701 {
1702 /* Local clients of various types */
1703 if(IsPerson(source_p))
1704 return exit_local_client(client_p, source_p, from, comment);
1705 else if(IsServer(source_p))
1706 return exit_local_server(client_p, source_p, from, comment);
1707 /* IsUnknown || IsConnecting || IsHandShake */
1708 else if(!IsReject(source_p))
1709 return exit_unknown_client(client_p, source_p, from, comment);
1710 }
1711 else
1712 {
1713 /* Remotes */
1714 if(IsPerson(source_p))
1715 return exit_remote_client(client_p, source_p, from, comment);
1716 else if(IsServer(source_p))
1717 return exit_remote_server(client_p, source_p, from, comment);
1718 }
1719
1720 return -1;
1721}
1722
1723/*
1724 * Count up local client memory
1725 */
1726
1727/* XXX one common Client list now */
1728void
1729count_local_client_memory(size_t * count, size_t * local_client_memory_used)
1730{
1731 size_t lusage;
1732 BlockHeapUsage(lclient_heap, count, NULL, &lusage);
1733 *local_client_memory_used = lusage + (*count * (sizeof(MemBlock) + sizeof(struct Client)));
1734}
1735
1736/*
1737 * Count up remote client memory
1738 */
1739void
1740count_remote_client_memory(size_t * count, size_t * remote_client_memory_used)
1741{
1742 size_t lcount, rcount;
1743 BlockHeapUsage(lclient_heap, &lcount, NULL, NULL);
1744 BlockHeapUsage(client_heap, &rcount, NULL, NULL);
1745 *count = rcount - lcount;
1746 *remote_client_memory_used = *count * (sizeof(MemBlock) + sizeof(struct Client));
1747}
1748
1749
1750/*
1751 * accept processing, this adds a form of "caller ID" to ircd
1752 *
1753 * If a client puts themselves into "caller ID only" mode,
1754 * only clients that match a client pointer they have put on
1755 * the accept list will be allowed to message them.
1756 *
1757 * [ source.on_allow_list ] -> [ target1 ] -> [ target2 ]
1758 *
1759 * [target.allow_list] -> [ source1 ] -> [source2 ]
1760 *
1761 * i.e. a target will have a link list of source pointers it will allow
1762 * each source client then has a back pointer pointing back
1763 * to the client that has it on its accept list.
1764 * This allows for exit_one_client to remove these now bogus entries
1765 * from any client having an accept on them.
1766 */
1767/*
1768 * del_all_accepts
1769 *
1770 * inputs - pointer to exiting client
1771 * output - NONE
1772 * side effects - Walk through given clients allow_list and on_allow_list
1773 * remove all references to this client
1774 */
1775void
1776del_all_accepts(struct Client *client_p)
1777{
1778 dlink_node *ptr;
1779 dlink_node *next_ptr;
1780 struct Client *target_p;
1781
1782 if(MyClient(client_p) && client_p->localClient->allow_list.head)
1783 {
1784 /* clear this clients accept list, and remove them from
1785 * everyones on_accept_list
1786 */
1787 DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->localClient->allow_list.head)
1788 {
1789 target_p = ptr->data;
1790 dlinkFindDestroy(client_p, &target_p->on_allow_list);
1791 dlinkDestroy(ptr, &client_p->localClient->allow_list);
1792 }
1793 }
1794
1795 /* remove this client from everyones accept list */
1796 DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->on_allow_list.head)
1797 {
1798 target_p = ptr->data;
1799 dlinkFindDestroy(client_p, &target_p->localClient->allow_list);
1800 dlinkDestroy(ptr, &client_p->on_allow_list);
1801 }
1802}
1803
1804/*
1805 * show_ip() - asks if the true IP shoudl be shown when source is
1806 * askin for info about target
1807 *
1808 * Inputs - source_p who is asking
1809 * - target_p who do we want the info on
1810 * Output - returns 1 if clear IP can be showed, otherwise 0
1811 * Side Effects - none
1812 */
1813
1814int
1815show_ip(struct Client *source_p, struct Client *target_p)
1816{
1817 if(IsAnyServer(target_p))
1818 {
1819#ifndef HIDE_SERVERS_IPS
1820 if(source_p == NULL || IsOper(source_p))
1821 return 1;
1822#endif
1823 return 0;
1824 }
1825 else if(IsIPSpoof(target_p))
1826 {
1827 /* source == NULL indicates message is being sent
1828 * to local opers.
1829 */
1830 if(!ConfigFileEntry.hide_spoof_ips &&
1831 (source_p == NULL || MyOper(source_p)))
1832 return 1;
1833 return 0;
1834 }
1835 else if(IsDynSpoof(target_p) && (source_p != NULL && !IsOper(source_p)))
1836 return 0;
1837 else
1838 return 1;
1839}
1840
1841int
1842show_ip_conf(struct ConfItem *aconf, struct Client *source_p)
1843{
1844 if(IsConfDoSpoofIp(aconf))
1845 {
1846 if(!ConfigFileEntry.hide_spoof_ips && MyOper(source_p))
1847 return 1;
1848
1849 return 0;
1850 }
1851 else
1852 return 1;
1853}
1854
1855/*
1856 * initUser
1857 *
1858 * inputs - none
1859 * outputs - none
1860 *
1861 * side effects - Creates a block heap for struct Users
1862 *
1863 */
1864static BlockHeap *user_heap;
1865void
1866initUser(void)
1867{
1868 user_heap = BlockHeapCreate(sizeof(struct User), USER_HEAP_SIZE);
1869 if(!user_heap)
1870 outofmemory();
1871}
1872
1873/*
1874 * make_user
1875 *
1876 * inputs - pointer to client struct
1877 * output - pointer to struct User
1878 * side effects - add's an User information block to a client
1879 * if it was not previously allocated.
1880 */
1881struct User *
1882make_user(struct Client *client_p)
1883{
1884 struct User *user;
1885
1886 user = client_p->user;
1887 if(!user)
1888 {
1889 user = (struct User *) BlockHeapAlloc(user_heap);
1890 user->refcnt = 1;
1891 client_p->user = user;
1892 }
1893 return user;
1894}
1895
1896/*
1897 * make_server
1898 *
1899 * inputs - pointer to client struct
1900 * output - pointer to server_t
1901 * side effects - add's an Server information block to a client
1902 * if it was not previously allocated.
1903 */
1904server_t *
1905make_server(struct Client *client_p)
1906{
1907 server_t *serv = client_p->serv;
1908
1909 if(!serv)
1910 {
1911 serv = (server_t *) MyMalloc(sizeof(server_t));
1912 client_p->serv = serv;
1913 }
1914 return client_p->serv;
1915}
1916
1917/*
1918 * free_user
1919 *
1920 * inputs - pointer to user struct
1921 * - pointer to client struct
1922 * output - none
1923 * side effects - Decrease user reference count by one and release block,
1924 * if count reaches 0
1925 */
1926void
1927free_user(struct User *user, struct Client *client_p)
1928{
1929 if(--user->refcnt <= 0)
1930 {
1931 if(user->away)
1932 MyFree((char *) user->away);
1933 /*
1934 * sanity check
1935 */
1936 if(user->refcnt < 0 || user->invited.head || user->channel.head)
1937 {
1938 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1939 "* %#lx user (%s!%s@%s) %#lx %#lx %#lx %lu %d *",
1940 (unsigned long) client_p,
1941 client_p ? client_p->
1942 name : "<noname>",
1943 client_p->username,
1944 client_p->host,
1945 (unsigned long) user,
1946 (unsigned long) user->invited.head,
1947 (unsigned long) user->channel.head,
1948 dlink_list_length(&user->channel),
1949 user->refcnt);
1950 s_assert(!user->refcnt);
1951 s_assert(!user->invited.head);
1952 s_assert(!user->channel.head);
1953 }
1954
1955 BlockHeapFree(user_heap, user);
1956 }
1957}
1958
1959void
1960init_uid(void)
1961{
1962 int i;
1963
1964 for(i = 0; i < 3; i++)
1965 current_uid[i] = me.id[i];
1966
1967 for(i = 3; i < 9; i++)
1968 current_uid[i] = 'A';
1969
1970 current_uid[9] = '\0';
1971}
1972
1973
1974char *
1975generate_uid(void)
1976{
1977 int i;
1978
1979 for(i = 8; i > 3; i--)
1980 {
1981 if(current_uid[i] == 'Z')
1982 {
1983 current_uid[i] = '0';
1984 return current_uid;
1985 }
1986 else if(current_uid[i] != '9')
1987 {
1988 current_uid[i]++;
1989 return current_uid;
1990 }
1991 else
1992 current_uid[i] = 'A';
1993 }
1994
1995 /* if this next if() triggers, we're fucked. */
1996 if(current_uid[3] == 'Z')
1997 {
1998 current_uid[i] = 'A';
1999 s_assert(0);
2000 }
2001 else
2002 current_uid[i]++;
2003
2004 return current_uid;
2005}
2006
2007/*
2008 * close_connection
2009 * Close the physical connection. This function must make
2010 * MyConnect(client_p) == FALSE, and set client_p->from == NULL.
2011 */
2012void
2013close_connection(struct Client *client_p)
2014{
2015 s_assert(client_p != NULL);
2016 if(client_p == NULL)
2017 return;
2018
2019 s_assert(MyConnect(client_p));
2020 if(!MyConnect(client_p))
2021 return;
2022
2023 if(IsServer(client_p))
2024 {
2025 struct server_conf *server_p;
2026
2027 ServerStats->is_sv++;
2028 ServerStats->is_sbs += client_p->localClient->sendB;
2029 ServerStats->is_sbr += client_p->localClient->receiveB;
2030 ServerStats->is_sks += client_p->localClient->sendK;
2031 ServerStats->is_skr += client_p->localClient->receiveK;
2032 ServerStats->is_sti += CurrentTime - client_p->localClient->firsttime;
2033 if(ServerStats->is_sbs > 2047)
2034 {
2035 ServerStats->is_sks += (ServerStats->is_sbs >> 10);
2036 ServerStats->is_sbs &= 0x3ff;
2037 }
2038 if(ServerStats->is_sbr > 2047)
2039 {
2040 ServerStats->is_skr += (ServerStats->is_sbr >> 10);
2041 ServerStats->is_sbr &= 0x3ff;
2042 }
2043
2044 /*
2045 * If the connection has been up for a long amount of time, schedule
2046 * a 'quick' reconnect, else reset the next-connect cycle.
2047 */
2048 if((server_p = find_server_conf(client_p->name)) != NULL)
2049 {
2050 /*
2051 * Reschedule a faster reconnect, if this was a automatically
2052 * connected configuration entry. (Note that if we have had
2053 * a rehash in between, the status has been changed to
2054 * CONF_ILLEGAL). But only do this if it was a "good" link.
2055 */
2056 server_p->hold = time(NULL);
2057 server_p->hold +=
2058 (server_p->hold - client_p->localClient->lasttime >
2059 HANGONGOODLINK) ? HANGONRETRYDELAY : ConFreq(server_p->class);
2060 }
2061
2062 }
2063 else if(IsClient(client_p))
2064 {
2065 ServerStats->is_cl++;
2066 ServerStats->is_cbs += client_p->localClient->sendB;
2067 ServerStats->is_cbr += client_p->localClient->receiveB;
2068 ServerStats->is_cks += client_p->localClient->sendK;
2069 ServerStats->is_ckr += client_p->localClient->receiveK;
2070 ServerStats->is_cti += CurrentTime - client_p->localClient->firsttime;
2071 if(ServerStats->is_cbs > 2047)
2072 {
2073 ServerStats->is_cks += (ServerStats->is_cbs >> 10);
2074 ServerStats->is_cbs &= 0x3ff;
2075 }
2076 if(ServerStats->is_cbr > 2047)
2077 {
2078 ServerStats->is_ckr += (ServerStats->is_cbr >> 10);
2079 ServerStats->is_cbr &= 0x3ff;
2080 }
2081 }
2082 else
2083 ServerStats->is_ni++;
2084
2085 if(-1 < client_p->localClient->fd)
2086 {
2087 /* attempt to flush any pending dbufs. Evil, but .. -- adrian */
2088 if(!IsIOError(client_p))
2089 send_queued_write(client_p->localClient->fd, client_p);
2090
2091 comm_close(client_p->localClient->fd);
2092 client_p->localClient->fd = -1;
2093 }
2094
64f2a7eb 2095 if(-1 < client_p->localClient->ctrlfd)
212380e3 2096 {
64f2a7eb 2097 comm_close(client_p->localClient->ctrlfd);
2098 client_p->localClient->ctrlfd = -1;
212380e3 2099 }
2100
2101 linebuf_donebuf(&client_p->localClient->buf_sendq);
2102 linebuf_donebuf(&client_p->localClient->buf_recvq);
2103 detach_conf(client_p);
2104
2105 /* XXX shouldnt really be done here. */
2106 detach_server_conf(client_p);
2107
2108 client_p->from = NULL; /* ...this should catch them! >:) --msa */
2109 ClearMyConnect(client_p);
2110 SetIOError(client_p);
2111}
2112
2113
2114
2115void
2116error_exit_client(struct Client *client_p, int error)
2117{
2118 /*
2119 * ...hmm, with non-blocking sockets we might get
2120 * here from quite valid reasons, although.. why
2121 * would select report "data available" when there
2122 * wasn't... so, this must be an error anyway... --msa
2123 * actually, EOF occurs when read() returns 0 and
2124 * in due course, select() returns that fd as ready
2125 * for reading even though it ends up being an EOF. -avalon
2126 */
2127 char errmsg[255];
2128 int current_error = comm_get_sockerr(client_p->localClient->fd);
2129
2130 SetIOError(client_p);
2131
2132 if(IsServer(client_p) || IsHandshake(client_p))
2133 {
2134 int connected = CurrentTime - client_p->localClient->firsttime;
2135
2136 if(error == 0)
2137 {
2138 sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) && !IsServer(client_p) ? L_NETWIDE : L_ALL,
2139 "Server %s closed the connection",
2140 get_server_name(client_p, SHOW_IP));
2141
2142 ilog(L_SERVER, "Server %s closed the connection",
2143 log_client_name(client_p, SHOW_IP));
2144 }
2145 else
2146 {
2147 sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) && !IsServer(client_p) ? L_NETWIDE : L_ALL,
2148 "Lost connection to %s: %s",
2149 client_p->name, strerror(current_error));
2150 ilog(L_SERVER, "Lost connection to %s: %s",
2151 log_client_name(client_p, SHOW_IP), strerror(current_error));
2152 }
2153
2154 sendto_realops_snomask(SNO_GENERAL, L_ALL,
2155 "%s had been connected for %d day%s, %2d:%02d:%02d",
2156 client_p->name, connected / 86400,
2157 (connected / 86400 == 1) ? "" : "s",
2158 (connected % 86400) / 3600,
2159 (connected % 3600) / 60, connected % 60);
2160 }
2161
2162 if(error == 0)
2163 strlcpy(errmsg, "Remote host closed the connection", sizeof(errmsg));
2164 else
2165 ircsnprintf(errmsg, sizeof(errmsg), "Read error: %s", strerror(current_error));
2166
2167 exit_client(client_p, client_p, &me, errmsg);
2168}