ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/src/client.c
Revision: 8828
Committed: Sat Feb 2 16:49:32 2019 UTC (5 years, 1 month ago) by michael
Content type: text/x-csrc
File size: 33233 byte(s)
Log Message:
- conf_connect_allowed, find_conf_by_address, find_address_conf, find_dline_conf: drop the aftype argument

File Contents

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

Properties

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