ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/src/client.c
Revision: 126
Committed: Fri Oct 14 02:41:46 2005 UTC (19 years, 10 months ago) by db
Content type: text/x-csrc
File size: 50519 byte(s)
Log Message:
- attach/conf cleanup take 2
- Each client has now one AccessItem for its connect
  stored in localClient->iline
- The corresponding class is now stored in localClient->class

The ramifications of this move are, there is no conf list to traverse
to find the AccessItem, the class is instantly available from the localClient
struct without having to traverse the confs list and indirectly through the
aconf. This speeds up get_sendq etc. functions. As a bonus, at least
4 fewer bytes are used in the Client struct, since a dlink list is 4 words.
It does mean there is no longer a separate conf oper, which leads to the
kludge of patching the clients iline into an oper conf when
a client opers up. I don't think the oper flags are used after the client
is opered, so the patching operation may not be necessary.

- Server confs are stored in ->serv->sconf as before but attaching
  happens much earlier.
- server hub/leaf masks continues to be a dlink list but linked from
  the ->serv which is only allocated for servers.

- cleaned up some comments, added a comment, notably to check_server()
  which badly needed it.
- Pass ClassItem or AccessItem etc. in when it makes more sense than passing
  in struct ConfItem. This simplified and clarified rebuild_cidr_class()

And lo, there was a great rejoicing.


