ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/src/client.c
Revision: 8436
Committed: Thu Mar 29 09:04:53 2018 UTC (8 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 34856 byte(s)
Log Message:
- Stylistic changes

File Contents

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

Properties

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