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