File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * client.c: Controls clients.
4 *
5 * Copyright (C) 2002 by the past and present ircd coders, and others.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 * $Id$
23 */
24
25 #include "stdinc.h"
26 #include "client.h"
27 #include "channel_mode.h"
28 #include "common.h"
29 #include "hash.h"
30 #include "ircd.h"
31 #include "s_gline.h"
32 #include "numeric.h"
33 #include "packet.h"
34 #include "s_auth.h"
35 #include "s_conf.h"
36 #include "parse_aline.h"
37 #include "s_serv.h"
38 #include "send.h"
39 #include "whowas.h"
40 #include "s_user.h"
41 #include "hostmask.h"
42 #include "listener.h"
43 #include "userhost.h"
44 #include "s_stats.h"
45
46 dlink_list listing_client_list = { NULL, NULL, 0 };
47 /* Pointer to beginning of Client list */
48 dlink_list global_client_list = {NULL, NULL, 0};
49 /* unknown/client pointer lists */
50 dlink_list unknown_list = {NULL, NULL, 0};
51 dlink_list local_client_list = {NULL, NULL, 0};
52 dlink_list serv_list = {NULL, NULL, 0};
53 dlink_list global_serv_list = {NULL, NULL, 0};
54 dlink_list oper_list = {NULL, NULL, 0};
55
56 static EVH check_pings;
57
58 static BlockHeap *client_heap = NULL;
59 static BlockHeap *lclient_heap = NULL;
60
61 static dlink_list dead_list = { NULL, NULL, 0};
62 static dlink_list abort_list = { NULL, NULL, 0};
63
64 static dlink_node *eac_next; /* next aborted client to exit */
65
66 static void check_pings_list(dlink_list *);
67 static void check_unknowns_list(void);
68 static void close_connection(struct Client *);
69 static void ban_them(struct Client *client_p, struct ConfItem *conf);
70
71
72 /* init_client()
73 *
74 * inputs - NONE
75 * output - NONE
76 * side effects - initialize client free memory
77 */
78 void
79 init_client(void)
80 {
81 /* start off the check ping event .. -- adrian
82 * Every 30 seconds is plenty -- db
83 */
84 client_heap = BlockHeapCreate("client", sizeof(struct Client), CLIENT_HEAP_SIZE);
85 lclient_heap = BlockHeapCreate("local client", sizeof(struct LocalUser), LCLIENT_HEAP_SIZE);
86 eventAdd("check_pings", check_pings, NULL, 5);
87 }
88
89 /*
90 * make_client - create a new Client struct and set it to initial state.
91 *
92 * from == NULL, create local client (a client connected
93 * to a socket).
94 * WARNING: This leaves the client in a dangerous
95 * state where fd == -1, dead flag is not set and
96 * the client is on the unknown_list; therefore,
97 * the first thing to do after calling make_client(NULL)
98 * is setting fd to something reasonable. -adx
99 *
100 * from, create remote client (behind a socket
101 * associated with the client defined by
102 * 'from'). ('from' is a local client!!).
103 */
104 struct Client *
105 make_client(struct Client *from)
106 {
107 struct Client *client_p = BlockHeapAlloc(client_heap);
108
109 if (from == NULL)
110 {
111 client_p->from = client_p; /* 'from' of local client is self! */
112 client_p->since = client_p->lasttime = client_p->firsttime = CurrentTime;
113
114 client_p->localClient = BlockHeapAlloc(lclient_heap);
115 /* as good a place as any... */
116 dlinkAdd(client_p, make_dlink_node(), &unknown_list);
117 }
118 else
119 client_p->from = from; /* 'from' of local client is self! */
120
121 client_p->hnext = client_p;
122 client_p->status = STAT_UNKNOWN;
123 strcpy(client_p->username, "unknown");
124
125 return client_p;
126 }
127
128 /*
129 * free_client
130 *
131 * inputs - pointer to client
132 * output - NONE
133 * side effects - client pointed to has its memory freed
134 */
135 static void
136 free_client(struct Client *client_p)
137 {
138 assert(client_p != NULL);
139 assert(client_p != &me);
140 assert(client_p->hnext == client_p);
141 assert(client_p->invited.head == NULL);
142 assert(client_p->channel.head == NULL);
143 assert(dlink_list_length(&client_p->invited) == 0);
144 assert(dlink_list_length(&client_p->channel) == 0);
145
146 MyFree(client_p->away);
147 MyFree(client_p->serv);
148
149 if (MyConnect(client_p))
150 {
151 assert(IsClosing(client_p) && IsDead(client_p));
152
153 MyFree(client_p->localClient->response);
154 MyFree(client_p->localClient->auth_oper);
155
156 /*
157 * clean up extra sockets from P-lines which have been discarded.
158 */
159 if (client_p->localClient->listener)
160 {
161 assert(0 < client_p->localClient->listener->ref_count);
162 if (0 == --client_p->localClient->listener->ref_count &&
163 !client_p->localClient->listener->active)
164 free_listener(client_p->localClient->listener);
165 }
166
167 dbuf_clear(&client_p->localClient->buf_recvq);
168 dbuf_clear(&client_p->localClient->buf_sendq);
169
170 BlockHeapFree(lclient_heap, client_p->localClient);
171 }
172
173 BlockHeapFree(client_heap, client_p);
174 }
175
176 /*
177 * check_pings - go through the local client list and check activity
178 * kill off stuff that should die
179 *
180 * inputs - NOT USED (from event)
181 * output - next time_t when check_pings() should be called again
182 * side effects -
183 *
184 *
185 * A PING can be sent to clients as necessary.
186 *
187 * Client/Server ping outs are handled.
188 */
189
190 /*
191 * Addon from adrian. We used to call this after nextping seconds,
192 * however I've changed it to run once a second. This is only for
193 * PING timeouts, not K/etc-line checks (thanks dianora!). Having it
194 * run once a second makes life a lot easier - when a new client connects
195 * and they need a ping in 4 seconds, if nextping was set to 20 seconds
196 * we end up waiting 20 seconds. This is stupid. :-)
197 * I will optimise (hah!) check_pings() once I've finished working on
198 * tidying up other network IO evilnesses.
199 * -- adrian
200 */
201
202 static void
203 check_pings(void *notused)
204 {
205 check_pings_list(&local_client_list);
206 check_pings_list(&serv_list);
207 check_unknowns_list();
208 }
209
210 /* check_pings_list()
211 *
212 * inputs - pointer to list to check
213 * output - NONE
214 * side effects -
215 */
216 static void
217 check_pings_list(dlink_list *list)
218 {
219 char scratch[32]; /* way too generous but... */
220 struct Client *client_p; /* current local client_p being examined */
221 int ping, pingwarn; /* ping time value from client */
222 dlink_node *ptr, *next_ptr;
223
224 DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
225 {
226 client_p = ptr->data;
227
228 /*
229 ** Note: No need to notify opers here. It's
230 ** already done when "FLAGS_DEADSOCKET" is set.
231 */
232 if (IsDead(client_p))
233 {
234 /* Ignore it, its been exited already */
235 continue;
236 }
237
238 if (client_p->localClient->reject_delay > 0)
239 {
240 if (client_p->localClient->reject_delay <= CurrentTime)
241 exit_client(client_p, &me, "Rejected");
242 continue;
243 }
244
245 if (GlobalSetOptions.idletime && IsClient(client_p))
246 {
247 if (!IsExemptKline(client_p) && !IsOper(client_p) &&
248 !IsIdlelined(client_p) &&
249 ((CurrentTime - client_p->localClient->last) > GlobalSetOptions.idletime))
250 {
251 struct ConfItem *conf;
252 struct AccessItem *aconf;
253
254 conf = make_conf_item(KLINE_TYPE);
255 aconf = (struct AccessItem *)map_to_conf(conf);
256
257 DupString(aconf->host, client_p->host);
258 DupString(aconf->reason, "idle exceeder");
259 DupString(aconf->user, client_p->username);
260 aconf->hold = CurrentTime + 60;
261 add_temp_line(conf);
262
263 sendto_realops_flags(UMODE_ALL, L_ALL,
264 "Idle time limit exceeded for %s - temp k-lining",
265 get_client_name(client_p, HIDE_IP));
266 exit_client(client_p, &me, aconf->reason);
267 continue;
268 }
269 }
270
271 if (!IsRegistered(client_p))
272 ping = CONNECTTIMEOUT, pingwarn = 0;
273 else
274 ping = get_client_ping(client_p, &pingwarn);
275
276 if (ping < CurrentTime - client_p->lasttime)
277 {
278 if (!IsPingSent(client_p))
279 {
280 /*
281 * if we havent PINGed the connection and we havent
282 * heard from it in a while, PING it to make sure
283 * it is still alive.
284 */
285 SetPingSent(client_p);
286 ClearPingWarning(client_p);
287 client_p->lasttime = CurrentTime - ping;
288 sendto_one(client_p, "PING :%s", ID_or_name(&me, client_p));
289 }
290 else
291 {
292 if (CurrentTime - client_p->lasttime >= 2 * ping)
293 {
294 /*
295 * If the client/server hasn't talked to us in 2*ping seconds
296 * and it has a ping time, then close its connection.
297 */
298 if (IsServer(client_p) || IsHandshake(client_p))
299 {
300 sendto_realops_flags(UMODE_ALL, L_ADMIN,
301 "No response from %s, closing link",
302 get_client_name(client_p, HIDE_IP));
303 sendto_realops_flags(UMODE_ALL, L_OPER,
304 "No response from %s, closing link",
305 get_client_name(client_p, MASK_IP));
306 ilog(L_NOTICE, "No response from %s, closing link",
307 get_client_name(client_p, HIDE_IP));
308 }
309 ircsprintf(scratch, "Ping timeout: %d seconds",
310 (int)(CurrentTime - client_p->lasttime));
311
312 exit_client(client_p, &me, scratch);
313 }
314 else if (!IsPingWarning(client_p) && pingwarn > 0 &&
315 (IsServer(client_p) || IsHandshake(client_p)) &&
316 CurrentTime - client_p->lasttime >= ping + pingwarn)
317 {
318 /*
319 * If the server hasn't replied in pingwarn seconds after sending
320 * the PING, notify the opers so that they are aware of the problem.
321 */
322 SetPingWarning(client_p);
323 sendto_realops_flags(UMODE_ALL, L_ADMIN,
324 "Warning, no response from %s in %d seconds",
325 get_client_name(client_p, HIDE_IP), pingwarn);
326 sendto_realops_flags(UMODE_ALL, L_OPER,
327 "Warning, no response from %s in %d seconds",
328 get_client_name(client_p, MASK_IP), pingwarn);
329 ilog(L_NOTICE, "No response from %s in %d seconds",
330 get_client_name(client_p, HIDE_IP), pingwarn);
331 }
332 }
333 }
334 }
335 }
336
337 /* check_unknowns_list()
338 *
339 * inputs - pointer to list of unknown clients
340 * output - NONE
341 * side effects - unknown clients get marked for termination after n seconds
342 */
343 static void
344 check_unknowns_list(void)
345 {
346 dlink_node *ptr, *next_ptr;
347
348 DLINK_FOREACH_SAFE(ptr, next_ptr, unknown_list.head)
349 {
350 struct Client *client_p = ptr->data;
351
352 if (client_p->localClient->reject_delay > 0)
353 {
354 if (client_p->localClient->reject_delay <= CurrentTime)
355 exit_client(client_p, &me, "Rejected");
356 continue;
357 }
358
359 /* Check UNKNOWN connections - if they have been in this state
360 * for > 30s, close them.
361 */
362 if (client_p->firsttime ? ((CurrentTime - client_p->firsttime) > 30) : 0)
363 exit_client(client_p, &me, "Connection timed out");
364 }
365 }
366
367 /* check_conf_klines()
368 *
369 * inputs - NONE
370 * output - NONE
371 * side effects - Check all connections for a pending kline against the
372 * client, exit the client if a kline matches.
373 */
374 void
375 check_conf_klines(void)
376 {
377 struct Client *client_p = NULL; /* current local client_p being examined */
378 struct AccessItem *aconf = NULL;
379 struct ConfItem *conf = NULL;
380 dlink_node *ptr, *next_ptr;
381
382 DLINK_FOREACH_SAFE(ptr, next_ptr, local_client_list.head)
383 {
384 client_p = ptr->data;
385
386 /* If a client is already being exited
387 */
388 if (IsDead(client_p) || !IsClient(client_p))
389 continue;
390
391 /* if there is a returned struct ConfItem then kill it */
392 if ((aconf = find_dline_conf(&client_p->localClient->ip,
393 client_p->localClient->aftype)) != NULL)
394 {
395 if (aconf->status & CONF_EXEMPTDLINE)
396 continue;
397
398 conf = unmap_conf_item(aconf);
399 ban_them(client_p, conf);
400 continue; /* and go examine next fd/client_p */
401 }
402
403 if (ConfigFileEntry.glines && (aconf = find_gline(client_p)))
404 {
405 if (IsExemptKline(client_p) ||
406 IsExemptGline(client_p))
407 {
408 sendto_realops_flags(UMODE_ALL, L_ALL,
409 "GLINE over-ruled for %s, client is %sline_exempt",
410 get_client_name(client_p, HIDE_IP), IsExemptKline(client_p) ? "k" : "g");
411 continue;
412 }
413
414 conf = unmap_conf_item(aconf);
415 ban_them(client_p, conf);
416 /* and go examine next fd/client_p */
417 continue;
418 }
419
420 if ((aconf = find_kill(client_p)) != NULL)
421 {
422
423 /* if there is a returned struct AccessItem.. then kill it */
424 if (IsExemptKline(client_p))
425 {
426 sendto_realops_flags(UMODE_ALL, L_ALL,
427 "KLINE over-ruled for %s, client is kline_exempt",
428 get_client_name(client_p, HIDE_IP));
429 continue;
430 }
431
432 conf = unmap_conf_item(aconf);
433 ban_them(client_p, conf);
434 continue;
435 }
436
437 /* if there is a returned struct MatchItem then kill it */
438 if ((conf = find_matching_name_conf(XLINE_TYPE, client_p->info,
439 NULL, NULL, 0)) != NULL ||
440 (conf = find_matching_name_conf(RXLINE_TYPE, client_p->info,
441 NULL, NULL, 0)) != NULL)
442 {
443 ban_them(client_p, conf);
444 continue;
445 }
446 }
447
448 /* also check the unknowns list for new dlines */
449 DLINK_FOREACH_SAFE(ptr, next_ptr, unknown_list.head)
450 {
451 client_p = ptr->data;
452
453 if ((aconf = find_dline_conf(&client_p->localClient->ip,
454 client_p->localClient->aftype)))
455 {
456 if (aconf->status & CONF_EXEMPTDLINE)
457 continue;
458
459 exit_client(client_p, &me, "D-lined");
460 }
461 }
462 }
463
464 /*
465 * ban_them
466 *
467 * inputs - pointer to client to ban
468 * - pointer to ConfItem
469 * output - NONE
470 * side effects - given client_p is banned
471 */
472 static void
473 ban_them(struct Client *client_p, struct ConfItem *conf)
474 {
475 const char *user_reason = NULL; /* What is sent to user */
476 const char *channel_reason = NULL; /* What is sent to channel */
477 struct AccessItem *aconf = NULL;
478 struct MatchItem *xconf = NULL;
479 const char *type_string = NULL;
480 const char dline_string[] = "D-line";
481 const char kline_string[] = "K-line";
482 const char gline_string[] = "G-line";
483 const char xline_string[] = "X-line";
484
485 switch (conf->type)
486 {
487 case RKLINE_TYPE:
488 case KLINE_TYPE:
489 type_string = kline_string;
490 aconf = map_to_conf(conf);
491 break;
492 case DLINE_TYPE:
493 type_string = dline_string;
494 aconf = map_to_conf(conf);
495 break;
496 case GLINE_TYPE:
497 type_string = gline_string;
498 aconf = map_to_conf(conf);
499 break;
500 case RXLINE_TYPE:
501 case XLINE_TYPE:
502 type_string = xline_string;
503 xconf = map_to_conf(conf);
504 ++xconf->count;
505 break;
506 default:
507 assert(0);
508 break;
509 }
510
511 if (ConfigFileEntry.kline_with_reason)
512 {
513 if (aconf != NULL)
514 user_reason = aconf->reason ? aconf->reason : type_string;
515 if (xconf != NULL)
516 user_reason = xconf->reason ? xconf->reason : type_string;
517 }
518 else
519 user_reason = type_string;
520
521 if (ConfigFileEntry.kline_reason != NULL)
522 channel_reason = ConfigFileEntry.kline_reason;
523 else
524 channel_reason = user_reason;
525
526 sendto_realops_flags(UMODE_ALL, L_ALL, "%s active for %s",
527 type_string, get_client_name(client_p, HIDE_IP));
528
529 if (IsClient(client_p))
530 sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP),
531 me.name, client_p->name, user_reason);
532
533 exit_client(client_p, &me, channel_reason);
534 }
535
536 /* update_client_exit_stats()
537 *
538 * input - pointer to client
539 * output - NONE
540 * side effects -
541 */
542 static void
543 update_client_exit_stats(struct Client *client_p)
544 {
545 if (IsServer(client_p))
546 {
547 sendto_realops_flags(UMODE_EXTERNAL, L_ALL,
548 "Server %s split from %s",
549 client_p->name, client_p->servptr->name);
550 }
551 else if (IsClient(client_p))
552 {
553 --Count.total;
554 if (IsOper(client_p))
555 --Count.oper;
556 if (IsInvisible(client_p))
557 --Count.invisi;
558 }
559
560 if (splitchecking && !splitmode)
561 check_splitmode(NULL);
562 }
563
564 /* find_person()
565 *
566 * inputs - pointer to name
567 * output - return client pointer
568 * side effects - find person by (nick)name
569 */
570 /* XXX - ugly wrapper */
571 struct Client *
572 find_person(const struct Client *client_p, const char *name)
573 {
574 struct Client *c2ptr;
575
576 if (IsDigit(*name))
577 {
578 if ((c2ptr = hash_find_id(name)) != NULL)
579 {
580 /* invisible users shall not be found by UID guessing */
581 if (IsInvisible(c2ptr) && !IsServer(client_p))
582 c2ptr = NULL;
583 }
584 }
585 else
586 c2ptr = find_client(name);
587
588 return ((c2ptr != NULL && IsClient(c2ptr)) ? c2ptr : NULL);
589 }
590
591 /*
592 * find_chasing - find the client structure for a nick name (user)
593 * using history mechanism if necessary. If the client is not found,
594 * an error message (NO SUCH NICK) is generated. If the client was found
595 * through the history, chasing will be 1 and otherwise 0.
596 */
597 struct Client *
598 find_chasing(struct Client *client_p, struct Client *source_p, const char *user, int *chasing)
599 {
600 struct Client *who = find_person(client_p, user);
601
602 if (chasing)
603 *chasing = 0;
604
605 if (who)
606 return(who);
607
608 if (IsDigit(*user))
609 return(NULL);
610
611 if ((who = get_history(user,
612 (time_t)ConfigFileEntry.kill_chase_time_limit))
613 == NULL)
614 {
615 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
616 me.name, source_p->name, user);
617 return(NULL);
618 }
619
620 if (chasing)
621 *chasing = 1;
622
623 return(who);
624 }
625
626 /*
627 * get_client_name - Return the name of the client
628 * for various tracking and
629 * admin purposes. The main purpose of this function is to
630 * return the "socket host" name of the client, if that
631 * differs from the advertised name (other than case).
632 * But, this can be used to any client structure.
633 *
634 * NOTE 1:
635 * Watch out the allocation of "nbuf", if either source_p->name
636 * or source_p->sockhost gets changed into pointers instead of
637 * directly allocated within the structure...
638 *
639 * NOTE 2:
640 * Function return either a pointer to the structure (source_p) or
641 * to internal buffer (nbuf). *NEVER* use the returned pointer
642 * to modify what it points!!!
643 */
644 const char *
645 get_client_name(struct Client *client, int showip)
646 {
647 static char nbuf[HOSTLEN * 2 + USERLEN + 5];
648
649 assert(client != NULL);
650
651 if (irccmp(client->name, client->host) == 0)
652 return(client->name);
653
654 if (ConfigServerHide.hide_server_ips)
655 if (IsServer(client) || IsConnecting(client) || IsHandshake(client))
656 showip = MASK_IP;
657
658 if (ConfigFileEntry.hide_spoof_ips)
659 if (showip == SHOW_IP && IsIPSpoof(client))
660 showip = MASK_IP;
661
662 /* And finally, let's get the host information, ip or name */
663 switch (showip)
664 {
665 case SHOW_IP:
666 if (MyConnect(client))
667 {
668 ircsprintf(nbuf, "%s[%s@%s]", client->name, client->username,
669 client->sockhost);
670 break;
671 }
672 case MASK_IP:
673 ircsprintf(nbuf, "%s[%s@255.255.255.255]", client->name,
674 client->username);
675 break;
676 default:
677 ircsprintf(nbuf, "%s[%s@%s]", client->name, client->username,
678 client->host);
679 }
680
681 return(nbuf);
682 }
683
684 void
685 free_exited_clients(void)
686 {
687 dlink_node *ptr, *next;
688 struct Client *target_p;
689
690 DLINK_FOREACH_SAFE(ptr, next, dead_list.head)
691 {
692 target_p = ptr->data;
693
694 if (ptr->data == NULL)
695 {
696 sendto_realops_flags(UMODE_ALL, L_ALL,
697 "Warning: null client on dead_list!");
698 dlinkDelete(ptr, &dead_list);
699 free_dlink_node(ptr);
700 continue;
701 }
702
703 free_client(target_p);
704 dlinkDelete(ptr, &dead_list);
705 free_dlink_node(ptr);
706 }
707 }
708
709 /*
710 * Exit one client, local or remote. Assuming all dependents have
711 * been already removed, and socket closed for local client.
712 *
713 * The only messages generated are QUITs on channels.
714 */
715 static void
716 exit_one_client(struct Client *source_p, const char *quitmsg)
717 {
718 dlink_node *lp = NULL, *next_lp = NULL;
719
720 assert(!IsMe(source_p));
721
722 if (IsServer(source_p))
723 {
724 dlinkDelete(&source_p->lnode, &source_p->servptr->serv->servers);
725
726 if ((lp = dlinkFindDelete(&global_serv_list, source_p)) != NULL)
727 free_dlink_node(lp);
728
729 if (!MyConnect(source_p))
730 {
731 source_p->from->serv->dep_servers--;
732 assert(source_p->from->serv->dep_servers > 0);
733 }
734 }
735 else if (IsClient(source_p))
736 {
737 if (source_p->servptr->serv != NULL)
738 dlinkDelete(&source_p->lnode, &source_p->servptr->serv->users);
739
740 /* If a person is on a channel, send a QUIT notice
741 ** to every client (person) on the same channel (so
742 ** that the client can show the "**signoff" message).
743 ** (Note: The notice is to the local clients *only*)
744 */
745 sendto_common_channels_local(source_p, 0, ":%s!%s@%s QUIT :%s",
746 source_p->name, source_p->username,
747 source_p->host, quitmsg);
748 DLINK_FOREACH_SAFE(lp, next_lp, source_p->channel.head)
749 remove_user_from_channel(lp->data);
750
751 /* Clean up invitefield */
752 DLINK_FOREACH_SAFE(lp, next_lp, source_p->invited.head)
753 del_invite(lp->data, source_p);
754
755 /* Clean up allow lists */
756 del_all_accepts(source_p);
757 add_history(source_p, 0);
758 off_history(source_p);
759
760 if (!MyConnect(source_p))
761 {
762 source_p->from->serv->dep_users--;
763 assert(source_p->from->serv->dep_users >= 0);
764 }
765 }
766
767 /* Remove source_p from the client lists */
768 if (HasID(source_p))
769 hash_del_id(source_p);
770 if (source_p->name[0])
771 hash_del_client(source_p);
772
773 if (IsUserHostIp(source_p))
774 delete_user_host(source_p->username, source_p->host, !MyConnect(source_p));
775
776 /* remove from global client list
777 * NOTE: source_p->node.next cannot be NULL if the client is added
778 * to global_client_list (there is always &me at its end)
779 */
780 if (source_p != NULL && source_p->node.next != NULL)
781 dlinkDelete(&source_p->node, &global_client_list);
782
783 update_client_exit_stats(source_p);
784
785 /* Check to see if the client isn't already on the dead list */
786 assert(dlinkFind(&dead_list, source_p) == NULL);
787
788 /* add to dead client dlist */
789 SetDead(source_p);
790 dlinkAdd(source_p, make_dlink_node(), &dead_list);
791 }
792
793 /* Recursively send QUITs and SQUITs for source_p and all its dependent clients
794 * and servers to those servers that need them. A server needs the client
795 * QUITs if it can't figure them out from the SQUIT (ie pre-TS4) or if it
796 * isn't getting the SQUIT because of @#(*&@)# hostmasking. With TS4, once
797 * a link gets a SQUIT, it doesn't need any QUIT/SQUITs for clients depending
798 * on that one -orabidoo
799 *
800 * This is now called on each local server -adx
801 */
802 static void
803 recurse_send_quits(struct Client *original_source_p, struct Client *source_p,
804 struct Client *from, struct Client *to, const char *comment,
805 const char *splitstr, const char *myname)
806 {
807 dlink_node *ptr, *next;
808 struct Client *target_p;
809 int hidden = match(myname, source_p->name);
810
811 assert(to != source_p); /* should be already removed from serv_list */
812
813 /* If this server can handle quit storm (QS) removal
814 * of dependents, just send the SQUIT
815 *
816 * Always check *all* dependent servers if some of them are
817 * hidden behind fakename. If so, send out the QUITs -adx
818 */
819 if (hidden || !IsCapable(to, CAP_QS))
820 DLINK_FOREACH_SAFE(ptr, next, source_p->serv->users.head)
821 {
822 target_p = ptr->data;
823 sendto_one(to, ":%s QUIT :%s", target_p->name, splitstr);
824 }
825
826 DLINK_FOREACH_SAFE(ptr, next, source_p->serv->servers.head)
827 recurse_send_quits(original_source_p, ptr->data, from, to,
828 comment, splitstr, myname);
829
830 if (!hidden && ((source_p == original_source_p && to != from) ||
831 !IsCapable(to, CAP_QS)))
832 {
833 /* don't use a prefix here - we have to be 100% sure the message
834 * will be accepted without Unknown prefix etc.. */
835 sendto_one(to, "SQUIT %s :%s", ID_or_name(source_p, to), comment);
836 }
837 }
838
839 /*
840 * Remove all clients that depend on source_p; assumes all (S)QUITs have
841 * already been sent. we make sure to exit a server's dependent clients
842 * and servers before the server itself; exit_one_client takes care of
843 * actually removing things off llists. tweaked from +CSr31 -orabidoo
844 */
845 static void
846 recurse_remove_clients(struct Client *source_p, const char *quitmsg)
847 {
848 dlink_node *ptr, *next;
849
850 DLINK_FOREACH_SAFE(ptr, next, source_p->serv->users.head)
851 exit_one_client(ptr->data, quitmsg);
852
853 DLINK_FOREACH_SAFE(ptr, next, source_p->serv->servers.head)
854 {
855 recurse_remove_clients(ptr->data, quitmsg);
856 exit_one_client(ptr->data, quitmsg);
857 }
858
859 assert(source_p->serv->dep_servers == 1);
860 assert(source_p->serv->dep_users == 0);
861 }
862
863 /*
864 ** Remove *everything* that depends on source_p, from all lists, and sending
865 ** all necessary QUITs and SQUITs. source_p itself is still on the lists,
866 ** and its SQUITs have been sent except for the upstream one -orabidoo
867 */
868 static void
869 remove_dependents(struct Client *source_p, struct Client *from,
870 const char *comment, const char *splitstr)
871 {
872 struct Client *to;
873 struct ConfItem *conf;
874 struct AccessItem *aconf;
875 static char myname[HOSTLEN+1];
876 dlink_node *ptr;
877
878 DLINK_FOREACH(ptr, serv_list.head)
879 {
880 to = ptr->data;
881
882 if ((conf = to->serv->sconf) != NULL)
883 {
884 aconf = map_to_conf(conf);
885 strlcpy(myname, my_name_for_link(aconf), sizeof(myname));
886 }
887 else
888 strlcpy(myname, me.name, sizeof(myname));
889 recurse_send_quits(source_p, source_p, from, to,
890 comment, splitstr, myname);
891 }
892
893 recurse_remove_clients(source_p, splitstr);
894 }
895
896 /*
897 * exit_client - exit a client of any type. Generally, you can use
898 * this on any struct Client, regardless of its state.
899 *
900 * Note, you shouldn't exit remote _users_ without first doing
901 * SetKilled and propagating a kill or similar message. However,
902 * it is perfectly correct to call exit_client to force a _server_
903 * quit (either local or remote one).
904 *
905 * inputs: - a client pointer that is going to be exited
906 * - for servers, the second argument is a pointer to who
907 * is firing the server. This side won't get any generated
908 * messages. NEVER NULL!
909 * output: none
910 * side effects: the client is delinked from all lists, disconnected,
911 * and the rest of IRC network is notified of the exit.
912 * Client memory is scheduled to be freed
913 */
914 void
915 exit_client(struct Client *source_p, struct Client *from, const char *comment)
916 {
917 dlink_node *m;
918
919 if (MyConnect(source_p))
920 {
921 /* DO NOT REMOVE. exit_client can be called twice after a failed
922 * read/write.
923 */
924 if (IsClosing(source_p))
925 return;
926
927 SetClosing(source_p);
928
929 if (IsIpHash(source_p))
930 remove_one_ip(&source_p->localClient->ip);
931
932 delete_auth(source_p);
933
934 /* This source_p could have status of one of STAT_UNKNOWN, STAT_CONNECTING
935 * STAT_HANDSHAKE or STAT_UNKNOWN
936 * all of which are lumped together into unknown_list
937 *
938 * In all above cases IsRegistered() will not be true.
939 */
940 if (!IsRegistered(source_p))
941 {
942 if ((m = dlinkFindDelete(&unknown_list, source_p)) != NULL)
943 free_dlink_node(m);
944 }
945 else if (IsClient(source_p))
946 {
947 Count.local--;
948
949 if (IsOper(source_p))
950 {
951 if ((m = dlinkFindDelete(&oper_list, source_p)) != NULL)
952 free_dlink_node(m);
953 }
954
955 dlinkDelete(&source_p->localClient->lclient_node, &local_client_list);
956 if (source_p->localClient->list_task != NULL)
957 free_list_task(source_p->localClient->list_task, source_p);
958
959 sendto_realops_flags(UMODE_CCONN, L_ALL, "Client exiting: %s (%s@%s) [%s] [%s]",
960 source_p->name, source_p->username, source_p->host, comment,
961 ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ?
962 "255.255.255.255" : source_p->sockhost);
963 }
964
965 /* As soon as a client is known to be a server of some sort
966 * it has to be put on the serv_list, or SJOIN's to this new server
967 * from the connect burst will not be seen.
968 */
969 if (IsServer(source_p) || IsConnecting(source_p) ||
970 IsHandshake(source_p))
971 {
972 if ((m = dlinkFindDelete(&serv_list, source_p)) != NULL)
973 {
974 free_dlink_node(m);
975 unset_chcap_usage_counts(source_p);
976 }
977
978 if (IsServer(source_p))
979 {
980 Count.myserver--;
981 if (ServerInfo.hub)
982 remove_lazylink_flags(source_p->localClient->serverMask);
983 else
984 uplink = NULL;
985 }
986 }
987
988 log_user_exit(source_p);
989
990 if (!IsDead(source_p))
991 {
992 if (IsServer(source_p))
993 {
994 /* for them, we are exiting the network */
995 sendto_one(source_p, ":%s SQUIT %s :%s",
996 ID_or_name(from, source_p), me.name, comment);
997 }
998
999 sendto_one(source_p, "ERROR :Closing Link: %s (%s)",
1000 source_p->host, comment);
1001 }
1002
1003 /*
1004 ** Currently only server connections can have
1005 ** depending remote clients here, but it does no
1006 ** harm to check for all local clients. In
1007 ** future some other clients than servers might
1008 ** have remotes too...
1009 **
1010 ** Close the Client connection first and mark it
1011 ** so that no messages are attempted to send to it.
1012 ** Remember it makes source_p->from == NULL.
1013 */
1014 close_connection(source_p);
1015 }
1016
1017 if (IsServer(source_p))
1018 {
1019 char splitstr[HOSTLEN + HOSTLEN + 2];
1020
1021 /* This shouldn't ever happen */
1022 assert(source_p->serv != NULL && source_p->servptr != NULL);
1023
1024 if (ConfigServerHide.hide_servers)
1025 /* set netsplit message to "*.net *.split" to still show
1026 * that its a split, but hide the servers splitting
1027 */
1028 strcpy(splitstr, "*.net *.split");
1029 else
1030 snprintf(splitstr, sizeof(splitstr), "%s %s",
1031 source_p->servptr->name, source_p->name);
1032
1033 remove_dependents(source_p, from->from, comment, splitstr);
1034
1035 if (source_p->servptr == &me)
1036 {
1037 sendto_realops_flags(UMODE_ALL, L_ALL,
1038 "%s was connected for %d seconds. %llu/%llu sendK/recvK.",
1039 source_p->name, (int)(CurrentTime - source_p->firsttime),
1040 source_p->localClient->send.bytes >> 10,
1041 source_p->localClient->recv.bytes >> 10);
1042 ilog(L_NOTICE, "%s was connected for %d seconds. %llu/%llu sendK/recvK.",
1043 source_p->name, (int)(CurrentTime - source_p->firsttime),
1044 source_p->localClient->send.bytes >> 10,
1045 source_p->localClient->recv.bytes >> 10);
1046 }
1047 }
1048 else if (IsClient(source_p) && !IsKilled(source_p))
1049 {
1050 sendto_server(NULL, source_p, NULL, CAP_TS6, NOCAPS, NOFLAGS,
1051 ":%s QUIT :%s", ID(source_p), comment);
1052 sendto_server(NULL, source_p, NULL, NOCAPS, CAP_TS6, NOFLAGS,
1053 ":%s QUIT :%s", source_p->name, comment);
1054 }
1055
1056 /* The client *better* be off all of the lists */
1057 assert(dlinkFind(&unknown_list, source_p) == NULL);
1058 assert(dlinkFind(&local_client_list, source_p) == NULL);
1059 assert(dlinkFind(&serv_list, source_p) == NULL);
1060 assert(dlinkFind(&oper_list, source_p) == NULL);
1061
1062 exit_one_client(source_p, comment);
1063 }
1064
1065 /*
1066 * close_connection
1067 * Close the physical connection. This function must make
1068 * MyConnect(client_p) == FALSE, and set client_p->from == NULL.
1069 */
1070 static void
1071 close_connection(struct Client *client_p)
1072 {
1073 struct ConfItem *conf;
1074 struct AccessItem *aconf;
1075 struct ClassItem *aclass;
1076
1077 assert(NULL != client_p);
1078
1079 if (IsServer(client_p))
1080 {
1081 ServerStats->is_sv++;
1082 ServerStats->is_sbs += client_p->localClient->send.bytes;
1083 ServerStats->is_sbr += client_p->localClient->recv.bytes;
1084 ServerStats->is_sti += CurrentTime - client_p->firsttime;
1085
1086 /* XXX Does this even make any sense at all anymore?
1087 * scheduling a 'quick' reconnect could cause a pile of
1088 * nick collides under TSora protocol... -db
1089 */
1090 /*
1091 * If the connection has been up for a long amount of time, schedule
1092 * a 'quick' reconnect, else reset the next-connect cycle.
1093 */
1094 if ((conf = find_exact_name_conf(SERVER_TYPE,
1095 client_p->name, client_p->username,
1096 client_p->host)))
1097 {
1098 /*
1099 * Reschedule a faster reconnect, if this was a automatically
1100 * connected configuration entry. (Note that if we have had
1101 * a rehash in between, the status has been changed to
1102 * CONF_ILLEGAL). But only do this if it was a "good" link.
1103 */
1104 aconf = (struct AccessItem *)map_to_conf(conf);
1105 aclass = (struct ClassItem *)map_to_conf(aconf->class_ptr);
1106 aconf->hold = time(NULL);
1107 aconf->hold += (aconf->hold - client_p->since > HANGONGOODLINK) ?
1108 HANGONRETRYDELAY : ConFreq(aclass);
1109 if (nextconnect > aconf->hold)
1110 nextconnect = aconf->hold;
1111 }
1112 }
1113 else if (IsClient(client_p))
1114 {
1115 ServerStats->is_cl++;
1116 ServerStats->is_cbs += client_p->localClient->send.bytes;
1117 ServerStats->is_cbr += client_p->localClient->recv.bytes;
1118 ServerStats->is_cti += CurrentTime - client_p->firsttime;
1119 }
1120 else
1121 ServerStats->is_ni++;
1122
1123 if (!IsDead(client_p))
1124 {
1125 /* attempt to flush any pending dbufs. Evil, but .. -- adrian */
1126 /* there is still a chance that we might send data to this socket
1127 * even if it is marked as blocked (COMM_SELECT_READ handler is called
1128 * before COMM_SELECT_WRITE). Let's try, nothing to lose.. -adx
1129 */
1130 ClearSendqBlocked(client_p);
1131 send_queued_write(client_p);
1132 }
1133
1134 #ifdef HAVE_LIBCRYPTO
1135 if (client_p->localClient->fd.ssl)
1136 SSL_shutdown(client_p->localClient->fd.ssl);
1137 #endif
1138 if (client_p->localClient->fd.flags.open)
1139 fd_close(&client_p->localClient->fd);
1140
1141 if (HasServlink(client_p))
1142 {
1143 if (client_p->localClient->ctrlfd.flags.open)
1144 fd_close(&client_p->localClient->ctrlfd);
1145 }
1146
1147 dbuf_clear(&client_p->localClient->buf_sendq);
1148 dbuf_clear(&client_p->localClient->buf_recvq);
1149
1150 MyFree(client_p->localClient->passwd);
1151 detach_conf(client_p, CONF_TYPE);
1152 client_p->from = NULL; /* ...this should catch them! >:) --msa */
1153 }
1154
1155 /*
1156 * report_error - report an error from an errno.
1157 * Record error to log and also send a copy to all *LOCAL* opers online.
1158 *
1159 * text is a *format* string for outputing error. It must
1160 * contain only two '%s', the first will be replaced
1161 * by the sockhost from the client_p, and the latter will
1162 * be taken from sys_errlist[errno].
1163 *
1164 * client_p if not NULL, is the *LOCAL* client associated with
1165 * the error.
1166 *
1167 * Cannot use perror() within daemon. stderr is closed in
1168 * ircd and cannot be used. And, worse yet, it might have
1169 * been reassigned to a normal connection...
1170 *
1171 * Actually stderr is still there IFF ircd was run with -s --Rodder
1172 */
1173 void
1174 report_error(int level, const char* text, const char* who, int error)
1175 {
1176 who = (who) ? who : "";
1177
1178 sendto_realops_flags(UMODE_DEBUG, level, text, who, strerror(error));
1179 log_oper_action(LOG_IOERR_TYPE, NULL, "%s %s %s\n", who, text, strerror(error));
1180 ilog(L_ERROR, text, who, strerror(error));
1181 }
1182
1183 /*
1184 * dead_link_on_write - report a write error if not already dead,
1185 * mark it as dead then exit it
1186 */
1187 void
1188 dead_link_on_write(struct Client *client_p, int ierrno)
1189 {
1190 dlink_node *ptr;
1191
1192 if (IsDefunct(client_p))
1193 return;
1194
1195 dbuf_clear(&client_p->localClient->buf_recvq);
1196 dbuf_clear(&client_p->localClient->buf_sendq);
1197
1198 assert(dlinkFind(&abort_list, client_p) == NULL);
1199 ptr = make_dlink_node();
1200 /* don't let exit_aborted_clients() finish yet */
1201 dlinkAddTail(client_p, ptr, &abort_list);
1202
1203 if (eac_next == NULL)
1204 eac_next = ptr;
1205
1206 SetDead(client_p); /* You are dead my friend */
1207 }
1208
1209 /*
1210 * dead_link_on_read - report a read error if not already dead,
1211 * mark it as dead then exit it
1212 */
1213 void
1214 dead_link_on_read(struct Client *client_p, int error)
1215 {
1216 char errmsg[255];
1217 int current_error;
1218
1219 if (IsDefunct(client_p))
1220 return;
1221
1222 dbuf_clear(&client_p->localClient->buf_recvq);
1223 dbuf_clear(&client_p->localClient->buf_sendq);
1224
1225 current_error = get_sockerr(client_p->localClient->fd.fd);
1226
1227 if (IsServer(client_p) || IsHandshake(client_p))
1228 {
1229 int connected = CurrentTime - client_p->firsttime;
1230
1231 if (error == 0)
1232 {
1233 /* Admins get the real IP */
1234 sendto_realops_flags(UMODE_ALL, L_ADMIN,
1235 "Server %s closed the connection",
1236 get_client_name(client_p, SHOW_IP));
1237
1238 /* Opers get a masked IP */
1239 sendto_realops_flags(UMODE_ALL, L_OPER,
1240 "Server %s closed the connection",
1241 get_client_name(client_p, MASK_IP));
1242
1243 ilog(L_NOTICE, "Server %s closed the connection",
1244 get_client_name(client_p, SHOW_IP));
1245 }
1246 else
1247 {
1248 report_error(L_ADMIN, "Lost connection to %s: %d",
1249 get_client_name(client_p, SHOW_IP), current_error);
1250 report_error(L_OPER, "Lost connection to %s: %d",
1251 get_client_name(client_p, MASK_IP), current_error);
1252 }
1253
1254 sendto_realops_flags(UMODE_ALL, L_ALL,
1255 "%s had been connected for %d day%s, %2d:%02d:%02d",
1256 client_p->name, connected/86400,
1257 (connected/86400 == 1) ? "" : "s",
1258 (connected % 86400) / 3600, (connected % 3600) / 60,
1259 connected % 60);
1260 }
1261
1262 if (error == 0)
1263 strlcpy(errmsg, "Remote host closed the connection",
1264 sizeof(errmsg));
1265 else
1266 ircsprintf(errmsg, "Read error: %s",
1267 strerror(current_error));
1268
1269 exit_client(client_p, &me, errmsg);
1270 }
1271
1272 void
1273 exit_aborted_clients(void)
1274 {
1275 dlink_node *ptr;
1276 struct Client *target_p;
1277 const char *notice;
1278
1279 DLINK_FOREACH_SAFE(ptr, eac_next, abort_list.head)
1280 {
1281 target_p = ptr->data;
1282 eac_next = ptr->next;
1283
1284 if (target_p == NULL)
1285 {
1286 sendto_realops_flags(UMODE_ALL, L_ALL,
1287 "Warning: null client on abort_list!");
1288 dlinkDelete(ptr, &abort_list);
1289 free_dlink_node(ptr);
1290 continue;
1291 }
1292
1293 dlinkDelete(ptr, &abort_list);
1294
1295 if (IsSendQExceeded(target_p))
1296 notice = "Max SendQ exceeded";
1297 else
1298 notice = "Write error: connection closed";
1299
1300 exit_client(target_p, &me, notice);
1301 free_dlink_node(ptr);
1302 }
1303 }
1304
1305 /*
1306 * accept processing, this adds a form of "caller ID" to ircd
1307 *
1308 * If a client puts themselves into "caller ID only" mode,
1309 * only clients that match a client pointer they have put on
1310 * the accept list will be allowed to message them.
1311 *
1312 * [ source.on_allow_list ] -> [ target1 ] -> [ target2 ]
1313 *
1314 * [target.allow_list] -> [ source1 ] -> [source2 ]
1315 *
1316 * i.e. a target will have a link list of source pointers it will allow
1317 * each source client then has a back pointer pointing back
1318 * to the client that has it on its accept list.
1319 * This allows for exit_one_client to remove these now bogus entries
1320 * from any client having an accept on them.
1321 */
1322
1323 /* accept_message()
1324 *
1325 * inputs - pointer to source client
1326 * - pointer to target client
1327 * output - 1 if accept this message 0 if not
1328 * side effects - See if source is on target's allow list
1329 */
1330 int
1331 accept_message(struct Client *source, struct Client *target)
1332 {
1333 dlink_node *ptr;
1334
1335 DLINK_FOREACH(ptr, target->allow_list.head)
1336 {
1337 struct Client *target_p = ptr->data;
1338
1339 if (source == target_p)
1340 return (1);
1341 }
1342
1343 if (IsSoftCallerId(target))
1344 {
1345 DLINK_FOREACH(ptr, target->channel.head)
1346 if (IsMember(source, ptr->data))
1347 return (1);
1348 }
1349
1350 return (0);
1351 }
1352
1353 /* del_from_accept()
1354 *
1355 * inputs - pointer to source client
1356 * - pointer to target client
1357 * output - NONE
1358 * side effects - Delete's source pointer to targets allow list
1359 *
1360 * Walk through the target's accept list, remove if source is found,
1361 * Then walk through the source's on_accept_list remove target if found.
1362 */
1363 void
1364 del_from_accept(struct Client *source, struct Client *target)
1365 {
1366 dlink_node *ptr;
1367 dlink_node *ptr2;
1368 dlink_node *next_ptr;
1369 dlink_node *next_ptr2;
1370 struct Client *target_p;
1371
1372 DLINK_FOREACH_SAFE(ptr, next_ptr, target->allow_list.head)
1373 {
1374 target_p = ptr->data;
1375
1376 if (source == target_p)
1377 {
1378 dlinkDelete(ptr, &target->allow_list);
1379 free_dlink_node(ptr);
1380
1381 DLINK_FOREACH_SAFE(ptr2, next_ptr2, source->on_allow_list.head)
1382 {
1383 target_p = ptr2->data;
1384
1385 if (target == target_p)
1386 {
1387 dlinkDelete(ptr2, &source->on_allow_list);
1388 free_dlink_node(ptr2);
1389 }
1390 }
1391 }
1392 }
1393 }
1394
1395 /* del_all_accepts()
1396 *
1397 * inputs - pointer to exiting client
1398 * output - NONE
1399 * side effects - Walk through given clients allow_list and on_allow_list
1400 * remove all references to this client
1401 */
1402 void
1403 del_all_accepts(struct Client *client_p)
1404 {
1405 dlink_node *ptr, *next_ptr;
1406
1407 DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->allow_list.head)
1408 del_from_accept(ptr->data, client_p);
1409
1410 DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->on_allow_list.head)
1411 del_from_accept(client_p, ptr->data);
1412 }
1413
1414 /* del_all_their_accepts()
1415 *
1416 * inputs - pointer to exiting client
1417 * output - NONE
1418 * side effects - Walk through given clients on_allow_list
1419 * remove all references to this client,
1420 * allow this client to keep their own allow_list
1421 */
1422 void
1423 del_all_their_accepts(struct Client *client_p)
1424 {
1425 dlink_node *ptr, *next_ptr;
1426
1427 DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->on_allow_list.head)
1428 del_from_accept(client_p, ptr->data);
1429 }
1430
1431 /* set_initial_nick()
1432 *
1433 * inputs
1434 * output
1435 * side effects -
1436 *
1437 * This function is only called to set up an initially registering
1438 * client.
1439 */
1440 void
1441 set_initial_nick(struct Client *client_p, struct Client *source_p,
1442 const char *nick)
1443 {
1444 char buf[USERLEN + 1];
1445
1446 /* Client setting NICK the first time */
1447
1448 /* This had to be copied here to avoid problems.. */
1449 source_p->tsinfo = CurrentTime;
1450
1451 if (source_p->name[0])
1452 hash_del_client(source_p);
1453
1454 strlcpy(source_p->name, nick, sizeof(source_p->name));
1455 hash_add_client(source_p);
1456
1457 /* fd_desc is long enough */
1458 fd_note(&client_p->localClient->fd, "Nick: %s", nick);
1459
1460 /* They have the nick they want now.. */
1461 client_p->localClient->llname[0] = '\0';
1462
1463 if (source_p->flags & FLAGS_GOTUSER)
1464 {
1465 strlcpy(buf, source_p->username, sizeof(buf));
1466
1467 /*
1468 * USER already received, now we have NICK.
1469 * *NOTE* For servers "NICK" *must* precede the
1470 * user message (giving USER before NICK is possible
1471 * only for local client connection!). register_user
1472 * may reject the client and call exit_client for it
1473 * --must test this and exit m_nick too!!!
1474 */
1475 register_local_user(client_p, source_p, nick, buf);
1476 }
1477 }
1478
1479 /* change_local_nick()
1480 *
1481 * inputs - pointer to server
1482 * - pointer to client
1483 * - nick
1484 * output -
1485 * side effects - changes nick of a LOCAL user
1486 */
1487 void
1488 change_local_nick(struct Client *client_p, struct Client *source_p, const char *nick)
1489 {
1490 /*
1491 ** Client just changing his/her nick. If he/she is
1492 ** on a channel, send note of change to all clients
1493 ** on that channel. Propagate notice to other servers.
1494 */
1495 if ((source_p->localClient->last_nick_change +
1496 ConfigFileEntry.max_nick_time) < CurrentTime)
1497 source_p->localClient->number_of_nick_changes = 0;
1498 source_p->localClient->last_nick_change = CurrentTime;
1499 source_p->localClient->number_of_nick_changes++;
1500
1501 if ((ConfigFileEntry.anti_nick_flood &&
1502 (source_p->localClient->number_of_nick_changes
1503 <= ConfigFileEntry.max_nick_changes)) ||
1504 !ConfigFileEntry.anti_nick_flood ||
1505 (IsOper(source_p) && ConfigFileEntry.no_oper_flood))
1506 {
1507 if (irccmp(source_p->name, nick))
1508 source_p->tsinfo = CurrentTime;
1509
1510 /* XXX - the format of this notice should eventually be changed
1511 * to either %s[%s@%s], or even better would be get_client_name() -bill
1512 */
1513 sendto_realops_flags(UMODE_NCHANGE, L_ALL, "Nick change: From %s to %s [%s@%s]",
1514 source_p->name, nick, source_p->username, source_p->host);
1515 sendto_common_channels_local(source_p, 1, ":%s!%s@%s NICK :%s",
1516 source_p->name, source_p->username,
1517 source_p->host, nick);
1518
1519 add_history(source_p, 1);
1520
1521 /* Only hubs care about lazy link nicks not being sent on yet
1522 * lazylink leafs/leafs always send their nicks up to hub,
1523 * hence must always propagate nick changes.
1524 * hubs might not propagate a nick change, if the leaf
1525 * does not know about that client yet.
1526 */
1527 sendto_server(client_p, source_p, NULL, CAP_TS6, NOCAPS, NOFLAGS,
1528 ":%s NICK %s :%lu",
1529 ID(source_p), nick, (unsigned long)source_p->tsinfo);
1530 sendto_server(client_p, source_p, NULL, NOCAPS, CAP_TS6, NOFLAGS,
1531 ":%s NICK %s :%lu",
1532 source_p->name, nick, (unsigned long)source_p->tsinfo);
1533 }
1534 else
1535 {
1536 sendto_one(source_p, form_str(ERR_NICKTOOFAST),
1537 me.name, source_p->name, source_p->name,
1538 nick, ConfigFileEntry.max_nick_time);
1539 return;
1540 }
1541
1542 /* Finally, add to hash */
1543 if (source_p->name[0])
1544 hash_del_client(source_p);
1545
1546 strcpy(source_p->name, nick);
1547 hash_add_client(source_p);
1548
1549 /* Make sure everyone that has this client on its accept list
1550 * loses that reference.
1551 */
1552 del_all_their_accepts(source_p);
1553
1554 /* fd_desc is long enough */
1555 fd_note(&client_p->localClient->fd, "Nick: %s", nick);
1556 }
1557
1558 /* log_user_exit()
1559 *
1560 * inputs - pointer to connecting client
1561 * output - NONE
1562 * side effects - Current exiting client is logged to
1563 * either SYSLOG or to file.
1564 */
1565 void
1566 log_user_exit(struct Client *source_p)
1567 {
1568 time_t on_for = CurrentTime - source_p->firsttime;
1569 #ifdef SYSLOG_USERS
1570 if (IsClient(source_p))
1571 {
1572 ilog(L_INFO, "%s (%3ld:%02ld:%02ld): %s!%s@%s %llu/%llu\n",
1573 myctime(source_p->firsttime),
1574 (signed long) on_for / 3600,
1575 (signed long) (on_for % 3600)/60,
1576 (signed long) on_for % 60,
1577 source_p->name, source_p->username, source_p->host,
1578 source_p->localClient->send.bytes>>10,
1579 source_p->localClient->recv.bytes>>10);
1580 }
1581 #else
1582 {
1583 char linebuf[BUFSIZ];
1584
1585 /*
1586 * This conditional makes the logfile active only after
1587 * it's been created - thus logging can be turned off by
1588 * removing the file.
1589 * -Taner
1590 */
1591 if (IsClient(source_p))
1592 {
1593 if (user_log_fb == NULL)
1594 {
1595 if ((ConfigLoggingEntry.userlog[0] != '\0') &&
1596 (user_log_fb = fbopen(ConfigLoggingEntry.userlog, "r")) != NULL)
1597 {
1598 fbclose(user_log_fb);
1599 user_log_fb = fbopen(ConfigLoggingEntry.userlog, "a");
1600 }
1601 }
1602
1603 if (user_log_fb != NULL)
1604 {
1605 size_t nbytes = ircsprintf(linebuf,
1606 "%s (%3ld:%02ld:%02ld): %s!%s@%s %llu/%llu\n",
1607 myctime(source_p->firsttime),
1608 (signed long) on_for / 3600,
1609 (signed long) (on_for % 3600)/60,
1610 (signed long) on_for % 60,
1611 source_p->name, source_p->username, source_p->host,
1612 source_p->localClient->send.bytes>>10,
1613 source_p->localClient->recv.bytes>>10);
1614 fbputs(linebuf, user_log_fb, nbytes);
1615 }
1616 }
1617 }
1618 #endif
1619 }
1620
1621
1622 /* log_oper_action()
1623 *
1624 * inputs - type of oper log entry
1625 * - pointer to oper
1626 * - const char *pattern == format string
1627 * - var args for format string
1628 * output - none
1629 * side effects - corresponding log is written to, if its present.
1630 *
1631 * rewritten sept 5 2005 - Dianora
1632 */
1633 void
1634 log_oper_action(int log_type, const struct Client *source_p,
1635 const char *pattern, ...)
1636 {
1637 va_list args;
1638 char linebuf[IRCD_BUFSIZE];
1639 FBFILE *log_fb;
1640 char *logfile;
1641 const char *log_message;
1642 size_t nbytes;
1643 size_t n_preamble;
1644 char *p;
1645
1646 switch(log_type)
1647 {
1648 case LOG_OPER_TYPE:
1649 logfile = ConfigLoggingEntry.operlog;
1650 log_message = "OPER";
1651 break;
1652 case LOG_FAILED_OPER_TYPE:
1653 logfile = ConfigLoggingEntry.failed_operlog;
1654 log_message = "FAILED OPER";
1655 break;
1656 case LOG_KLINE_TYPE:
1657 logfile = ConfigLoggingEntry.klinelog;
1658 log_message = "KLINE";
1659 break;
1660 case LOG_RKLINE_TYPE:
1661 logfile = ConfigLoggingEntry.klinelog;
1662 log_message = "RKLINE";
1663 break;
1664 case LOG_DLINE_TYPE:
1665 logfile = ConfigLoggingEntry.klinelog;
1666 log_message = "DLINE";
1667 break;
1668 case LOG_TEMP_DLINE_TYPE:
1669 logfile = ConfigLoggingEntry.klinelog;
1670 log_message = "TEMP DLINE";
1671 break;
1672 case LOG_TEMP_KLINE_TYPE:
1673 logfile = ConfigLoggingEntry.klinelog;
1674 log_message = "TEMP KLINE";
1675 break;
1676 case LOG_GLINE_TYPE:
1677 logfile = ConfigLoggingEntry.glinelog;
1678 log_message = "GLINE";
1679 break;
1680 case LOG_KILL_TYPE:
1681 logfile = ConfigLoggingEntry.killlog;
1682 log_message = "KILL";
1683 break;
1684 case LOG_IOERR_TYPE:
1685 logfile = ConfigLoggingEntry.ioerrlog;
1686 log_message = "IO ERR";
1687 break;
1688 default:
1689 return;
1690 }
1691
1692 if (*logfile == '\0')
1693 return;
1694
1695 p = linebuf;
1696 if (source_p != NULL)
1697 {
1698 n_preamble = ircsprintf(linebuf, "%s %s by (%s!%s@%s) :",
1699 myctime(CurrentTime), log_message,
1700 source_p->name, source_p->username, source_p->host);
1701
1702 }
1703 else
1704 {
1705 n_preamble = ircsprintf(linebuf, "%s %s :",
1706 myctime(CurrentTime), log_message);
1707 }
1708
1709 p += n_preamble;
1710
1711 if ((log_fb = fbopen(logfile, "r")) != NULL)
1712 {
1713 fbclose(log_fb);
1714 log_fb = fbopen(logfile, "a");
1715 if (log_fb == NULL)
1716 return;
1717 va_start(args, pattern);
1718 /* XXX add check for IRCD_BUFSIZE-(n_preamble+1) < 0 ? -db */
1719 nbytes = vsnprintf(p, IRCD_BUFSIZE-(n_preamble+1), pattern, args);
1720 nbytes += n_preamble;
1721 va_end(args);
1722 fbputs(linebuf, log_fb, nbytes);
1723 fbclose(log_fb);
1724 }
1725 }

Properties

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