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