]> jfr.im git - solanum.git/blame - ircd/client.c
strcpy: mass-migrate to strlcpy where appropriate
[solanum.git] / ircd / client.c
CommitLineData
212380e3 1/*
b37021a4 2 * charybdis: an advanced ircd.
212380e3
AC
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
b37021a4 8 * Copyright (C) 2007 William Pitcock
212380e3
AC
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
212380e3
AC
24 */
25#include "stdinc.h"
9b8e9eb3 26#include "defaults.h"
212380e3 27
212380e3
AC
28#include "client.h"
29#include "class.h"
212380e3 30#include "hash.h"
4562c604 31#include "match.h"
212380e3 32#include "ircd.h"
212380e3
AC
33#include "numeric.h"
34#include "packet.h"
64fae260 35#include "authproc.h"
212380e3
AC
36#include "s_conf.h"
37#include "s_newconf.h"
4016731b 38#include "logger.h"
212380e3
AC
39#include "s_serv.h"
40#include "s_stats.h"
41#include "send.h"
42#include "whowas.h"
43#include "s_user.h"
212380e3 44#include "hash.h"
212380e3 45#include "hostmask.h"
212380e3
AC
46#include "listener.h"
47#include "hook.h"
48#include "msg.h"
49#include "monitor.h"
54015b5f 50#include "reject.h"
994544c2 51#include "scache.h"
a4bf26dd 52#include "rb_dictionary.h"
c6d72037 53#include "sslproc.h"
c53ca1e0 54#include "wsproc.h"
77d3d2db 55#include "s_assert.h"
212380e3
AC
56
57#define DEBUG_EXITED_CLIENTS
58
330fc5c1
AC
59static void check_pings_list(rb_dlink_list * list);
60static void check_unknowns_list(rb_dlink_list * list);
212380e3
AC
61static void free_exited_clients(void *unused);
62static void exit_aborted_clients(void *unused);
63
64static int exit_remote_client(struct Client *, struct Client *, struct Client *,const char *);
65static int exit_remote_server(struct Client *, struct Client *, struct Client *,const char *);
66static int exit_local_client(struct Client *, struct Client *, struct Client *,const char *);
67static int exit_unknown_client(struct Client *, struct Client *, struct Client *,const char *);
68static int exit_local_server(struct Client *, struct Client *, struct Client *,const char *);
69static int qs_server(struct Client *, struct Client *, struct Client *, const char *comment);
70
71static EVH check_pings;
72
5433b83e
VY
73static rb_bh *client_heap = NULL;
74static rb_bh *lclient_heap = NULL;
b09cbaa3 75static rb_bh *pclient_heap = NULL;
5433b83e 76static rb_bh *user_heap = NULL;
c127b45b 77static rb_bh *away_heap = NULL;
5433b83e 78static char current_uid[IDLEN];
de7cf7e0 79static uint32_t current_connid = 0;
212380e3 80
4177311e 81rb_dictionary *nd_dict = NULL;
43de0f45 82
212380e3
AC
83enum
84{
85 D_LINED,
aae358c0 86 K_LINED
212380e3
AC
87};
88
330fc5c1 89rb_dlink_list dead_list;
212380e3 90#ifdef DEBUG_EXITED_CLIENTS
330fc5c1 91static rb_dlink_list dead_remote_list;
212380e3
AC
92#endif
93
94struct abort_client
95{
330fc5c1 96 rb_dlink_node node;
212380e3
AC
97 struct Client *client;
98 char notice[REASONLEN];
99};
100
330fc5c1 101static rb_dlink_list abort_list;
212380e3
AC
102
103
104/*
105 * init_client
106 *
107 * inputs - NONE
108 * output - NONE
109 * side effects - initialize client free memory
110 */
111void
112init_client(void)
113{
114 /*
115 * start off the check ping event .. -- adrian
116 * Every 30 seconds is plenty -- db
117 */
1087485c 118 client_heap = rb_bh_create(sizeof(struct Client), CLIENT_HEAP_SIZE, "client_heap");
adc6cc42
VY
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");
b09cbaa3 121 user_heap = rb_bh_create(sizeof(struct User), USER_HEAP_SIZE, "user_heap");
c127b45b 122 away_heap = rb_bh_create(AWAYLEN, AWAY_HEAP_SIZE, "away_heap");
adc6cc42 123
3b2ebd04
JT
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);
5a606a8f 127 rb_event_add("flood_recalc", flood_recalc, NULL, 1);
43de0f45 128
a4bf26dd 129 nd_dict = rb_dictionary_create("nickdelay", irccmp);
212380e3
AC
130}
131
de7cf7e0
AC
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 */
140uint32_t
141connid_get(struct Client *client_p)
142{
5c63bfe8
AC
143 s_assert(MyConnect(client_p));
144 if (!MyConnect(client_p))
de7cf7e0
AC
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 */
168void
169connid_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 */
192void
193client_release_connids(struct Client *client_p)
194{
195 rb_dlink_node *ptr, *ptr2;
196
cc02bdf3
SA
197 if (client_p->localClient->connids.head)
198 s_assert(MyConnect(client_p));
de7cf7e0 199
558744e5
SA
200 if (!MyConnect(client_p))
201 return;
202
de7cf7e0
AC
203 RB_DLINK_FOREACH_SAFE(ptr, ptr2, client_p->localClient->connids.head)
204 connid_put(RB_POINTER_TO_UINT(ptr->data));
205}
212380e3
AC
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 */
217struct Client *
218make_client(struct Client *from)
219{
220 struct Client *client_p = NULL;
221 struct LocalUser *localClient;
222
398b6a73 223 client_p = rb_bh_alloc(client_heap);
212380e3
AC
224
225 if(from == NULL)
226 {
227 client_p->from = client_p; /* 'from' of local client is self! */
228
b09cbaa3 229 localClient = rb_bh_alloc(lclient_heap);
212380e3
AC
230 SetMyConnect(client_p);
231 client_p->localClient = localClient;
232
e3354945 233 client_p->localClient->lasttime = client_p->localClient->firsttime = rb_current_time();
212380e3 234
c5c2f506 235 client_p->localClient->F = NULL;
212380e3 236
5ef68b13 237 client_p->preClient = rb_bh_alloc(pclient_heap);
212380e3
AC
238
239 /* as good a place as any... */
330fc5c1 240 rb_dlinkAdd(client_p, &client_p->localClient->tnode, &unknown_list);
212380e3
AC
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 }
55abcbb2 248
212380e3 249 SetUnknown(client_p);
4d5a902f 250 rb_strlcpy(client_p->username, "unknown", sizeof(client_p->username));
212380e3
AC
251
252 return client_p;
253}
254
255void
256free_pre_client(struct Client *client_p)
257{
212380e3
AC
258 s_assert(NULL != client_p);
259
260 if(client_p->preClient == NULL)
261 return;
262
154dc91e 263 s_assert(client_p->preClient->auth.cid == 0);
d3f6b808 264
154dc91e
EM
265 rb_free(client_p->preClient->auth.data);
266 rb_free(client_p->preClient->auth.reason);
7fc09bc4 267
398b6a73 268 rb_bh_free(pclient_heap, client_p->preClient);
212380e3
AC
269 client_p->preClient = NULL;
270}
271
272static void
273free_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
de7cf7e0 293 client_release_connids(client_p);
c6d72037
VY
294 if(client_p->localClient->F != NULL)
295 {
3b2ebd04 296 rb_close(client_p->localClient->F);
c6d72037 297 }
212380e3
AC
298
299 if(client_p->localClient->passwd)
300 {
301 memset(client_p->localClient->passwd, 0,
302 strlen(client_p->localClient->passwd));
637c4932 303 rb_free(client_p->localClient->passwd);
212380e3
AC
304 }
305
90afc118 306 rb_free(client_p->localClient->auth_user);
637c4932
VY
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);
0e52d0d4
JT
311 if (client_p->localClient->privset)
312 privilegeset_unref(client_p->localClient->privset);
212380e3 313
c53ca1e0
AC
314 if (IsSSL(client_p))
315 ssld_decrement_clicount(client_p->localClient->ssl_ctl);
55abcbb2 316
c53ca1e0
AC
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);
c6d72037 322
398b6a73 323 rb_bh_free(lclient_heap, client_p->localClient);
212380e3
AC
324 client_p->localClient = NULL;
325}
326
327void
328free_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);
8eda114a 334 rb_free(client_p->certfp);
398b6a73 335 rb_bh_free(client_heap, client_p);
212380e3
AC
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
55abcbb2 344 * side effects -
212380e3
AC
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
364static void
365check_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
55abcbb2 377 * side effects -
212380e3
AC
378 */
379static void
330fc5c1 380check_pings_list(rb_dlink_list * list)
212380e3
AC
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 */
637c4932 385 rb_dlink_node *ptr, *next_ptr;
212380e3 386
637c4932 387 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
212380e3
AC
388 {
389 client_p = ptr->data;
390
212380e3
AC
391 if(!MyConnect(client_p) || IsDead(client_p))
392 continue;
393
e2a98043 394 ping = get_client_ping(client_p);
212380e3 395
e3354945 396 if(ping < (rb_current_time() - client_p->localClient->lasttime))
212380e3
AC
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 */
e3354945 402 if(((rb_current_time() - client_p->localClient->lasttime) >= (2 * ping)
212380e3
AC
403 && (client_p->flags & FLAGS_PINGSENT)))
404 {
e2a98043 405 if(IsServer(client_p))
212380e3 406 {
e2a98043 407 sendto_realops_snomask(SNO_GENERAL, L_ALL,
212380e3 408 "No response from %s, closing link",
b3ebc7ab 409 client_p->name);
212380e3
AC
410 ilog(L_SERVER,
411 "No response from %s, closing link",
412 log_client_name(client_p, HIDE_IP));
413 }
5203cba5 414 (void) snprintf(scratch, sizeof(scratch),
212380e3 415 "Ping timeout: %d seconds",
e3354945 416 (int) (rb_current_time() - client_p->localClient->lasttime));
212380e3
AC
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 */
e3354945 430 client_p->localClient->lasttime = rb_current_time() - ping;
212380e3
AC
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 */
446static void
330fc5c1 447check_unknowns_list(rb_dlink_list * list)
212380e3 448{
637c4932 449 rb_dlink_node *ptr, *next_ptr;
212380e3 450 struct Client *client_p;
35cf4c79 451 int timeout;
212380e3 452
637c4932 453 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
212380e3
AC
454 {
455 client_p = ptr->data;
456
457 if(IsDead(client_p) || IsClosing(client_p))
458 continue;
459
d3f6b808 460 /* Still querying with authd */
154dc91e 461 if(client_p->preClient != NULL && client_p->preClient->auth.cid != 0)
6bb4fb83
JT
462 continue;
463
212380e3
AC
464 /*
465 * Check UNKNOWN connections - if they have been in this state
466 * for > 30s, close them.
467 */
468
35cf4c79 469 timeout = IsAnyServer(client_p) ? ConfigFileEntry.connect_timeout : 30;
e3354945 470 if((rb_current_time() - client_p->localClient->firsttime) > timeout)
35cf4c79
JT
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",
b3ebc7ab 476 client_p->name);
35cf4c79
JT
477 ilog(L_SERVER,
478 "No response from %s, closing link",
479 log_client_name(client_p, HIDE_IP));
480 }
212380e3 481 exit_client(client_p, client_p, &me, "Connection timed out");
35cf4c79 482 }
212380e3
AC
483 }
484}
485
486static void
487notify_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";
212380e3
AC
492 const char *reason = NULL;
493 const char *exit_reason = conn_closed;
494
a12ad044 495 if(ConfigFileEntry.kline_with_reason)
212380e3 496 {
a12ad044 497 reason = get_user_ban_reason(aconf);
b52c2949 498 exit_reason = reason;
212380e3
AC
499 }
500 else
501 {
405ae5ce 502 reason = aconf->status == D_LINED ? d_lined : k_lined;
212380e3
AC
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);
55abcbb2
KB
510
511 exit_client(client_p, client_p, &me,
212380e3
AC
512 EmptyString(ConfigFileEntry.kline_reason) ? exit_reason :
513 ConfigFileEntry.kline_reason);
514}
515
516/*
517 * check_banned_lines
518 * inputs - NONE
519 * output - NONE
170703fe 520 * side effects - Check all connections for a pending k/dline against the
212380e3
AC
521 * client, exit the client if found.
522 */
523void
524check_banned_lines(void)
525{
1bb1f1b0
JT
526 check_dlines();
527 check_klines();
528 check_xlines();
212380e3
AC
529}
530
531/* check_klines_event()
532 *
533 * inputs -
534 * outputs -
535 * side effects - check_klines() is called, kline_queued unset
536 */
537void
538check_klines_event(void *unused)
539{
f66f0baa 540 kline_queued = false;
212380e3
AC
541 check_klines();
542}
543
544/* check_klines
545 *
546 * inputs -
547 * outputs -
548 * side effects - all clients will be checked for klines
549 */
550void
551check_klines(void)
552{
553 struct Client *client_p;
554 struct ConfItem *aconf;
330fc5c1 555 rb_dlink_node *ptr;
637c4932 556 rb_dlink_node *next_ptr;
212380e3 557
637c4932 558 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, lclient_list.head)
212380e3
AC
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,
408024fa
JT
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);
212380e3
AC
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
212380e3
AC
586/* check_dlines()
587 *
588 * inputs -
589 * outputs -
590 * side effects - all clients will be checked for dlines
591 */
592void
593check_dlines(void)
594{
595 struct Client *client_p;
596 struct ConfItem *aconf;
330fc5c1 597 rb_dlink_node *ptr;
637c4932 598 rb_dlink_node *next_ptr;
212380e3 599
637c4932 600 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, lclient_list.head)
212380e3
AC
601 {
602 client_p = ptr->data;
603
604 if(IsMe(client_p))
605 continue;
606
e867208d 607 if((aconf = find_dline((struct sockaddr *)&client_p->localClient->ip, GET_SS_FAMILY(&client_p->localClient->ip))) != NULL)
212380e3
AC
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 */
637c4932 622 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, unknown_list.head)
212380e3
AC
623 {
624 client_p = ptr->data;
625
e867208d 626 if((aconf = find_dline((struct sockaddr *)&client_p->localClient->ip, GET_SS_FAMILY(&client_p->localClient->ip))) != NULL)
212380e3
AC
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 */
642void
643check_xlines(void)
644{
645 struct Client *client_p;
646 struct ConfItem *aconf;
330fc5c1 647 rb_dlink_node *ptr;
637c4932 648 rb_dlink_node *next_ptr;
212380e3 649
637c4932 650 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, lclient_list.head)
212380e3
AC
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,
408024fa
JT
662 "XLINE over-ruled for %s, client is kline_exempt [%s]",
663 get_client_name(client_p, HIDE_IP),
70ea02eb 664 aconf->host);
212380e3
AC
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
330692a1
KB
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 */
683void
684resv_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
07d3283f
KB
702 /* Skip users that already have UID nicks. */
703 if(IsDigit(client_p->name[0]))
704 continue;
705
330692a1
KB
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();
b47f8a4f 735 whowas_add_history(client_p, 1);
330692a1 736
07d3283f
KB
737 monitor_signoff(client_p);
738
330692a1
KB
739 invalidate_bancache_user(client_p);
740
583f064f 741 sendto_common_channels_local(client_p, NOCAPS, NOCAPS, ":%s!%s@%s NICK :%s",
330692a1
KB
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
07d3283f
KB
750 monitor_signon(client_p);
751
330692a1
KB
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
5203cba5 759 snprintf(note, sizeof(note), "Nick: %s", nick);
330692a1
KB
760 rb_note(client_p->localClient->F, note);
761 }
762 }
763}
764
212380e3
AC
765/*
766 * update_client_exit_stats
767 *
768 * input - pointer to client
769 * output - NONE
55abcbb2 770 * side effects -
212380e3
AC
771 */
772static void
773update_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
55abcbb2 801 * side effects -
212380e3
AC
802 */
803static void
804release_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)
637c4932
VY
815 rb_free(client_p->serv->fullcaps);
816 rb_free(client_p->serv);
212380e3
AC
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 */
827static void
828remove_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
330fc5c1 844 rb_dlinkDelete(&client_p->node, &global_client_list);
212380e3
AC
845
846 update_client_exit_stats(client_p);
847}
848
849
2d28539c
JT
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 */
856int
857clean_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
212380e3
AC
882/*
883 * find_person - find person by (nick)name.
884 * inputs - pointer to name
885 * output - return client pointer
886 * side effects -
887 */
888struct Client *
889find_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
900struct Client *
901find_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/*
55abcbb2
KB
914 * find_chasing - find the client structure for a nick name (user)
915 * using history mechanism if necessary. If the client is not found,
212380e3
AC
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 */
919struct Client *
920find_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
b47f8a4f 935 if(!(who = whowas_get_history(user, (long) KILLCHASETIMELIMIT)))
212380e3
AC
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
965const char *
966get_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
55abcbb2 979 if(ConfigFileEntry.hide_spoof_ips &&
212380e3
AC
980 showip == SHOW_IP && IsIPSpoof(client))
981 showip = MASK_IP;
212380e3
AC
982 if(IsAnyServer(client))
983 showip = MASK_IP;
212380e3
AC
984
985 /* And finally, let's get the host information, ip or name */
986 switch (showip)
987 {
988 case SHOW_IP:
5203cba5 989 snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
55abcbb2 990 client->name, client->username,
212380e3
AC
991 client->sockhost);
992 break;
993 case MASK_IP:
5203cba5 994 snprintf(nbuf, sizeof(nbuf), "%s[%s@255.255.255.255]",
212380e3
AC
995 client->name, client->username);
996 break;
997 default:
5203cba5 998 snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
212380e3
AC
999 client->name, client->username, client->host);
1000 }
1001 return nbuf;
1002 }
1003
55abcbb2 1004 /* As pointed out by Adel Mezibra
212380e3
AC
1005 * Neph|l|m@EFnet. Was missing a return here.
1006 */
1007 return client->name;
1008}
55abcbb2 1009
212380e3
AC
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 */
1015const char *
1016log_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:
5203cba5 1031 snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]", target_p->name,
212380e3
AC
1032 target_p->username, target_p->sockhost);
1033 break;
1034
212380e3 1035 default:
5203cba5 1036 snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]", target_p->name,
212380e3
AC
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) */
1048int
1049is_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
1059static void
1060free_exited_clients(void *unused)
1061{
330fc5c1 1062 rb_dlink_node *ptr, *next;
212380e3
AC
1063 struct Client *target_p;
1064
5cefa1d6 1065 RB_DLINK_FOREACH_SAFE(ptr, next, dead_list.head)
212380e3
AC
1066 {
1067 target_p = ptr->data;
1068
1069#ifdef DEBUG_EXITED_CLIENTS
1070 {
1071 struct abort_client *abt;
330fc5c1 1072 rb_dlink_node *aptr;
212380e3
AC
1073 int found = 0;
1074
5cefa1d6 1075 RB_DLINK_FOREACH(aptr, abort_list.head)
212380e3
AC
1076 {
1077 abt = aptr->data;
1078 if(abt->client == target_p)
1079 {
1080 s_assert(0);
55abcbb2 1081 sendto_realops_snomask(SNO_GENERAL, L_ALL,
66f7fe67 1082 "On abort_list: %s stat: %u flags: %llu handler: %c",
212380e3 1083 target_p->name, (unsigned int) target_p->status,
d19aab33 1084 (unsigned long long)target_p->flags, target_p->handler);
212380e3 1085 sendto_realops_snomask(SNO_GENERAL, L_ALL,
f80a1823 1086 "Please report this to the charybdis developers!");
212380e3
AC
1087 found++;
1088 }
1089 }
1090
1091 if(found)
1092 {
330fc5c1 1093 rb_dlinkDestroy(ptr, &dead_list);
212380e3
AC
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!");
330fc5c1 1103 rb_dlinkDestroy(ptr, &dead_list);
212380e3
AC
1104 continue;
1105 }
1106 release_client_state(target_p);
1107 free_client(target_p);
330fc5c1 1108 rb_dlinkDestroy(ptr, &dead_list);
212380e3
AC
1109 }
1110
1111#ifdef DEBUG_EXITED_CLIENTS
5cefa1d6 1112 RB_DLINK_FOREACH_SAFE(ptr, next, dead_remote_list.head)
212380e3
AC
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!");
330fc5c1 1120 rb_dlinkDestroy(ptr, &dead_list);
212380e3
AC
1121 continue;
1122 }
1123 release_client_state(target_p);
1124 free_client(target_p);
330fc5c1 1125 rb_dlinkDestroy(ptr, &dead_remote_list);
212380e3
AC
1126 }
1127#endif
55abcbb2 1128
212380e3
AC
1129}
1130
55abcbb2 1131/*
212380e3 1132** Remove all clients that depend on source_p; assumes all (S)QUITs have
55abcbb2
KB
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
212380e3 1135** actually removing things off llists. tweaked from +CSr31 -orabidoo
cbeab4bc 1136 */
212380e3
AC
1137/*
1138 * added sanity test code.... source_p->serv might be NULL...
1139 */
1140static void
1141recurse_remove_clients(struct Client *source_p, const char *comment)
1142{
1143 struct Client *target_p;
330fc5c1 1144 rb_dlink_node *ptr, *ptr_next;
212380e3
AC
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 {
5cefa1d6 1155 RB_DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->serv->users.head)
212380e3
AC
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 {
5cefa1d6 1167 RB_DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->serv->users.head)
212380e3
AC
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 }
55abcbb2 1175 }
212380e3 1176
5cefa1d6 1177 RB_DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->serv->servers.head)
212380e3
AC
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
856df9a3 1187** all necessary SQUITs. source_p itself is still on the lists,
212380e3 1188** and its SQUITs have been sent except for the upstream one -orabidoo
cbeab4bc 1189 */
212380e3
AC
1190static void
1191remove_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;
330fc5c1 1196 rb_dlink_node *ptr, *next;
212380e3 1197
5cefa1d6 1198 RB_DLINK_FOREACH_SAFE(ptr, next, serv_list.head)
212380e3
AC
1199 {
1200 to = ptr->data;
1201
856df9a3 1202 if(IsMe(to) || to == source_p->from || to == client_p)
212380e3
AC
1203 continue;
1204
856df9a3 1205 sendto_one(to, "SQUIT %s :%s", get_id(source_p, to), comment);
212380e3
AC
1206 }
1207
1208 recurse_remove_clients(source_p, comment1);
1209}
1210
1211void
1212exit_aborted_clients(void *unused)
1213{
1214 struct abort_client *abt;
330fc5c1 1215 rb_dlink_node *ptr, *next;
5cefa1d6 1216 RB_DLINK_FOREACH_SAFE(ptr, next, abort_list.head)
212380e3
AC
1217 {
1218 abt = ptr->data;
1219
1220#ifdef DEBUG_EXITED_CLIENTS
1221 {
330fc5c1 1222 if(rb_dlinkFind(abt->client, &dead_list))
212380e3
AC
1223 {
1224 s_assert(0);
55abcbb2 1225 sendto_realops_snomask(SNO_GENERAL, L_ALL,
66f7fe67 1226 "On dead_list: %s stat: %u flags: %llu handler: %c",
212380e3 1227 abt->client->name, (unsigned int) abt->client->status,
d19aab33 1228 (unsigned long long)abt->client->flags, abt->client->handler);
212380e3 1229 sendto_realops_snomask(SNO_GENERAL, L_ALL,
f80a1823 1230 "Please report this to the charybdis developers!");
212380e3
AC
1231 continue;
1232 }
1233 }
1234#endif
1235
1236 s_assert(*((unsigned long*)abt->client) != 0xdeadbeef); /* This is lame but its a debug thing */
330fc5c1 1237 rb_dlinkDelete(ptr, &abort_list);
212380e3
AC
1238
1239 if(IsAnyServer(abt->client))
1240 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1241 "Closing link to %s: %s",
b3ebc7ab 1242 abt->client->name, abt->notice);
212380e3
AC
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);
637c4932 1249 rb_free(abt);
212380e3
AC
1250 }
1251}
1252
1253
1254/*
1255 * dead_link - Adds client to a list of clients that need an exit_client()
212380e3
AC
1256 */
1257void
cef7a7bc 1258dead_link(struct Client *client_p, int sendqex)
212380e3
AC
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
eddc2ab6 1266 abt = (struct abort_client *) rb_malloc(sizeof(struct abort_client));
212380e3 1267
cef7a7bc 1268 if(sendqex)
f427c8b0 1269 rb_strlcpy(abt->notice, "Max SendQ exceeded", sizeof(abt->notice));
212380e3 1270 else
5203cba5 1271 snprintf(abt->notice, sizeof(abt->notice), "Write error: %s", strerror(errno));
212380e3
AC
1272
1273 abt->client = client_p;
1274 SetIOError(client_p);
1275 SetDead(client_p);
1276 SetClosing(client_p);
330fc5c1 1277 rb_dlinkAdd(abt, &abt->node, &abort_list);
212380e3
AC
1278}
1279
1280
1281/* This does the remove of the user from channels..local or remote */
1282static inline void
1283exit_generic_client(struct Client *client_p, struct Client *source_p, struct Client *from,
1284 const char *comment)
1285{
637c4932 1286 rb_dlink_node *ptr, *next_ptr;
212380e3
AC
1287
1288 if(IsOper(source_p))
330fc5c1 1289 rb_dlinkFindDestroy(source_p, &oper_list);
212380e3 1290
583f064f 1291 sendto_common_channels_local(source_p, NOCAPS, NOCAPS, ":%s!%s@%s QUIT :%s",
212380e3
AC
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 */
637c4932 1301 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, source_p->user->invited.head)
212380e3
AC
1302 {
1303 del_invite(ptr->data, source_p);
1304 }
1305
1306 /* Clean up allow lists */
1307 del_all_accepts(source_p);
1308
b47f8a4f
AC
1309 whowas_add_history(source_p, 0);
1310 whowas_off_history(source_p);
212380e3
AC
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
55abcbb2 1322/*
212380e3
AC
1323 * Assumes IsPerson(source_p) && !MyConnect(source_p)
1324 */
1325
1326static int
1327exit_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);
55abcbb2 1331
212380e3
AC
1332 if(source_p->servptr && source_p->servptr->serv)
1333 {
330fc5c1 1334 rb_dlinkDelete(&source_p->lnode, &source_p->servptr->serv->users);
212380e3
AC
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);
212380e3
AC
1341 }
1342
1343 SetDead(source_p);
1344#ifdef DEBUG_EXITED_CLIENTS
330fc5c1 1345 rb_dlinkAddAlloc(source_p, &dead_remote_list);
212380e3 1346#else
330fc5c1 1347 rb_dlinkAddAlloc(source_p, &dead_list);
212380e3
AC
1348#endif
1349 return(CLIENT_EXITED);
1350}
1351
1352/*
07554369 1353 * This assumes IsUnknown(source_p) == true and MyConnect(source_p) == true
212380e3
AC
1354 */
1355
1356static int
d2a4981a
SA
1357exit_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)
212380e3 1367{
d2a4981a 1368 authd_abort_client(source_p);
330fc5c1 1369 rb_dlinkDelete(&source_p->localClient->tnode, &unknown_list);
212380e3
AC
1370
1371 if(!IsIOError(source_p))
dd12a19c
JT
1372 sendto_one(source_p, "ERROR :Closing Link: %s (%s)",
1373 source_p->user != NULL ? source_p->host : "127.0.0.1",
1374 comment);
212380e3
AC
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);
212380e3 1384 SetDead(source_p);
330fc5c1 1385 rb_dlinkAddAlloc(source_p, &dead_list);
212380e3
AC
1386
1387 /* Note that we don't need to add unknowns to the dead_list */
1388 return(CLIENT_EXITED);
1389}
1390
1391static int
55abcbb2 1392exit_remote_server(struct Client *client_p, struct Client *source_p, struct Client *from,
212380e3
AC
1393 const char *comment)
1394{
1395 static char comment1[(HOSTLEN*2)+2];
1396 static char newcomment[BUFSIZE];
1397 struct Client *target_p;
55abcbb2 1398
212380e3
AC
1399 if(ConfigServerHide.flatten_links)
1400 strcpy(comment1, "*.net *.split");
1401 else
1402 {
66c8fdd2 1403 strcpy(comment1, source_p->servptr->name);
212380e3
AC
1404 strcat(comment1, " ");
1405 strcat(comment1, source_p->name);
1406 }
1407 if (IsPerson(from))
5203cba5 1408 snprintf(newcomment, sizeof(newcomment), "by %s: %s",
212380e3
AC
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)
330fc5c1 1415 rb_dlinkDelete(&source_p->lnode, &source_p->servptr->serv->servers);
212380e3
AC
1416 else
1417 s_assert(0);
1418
330fc5c1 1419 rb_dlinkFindDestroy(source_p, &global_serv_list);
212380e3 1420 target_p = source_p->from;
55abcbb2 1421
212380e3
AC
1422 if(target_p != NULL && IsServer(target_p) && target_p != client_p &&
1423 !IsMe(target_p) && (source_p->flags & FLAGS_KILLED) == 0)
1424 {
55abcbb2 1425 sendto_one(target_p, ":%s SQUIT %s :%s",
212380e3
AC
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);
55abcbb2 1434 remove_client_from_list(source_p);
994544c2 1435 scache_split(source_p->serv->nameinfo);
55abcbb2 1436
212380e3
AC
1437 SetDead(source_p);
1438#ifdef DEBUG_EXITED_CLIENTS
330fc5c1 1439 rb_dlinkAddAlloc(source_p, &dead_remote_list);
212380e3 1440#else
330fc5c1 1441 rb_dlinkAddAlloc(source_p, &dead_list);
212380e3
AC
1442#endif
1443 return 0;
1444}
1445
1446static int
55abcbb2 1447qs_server(struct Client *client_p, struct Client *source_p, struct Client *from,
212380e3
AC
1448 const char *comment)
1449{
212380e3 1450 if(source_p->servptr && source_p->servptr->serv)
330fc5c1 1451 rb_dlinkDelete(&source_p->lnode, &source_p->servptr->serv->servers);
212380e3
AC
1452 else
1453 s_assert(0);
1454
330fc5c1 1455 rb_dlinkFindDestroy(source_p, &global_serv_list);
55abcbb2 1456
212380e3
AC
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);
55abcbb2 1461 remove_client_from_list(source_p);
19807b5b 1462 scache_split(source_p->serv->nameinfo);
55abcbb2 1463
212380e3 1464 SetDead(source_p);
55abcbb2 1465 rb_dlinkAddAlloc(source_p, &dead_list);
212380e3
AC
1466 return 0;
1467}
1468
1469static int
55abcbb2 1470exit_local_server(struct Client *client_p, struct Client *source_p, struct Client *from,
212380e3
AC
1471 const char *comment)
1472{
1473 static char comment1[(HOSTLEN*2)+2];
1474 static char newcomment[BUFSIZE];
1475 unsigned int sendk, recvk;
55abcbb2 1476
330fc5c1
AC
1477 rb_dlinkDelete(&source_p->localClient->tnode, &serv_list);
1478 rb_dlinkFindDestroy(source_p, &global_serv_list);
55abcbb2 1479
212380e3
AC
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 */
5203cba5 1486 snprintf(newcomment, sizeof(newcomment), "by %s: %s",
212380e3
AC
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 }
55abcbb2 1496
212380e3 1497 if(source_p->servptr && source_p->servptr->serv)
330fc5c1 1498 rb_dlinkDelete(&source_p->lnode, &source_p->servptr->serv->servers);
212380e3
AC
1499 else
1500 s_assert(0);
1501
1502
1503 close_connection(source_p);
55abcbb2 1504
212380e3
AC
1505 if(ConfigServerHide.flatten_links)
1506 strcpy(comment1, "*.net *.split");
1507 else
1508 {
66c8fdd2 1509 strcpy(comment1, source_p->servptr->name);
212380e3
AC
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.",
adc6cc42 1519 source_p->name, (long) rb_current_time() - source_p->localClient->firsttime, sendk, recvk);
212380e3
AC
1520
1521 ilog(L_SERVER, "%s was connected for %ld seconds. %d/%d sendK/recvK.",
adc6cc42 1522 source_p->name, (long) rb_current_time() - source_p->localClient->firsttime, sendk, recvk);
55abcbb2 1523
212380e3
AC
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);
994544c2 1529 scache_split(source_p->serv->nameinfo);
55abcbb2 1530
212380e3 1531 SetDead(source_p);
330fc5c1 1532 rb_dlinkAddAlloc(source_p, &dead_list);
212380e3
AC
1533 return 0;
1534}
1535
1536
55abcbb2 1537/*
07554369 1538 * This assumes IsPerson(source_p) == true && MyConnect(source_p) == true
212380e3
AC
1539 */
1540
1541static int
1542exit_local_client(struct Client *client_p, struct Client *source_p, struct Client *from,
1543 const char *comment)
1544{
1545 unsigned long on_for;
08d75d97 1546 char tbuf[26];
212380e3
AC
1547
1548 exit_generic_client(client_p, source_p, from, comment);
1549 clear_monitor(source_p);
1550
1551 s_assert(IsPerson(source_p));
330fc5c1
AC
1552 rb_dlinkDelete(&source_p->localClient->tnode, &lclient_list);
1553 rb_dlinkDelete(&source_p->lnode, &me.serv->users);
212380e3
AC
1554
1555 if(IsOper(source_p))
330fc5c1 1556 rb_dlinkFindDestroy(source_p, &local_oper_list);
212380e3
AC
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
e3354945 1570 on_for = rb_current_time() - source_p->localClient->firsttime;
212380e3 1571
9641f156 1572 ilog(L_USER, "%s (%3lu:%02lu:%02lu): %s!%s@%s %s %d/%d",
08d75d97 1573 rb_ctime(rb_current_time(), tbuf, sizeof(tbuf)), on_for / 3600,
212380e3
AC
1574 (on_for % 3600) / 60, on_for % 60,
1575 source_p->name, source_p->username, source_p->host,
9641f156 1576 source_p->sockhost,
212380e3
AC
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);
212380e3
AC
1586 }
1587
1588 SetDead(source_p);
330fc5c1 1589 rb_dlinkAddAlloc(source_p, &dead_list);
212380e3
AC
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)
cbeab4bc 1613 */
212380e3
AC
1614int
1615exit_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);
55abcbb2
KB
1653 }
1654 else
212380e3
AC
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 */
1671void
1672count_local_client_memory(size_t * count, size_t * local_client_memory_used)
1673{
1087485c
JT
1674 size_t lusage;
1675 rb_bh_usage(lclient_heap, count, NULL, &lusage, NULL);
adc6cc42 1676 *local_client_memory_used = lusage + (*count * (sizeof(void *) + sizeof(struct Client)));
212380e3
AC
1677}
1678
1679/*
1680 * Count up remote client memory
1681 */
1682void
1683count_remote_client_memory(size_t * count, size_t * remote_client_memory_used)
1684{
1087485c
JT
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;
adc6cc42 1689 *remote_client_memory_used = *count * (sizeof(void *) + sizeof(struct Client));
212380e3
AC
1690}
1691
1692
1693/*
1694 * accept processing, this adds a form of "caller ID" to ircd
55abcbb2 1695 *
212380e3 1696 * If a client puts themselves into "caller ID only" mode,
55abcbb2 1697 * only clients that match a client pointer they have put on
212380e3
AC
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
55abcbb2 1708 * from any client having an accept on them.
212380e3
AC
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 */
1718void
1719del_all_accepts(struct Client *client_p)
1720{
330fc5c1 1721 rb_dlink_node *ptr;
637c4932 1722 rb_dlink_node *next_ptr;
212380e3
AC
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 */
637c4932 1730 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->localClient->allow_list.head)
212380e3
AC
1731 {
1732 target_p = ptr->data;
330fc5c1
AC
1733 rb_dlinkFindDestroy(client_p, &target_p->on_allow_list);
1734 rb_dlinkDestroy(ptr, &client_p->localClient->allow_list);
212380e3
AC
1735 }
1736 }
1737
1738 /* remove this client from everyones accept list */
637c4932 1739 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->on_allow_list.head)
212380e3
AC
1740 {
1741 target_p = ptr->data;
330fc5c1
AC
1742 rb_dlinkFindDestroy(client_p, &target_p->localClient->allow_list);
1743 rb_dlinkDestroy(ptr, &client_p->on_allow_list);
212380e3
AC
1744 }
1745}
1746
1747/*
521f9d63 1748 * show_ip() - asks if the true IP should be shown when source is
55abcbb2 1749 * asking for info about target
212380e3
AC
1750 *
1751 * Inputs - source_p who is asking
1752 * - target_p who do we want the info on
521f9d63 1753 * Output - returns 1 if clear IP can be shown, otherwise 0
212380e3
AC
1754 * Side Effects - none
1755 */
1756
1757int
1758show_ip(struct Client *source_p, struct Client *target_p)
1759{
1760 if(IsAnyServer(target_p))
1761 {
212380e3
AC
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
1780int
1781show_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
364e59f8
JT
1794int
1795show_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
212380e3
AC
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 */
1814struct User *
1815make_user(struct Client *client_p)
1816{
1817 struct User *user;
1818
1819 user = client_p->user;
1820 if(!user)
1821 {
398b6a73 1822 user = (struct User *) rb_bh_alloc(user_heap);
212380e3
AC
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 */
8f103562 1837struct Server *
212380e3
AC
1838make_server(struct Client *client_p)
1839{
8f103562 1840 struct Server *serv = client_p->serv;
212380e3
AC
1841
1842 if(!serv)
1843 {
8f103562 1844 serv = (struct Server *) rb_malloc(sizeof(struct Server));
212380e3
AC
1845 client_p->serv = serv;
1846 }
1847 return client_p->serv;
1848}
1849
1850/*
1851 * free_user
55abcbb2 1852 *
212380e3
AC
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 */
1859void
1860free_user(struct User *user, struct Client *client_p)
1861{
c127b45b
SB
1862 free_away(client_p);
1863
212380e3
AC
1864 if(--user->refcnt <= 0)
1865 {
c127b45b
SB
1866 if(user->away)
1867 rb_free((char *) user->away);
212380e3
AC
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,
0b9aca38
AC
1874 "* %p user (%s!%s@%s) %p %p %p %lu %d *",
1875 client_p,
212380e3
AC
1876 client_p ? client_p->
1877 name : "<noname>",
1878 client_p->username,
1879 client_p->host,
0b9aca38
AC
1880 user,
1881 user->invited.head,
1882 user->channel.head,
330fc5c1 1883 rb_dlink_list_length(&user->channel),
212380e3
AC
1884 user->refcnt);
1885 s_assert(!user->refcnt);
1886 s_assert(!user->invited.head);
1887 s_assert(!user->channel.head);
1888 }
1889
398b6a73 1890 rb_bh_free(user_heap, user);
212380e3
AC
1891 }
1892}
1893
e581ea8e 1894void
c127b45b 1895allocate_away(struct Client *client_p)
e581ea8e 1896{
c127b45b 1897 if(client_p->user->away == NULL)
55abcbb2 1898 client_p->user->away = rb_bh_alloc(away_heap);
e581ea8e
AC
1899}
1900
c127b45b 1901
e581ea8e 1902void
c127b45b 1903free_away(struct Client *client_p)
e581ea8e 1904{
c127b45b
SB
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;
e581ea8e
AC
1908 }
1909}
1910
212380e3
AC
1911void
1912init_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
1926char *
1927generate_uid(void)
1928{
428f9bc1 1929 static int flipped = 0;
212380e3
AC
1930 int i;
1931
428f9bc1 1932uid_restart:
212380e3
AC
1933 for(i = 8; i > 3; i--)
1934 {
1935 if(current_uid[i] == 'Z')
1936 {
1937 current_uid[i] = '0';
428f9bc1 1938 goto out;
212380e3
AC
1939 }
1940 else if(current_uid[i] != '9')
1941 {
1942 current_uid[i]++;
428f9bc1 1943 goto out;
212380e3
AC
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';
428f9bc1 1953 flipped = 1;
212380e3
AC
1954 }
1955 else
1956 current_uid[i]++;
428f9bc1
AC
1957out:
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 }
212380e3
AC
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 */
1973void
1974close_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;
55abcbb2 1983
212380e3
AC
1984 if(IsServer(client_p))
1985 {
1986 struct server_conf *server_p;
1987
8bd5767b
JT
1988 ServerStats.is_sv++;
1989 ServerStats.is_sbs += client_p->localClient->sendB;
1990 ServerStats.is_sbr += client_p->localClient->receiveB;
679ccbe5 1991 ServerStats.is_sti += (unsigned long long)(rb_current_time() - client_p->localClient->firsttime);
212380e3
AC
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 {
8bd5767b
JT
2014 ServerStats.is_cl++;
2015 ServerStats.is_cbs += client_p->localClient->sendB;
2016 ServerStats.is_cbr += client_p->localClient->receiveB;
679ccbe5 2017 ServerStats.is_cti += (unsigned long long)(rb_current_time() - client_p->localClient->firsttime);
212380e3
AC
2018 }
2019 else
47adde3d 2020 ServerStats.is_ni++;
54ac8b60 2021
de7cf7e0 2022 client_release_connids(client_p);
36f0ec74 2023
c6d72037 2024 if(client_p->localClient->F != NULL)
54ac8b60
VY
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
734d420e
JT
2034 rb_linebuf_donebuf(&client_p->localClient->buf_sendq);
2035 rb_linebuf_donebuf(&client_p->localClient->buf_recvq);
212380e3
AC
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
2048void
2049error_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];
734d420e 2061 int current_error = rb_get_sockerr(client_p->localClient->F);
212380e3
AC
2062
2063 SetIOError(client_p);
2064
2065 if(IsServer(client_p) || IsHandshake(client_p))
2066 {
212380e3
AC
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",
b3ebc7ab 2071 client_p->name);
212380e3
AC
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 }
212380e3
AC
2084 }
2085
2086 if(error == 0)
f427c8b0 2087 rb_strlcpy(errmsg, "Remote host closed the connection", sizeof(errmsg));
212380e3 2088 else
5203cba5 2089 snprintf(errmsg, sizeof(errmsg), "Read error: %s", strerror(current_error));
212380e3
AC
2090
2091 exit_client(client_p, client_p, &me, errmsg);
2092}