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