/[svn]/ircd-hybrid-8/src/client.c
ViewVC logotype

Contents of /ircd-hybrid-8/src/client.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1529 - (show annotations)
Sun Sep 16 10:27:19 2012 UTC (7 years, 9 months ago) by michael
File MIME type: text/x-chdr
File size: 37532 byte(s)
- removed server hostmasking leftovers

1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * client.c: Controls clients.
4 *
5 * Copyright (C) 2002 by the past and present ircd coders, and others.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 * $Id$
23 */
24
25 #include "stdinc.h"
26 #include "list.h"
27 #include "client.h"
28 #include "channel_mode.h"
29 #include "event.h"
30 #include "fdlist.h"
31 #include "hash.h"
32 #include "irc_string.h"
33 #include "ircd.h"
34 #include "s_gline.h"
35 #include "numeric.h"
36 #include "packet.h"
37 #include "s_auth.h"
38 #include "s_bsd.h"
39 #include "conf.h"
40 #include "log.h"
41 #include "s_misc.h"
42 #include "s_serv.h"
43 #include "send.h"
44 #include "whowas.h"
45 #include "s_user.h"
46 #include "dbuf.h"
47 #include "memory.h"
48 #include "hostmask.h"
49 #include "balloc.h"
50 #include "listener.h"
51 #include "irc_res.h"
52 #include "userhost.h"
53 #include "watch.h"
54
55 dlink_list listing_client_list = { NULL, NULL, 0 };
56 /* Pointer to beginning of Client list */
57 dlink_list global_client_list = {NULL, NULL, 0};
58 /* unknown/client pointer lists */
59 dlink_list unknown_list = {NULL, NULL, 0};
60 dlink_list local_client_list = {NULL, NULL, 0};
61 dlink_list serv_list = {NULL, NULL, 0};
62 dlink_list global_serv_list = {NULL, NULL, 0};
63 dlink_list oper_list = {NULL, NULL, 0};
64
65 static EVH check_pings;
66
67 static BlockHeap *client_heap = NULL;
68 static BlockHeap *lclient_heap = NULL;
69
70 static dlink_list dead_list = { NULL, NULL, 0};
71 static dlink_list abort_list = { NULL, NULL, 0};
72
73 static dlink_node *eac_next; /* next aborted client to exit */
74
75 static void check_pings_list(dlink_list *);
76 static void check_unknowns_list(void);
77 static void ban_them(struct Client *, struct ConfItem *);
78
79
80 /* init_client()
81 *
82 * inputs - NONE
83 * output - NONE
84 * side effects - initialize client free memory
85 */
86 void
87 init_client(void)
88 {
89 /* start off the check ping event .. -- adrian
90 * Every 30 seconds is plenty -- db
91 */
92 client_heap = BlockHeapCreate("client", sizeof(struct Client), CLIENT_HEAP_SIZE);
93 lclient_heap = BlockHeapCreate("local client", sizeof(struct LocalUser), LCLIENT_HEAP_SIZE);
94 eventAdd("check_pings", check_pings, NULL, 5);
95 }
96
97 /*
98 * make_client - create a new Client struct and set it to initial state.
99 *
100 * from == NULL, create local client (a client connected
101 * to a socket).
102 * WARNING: This leaves the client in a dangerous
103 * state where fd == -1, dead flag is not set and
104 * the client is on the unknown_list; therefore,
105 * the first thing to do after calling make_client(NULL)
106 * is setting fd to something reasonable. -adx
107 *
108 * from, create remote client (behind a socket
109 * associated with the client defined by
110 * 'from'). ('from' is a local client!!).
111 */
112 struct Client *
113 make_client(struct Client *from)
114 {
115 struct Client *client_p = BlockHeapAlloc(client_heap);
116
117 if (from == NULL)
118 {
119 client_p->from = client_p; /* 'from' of local client is self! */
120 client_p->localClient = BlockHeapAlloc(lclient_heap);
121 client_p->localClient->since = CurrentTime;
122 client_p->localClient->lasttime = CurrentTime;
123 client_p->localClient->firsttime = CurrentTime;
124 client_p->localClient->registration = REG_INIT;
125
126 /* as good a place as any... */
127 dlinkAdd(client_p, &client_p->localClient->lclient_node, &unknown_list);
128 }
129 else
130 client_p->from = from; /* 'from' of local client is self! */
131
132 client_p->idhnext = client_p;
133 client_p->hnext = client_p;
134 client_p->status = STAT_UNKNOWN;
135 strcpy(client_p->username, "unknown");
136
137 return client_p;
138 }
139
140 /*
141 * free_client
142 *
143 * inputs - pointer to client
144 * output - NONE
145 * side effects - client pointed to has its memory freed
146 */
147 static void
148 free_client(struct Client *client_p)
149 {
150 assert(client_p != NULL);
151 assert(client_p != &me);
152 assert(client_p->hnext == client_p);
153 assert(client_p->idhnext == client_p);
154 assert(client_p->channel.head == NULL);
155 assert(dlink_list_length(&client_p->channel) == 0);
156 assert(dlink_list_length(&client_p->whowas) == 0);
157 assert(!IsServer(client_p) || IsServer(client_p) && client_p->serv);
158
159 MyFree(client_p->serv);
160
161 if (MyConnect(client_p))
162 {
163 assert(client_p->localClient->invited.head == NULL);
164 assert(dlink_list_length(&client_p->localClient->invited) == 0);
165 assert(dlink_list_length(&client_p->localClient->watches) == 0);
166 assert(IsClosing(client_p) && IsDead(client_p));
167
168 MyFree(client_p->localClient->response);
169 MyFree(client_p->localClient->auth_oper);
170
171 /*
172 * clean up extra sockets from P-lines which have been discarded.
173 */
174 if (client_p->localClient->listener)
175 {
176 assert(0 < client_p->localClient->listener->ref_count);
177 if (0 == --client_p->localClient->listener->ref_count &&
178 !client_p->localClient->listener->active)
179 free_listener(client_p->localClient->listener);
180 }
181
182 dbuf_clear(&client_p->localClient->buf_recvq);
183 dbuf_clear(&client_p->localClient->buf_sendq);
184
185 BlockHeapFree(lclient_heap, client_p->localClient);
186 }
187
188 BlockHeapFree(client_heap, client_p);
189 }
190
191 /*
192 * check_pings - go through the local client list and check activity
193 * kill off stuff that should die
194 *
195 * inputs - NOT USED (from event)
196 * output - next time_t when check_pings() should be called again
197 * side effects -
198 *
199 *
200 * A PING can be sent to clients as necessary.
201 *
202 * Client/Server ping outs are handled.
203 */
204
205 /*
206 * Addon from adrian. We used to call this after nextping seconds,
207 * however I've changed it to run once a second. This is only for
208 * PING timeouts, not K/etc-line checks (thanks dianora!). Having it
209 * run once a second makes life a lot easier - when a new client connects
210 * and they need a ping in 4 seconds, if nextping was set to 20 seconds
211 * we end up waiting 20 seconds. This is stupid. :-)
212 * I will optimise (hah!) check_pings() once I've finished working on
213 * tidying up other network IO evilnesses.
214 * -- adrian
215 */
216
217 static void
218 check_pings(void *notused)
219 {
220 check_pings_list(&local_client_list);
221 check_pings_list(&serv_list);
222 check_unknowns_list();
223 }
224
225 /* check_pings_list()
226 *
227 * inputs - pointer to list to check
228 * output - NONE
229 * side effects -
230 */
231 static void
232 check_pings_list(dlink_list *list)
233 {
234 char scratch[32]; /* way too generous but... */
235 struct Client *client_p; /* current local client_p being examined */
236 int ping, pingwarn; /* ping time value from client */
237 dlink_node *ptr, *next_ptr;
238
239 DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
240 {
241 client_p = ptr->data;
242
243 /*
244 ** Note: No need to notify opers here. It's
245 ** already done when "FLAGS_DEADSOCKET" is set.
246 */
247 if (IsDead(client_p))
248 {
249 /* Ignore it, its been exited already */
250 continue;
251 }
252
253 if (client_p->localClient->reject_delay > 0)
254 {
255 if (client_p->localClient->reject_delay <= CurrentTime)
256 exit_client(client_p, &me, "Rejected");
257 continue;
258 }
259
260 if (!IsRegistered(client_p))
261 ping = CONNECTTIMEOUT, pingwarn = 0;
262 else
263 ping = get_client_ping(client_p, &pingwarn);
264
265 if (ping < CurrentTime - client_p->localClient->lasttime)
266 {
267 if (!IsPingSent(client_p))
268 {
269 /*
270 * if we havent PINGed the connection and we havent
271 * heard from it in a while, PING it to make sure
272 * it is still alive.
273 */
274 SetPingSent(client_p);
275 ClearPingWarning(client_p);
276 client_p->localClient->lasttime = CurrentTime - ping;
277 sendto_one(client_p, "PING :%s", ID_or_name(&me, client_p));
278 }
279 else
280 {
281 if (CurrentTime - client_p->localClient->lasttime >= 2 * ping)
282 {
283 /*
284 * If the client/server hasn't talked to us in 2*ping seconds
285 * and it has a ping time, then close its connection.
286 */
287 if (IsServer(client_p) || IsHandshake(client_p))
288 {
289 sendto_realops_flags(UMODE_ALL, L_ADMIN,
290 "No response from %s, closing link",
291 get_client_name(client_p, HIDE_IP));
292 sendto_realops_flags(UMODE_ALL, L_OPER,
293 "No response from %s, closing link",
294 get_client_name(client_p, MASK_IP));
295 ilog(LOG_TYPE_IRCD, "No response from %s, closing link",
296 get_client_name(client_p, HIDE_IP));
297 }
298
299 snprintf(scratch, sizeof(scratch), "Ping timeout: %d seconds",
300 (int)(CurrentTime - client_p->localClient->lasttime));
301 exit_client(client_p, &me, scratch);
302 }
303 else if (!IsPingWarning(client_p) && pingwarn > 0 &&
304 (IsServer(client_p) || IsHandshake(client_p)) &&
305 CurrentTime - client_p->localClient->lasttime >= ping + pingwarn)
306 {
307 /*
308 * If the server hasn't replied in pingwarn seconds after sending
309 * the PING, notify the opers so that they are aware of the problem.
310 */
311 SetPingWarning(client_p);
312 sendto_realops_flags(UMODE_ALL, L_ADMIN,
313 "Warning, no response from %s in %d seconds",
314 get_client_name(client_p, HIDE_IP), pingwarn);
315 sendto_realops_flags(UMODE_ALL, L_OPER,
316 "Warning, no response from %s in %d seconds",
317 get_client_name(client_p, MASK_IP), pingwarn);
318 ilog(LOG_TYPE_IRCD, "No response from %s in %d seconds",
319 get_client_name(client_p, HIDE_IP), pingwarn);
320 }
321 }
322 }
323 }
324 }
325
326 /* check_unknowns_list()
327 *
328 * inputs - pointer to list of unknown clients
329 * output - NONE
330 * side effects - unknown clients get marked for termination after n seconds
331 */
332 static void
333 check_unknowns_list(void)
334 {
335 dlink_node *ptr, *next_ptr;
336
337 DLINK_FOREACH_SAFE(ptr, next_ptr, unknown_list.head)
338 {
339 struct Client *client_p = ptr->data;
340
341 if (client_p->localClient->reject_delay > 0)
342 {
343 if (client_p->localClient->reject_delay <= CurrentTime)
344 exit_client(client_p, &me, "Rejected");
345 continue;
346 }
347
348 /*
349 * Check UNKNOWN connections - if they have been in this state
350 * for > 30s, close them.
351 */
352 if (IsAuthFinished(client_p) && (CurrentTime - client_p->localClient->firsttime) > 30)
353 exit_client(client_p, &me, "Registration timed out");
354 }
355 }
356
357 /* check_conf_klines()
358 *
359 * inputs - NONE
360 * output - NONE
361 * side effects - Check all connections for a pending kline against the
362 * client, exit the client if a kline matches.
363 */
364 void
365 check_conf_klines(void)
366 {
367 struct Client *client_p = NULL; /* current local client_p being examined */
368 struct AccessItem *aconf = NULL;
369 struct ConfItem *conf = NULL;
370 dlink_node *ptr, *next_ptr;
371
372 DLINK_FOREACH_SAFE(ptr, next_ptr, local_client_list.head)
373 {
374 client_p = ptr->data;
375
376 /* If a client is already being exited
377 */
378 if (IsDead(client_p) || !IsClient(client_p))
379 continue;
380
381 /* if there is a returned struct ConfItem then kill it */
382 if ((aconf = find_dline_conf(&client_p->localClient->ip,
383 client_p->localClient->aftype)) != NULL)
384 {
385 if (aconf->status & CONF_EXEMPTDLINE)
386 continue;
387
388 conf = unmap_conf_item(aconf);
389 ban_them(client_p, conf);
390 continue; /* and go examine next fd/client_p */
391 }
392
393 if (ConfigFileEntry.glines && (aconf = find_gline(client_p)))
394 {
395 if (IsExemptKline(client_p) ||
396 IsExemptGline(client_p))
397 {
398 sendto_realops_flags(UMODE_ALL, L_ALL,
399 "GLINE over-ruled for %s, client is %sline_exempt",
400 get_client_name(client_p, HIDE_IP), IsExemptKline(client_p) ? "k" : "g");
401 continue;
402 }
403
404 conf = unmap_conf_item(aconf);
405 ban_them(client_p, conf);
406 /* and go examine next fd/client_p */
407 continue;
408 }
409
410 if ((aconf = find_kill(client_p)) != NULL)
411 {
412
413 /* if there is a returned struct AccessItem.. then kill it */
414 if (IsExemptKline(client_p))
415 {
416 sendto_realops_flags(UMODE_ALL, L_ALL,
417 "KLINE over-ruled for %s, client is kline_exempt",
418 get_client_name(client_p, HIDE_IP));
419 continue;
420 }
421
422 conf = unmap_conf_item(aconf);
423 ban_them(client_p, conf);
424 continue;
425 }
426
427 /* if there is a returned struct MatchItem then kill it */
428 if ((conf = find_matching_name_conf(XLINE_TYPE, client_p->info,
429 NULL, NULL, 0)) != NULL ||
430 (conf = find_matching_name_conf(RXLINE_TYPE, client_p->info,
431 NULL, NULL, 0)) != NULL)
432 {
433 ban_them(client_p, conf);
434 continue;
435 }
436 }
437
438 /* also check the unknowns list for new dlines */
439 DLINK_FOREACH_SAFE(ptr, next_ptr, unknown_list.head)
440 {
441 client_p = ptr->data;
442
443 if ((aconf = find_dline_conf(&client_p->localClient->ip,
444 client_p->localClient->aftype)))
445 {
446 if (aconf->status & CONF_EXEMPTDLINE)
447 continue;
448
449 exit_client(client_p, &me, "D-lined");
450 }
451 }
452 }
453
454 /*
455 * ban_them
456 *
457 * inputs - pointer to client to ban
458 * - pointer to ConfItem
459 * output - NONE
460 * side effects - given client_p is banned
461 */
462 static void
463 ban_them(struct Client *client_p, struct ConfItem *conf)
464 {
465 const char *user_reason = NULL; /* What is sent to user */
466 const char *channel_reason = NULL; /* What is sent to channel */
467 struct AccessItem *aconf = NULL;
468 struct MatchItem *xconf = NULL;
469 const char *type_string = NULL;
470 const char dline_string[] = "D-line";
471 const char kline_string[] = "K-line";
472 const char gline_string[] = "G-line";
473 const char xline_string[] = "X-line";
474
475 switch (conf->type)
476 {
477 case RKLINE_TYPE:
478 case KLINE_TYPE:
479 type_string = kline_string;
480 aconf = map_to_conf(conf);
481 break;
482 case DLINE_TYPE:
483 type_string = dline_string;
484 aconf = map_to_conf(conf);
485 break;
486 case GLINE_TYPE:
487 type_string = gline_string;
488 aconf = map_to_conf(conf);
489 break;
490 case RXLINE_TYPE:
491 case XLINE_TYPE:
492 type_string = xline_string;
493 xconf = map_to_conf(conf);
494 ++xconf->count;
495 break;
496 default:
497 assert(0);
498 break;
499 }
500
501 if (ConfigFileEntry.kline_with_reason)
502 {
503 if (aconf != NULL)
504 user_reason = aconf->reason ? aconf->reason : type_string;
505 if (xconf != NULL)
506 user_reason = xconf->reason ? xconf->reason : type_string;
507 }
508 else
509 user_reason = type_string;
510
511 if (ConfigFileEntry.kline_reason != NULL)
512 channel_reason = ConfigFileEntry.kline_reason;
513 else
514 channel_reason = user_reason;
515
516 sendto_realops_flags(UMODE_ALL, L_ALL, "%s active for %s",
517 type_string, get_client_name(client_p, HIDE_IP));
518
519 if (IsClient(client_p))
520 sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP),
521 me.name, client_p->name, user_reason);
522
523 exit_client(client_p, &me, channel_reason);
524 }
525
526 /* update_client_exit_stats()
527 *
528 * input - pointer to client
529 * output - NONE
530 * side effects -
531 */
532 static void
533 update_client_exit_stats(struct Client *client_p)
534 {
535 if (IsClient(client_p))
536 {
537 assert(Count.total > 0);
538 --Count.total;
539 if (HasUMode(client_p, UMODE_OPER))
540 --Count.oper;
541 if (HasUMode(client_p, UMODE_INVISIBLE))
542 --Count.invisi;
543 }
544 else if (IsServer(client_p))
545 sendto_realops_flags(UMODE_EXTERNAL, L_ALL, "Server %s split from %s",
546 client_p->name, client_p->servptr->name);
547
548 if (splitchecking && !splitmode)
549 check_splitmode(NULL);
550 }
551
552 /* find_person()
553 *
554 * inputs - pointer to name
555 * output - return client pointer
556 * side effects - find person by (nick)name
557 */
558 struct Client *
559 find_person(const struct Client *client_p, const char *name)
560 {
561 struct Client *c2ptr;
562
563 if (IsDigit(*name))
564 {
565 if ((c2ptr = hash_find_id(name)) != NULL)
566 {
567 /* invisible users shall not be found by UID guessing */
568 if (HasUMode(c2ptr, UMODE_INVISIBLE) && !IsServer(client_p))
569 c2ptr = NULL;
570 }
571 }
572 else
573 c2ptr = hash_find_client(name);
574
575 return ((c2ptr != NULL && IsClient(c2ptr)) ? c2ptr : NULL);
576 }
577
578 /*
579 * find_chasing - find the client structure for a nick name (user)
580 * using history mechanism if necessary. If the client is not found,
581 * an error message (NO SUCH NICK) is generated. If the client was found
582 * through the history, chasing will be 1 and otherwise 0.
583 */
584 struct Client *
585 find_chasing(struct Client *client_p, struct Client *source_p, const char *user, int *chasing)
586 {
587 struct Client *who = find_person(client_p, user);
588
589 if (chasing)
590 *chasing = 0;
591
592 if (who)
593 return who;
594
595 if (IsDigit(*user))
596 return NULL;
597
598 if ((who = get_history(user,
599 (time_t)ConfigFileEntry.kill_chase_time_limit))
600 == NULL)
601 {
602 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
603 me.name, source_p->name, user);
604 return NULL;
605 }
606
607 if (chasing)
608 *chasing = 1;
609
610 return who;
611 }
612
613 /*
614 * get_client_name - Return the name of the client
615 * for various tracking and
616 * admin purposes. The main purpose of this function is to
617 * return the "socket host" name of the client, if that
618 * differs from the advertised name (other than case).
619 * But, this can be used to any client structure.
620 *
621 * NOTE 1:
622 * Watch out the allocation of "nbuf", if either source_p->name
623 * or source_p->sockhost gets changed into pointers instead of
624 * directly allocated within the structure...
625 *
626 * NOTE 2:
627 * Function return either a pointer to the structure (source_p) or
628 * to internal buffer (nbuf). *NEVER* use the returned pointer
629 * to modify what it points!!!
630 */
631 const char *
632 get_client_name(const struct Client *client, enum addr_mask_type type)
633 {
634 static char nbuf[HOSTLEN * 2 + USERLEN + 5];
635
636 assert(client != NULL);
637
638 if (!MyConnect(client))
639 return client->name;
640
641 if (IsServer(client) || IsConnecting(client) || IsHandshake(client))
642 {
643 if (!irccmp(client->name, client->host))
644 return client->name;
645 else if (ConfigServerHide.hide_server_ips)
646 type = MASK_IP;
647 }
648
649 if (ConfigFileEntry.hide_spoof_ips)
650 if (type == SHOW_IP && IsIPSpoof(client))
651 type = MASK_IP;
652
653 /* And finally, let's get the host information, ip or name */
654 switch (type)
655 {
656 case SHOW_IP:
657 snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
658 client->name,
659 client->username, client->sockhost);
660 break;
661 case MASK_IP:
662 if (client->localClient->aftype == AF_INET)
663 snprintf(nbuf, sizeof(nbuf), "%s[%s@255.255.255.255]",
664 client->name, client->username);
665 else
666 snprintf(nbuf, sizeof(nbuf), "%s[%s@ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]",
667 client->name, client->username);
668 break;
669 default:
670 snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
671 client->name,
672 client->username, client->host);
673 }
674
675 return nbuf;
676 }
677
678 void
679 free_exited_clients(void)
680 {
681 dlink_node *ptr = NULL, *next = NULL;
682
683 DLINK_FOREACH_SAFE(ptr, next, dead_list.head)
684 {
685 free_client(ptr->data);
686 dlinkDelete(ptr, &dead_list);
687 free_dlink_node(ptr);
688 }
689 }
690
691 /*
692 * Exit one client, local or remote. Assuming all dependents have
693 * been already removed, and socket closed for local client.
694 *
695 * The only messages generated are QUITs on channels.
696 */
697 static void
698 exit_one_client(struct Client *source_p, const char *quitmsg)
699 {
700 dlink_node *lp = NULL, *next_lp = NULL;
701
702 assert(!IsMe(source_p));
703
704 if (IsClient(source_p))
705 {
706 if (source_p->servptr->serv != NULL)
707 dlinkDelete(&source_p->lnode, &source_p->servptr->serv->client_list);
708
709 /*
710 * If a person is on a channel, send a QUIT notice
711 * to every client (person) on the same channel (so
712 * that the client can show the "**signoff" message).
713 * (Note: The notice is to the local clients *only*)
714 */
715 sendto_common_channels_local(source_p, 0, ":%s!%s@%s QUIT :%s",
716 source_p->name, source_p->username,
717 source_p->host, quitmsg);
718 DLINK_FOREACH_SAFE(lp, next_lp, source_p->channel.head)
719 remove_user_from_channel(lp->data);
720
721 add_history(source_p, 0);
722 off_history(source_p);
723
724 watch_check_hash(source_p, RPL_LOGOFF);
725
726 if (MyConnect(source_p))
727 {
728 /* Clean up invitefield */
729 DLINK_FOREACH_SAFE(lp, next_lp, source_p->localClient->invited.head)
730 del_invite(lp->data, source_p);
731
732 del_all_accepts(source_p);
733 }
734 }
735 else if (IsServer(source_p))
736 {
737 dlinkDelete(&source_p->lnode, &source_p->servptr->serv->server_list);
738
739 if ((lp = dlinkFindDelete(&global_serv_list, source_p)) != NULL)
740 free_dlink_node(lp);
741 }
742
743 /* Remove source_p from the client lists */
744 if (HasID(source_p))
745 hash_del_id(source_p);
746 if (source_p->name[0])
747 hash_del_client(source_p);
748
749 if (IsUserHostIp(source_p))
750 delete_user_host(source_p->username, source_p->host, !MyConnect(source_p));
751
752 /* remove from global client list
753 * NOTE: source_p->node.next cannot be NULL if the client is added
754 * to global_client_list (there is always &me at its end)
755 */
756 if (source_p != NULL && source_p->node.next != NULL)
757 dlinkDelete(&source_p->node, &global_client_list);
758
759 update_client_exit_stats(source_p);
760
761 /* Check to see if the client isn't already on the dead list */
762 assert(dlinkFind(&dead_list, source_p) == NULL);
763
764 /* add to dead client dlist */
765 SetDead(source_p);
766 dlinkAdd(source_p, make_dlink_node(), &dead_list);
767 }
768
769 /* Recursively send QUITs and SQUITs for source_p and all its dependent clients
770 * and servers to those servers that need them. A server needs the client
771 * QUITs if it can't figure them out from the SQUIT (ie pre-TS4) or if it
772 * isn't getting the SQUIT because of @#(*&@)# hostmasking. With TS4, once
773 * a link gets a SQUIT, it doesn't need any QUIT/SQUITs for clients depending
774 * on that one -orabidoo
775 *
776 * This is now called on each local server -adx
777 */
778 static void
779 recurse_send_quits(struct Client *original_source_p, struct Client *source_p,
780 struct Client *from, struct Client *to, const char *comment,
781 const char *splitstr)
782 {
783 dlink_node *ptr, *next;
784 struct Client *target_p;
785
786 assert(to != source_p); /* should be already removed from serv_list */
787
788 /* If this server can handle quit storm (QS) removal
789 * of dependents, just send the SQUIT
790 */
791 if (!IsCapable(to, CAP_QS))
792 DLINK_FOREACH_SAFE(ptr, next, source_p->serv->client_list.head)
793 {
794 target_p = ptr->data;
795 sendto_one(to, ":%s QUIT :%s", target_p->name, splitstr);
796 }
797
798 DLINK_FOREACH_SAFE(ptr, next, source_p->serv->server_list.head)
799 recurse_send_quits(original_source_p, ptr->data, from, to,
800 comment, splitstr);
801
802 if ((source_p == original_source_p && to != from) ||
803 !IsCapable(to, CAP_QS))
804 {
805 /* don't use a prefix here - we have to be 100% sure the message
806 * will be accepted without Unknown prefix etc.. */
807 sendto_one(to, "SQUIT %s :%s", ID_or_name(source_p, to), comment);
808 }
809 }
810
811 /*
812 * Remove all clients that depend on source_p; assumes all (S)QUITs have
813 * already been sent. we make sure to exit a server's dependent clients
814 * and servers before the server itself; exit_one_client takes care of
815 * actually removing things off llists. tweaked from +CSr31 -orabidoo
816 */
817 static void
818 recurse_remove_clients(struct Client *source_p, const char *quitmsg)
819 {
820 dlink_node *ptr, *next;
821
822 DLINK_FOREACH_SAFE(ptr, next, source_p->serv->client_list.head)
823 exit_one_client(ptr->data, quitmsg);
824
825 DLINK_FOREACH_SAFE(ptr, next, source_p->serv->server_list.head)
826 {
827 recurse_remove_clients(ptr->data, quitmsg);
828 exit_one_client(ptr->data, quitmsg);
829 }
830 }
831
832 /*
833 ** Remove *everything* that depends on source_p, from all lists, and sending
834 ** all necessary QUITs and SQUITs. source_p itself is still on the lists,
835 ** and its SQUITs have been sent except for the upstream one -orabidoo
836 */
837 static void
838 remove_dependents(struct Client *source_p, struct Client *from,
839 const char *comment, const char *splitstr)
840 {
841 dlink_node *ptr = NULL;
842
843 DLINK_FOREACH(ptr, serv_list.head)
844 recurse_send_quits(source_p, source_p, from, ptr->data,
845 comment, splitstr);
846
847 recurse_remove_clients(source_p, splitstr);
848 }
849
850 /*
851 * exit_client - exit a client of any type. Generally, you can use
852 * this on any struct Client, regardless of its state.
853 *
854 * Note, you shouldn't exit remote _users_ without first doing
855 * AddFlag(x, FLAGS_KILLED) and propagating a kill or similar message.
856 * However, it is perfectly correct to call exit_client to force a _server_
857 * quit (either local or remote one).
858 *
859 * inputs: - a client pointer that is going to be exited
860 * - for servers, the second argument is a pointer to who
861 * is firing the server. This side won't get any generated
862 * messages. NEVER NULL!
863 * output: none
864 * side effects: the client is delinked from all lists, disconnected,
865 * and the rest of IRC network is notified of the exit.
866 * Client memory is scheduled to be freed
867 */
868 void
869 exit_client(struct Client *source_p, struct Client *from, const char *comment)
870 {
871 dlink_node *m = NULL;
872
873 if (MyConnect(source_p))
874 {
875 /* DO NOT REMOVE. exit_client can be called twice after a failed
876 * read/write.
877 */
878 if (IsClosing(source_p))
879 return;
880
881 SetClosing(source_p);
882
883 if (IsIpHash(source_p))
884 remove_one_ip(&source_p->localClient->ip);
885
886 if (source_p->localClient->auth)
887 {
888 delete_auth(source_p->localClient->auth);
889 source_p->localClient->auth = NULL;
890 }
891
892 /* This source_p could have status of one of STAT_UNKNOWN, STAT_CONNECTING
893 * STAT_HANDSHAKE or STAT_UNKNOWN
894 * all of which are lumped together into unknown_list
895 *
896 * In all above cases IsRegistered() will not be true.
897 */
898 if (!IsRegistered(source_p))
899 {
900 assert(dlinkFind(&unknown_list, source_p));
901
902 dlinkDelete(&source_p->localClient->lclient_node, &unknown_list);
903 }
904 else if (IsClient(source_p))
905 {
906 time_t on_for = CurrentTime - source_p->localClient->firsttime;
907 assert(Count.local > 0);
908 Count.local--;
909
910 if (HasUMode(source_p, UMODE_OPER))
911 {
912 if ((m = dlinkFindDelete(&oper_list, source_p)) != NULL)
913 free_dlink_node(m);
914 }
915
916 assert(dlinkFind(&local_client_list, source_p));
917 dlinkDelete(&source_p->localClient->lclient_node, &local_client_list);
918
919 if (source_p->localClient->list_task != NULL)
920 free_list_task(source_p->localClient->list_task, source_p);
921
922 watch_del_watch_list(source_p);
923 sendto_realops_flags(UMODE_CCONN, L_ALL, "Client exiting: %s (%s@%s) [%s] [%s]",
924 source_p->name, source_p->username, source_p->host, comment,
925 ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ?
926 "255.255.255.255" : source_p->sockhost);
927 sendto_realops_flags(UMODE_CCONN_FULL, L_ALL, "CLIEXIT: %s %s %s %s 0 %s",
928 source_p->name,
929 source_p->username,
930 source_p->host,
931 ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ?
932 "255.255.255.255" : source_p->sockhost,
933 comment);
934 ilog(LOG_TYPE_USER, "%s (%3u:%02u:%02u): %s!%s@%s %llu/%llu",
935 myctime(source_p->localClient->firsttime), (unsigned int)(on_for / 3600),
936 (unsigned int)((on_for % 3600)/60), (unsigned int)(on_for % 60),
937 source_p->name, source_p->username, source_p->host,
938 source_p->localClient->send.bytes>>10,
939 source_p->localClient->recv.bytes>>10);
940 }
941
942 /* As soon as a client is known to be a server of some sort
943 * it has to be put on the serv_list, or SJOIN's to this new server
944 * from the connect burst will not be seen.
945 * XXX - TBV. This is not true. The only place where we put a server on
946 * serv_list is in server_estab right now after registration process.
947 * And only after this, a burst is sent to the remote server, i.e. we never
948 * send a burst to STAT_CONNECTING, or STAT_HANDSHAKE. This will need
949 * more investigation later on, but for now, it's not a problem after all.
950 */
951 if (IsServer(source_p) || IsConnecting(source_p) ||
952 IsHandshake(source_p))
953 {
954 if (dlinkFind(&serv_list, source_p))
955 {
956 dlinkDelete(&source_p->localClient->lclient_node, &serv_list);
957 unset_chcap_usage_counts(source_p);
958 }
959
960 if (IsServer(source_p))
961 Count.myserver--;
962 }
963
964 if (!IsDead(source_p))
965 {
966 if (IsServer(source_p))
967 {
968 /* for them, we are exiting the network */
969 sendto_one(source_p, ":%s SQUIT %s :%s",
970 ID_or_name(from, source_p), me.name, comment);
971 }
972
973 sendto_one(source_p, "ERROR :Closing Link: %s (%s)",
974 source_p->host, comment);
975 }
976
977 /*
978 ** Currently only server connections can have
979 ** depending remote clients here, but it does no
980 ** harm to check for all local clients. In
981 ** future some other clients than servers might
982 ** have remotes too...
983 **
984 ** Close the Client connection first and mark it
985 ** so that no messages are attempted to send to it.
986 ** Remember it makes source_p->from == NULL.
987 */
988 close_connection(source_p);
989 }
990
991 if (IsServer(source_p))
992 {
993 char splitstr[HOSTLEN + HOSTLEN + 2];
994
995 /* This shouldn't ever happen */
996 assert(source_p->serv != NULL && source_p->servptr != NULL);
997
998 if (ConfigServerHide.hide_servers)
999 /*
1000 * Set netsplit message to "*.net *.split" to still show
1001 * that its a split, but hide the servers splitting
1002 */
1003 strcpy(splitstr, "*.net *.split");
1004 else
1005 snprintf(splitstr, sizeof(splitstr), "%s %s",
1006 source_p->servptr->name, source_p->name);
1007
1008 remove_dependents(source_p, from->from, comment, splitstr);
1009
1010 if (source_p->servptr == &me)
1011 {
1012 sendto_realops_flags(UMODE_ALL, L_ALL,
1013 "%s was connected for %d seconds. %llu/%llu sendK/recvK.",
1014 source_p->name, (int)(CurrentTime - source_p->localClient->firsttime),
1015 source_p->localClient->send.bytes >> 10,
1016 source_p->localClient->recv.bytes >> 10);
1017 ilog(LOG_TYPE_IRCD, "%s was connected for %d seconds. %llu/%llu sendK/recvK.",
1018 source_p->name, (int)(CurrentTime - source_p->localClient->firsttime),
1019 source_p->localClient->send.bytes >> 10,
1020 source_p->localClient->recv.bytes >> 10);
1021 }
1022 }
1023 else if (IsClient(source_p) && !HasFlag(source_p, FLAGS_KILLED))
1024 {
1025 sendto_server(from->from, CAP_TS6, NOCAPS,
1026 ":%s QUIT :%s", ID(source_p), comment);
1027 sendto_server(from->from, NOCAPS, CAP_TS6,
1028 ":%s QUIT :%s", source_p->name, comment);
1029 }
1030
1031 /* The client *better* be off all of the lists */
1032 assert(dlinkFind(&unknown_list, source_p) == NULL);
1033 assert(dlinkFind(&local_client_list, source_p) == NULL);
1034 assert(dlinkFind(&serv_list, source_p) == NULL);
1035 assert(dlinkFind(&oper_list, source_p) == NULL);
1036
1037 exit_one_client(source_p, comment);
1038 }
1039
1040 /*
1041 * dead_link_on_write - report a write error if not already dead,
1042 * mark it as dead then exit it
1043 */
1044 void
1045 dead_link_on_write(struct Client *client_p, int ierrno)
1046 {
1047 dlink_node *ptr;
1048
1049 if (IsDefunct(client_p))
1050 return;
1051
1052 dbuf_clear(&client_p->localClient->buf_recvq);
1053 dbuf_clear(&client_p->localClient->buf_sendq);
1054
1055 assert(dlinkFind(&abort_list, client_p) == NULL);
1056 ptr = make_dlink_node();
1057 /* don't let exit_aborted_clients() finish yet */
1058 dlinkAddTail(client_p, ptr, &abort_list);
1059
1060 if (eac_next == NULL)
1061 eac_next = ptr;
1062
1063 SetDead(client_p); /* You are dead my friend */
1064 }
1065
1066 /*
1067 * dead_link_on_read - report a read error if not already dead,
1068 * mark it as dead then exit it
1069 */
1070 void
1071 dead_link_on_read(struct Client *client_p, int error)
1072 {
1073 char errmsg[255];
1074 int current_error;
1075
1076 if (IsDefunct(client_p))
1077 return;
1078
1079 dbuf_clear(&client_p->localClient->buf_recvq);
1080 dbuf_clear(&client_p->localClient->buf_sendq);
1081
1082 current_error = get_sockerr(client_p->localClient->fd.fd);
1083
1084 if (IsServer(client_p) || IsHandshake(client_p))
1085 {
1086 int connected = CurrentTime - client_p->localClient->firsttime;
1087
1088 if (error == 0)
1089 {
1090 /* Admins get the real IP */
1091 sendto_realops_flags(UMODE_ALL, L_ADMIN,
1092 "Server %s closed the connection",
1093 get_client_name(client_p, SHOW_IP));
1094
1095 /* Opers get a masked IP */
1096 sendto_realops_flags(UMODE_ALL, L_OPER,
1097 "Server %s closed the connection",
1098 get_client_name(client_p, MASK_IP));
1099
1100 ilog(LOG_TYPE_IRCD, "Server %s closed the connection",
1101 get_client_name(client_p, SHOW_IP));
1102 }
1103 else
1104 {
1105 report_error(L_ADMIN, "Lost connection to %s: %s",
1106 get_client_name(client_p, SHOW_IP), current_error);
1107 report_error(L_OPER, "Lost connection to %s: %s",
1108 get_client_name(client_p, MASK_IP), current_error);
1109 }
1110
1111 sendto_realops_flags(UMODE_ALL, L_ALL,
1112 "%s had been connected for %d day%s, %2d:%02d:%02d",
1113 client_p->name, connected/86400,
1114 (connected/86400 == 1) ? "" : "s",
1115 (connected % 86400) / 3600, (connected % 3600) / 60,
1116 connected % 60);
1117 }
1118
1119 if (error == 0)
1120 strlcpy(errmsg, "Remote host closed the connection",
1121 sizeof(errmsg));
1122 else
1123 snprintf(errmsg, sizeof(errmsg), "Read error: %s",
1124 strerror(current_error));
1125
1126 exit_client(client_p, &me, errmsg);
1127 }
1128
1129 void
1130 exit_aborted_clients(void)
1131 {
1132 dlink_node *ptr;
1133 struct Client *target_p;
1134 const char *notice;
1135
1136 DLINK_FOREACH_SAFE(ptr, eac_next, abort_list.head)
1137 {
1138 target_p = ptr->data;
1139 eac_next = ptr->next;
1140
1141 if (target_p == NULL)
1142 {
1143 sendto_realops_flags(UMODE_ALL, L_ALL,
1144 "Warning: null client on abort_list!");
1145 dlinkDelete(ptr, &abort_list);
1146 free_dlink_node(ptr);
1147 continue;
1148 }
1149
1150 dlinkDelete(ptr, &abort_list);
1151
1152 if (IsSendQExceeded(target_p))
1153 notice = "Max SendQ exceeded";
1154 else
1155 notice = "Write error: connection closed";
1156
1157 exit_client(target_p, &me, notice);
1158 free_dlink_node(ptr);
1159 }
1160 }
1161
1162 /*
1163 * accept processing, this adds a form of "caller ID" to ircd
1164 *
1165 * If a client puts themselves into "caller ID only" mode,
1166 * only clients that match a client pointer they have put on
1167 * the accept list will be allowed to message them.
1168 *
1169 * Diane Bruce, "Dianora" db@db.net
1170 */
1171
1172 void
1173 del_accept(struct split_nuh_item *accept_p, struct Client *client_p)
1174 {
1175 dlinkDelete(&accept_p->node, &client_p->localClient->acceptlist);
1176
1177 MyFree(accept_p->nickptr);
1178 MyFree(accept_p->userptr);
1179 MyFree(accept_p->hostptr);
1180 MyFree(accept_p);
1181 }
1182
1183 struct split_nuh_item *
1184 find_accept(const char *nick, const char *user,
1185 const char *host, struct Client *client_p, int do_match)
1186 {
1187 dlink_node *ptr = NULL;
1188 /* XXX We wouldn't need that if match() would return 0 on match */
1189 int (*cmpfunc)(const char *, const char *) = do_match ? match : irccmp;
1190
1191 DLINK_FOREACH(ptr, client_p->localClient->acceptlist.head)
1192 {
1193 struct split_nuh_item *accept_p = ptr->data;
1194
1195 if (cmpfunc(accept_p->nickptr, nick) == do_match &&
1196 cmpfunc(accept_p->userptr, user) == do_match &&
1197 cmpfunc(accept_p->hostptr, host) == do_match)
1198 return accept_p;
1199 }
1200
1201 return NULL;
1202 }
1203
1204 /* accept_message()
1205 *
1206 * inputs - pointer to source client
1207 * - pointer to target client
1208 * output - 1 if accept this message 0 if not
1209 * side effects - See if source is on target's allow list
1210 */
1211 int
1212 accept_message(struct Client *source,
1213 struct Client *target)
1214 {
1215 dlink_node *ptr = NULL;
1216
1217 if (source == target || find_accept(source->name, source->username,
1218 source->host, target, 1))
1219 return 1;
1220
1221 if (HasUMode(target, UMODE_SOFTCALLERID))
1222 DLINK_FOREACH(ptr, target->channel.head)
1223 if (IsMember(source, ((struct Membership *)ptr->data)->chptr))
1224 return 1;
1225
1226 return 0;
1227 }
1228
1229 /* del_all_accepts()
1230 *
1231 * inputs - pointer to exiting client
1232 * output - NONE
1233 * side effects - Walk through given clients acceptlist and remove all entries
1234 */
1235 void
1236 del_all_accepts(struct Client *client_p)
1237 {
1238 dlink_node *ptr = NULL, *next_ptr = NULL;
1239
1240 DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->localClient->acceptlist.head)
1241 del_accept(ptr->data, client_p);
1242 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28