/[svn]/ircd-hybrid/branches/8.2.x/src/client.c
ViewVC logotype

Contents of /ircd-hybrid/branches/8.2.x/src/client.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9870 - (show annotations)
Sun Jan 3 08:12:58 2021 UTC (19 months, 2 weeks ago) by michael
File MIME type: text/x-chdr
File size: 33457 byte(s)
- client.c:exit_client(): documenting

1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2021 ircd-hybrid development team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 * USA
20 */
21
22 /*! \file client.c
23 * \brief Controls clients.
24 * \version $Id$
25 */
26
27 #include "stdinc.h"
28 #include "list.h"
29 #include "client.h"
30 #include "client_svstag.h"
31 #include "event.h"
32 #include "hash.h"
33 #include "irc_string.h"
34 #include "ircd.h"
35 #include "numeric.h"
36 #include "auth.h"
37 #include "s_bsd.h"
38 #include "conf.h"
39 #include "conf_gecos.h"
40 #include "log.h"
41 #include "misc.h"
42 #include "server.h"
43 #include "send.h"
44 #include "whowas.h"
45 #include "user.h"
46 #include "memory.h"
47 #include "hostmask.h"
48 #include "listener.h"
49 #include "monitor.h"
50 #include "rng_mt.h"
51 #include "parse.h"
52 #include "ipcache.h"
53 #include "channel.h"
54 #include "channel_invite.h"
55
56
57 dlink_list listing_client_list;
58 dlink_list unknown_list;
59 dlink_list local_client_list;
60 dlink_list local_server_list;
61 dlink_list global_client_list;
62 dlink_list global_server_list;
63 dlink_list oper_list;
64
65 static dlink_list dead_list, abort_list;
66 static dlink_node *eac_next; /* next aborted client to exit */
67
68
69 /*
70 * client_make - create a new Client struct and set it to initial state.
71 *
72 * from == NULL, create local client (a client connected
73 * to a socket).
74 * WARNING: This leaves the client in a dangerous
75 * state where fd == -1, dead flag is not set and
76 * the client is on the unknown_list; therefore,
77 * the first thing to do after calling make_client(NULL)
78 * is setting fd to something reasonable. -adx
79 *
80 * from, create remote client (behind a socket
81 * associated with the client defined by
82 * 'from'). ('from' is a local client!!).
83 */
84 struct Client *
85 client_make(struct Client *from)
86 {
87 struct Client *client = xcalloc(sizeof(*client));
88
89 if (from)
90 client->from = from;
91 else
92 {
93 client->from = client; /* 'from' of local client is self! */
94 client->connection = xcalloc(sizeof(*client->connection));
95 client->connection->last_data = event_base->time.sec_monotonic;
96 client->connection->last_ping = event_base->time.sec_monotonic;
97 client->connection->created_real = event_base->time.sec_real;
98 client->connection->created_monotonic = event_base->time.sec_monotonic;
99 client->connection->registration = REG_INIT;
100
101 /* as good a place as any... */
102 dlinkAdd(client, &client->connection->lclient_node, &unknown_list);
103 }
104
105 client->idhnext = client;
106 client->hnext = client;
107 SetUnknown(client);
108 strcpy(client->username, "unknown");
109 strcpy(client->account, "*");
110
111 return client;
112 }
113
114 /*
115 * client_free
116 *
117 * inputs - pointer to client
118 * output - NONE
119 * side effects - client pointed to has its memory freed
120 */
121 static void
122 client_free(struct Client *client)
123 {
124 assert(!IsMe(client));
125 assert(client != &me);
126 assert(client->hnext == client);
127 assert(client->idhnext == client);
128
129 assert(client->node.prev == NULL);
130 assert(client->node.next == NULL);
131
132 assert(client->lnode.prev == NULL);
133 assert(client->lnode.next == NULL);
134
135 assert(dlink_list_length(&client->whowas_list) == 0);
136 assert(client->whowas_list.head == NULL);
137 assert(client->whowas_list.tail == NULL);
138
139 assert(dlink_list_length(&client->channel) == 0);
140 assert(client->channel.head == NULL);
141 assert(client->channel.tail == NULL);
142
143 assert(dlink_list_length(&client->svstags) == 0);
144 assert(client->svstags.head == NULL);
145 assert(client->svstags.tail == NULL);
146
147
148 xfree(client->serv);
149 xfree(client->tls_certfp);
150 xfree(client->tls_cipher);
151
152 if (MyConnect(client))
153 {
154 assert(client->connection->lclient_node.prev == NULL);
155 assert(client->connection->lclient_node.next == NULL);
156
157 assert(client->connection->list_task == NULL);
158 assert(client->connection->auth == NULL);
159
160 assert(dlink_list_length(&client->connection->acceptlist) == 0);
161 assert(client->connection->acceptlist.head == NULL);
162 assert(client->connection->acceptlist.tail == NULL);
163
164
165 assert(dlink_list_length(&client->connection->monitors) == 0);
166 assert(client->connection->monitors.head == NULL);
167 assert(client->connection->monitors.tail == NULL);
168
169 assert(dlink_list_length(&client->connection->confs) == 0);
170 assert(client->connection->confs.head == NULL);
171 assert(client->connection->confs.tail == NULL);
172
173 assert(dlink_list_length(&client->connection->invited) == 0);
174 assert(client->connection->invited.head == NULL);
175 assert(client->connection->invited.tail == NULL);
176
177 assert(client->connection->fd == NULL);
178
179 assert(HasFlag(client, FLAGS_CLOSING) && IsDead(client));
180
181 /*
182 * Clean up extra sockets from listen {} blocks which have been discarded.
183 */
184 if (client->connection->listener)
185 {
186 listener_release(client->connection->listener);
187 client->connection->listener = NULL;
188 }
189
190 dbuf_clear(&client->connection->buf_recvq);
191 dbuf_clear(&client->connection->buf_sendq);
192
193 xfree(client->connection);
194 client->connection = NULL;
195 }
196
197 xfree(client);
198 }
199
200 /* check_pings_list()
201 *
202 * inputs - pointer to list to check
203 * output - NONE
204 * side effects -
205 */
206 static void
207 check_pings_list(dlink_list *list)
208 {
209 char buf[32]; /* 32 = sizeof("Ping timeout: 999999999 seconds") */
210 dlink_node *node, *node_next;
211
212 DLINK_FOREACH_SAFE(node, node_next, list->head)
213 {
214 struct Client *client = node->data;
215 assert(IsClient(client) || IsServer(client));
216
217 if (IsDead(client))
218 continue; /* Ignore it, it's been exited already */
219
220 unsigned int ping = get_client_ping(&client->connection->confs);
221 if (ping < event_base->time.sec_monotonic - client->connection->last_ping)
222 {
223 if (!HasFlag(client, FLAGS_PINGSENT))
224 {
225 /*
226 * If we haven't PINGed the connection and we haven't
227 * heard from it in a while, PING it to make sure
228 * it is still alive.
229 */
230 AddFlag(client, FLAGS_PINGSENT);
231 client->connection->last_ping = event_base->time.sec_monotonic - ping;
232 sendto_one(client, "PING :%s", ID_or_name(&me, client));
233 }
234 else
235 {
236 if (event_base->time.sec_monotonic - client->connection->last_ping >= 2 * ping)
237 {
238 /*
239 * If the client/server hasn't talked to us in 2*ping seconds
240 * and it has a ping time, then close its connection.
241 */
242 if (IsServer(client))
243 {
244 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
245 "No response from %s, closing link",
246 client_get_name(client, SHOW_IP));
247 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
248 "No response from %s, closing link",
249 client_get_name(client, MASK_IP));
250 ilog(LOG_TYPE_IRCD, "No response from %s, closing link",
251 client_get_name(client, SHOW_IP));
252 }
253
254 snprintf(buf, sizeof(buf), "Ping timeout: %ju seconds",
255 (event_base->time.sec_monotonic - client->connection->last_ping));
256 exit_client(client, buf);
257 }
258 }
259 }
260 }
261 }
262
263 /* check_unknowns_list()
264 *
265 * inputs - pointer to list of unknown clients
266 * output - NONE
267 * side effects - unknown clients get marked for termination after n seconds
268 */
269 static void
270 check_unknowns_list(void)
271 {
272 dlink_node *node, *node_next;
273
274 DLINK_FOREACH_SAFE(node, node_next, unknown_list.head)
275 {
276 struct Client *client = node->data;
277 bool exit = false;
278
279 /*
280 * Check UNKNOWN connections - if they have been in this state
281 * for > 30s, close them.
282 */
283 if ((event_base->time.sec_monotonic - client->connection->created_monotonic) <= 30)
284 continue;
285
286 if (IsHandshake(client))
287 {
288 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
289 "No response from %s during handshake, closing link",
290 client_get_name(client, SHOW_IP));
291 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
292 "No response from %s during handshake, closing link",
293 client_get_name(client, MASK_IP));
294 ilog(LOG_TYPE_IRCD, "No response from %s during handshake, closing link",
295 client_get_name(client, SHOW_IP));
296 exit = true;
297 }
298 else if (HasFlag(client, FLAGS_FINISHED_AUTH))
299 exit = true;
300
301 if (exit == true)
302 exit_client(client, "Registration timed out");
303 }
304 }
305
306 /*
307 * check_pings - go through the local client list and check activity
308 * kill off stuff that should die
309 *
310 * inputs - NOT USED (from event)
311 * side effects -
312 *
313 *
314 * A PING can be sent to clients as necessary.
315 *
316 * Client/Server ping outs are handled.
317 */
318
319 /*
320 * Addon from adrian. We used to call this after nextping seconds,
321 * however I've changed it to run once a second. This is only for
322 * PING timeouts, not K/etc-line checks (thanks dianora!). Having it
323 * run once a second makes life a lot easier - when a new client connects
324 * and they need a ping in 4 seconds, if nextping was set to 20 seconds
325 * we end up waiting 20 seconds. This is stupid. :-)
326 * I will optimise (hah!) check_pings() once I've finished working on
327 * tidying up other network IO evilnesses.
328 * -- adrian
329 */
330
331 static void
332 check_pings(void *unused)
333 {
334 check_pings_list(&local_client_list);
335 check_pings_list(&local_server_list);
336 check_unknowns_list();
337 }
338
339 /* check_conf_klines()
340 *
341 * inputs - NONE
342 * output - NONE
343 * side effects - Check all connections for a pending kline against the
344 * client, exit the client if a kline matches.
345 */
346 void
347 check_conf_klines(void)
348 {
349 dlink_node *node, *node_next;
350 const void *ptr;
351
352 DLINK_FOREACH_SAFE(node, node_next, local_client_list.head)
353 {
354 struct Client *client = node->data;
355
356 /* If a client is already being exited */
357 if (IsDead(client))
358 continue;
359
360 if ((ptr = find_conf_by_address(NULL, &client->ip, CONF_DLINE, NULL, NULL, 1)))
361 {
362 const struct MaskItem *conf = ptr;
363 conf_try_ban(client, CLIENT_BAN_DLINE, conf->reason);
364 continue; /* and go examine next Client */
365 }
366
367 if ((ptr = find_conf_by_address(client->host, &client->ip, CONF_KLINE,
368 client->username, NULL, 1)))
369 {
370 const struct MaskItem *conf = ptr;
371 conf_try_ban(client, CLIENT_BAN_KLINE, conf->reason);
372 continue; /* and go examine next Client */
373 }
374
375 if ((ptr = gecos_find(client->info, match)))
376 {
377 const struct GecosItem *conf = ptr;
378 conf_try_ban(client, CLIENT_BAN_XLINE, conf->reason);
379 continue; /* and go examine next Client */
380 }
381 }
382
383 /* Also check the unknowns list for new dlines */
384 DLINK_FOREACH_SAFE(node, node_next, unknown_list.head)
385 {
386 struct Client *client = node->data;
387
388 /* If a client is already being exited */
389 if (IsDead(client))
390 continue;
391
392 if ((ptr = find_conf_by_address(NULL, &client->ip, CONF_DLINE, NULL, NULL, 1)))
393 {
394 const struct MaskItem *conf = ptr;
395 conf_try_ban(client, CLIENT_BAN_DLINE, conf->reason);
396 continue; /* and go examine next Client */
397 }
398 }
399 }
400
401 /*
402 * conf_try_ban
403 *
404 * inputs - pointer to client to ban
405 * - pointer to MaskItem
406 * output - NONE
407 * side effects - given client is banned
408 */
409 void
410 conf_try_ban(struct Client *client, int type, const char *reason)
411 {
412 char ban_type = '?';
413
414 switch (type)
415 {
416 case CLIENT_BAN_KLINE:
417 if (HasFlag(client, FLAGS_EXEMPTKLINE))
418 {
419 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
420 "KLINE over-ruled for %s, client is kline_exempt",
421 client_get_name(client, HIDE_IP));
422 return;
423 }
424
425 ban_type = 'K';
426 break;
427 case CLIENT_BAN_DLINE:
428 if (find_conf_by_address(NULL, &client->ip, CONF_EXEMPT, NULL, NULL, 1))
429 return;
430 ban_type = 'D';
431 break;
432 case CLIENT_BAN_XLINE:
433 if (HasFlag(client, FLAGS_EXEMPTXLINE))
434 {
435 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
436 "XLINE over-ruled for %s, client is xline_exempt",
437 client_get_name(client, HIDE_IP));
438 return;
439 }
440
441 ban_type = 'X';
442 break;
443 default:
444 assert(0);
445 break;
446 }
447
448 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE, "%c-line active for %s",
449 ban_type, client_get_name(client, HIDE_IP));
450
451 if (IsClient(client))
452 sendto_one_numeric(client, &me, ERR_YOUREBANNEDCREEP, reason);
453
454 exit_client(client, reason);
455 }
456
457 /* find_person()
458 *
459 * inputs - pointer to name
460 * output - return client pointer
461 * side effects - find person by (nick)name
462 */
463 struct Client *
464 find_person(const struct Client *source_p, const char *name)
465 {
466 struct Client *target_p = NULL;
467
468 if (IsDigit(*name))
469 {
470 if (IsServer(source_p->from))
471 target_p = hash_find_id(name);
472 }
473 else
474 target_p = hash_find_client(name);
475
476 if (target_p && IsClient(target_p))
477 return target_p;
478
479 return NULL;
480 }
481
482 /*
483 * find_chasing - find the client structure for a nick name (name)
484 * using history mechanism if necessary. If the client is not found,
485 * an error message (NO SUCH NICK) is generated.
486 */
487 struct Client *
488 find_chasing(struct Client *source_p, const char *name)
489 {
490 struct Client *target_p = find_person(source_p, name);
491
492 if (target_p)
493 return target_p;
494
495 if (IsDigit(*name))
496 return NULL;
497
498 target_p = whowas_get_history(name, ConfigGeneral.kill_chase_time_limit);
499 if (target_p == NULL)
500 sendto_one_numeric(source_p, &me, ERR_NOSUCHNICK, name);
501
502 return target_p;
503 }
504
505 /*
506 * client_get_name - Return the name of the client
507 * for various tracking and
508 * admin purposes. The main purpose of this function is to
509 * return the "socket host" name of the client, if that
510 * differs from the advertised name (other than case).
511 * But, this can be used to any client structure.
512 */
513 const char *
514 client_get_name(const struct Client *client, enum addr_mask_type type)
515 {
516 static char buf[HOSTLEN * 2 + USERLEN + 4]; /* +4 for [,@,],\0 */
517
518 if (!MyConnect(client))
519 return client->name;
520
521 if (IsServer(client) || IsConnecting(client) || IsHandshake(client))
522 {
523 if (irccmp(client->name, client->host) == 0)
524 return client->name;
525 else if (ConfigServerHide.hide_server_ips)
526 type = MASK_IP;
527 }
528
529 /* And finally, let's get the host information, ip or name */
530 switch (type)
531 {
532 case SHOW_IP:
533 snprintf(buf, sizeof(buf), "%s[%s@%s]",
534 client->name,
535 client->username, client->sockhost);
536 break;
537 case MASK_IP:
538 if (client->ip.ss.ss_family == AF_INET)
539 snprintf(buf, sizeof(buf), "%s[%s@255.255.255.255]",
540 client->name, client->username);
541 else
542 snprintf(buf, sizeof(buf), "%s[%s@ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]",
543 client->name, client->username);
544 break;
545 default: /* HIDE_IP */
546 snprintf(buf, sizeof(buf), "%s[%s@%s]",
547 client->name,
548 client->username, client->host);
549 }
550
551 return buf;
552 }
553
554 void
555 free_exited_clients(void)
556 {
557 dlink_node *node, *node_next;
558
559 DLINK_FOREACH_SAFE(node, node_next, dead_list.head)
560 {
561 client_free(node->data);
562 dlinkDelete(node, &dead_list);
563 free_dlink_node(node);
564 }
565 }
566
567 /*
568 * client_close_connection
569 * Close the physical connection. This function must make
570 * MyConnect(client) == FALSE, and set client->from == NULL.
571 */
572 static void
573 client_close_connection(struct Client *client)
574 {
575 assert(client);
576
577 if (!IsDead(client))
578 {
579 /* Attempt to flush any pending dbufs. Evil, but .. -- adrian */
580 /*
581 * There is still a chance that we might send data to this socket
582 * even if it is marked as blocked (COMM_SELECT_READ handler is called
583 * before COMM_SELECT_WRITE). Let's try, nothing to lose.. -adx
584 */
585 DelFlag(client, FLAGS_BLOCKED);
586 send_queued_write(client);
587 }
588
589 if (IsClient(client))
590 {
591 ++ServerStats.is_cl;
592 ServerStats.is_cbs += client->connection->send.bytes;
593 ServerStats.is_cbr += client->connection->recv.bytes;
594 ServerStats.is_cti += event_base->time.sec_monotonic - client->connection->created_monotonic;
595 }
596 else if (IsServer(client))
597 {
598 dlink_node *node;
599
600 ++ServerStats.is_sv;
601 ServerStats.is_sbs += client->connection->send.bytes;
602 ServerStats.is_sbr += client->connection->recv.bytes;
603 ServerStats.is_sti += event_base->time.sec_monotonic - client->connection->created_monotonic;
604
605 DLINK_FOREACH(node, connect_items.head)
606 {
607 struct MaskItem *conf = node->data;
608
609 /*
610 * Reset next-connect cycle of all connect{} blocks that match
611 * this servername.
612 */
613 if (irccmp(conf->name, client->name) == 0)
614 conf->until = event_base->time.sec_monotonic + conf->class->con_freq;
615 }
616 }
617 else
618 ++ServerStats.is_ni;
619
620 if (tls_isusing(&client->connection->fd->tls))
621 tls_shutdown(&client->connection->fd->tls);
622
623 if (client->connection->fd)
624 {
625 fd_close(client->connection->fd);
626 client->connection->fd = NULL;
627 }
628
629 dbuf_clear(&client->connection->buf_sendq);
630 dbuf_clear(&client->connection->buf_recvq);
631
632 xfree(client->connection->password);
633 client->connection->password = NULL;
634
635 conf_detach(client, CONF_CLIENT | CONF_OPER | CONF_SERVER);
636 }
637
638 /*
639 * Exit one client, local or remote. Assuming all dependents have
640 * been already removed, and socket closed for local client.
641 *
642 * The only messages generated are QUITs on channels.
643 */
644 static void
645 exit_one_client(struct Client *client, const char *comment)
646 {
647 dlink_node *node, *node_next;
648
649 assert(!IsMe(client));
650 assert(client != &me);
651
652 if (IsClient(client))
653 {
654 if (HasUMode(client, UMODE_OPER))
655 --Count.oper;
656 if (HasUMode(client, UMODE_INVISIBLE))
657 --Count.invisi;
658
659 dlinkDelete(&client->lnode, &client->servptr->serv->client_list);
660 dlinkDelete(&client->node, &global_client_list);
661
662 /*
663 * If a person is on a channel, send a QUIT notice
664 * to every client (person) on the same channel (so
665 * that the client can show the "**signoff" message).
666 * (Note: The notice is to the local clients *only*)
667 */
668 sendto_common_channels_local(client, false, 0, 0, ":%s!%s@%s QUIT :%s",
669 client->name, client->username,
670 client->host, comment);
671
672 DLINK_FOREACH_SAFE(node, node_next, client->channel.head)
673 remove_user_from_channel(node->data);
674
675 svstag_clear_list(&client->svstags);
676
677 whowas_add_history(client, false);
678 whowas_off_history(client);
679
680 monitor_signoff(client);
681 }
682 else if (IsServer(client))
683 {
684 sendto_realops_flags(UMODE_EXTERNAL, L_ALL, SEND_NOTICE,
685 "Server %s split from %s",
686 client->name, client->servptr->name);
687
688 dlinkDelete(&client->lnode, &client->servptr->serv->server_list);
689 dlinkDelete(&client->node, &global_server_list);
690 }
691
692 if (client->id[0])
693 hash_del_id(client);
694
695 if (client->name[0])
696 hash_del_client(client);
697
698 if (HasFlag(client, FLAGS_IPHASH))
699 {
700 DelFlag(client, FLAGS_IPHASH);
701 ipcache_record_remove(&client->ip, MyConnect(client));
702 }
703
704 /* Check to see if the client isn't already on the dead list */
705 assert(dlinkFind(&dead_list, client) == NULL);
706
707 /* Add to dead client dlist */
708 SetDead(client);
709 dlinkAdd(client, make_dlink_node(), &dead_list);
710 }
711
712 /*
713 * Remove all clients that depend on 'client'; assumes all (S)QUITs have
714 * already been sent. we make sure to exit a server's dependent clients
715 * and servers before the server itself; exit_one_client takes care of
716 * actually removing things off llists. tweaked from +CSr31 -orabidoo
717 */
718 static void
719 recurse_remove_clients(struct Client *client, const char *comment)
720 {
721 dlink_node *node, *node_next;
722
723 DLINK_FOREACH_SAFE(node, node_next, client->serv->client_list.head)
724 exit_one_client(node->data, comment);
725
726 DLINK_FOREACH_SAFE(node, node_next, client->serv->server_list.head)
727 {
728 recurse_remove_clients(node->data, comment);
729 exit_one_client(node->data, comment);
730 }
731 }
732
733 /*
734 * exit_client - exit a client of any type. Generally, you can use
735 * this on any struct Client, regardless of its state.
736 *
737 * Note, you shouldn't exit remote _users_ without first doing
738 * AddFlag(x, FLAGS_KILLED) and propagating a kill or similar message.
739 *
740 * However, it is perfectly correct to call exit_client to force a _server_
741 * quit (either local or remote one).
742 *
743 *
744 * inputs: - a client pointer that is going to be exited
745 * output: none
746 * side effects: the client is delinked from all lists, disconnected,
747 * and the rest of IRC network is notified of the exit.
748 * Client memory is scheduled to be freed
749 */
750 void
751 exit_client(struct Client *client, const char *comment)
752 {
753 assert(!IsMe(client));
754 assert(client != &me);
755
756 if (MyConnect(client))
757 {
758 assert(client == client->from);
759
760 /*
761 * DO NOT REMOVE. exit_client can be called twice after a failed read/write.
762 */
763 if (HasFlag(client, FLAGS_CLOSING))
764 return;
765
766 AddFlag(client, FLAGS_CLOSING);
767
768 if (client->connection->auth)
769 {
770 auth_delete(client->connection->auth);
771 client->connection->auth = NULL;
772 }
773
774 if (IsClient(client))
775 {
776 if (HasUMode(client, UMODE_OPER))
777 {
778 dlink_node *node = dlinkFindDelete(&oper_list, client);
779 if (node)
780 free_dlink_node(node);
781 }
782
783 assert(dlinkFind(&local_client_list, client));
784 dlinkDelete(&client->connection->lclient_node, &local_client_list);
785
786 if (client->connection->list_task)
787 free_list_task(client);
788
789 invite_clear_list(&client->connection->invited);
790 del_all_accepts(client);
791 monitor_clear_list(client);
792
793 sendto_realops_flags(UMODE_CCONN, L_ALL, SEND_NOTICE,
794 "Client exiting: %s (%s@%s) [%s] [%s]",
795 client->name, client->username, client->realhost,
796 client->sockhost, comment);
797
798 ilog(LOG_TYPE_USER, "%s (%ju): %s!%s@%s %s %s %ju/%ju :%s",
799 date_ctime(client->connection->created_real),
800 event_base->time.sec_monotonic - client->connection->created_monotonic,
801 client->name, client->username, client->host,
802 client->sockhost, client->account,
803 client->connection->send.bytes >> 10,
804 client->connection->recv.bytes >> 10, client->info);
805 }
806 else if (IsServer(client))
807 {
808 assert(dlinkFind(&local_server_list, client));
809 dlinkDelete(&client->connection->lclient_node, &local_server_list);
810
811 if (!HasFlag(client, FLAGS_SQUIT))
812 /* For them, we are exiting the network */
813 sendto_one(client, ":%s SQUIT %s :%s", me.id, me.id, comment);
814 }
815 else
816 {
817 assert(dlinkFind(&unknown_list, client));
818 dlinkDelete(&client->connection->lclient_node, &unknown_list);
819 }
820
821 sendto_one(client, "ERROR :Closing Link: %s (%s)", client->host, comment);
822
823 client_close_connection(client);
824 }
825 else if (IsClient(client) && HasFlag(client->servptr, FLAGS_EOB))
826 sendto_realops_flags(UMODE_FARCONNECT, L_ALL, SEND_NOTICE,
827 "Client exiting at %s: %s (%s@%s) [%s] [%s]",
828 client->servptr->name, client->name,
829 client->username, client->realhost, client->sockhost, comment);
830
831 if (IsServer(client))
832 {
833 char splitstr[HOSTLEN + HOSTLEN + 2]; /* +2 for space and \0 */
834
835 assert(client->serv);
836 assert(client->servptr);
837
838 if (ConfigServerHide.hide_servers)
839 /*
840 * Set netsplit message to "*.net *.split" to still show that it's a split,
841 * but hide the servers splitting.
842 */
843 strlcpy(splitstr, "*.net *.split", sizeof(splitstr));
844 else
845 snprintf(splitstr, sizeof(splitstr), "%s %s",
846 client->servptr->name, client->name);
847
848 /* Send SQUIT for 'client' in every direction. 'client' is already off of local_server_list here */
849 if (!HasFlag(client, FLAGS_SQUIT))
850 sendto_server(NULL, 0, 0, "SQUIT %s :%s", client->id, comment);
851
852 /* Now exit the clients internally */
853 recurse_remove_clients(client, splitstr);
854
855 if (MyConnect(client))
856 {
857 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
858 "%s was connected for %s. %ju/%ju sendK/recvK.",
859 client->name, time_dissect(event_base->time.sec_monotonic - client->connection->created_monotonic),
860 client->connection->send.bytes >> 10,
861 client->connection->recv.bytes >> 10);
862 ilog(LOG_TYPE_IRCD, "%s was connected for %s. %ju/%ju sendK/recvK.",
863 client->name, time_dissect(event_base->time.sec_monotonic - client->connection->created_monotonic),
864 client->connection->send.bytes >> 10,
865 client->connection->recv.bytes >> 10);
866 }
867 }
868 else if (IsClient(client) && !HasFlag(client, FLAGS_KILLED))
869 sendto_server(client->from, 0, 0, ":%s QUIT :%s", client->id, comment);
870
871 /* The client *better* be off all of the lists */
872 assert(dlinkFind(&unknown_list, client) == NULL);
873 assert(dlinkFind(&local_client_list, client) == NULL);
874 assert(dlinkFind(&local_server_list, client) == NULL);
875 assert(dlinkFind(&oper_list, client) == NULL);
876 assert(dlinkFind(&listing_client_list, client) == NULL);
877 assert(dlinkFind(&abort_list, client) == NULL);
878
879 exit_one_client(client, comment);
880 }
881
882 /*
883 * dead_link_on_write - report a write error if not already dead,
884 * mark it as dead then exit it
885 */
886 void
887 dead_link_on_write(struct Client *client, int ierrno)
888 {
889 dlink_node *node;
890
891 if (IsDefunct(client))
892 return;
893
894 dbuf_clear(&client->connection->buf_recvq);
895 dbuf_clear(&client->connection->buf_sendq);
896
897 assert(dlinkFind(&abort_list, client) == NULL);
898 node = make_dlink_node();
899 /* don't let exit_aborted_clients() finish yet */
900 dlinkAddTail(client, node, &abort_list);
901
902 if (eac_next == NULL)
903 eac_next = node;
904
905 SetDead(client); /* You are dead my friend */
906 }
907
908 /*
909 * dead_link_on_read - report a read error if not already dead,
910 * mark it as dead then exit it
911 */
912 void
913 dead_link_on_read(struct Client *client, int error)
914 {
915 char errmsg[IRCD_BUFSIZE];
916 int current_error;
917
918 if (IsDefunct(client))
919 return;
920
921 dbuf_clear(&client->connection->buf_recvq);
922 dbuf_clear(&client->connection->buf_sendq);
923
924 current_error = comm_get_sockerr(client->connection->fd);
925
926 if (IsServer(client) || IsHandshake(client))
927 {
928 if (error == 0)
929 {
930 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
931 "Server %s closed the connection",
932 client_get_name(client, SHOW_IP));
933 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
934 "Server %s closed the connection",
935 client_get_name(client, MASK_IP));
936 ilog(LOG_TYPE_IRCD, "Server %s closed the connection",
937 client_get_name(client, SHOW_IP));
938 }
939 else
940 {
941 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
942 "Lost connection to %s: %s",
943 client_get_name(client, SHOW_IP), strerror(current_error));
944 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
945 "Lost connection to %s: %s",
946 client_get_name(client, MASK_IP), strerror(current_error));
947 ilog(LOG_TYPE_IRCD, "Lost connection to %s: %s",
948 client_get_name(client, SHOW_IP), strerror(current_error));
949 }
950
951 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
952 "%s was connected for %s",
953 client->name, time_dissect(event_base->time.sec_monotonic - client->connection->created_monotonic));
954 }
955
956 if (error == 0)
957 strlcpy(errmsg, "Remote host closed the connection",
958 sizeof(errmsg));
959 else
960 snprintf(errmsg, sizeof(errmsg), "Read error: %s",
961 strerror(current_error));
962
963 exit_client(client, errmsg);
964 }
965
966 void
967 exit_aborted_clients(void)
968 {
969 dlink_node *ptr;
970 const char *notice;
971
972 DLINK_FOREACH_SAFE(ptr, eac_next, abort_list.head)
973 {
974 struct Client *client = ptr->data;
975 eac_next = ptr->next;
976
977 dlinkDelete(ptr, &abort_list);
978 free_dlink_node(ptr);
979
980 if (client == NULL)
981 {
982 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
983 "Warning: null client on abort_list!");
984 continue;
985 }
986
987 if (HasFlag(client, FLAGS_SENDQEX))
988 notice = "Max SendQ exceeded";
989 else
990 notice = "Write error: connection closed";
991
992 exit_client(client, notice);
993 }
994 }
995
996 /*
997 * accept processing, this adds a form of "caller ID" to ircd
998 *
999 * If a client puts themselves into "caller ID only" mode,
1000 * only clients that match a client pointer they have put on
1001 * the accept list will be allowed to message them.
1002 *
1003 * Diane Bruce, "Dianora" db@db.net
1004 */
1005
1006 void
1007 del_accept(struct split_nuh_item *accept_p, struct Client *client)
1008 {
1009 dlinkDelete(&accept_p->node, &client->connection->acceptlist);
1010
1011 xfree(accept_p->nickptr);
1012 xfree(accept_p->userptr);
1013 xfree(accept_p->hostptr);
1014 xfree(accept_p);
1015 }
1016
1017 struct split_nuh_item *
1018 find_accept(const char *nick, const char *user,
1019 const char *host, struct Client *client,
1020 int (*compare)(const char *, const char *))
1021 {
1022 dlink_node *node;
1023
1024 DLINK_FOREACH(node, client->connection->acceptlist.head)
1025 {
1026 struct split_nuh_item *accept_p = node->data;
1027
1028 if (compare(accept_p->nickptr, nick) == 0 &&
1029 compare(accept_p->userptr, user) == 0 &&
1030 compare(accept_p->hostptr, host) == 0)
1031 return accept_p;
1032 }
1033
1034 return NULL;
1035 }
1036
1037 /* accept_message()
1038 *
1039 * inputs - pointer to source client
1040 * - pointer to target client
1041 * output - 1 if accept this message 0 if not
1042 * side effects - See if source is on target's allow list
1043 */
1044 bool
1045 accept_message(struct Client *source,
1046 struct Client *target)
1047 {
1048 dlink_node *node;
1049
1050 if (HasFlag(source, FLAGS_SERVICE) ||
1051 (HasUMode(source, UMODE_OPER) && ConfigGeneral.opers_bypass_callerid))
1052 return true;
1053
1054 if (source == target || find_accept(source->name, source->username,
1055 source->host, target, match))
1056 return true;
1057
1058 if (!HasUMode(target, UMODE_CALLERID) && HasUMode(target, UMODE_SOFTCALLERID))
1059 DLINK_FOREACH(node, target->channel.head)
1060 if (member_find_link(source, ((struct ChannelMember *)node->data)->channel))
1061 return true;
1062
1063 return false;
1064 }
1065
1066 /* del_all_accepts()
1067 *
1068 * inputs - pointer to exiting client
1069 * output - NONE
1070 * side effects - Walk through given clients acceptlist and remove all entries
1071 */
1072 void
1073 del_all_accepts(struct Client *client)
1074 {
1075 dlink_node *node, *node_next;
1076
1077 DLINK_FOREACH_SAFE(node, node_next, client->connection->acceptlist.head)
1078 del_accept(node->data, client);
1079 }
1080
1081 unsigned int
1082 client_get_idle_time(const struct Client *source_p,
1083 const struct Client *target_p)
1084 {
1085 unsigned int idle = 0;
1086 const struct ClassItem *const class = class_get_ptr(&target_p->connection->confs);
1087
1088 if (!(class->flags & CLASS_FLAGS_FAKE_IDLE) || target_p == source_p)
1089 return event_base->time.sec_monotonic - target_p->connection->last_privmsg;
1090
1091 if (HasUMode(source_p, UMODE_OPER) &&
1092 !(class->flags & CLASS_FLAGS_HIDE_IDLE_FROM_OPERS))
1093 return event_base->time.sec_monotonic - target_p->connection->last_privmsg;
1094
1095 const unsigned int min_idle = class->min_idle;
1096 const unsigned int max_idle = class->max_idle;
1097
1098 if (min_idle == max_idle)
1099 return min_idle;
1100
1101 if (class->flags & CLASS_FLAGS_RANDOM_IDLE)
1102 idle = genrand_int32();
1103 else
1104 idle = event_base->time.sec_monotonic - target_p->connection->last_privmsg;
1105
1106 if (max_idle)
1107 idle %= max_idle;
1108 else
1109 idle = 0;
1110
1111 if (idle < min_idle)
1112 idle = min_idle + (idle % (max_idle - min_idle));
1113
1114 return idle;
1115 }
1116
1117 /* client_init()
1118 *
1119 * inputs - NONE
1120 * output - NONE
1121 * side effects - initialize client free memory
1122 */
1123 void
1124 client_init(void)
1125 {
1126 static struct event event_ping =
1127 {
1128 .name = "check_pings",
1129 .handler = check_pings,
1130 .when = 5
1131 };
1132
1133 event_add(&event_ping, NULL);
1134 }

Properties

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

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