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