ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/src/client.c
Revision: 10190
Committed: Sun Jul 10 09:55:04 2022 UTC (21 months, 1 week ago) by michael
Content type: text/x-csrc
File size: 33322 byte(s)
Log Message:
- Renamings: add_user_to_channel -> channel_add_user, remove_user_from_channel -> channel_remove_user

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2022 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 = class_get_ping_freq(&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 channel_remove_user(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
791 accept_clear_list(&client->connection->acceptlist);
792
793 monitor_clear_list(client);
794
795 sendto_realops_flags(UMODE_CCONN, L_ALL, SEND_NOTICE,
796 "Client exiting: %s (%s@%s) [%s] [%s]",
797 client->name, client->username, client->realhost,
798 client->sockhost, comment);
799
800 ilog(LOG_TYPE_USER, "%s (%ju): %s!%s@%s %s %s %ju/%ju :%s",
801 date_ctime(client->connection->created_real),
802 event_base->time.sec_monotonic - client->connection->created_monotonic,
803 client->name, client->username, client->host,
804 client->sockhost, client->account,
805 client->connection->send.bytes >> 10,
806 client->connection->recv.bytes >> 10, client->info);
807 }
808 else if (IsServer(client))
809 {
810 assert(dlinkFind(&local_server_list, client));
811 dlinkDelete(&client->connection->lclient_node, &local_server_list);
812
813 if (!HasFlag(client, FLAGS_SQUIT))
814 /* For them, we are exiting the network */
815 sendto_one(client, ":%s SQUIT %s :%s", me.id, me.id, comment);
816 }
817 else
818 {
819 assert(dlinkFind(&unknown_list, client));
820 dlinkDelete(&client->connection->lclient_node, &unknown_list);
821 }
822
823 sendto_one(client, "ERROR :Closing Link: %s (%s)", client->host, comment);
824
825 client_close_connection(client);
826 }
827 else if (IsClient(client) && HasFlag(client->servptr, FLAGS_EOB))
828 sendto_realops_flags(UMODE_FARCONNECT, L_ALL, SEND_NOTICE,
829 "Client exiting at %s: %s (%s@%s) [%s] [%s]",
830 client->servptr->name, client->name,
831 client->username, client->realhost, client->sockhost, comment);
832
833 if (IsServer(client))
834 {
835 char splitstr[HOSTLEN + HOSTLEN + 2]; /* +2 for space and \0 */
836
837 assert(client->serv);
838 assert(client->servptr);
839
840 if (ConfigServerHide.hide_servers)
841 /*
842 * Set netsplit message to "*.net *.split" to still show that it's a split,
843 * but hide the servers splitting.
844 */
845 strlcpy(splitstr, "*.net *.split", sizeof(splitstr));
846 else
847 snprintf(splitstr, sizeof(splitstr), "%s %s",
848 client->servptr->name, client->name);
849
850 /* Send SQUIT for 'client' in every direction. 'client' is already off of local_server_list here */
851 if (!HasFlag(client, FLAGS_SQUIT))
852 sendto_server(NULL, 0, 0, "SQUIT %s :%s", client->id, comment);
853
854 /* Now exit the clients internally */
855 recurse_remove_clients(client, splitstr);
856
857 if (MyConnect(client))
858 {
859 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
860 "%s was connected for %s. %ju/%ju sendK/recvK.",
861 client->name, time_dissect(event_base->time.sec_monotonic - client->connection->created_monotonic),
862 client->connection->send.bytes >> 10,
863 client->connection->recv.bytes >> 10);
864 ilog(LOG_TYPE_IRCD, "%s was connected for %s. %ju/%ju sendK/recvK.",
865 client->name, time_dissect(event_base->time.sec_monotonic - client->connection->created_monotonic),
866 client->connection->send.bytes >> 10,
867 client->connection->recv.bytes >> 10);
868 }
869 }
870 else if (IsClient(client) && !HasFlag(client, FLAGS_KILLED))
871 sendto_server(client->from, 0, 0, ":%s QUIT :%s", client->id, comment);
872
873 /* The client *better* be off all of the lists */
874 assert(dlinkFind(&unknown_list, client) == NULL);
875 assert(dlinkFind(&local_client_list, client) == NULL);
876 assert(dlinkFind(&local_server_list, client) == NULL);
877 assert(dlinkFind(&oper_list, client) == NULL);
878 assert(dlinkFind(&listing_client_list, client) == NULL);
879 assert(dlinkFind(&abort_list, client) == NULL);
880
881 exit_one_client(client, comment);
882 }
883
884 /*
885 * dead_link_on_write - report a write error if not already dead,
886 * mark it as dead then exit it
887 */
888 void
889 dead_link_on_write(struct Client *client, int ierrno)
890 {
891 dlink_node *node;
892
893 if (IsDefunct(client))
894 return;
895
896 dbuf_clear(&client->connection->buf_recvq);
897 dbuf_clear(&client->connection->buf_sendq);
898
899 assert(dlinkFind(&abort_list, client) == NULL);
900 node = make_dlink_node();
901 /* don't let exit_aborted_clients() finish yet */
902 dlinkAddTail(client, node, &abort_list);
903
904 if (eac_next == NULL)
905 eac_next = node;
906
907 SetDead(client); /* You are dead my friend */
908 }
909
910 /*
911 * dead_link_on_read - report a read error if not already dead,
912 * mark it as dead then exit it
913 */
914 void
915 dead_link_on_read(struct Client *client, int error)
916 {
917 char errmsg[IRCD_BUFSIZE];
918 int current_error;
919
920 if (IsDefunct(client))
921 return;
922
923 dbuf_clear(&client->connection->buf_recvq);
924 dbuf_clear(&client->connection->buf_sendq);
925
926 current_error = comm_get_sockerr(client->connection->fd);
927
928 if (IsServer(client) || IsHandshake(client))
929 {
930 if (error == 0)
931 {
932 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
933 "Server %s closed the connection",
934 client_get_name(client, SHOW_IP));
935 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
936 "Server %s closed the connection",
937 client_get_name(client, MASK_IP));
938 ilog(LOG_TYPE_IRCD, "Server %s closed the connection",
939 client_get_name(client, SHOW_IP));
940 }
941 else
942 {
943 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
944 "Lost connection to %s: %s",
945 client_get_name(client, SHOW_IP), strerror(current_error));
946 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
947 "Lost connection to %s: %s",
948 client_get_name(client, MASK_IP), strerror(current_error));
949 ilog(LOG_TYPE_IRCD, "Lost connection to %s: %s",
950 client_get_name(client, SHOW_IP), strerror(current_error));
951 }
952
953 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
954 "%s was connected for %s",
955 client->name, time_dissect(event_base->time.sec_monotonic - client->connection->created_monotonic));
956 }
957
958 if (error == 0)
959 strlcpy(errmsg, "Remote host closed the connection",
960 sizeof(errmsg));
961 else
962 snprintf(errmsg, sizeof(errmsg), "Read error: %s",
963 strerror(current_error));
964
965 exit_client(client, errmsg);
966 }
967
968 void
969 exit_aborted_clients(void)
970 {
971 dlink_node *ptr;
972 const char *notice;
973
974 DLINK_FOREACH_SAFE(ptr, eac_next, abort_list.head)
975 {
976 struct Client *client = ptr->data;
977 eac_next = ptr->next;
978
979 dlinkDelete(ptr, &abort_list);
980 free_dlink_node(ptr);
981
982 if (client == NULL)
983 {
984 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
985 "Warning: null client on abort_list!");
986 continue;
987 }
988
989 if (HasFlag(client, FLAGS_SENDQEX))
990 notice = "Max SendQ exceeded";
991 else
992 notice = "Write error: connection closed";
993
994 exit_client(client, notice);
995 }
996 }
997
998 /*
999 * accept processing, this adds a form of "caller ID" to ircd
1000 *
1001 * If a client puts themselves into "caller ID only" mode,
1002 * only clients that match a client pointer they have put on
1003 * the accept list will be allowed to message them.
1004 *
1005 * Diane Bruce, "Dianora" db@db.net
1006 */
1007
1008 void
1009 accept_del(struct AcceptItem *accept, dlink_list *list)
1010 {
1011 dlinkDelete(&accept->node, list);
1012
1013 xfree(accept->nick);
1014 xfree(accept->user);
1015 xfree(accept->host);
1016 xfree(accept);
1017 }
1018
1019 struct AcceptItem *
1020 accept_find(const char *nick,
1021 const char *user,
1022 const char *host, dlink_list *list,
1023 int (*compare)(const char *, const char *))
1024 {
1025 dlink_node *node;
1026
1027 DLINK_FOREACH(node, list->head)
1028 {
1029 struct AcceptItem *accept = node->data;
1030
1031 if (compare(accept->nick, nick) == 0 &&
1032 compare(accept->user, user) == 0 &&
1033 compare(accept->host, host) == 0)
1034 return accept;
1035 }
1036
1037 return NULL;
1038 }
1039
1040 /* accept_message()
1041 *
1042 * inputs - pointer to source client
1043 * - pointer to target client
1044 * output - 1 if accept this message 0 if not
1045 * side effects - See if source is on target's allow list
1046 */
1047 bool
1048 accept_message(struct Client *source,
1049 struct Client *target)
1050 {
1051 dlink_node *node;
1052
1053 if (HasFlag(source, FLAGS_SERVICE) ||
1054 (HasUMode(source, UMODE_OPER) && ConfigGeneral.opers_bypass_callerid))
1055 return true;
1056
1057 if (source == target || accept_find(source->name, source->username, source->host,
1058 &target->connection->acceptlist, match))
1059 return true;
1060
1061 if (!HasUMode(target, UMODE_CALLERID) && HasUMode(target, UMODE_SOFTCALLERID))
1062 DLINK_FOREACH(node, target->channel.head)
1063 if (member_find_link(source, ((struct ChannelMember *)node->data)->channel))
1064 return true;
1065
1066 return false;
1067 }
1068
1069 /* del_all_accepts()
1070 *
1071 * inputs - pointer to exiting client
1072 * output - NONE
1073 * side effects - Walk through given clients acceptlist and remove all entries
1074 */
1075 void
1076 accept_clear_list(dlink_list *list)
1077 {
1078 while (list->head)
1079 accept_del(list->head->data, list);
1080 }
1081
1082 unsigned int
1083 client_get_idle_time(const struct Client *source_p,
1084 const struct Client *target_p)
1085 {
1086 unsigned int idle = 0;
1087 const struct ClassItem *const class = class_get_ptr(&target_p->connection->confs);
1088
1089 if (!(class->flags & CLASS_FLAGS_FAKE_IDLE) || target_p == source_p)
1090 return event_base->time.sec_monotonic - target_p->connection->last_privmsg;
1091
1092 if (HasUMode(source_p, UMODE_OPER) &&
1093 !(class->flags & CLASS_FLAGS_HIDE_IDLE_FROM_OPERS))
1094 return event_base->time.sec_monotonic - target_p->connection->last_privmsg;
1095
1096 const unsigned int min_idle = class->min_idle;
1097 const unsigned int max_idle = class->max_idle;
1098
1099 if (min_idle == max_idle)
1100 return min_idle;
1101
1102 if (class->flags & CLASS_FLAGS_RANDOM_IDLE)
1103 idle = genrand_int32();
1104 else
1105 idle = event_base->time.sec_monotonic - target_p->connection->last_privmsg;
1106
1107 if (max_idle)
1108 idle %= max_idle;
1109 else
1110 idle = 0;
1111
1112 if (idle < min_idle)
1113 idle = min_idle + (idle % (max_idle - min_idle));
1114
1115 return idle;
1116 }
1117
1118 /* client_init()
1119 *
1120 * inputs - NONE
1121 * output - NONE
1122 * side effects - initialize client free memory
1123 */
1124 void
1125 client_init(void)
1126 {
1127 static struct event event_ping =
1128 {
1129 .name = "check_pings",
1130 .handler = check_pings,
1131 .when = 5
1132 };
1133
1134 event_add(&event_ping, NULL);
1135 }

Properties

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