ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/client.c
Revision: 9750
Committed: Sun Nov 29 16:51:58 2020 UTC (4 years, 8 months ago) by michael
Content type: text/x-csrc
File size: 33415 byte(s)
Log Message:
- Replace WATCH with IRCv3.2 MONITOR

File Contents

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

Properties

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