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