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