ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/src/client.c
Revision: 688
Committed: Sat Jun 17 11:21:50 2006 UTC (17 years, 9 months ago) by michael
Content type: text/x-csrc
File size: 46782 byte(s)
Log Message:
- Merged update_client_exit_stats() into exit_one_client()

File Contents

# User Rev Content
1 adx 30 /*
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 knight 31 * $Id$
23 adx 30 */
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 "numeric.h"
32     #include "packet.h"
33     #include "s_auth.h"
34     #include "s_conf.h"
35 db 101 #include "parse_aline.h"
36 adx 30 #include "s_serv.h"
37     #include "send.h"
38     #include "whowas.h"
39     #include "s_user.h"
40     #include "hostmask.h"
41     #include "listener.h"
42     #include "userhost.h"
43 michael 221 #include "watch.h"
44 adx 30
45     dlink_list listing_client_list = { NULL, NULL, 0 };
46     /* Pointer to beginning of Client list */
47     dlink_list global_client_list = {NULL, NULL, 0};
48     /* unknown/client pointer lists */
49     dlink_list unknown_list = {NULL, NULL, 0};
50     dlink_list local_client_list = {NULL, NULL, 0};
51     dlink_list serv_list = {NULL, NULL, 0};
52     dlink_list global_serv_list = {NULL, NULL, 0};
53     dlink_list oper_list = {NULL, NULL, 0};
54    
55     static EVH check_pings;
56    
57     static BlockHeap *client_heap = NULL;
58     static BlockHeap *lclient_heap = NULL;
59    
60     static dlink_list dead_list = { NULL, NULL, 0};
61     static dlink_list abort_list = { NULL, NULL, 0};
62    
63     static dlink_node *eac_next; /* next aborted client to exit */
64    
65     static void check_pings_list(dlink_list *);
66     static void check_unknowns_list(void);
67 adx 68 static void close_connection(struct Client *);
68 adx 30 static void ban_them(struct Client *client_p, struct ConfItem *conf);
69 db 232 static void del_all_accepts(struct Client *);
70 adx 30
71     /* init_client()
72     *
73     * inputs - NONE
74     * output - NONE
75     * side effects - initialize client free memory
76     */
77     void
78     init_client(void)
79     {
80     /* start off the check ping event .. -- adrian
81     * Every 30 seconds is plenty -- db
82     */
83     client_heap = BlockHeapCreate("client", sizeof(struct Client), CLIENT_HEAP_SIZE);
84     lclient_heap = BlockHeapCreate("local client", sizeof(struct LocalUser), LCLIENT_HEAP_SIZE);
85     eventAdd("check_pings", check_pings, NULL, 5);
86     }
87    
88     /*
89     * make_client - create a new Client struct and set it to initial state.
90     *
91     * from == NULL, create local client (a client connected
92     * to a socket).
93     * WARNING: This leaves the client in a dangerous
94     * state where fd == -1, dead flag is not set and
95     * the client is on the unknown_list; therefore,
96     * the first thing to do after calling make_client(NULL)
97     * is setting fd to something reasonable. -adx
98     *
99     * from, create remote client (behind a socket
100     * associated with the client defined by
101     * 'from'). ('from' is a local client!!).
102     */
103     struct Client *
104     make_client(struct Client *from)
105     {
106     struct Client *client_p = BlockHeapAlloc(client_heap);
107    
108     if (from == NULL)
109     {
110     client_p->from = client_p; /* 'from' of local client is self! */
111     client_p->since = client_p->lasttime = client_p->firsttime = CurrentTime;
112    
113     client_p->localClient = BlockHeapAlloc(lclient_heap);
114 michael 502 client_p->localClient->registration = REG_INIT;
115 adx 30 /* as good a place as any... */
116 michael 471 dlinkAdd(client_p, &client_p->localClient->lclient_node, &unknown_list);
117 adx 30 }
118     else
119 michael 316 client_p->from = from;
120 adx 30
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->channel.head == NULL);
142     assert(dlink_list_length(&client_p->channel) == 0);
143    
144     MyFree(client_p->away);
145     MyFree(client_p->serv);
146    
147     if (MyConnect(client_p))
148     {
149 michael 315 assert(dlink_list_length(&client_p->localClient->invited) == 0);
150     assert(client_p->localClient->invited.head == NULL);
151 adx 30 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 db 139 aconf = &conf->conf.AccessItem;
256 adx 30
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 michael 651 dlink_node *ptr = NULL, *next_ptr = NULL;
347 adx 30
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 adx 224 exit_client(client_p, &me, "Rejected");
356 adx 30 continue;
357     }
358    
359 michael 651 /*
360     * Check UNKNOWN connections - if they have been in this state
361 adx 30 * for > 30s, close them.
362     */
363 michael 651 if (IsAuthFinished(client_p) && (CurrentTime - client_p->firsttime) > 30)
364     exit_client(client_p, &me, "Registration timed out");
365 adx 30 }
366     }
367    
368     /* check_conf_klines()
369     *
370     * inputs - NONE
371     * output - NONE
372     * side effects - Check all connections for a pending kline against the
373     * client, exit the client if a kline matches.
374     */
375     void
376     check_conf_klines(void)
377     {
378     struct Client *client_p = NULL; /* current local client_p being examined */
379     struct AccessItem *aconf = NULL;
380     struct ConfItem *conf = NULL;
381     dlink_node *ptr, *next_ptr;
382    
383     DLINK_FOREACH_SAFE(ptr, next_ptr, local_client_list.head)
384     {
385     client_p = ptr->data;
386    
387     /* If a client is already being exited
388     */
389     if (IsDead(client_p) || !IsClient(client_p))
390     continue;
391    
392     /* if there is a returned struct ConfItem then kill it */
393     if ((aconf = find_dline_conf(&client_p->localClient->ip,
394     client_p->localClient->aftype)) != NULL)
395     {
396     if (aconf->status & CONF_EXEMPTDLINE)
397 adx 224 continue;
398 adx 30
399 db 141 conf = aconf->conf_ptr;
400 adx 30 ban_them(client_p, conf);
401     continue; /* and go examine next fd/client_p */
402     }
403    
404 adx 224 if (ConfigFileEntry.glines && (aconf = find_gline(client_p)) != NULL)
405 adx 30 {
406 adx 224 if (IsExemptKline(client_p) || IsExemptGline(client_p))
407 adx 30 {
408     sendto_realops_flags(UMODE_ALL, L_ALL,
409 adx 224 "GLINE over-ruled for %s, client is %cline_exempt",
410     get_client_name(client_p, HIDE_IP),
411     IsExemptKline(client_p) ? 'k' : 'g');
412 adx 30 continue;
413     }
414    
415 db 141 conf = aconf->conf_ptr;
416 adx 30 ban_them(client_p, conf);
417     /* and go examine next fd/client_p */
418     continue;
419     }
420    
421     if ((aconf = find_kill(client_p)) != NULL)
422     {
423    
424     /* if there is a returned struct AccessItem.. then kill it */
425     if (IsExemptKline(client_p))
426     {
427     sendto_realops_flags(UMODE_ALL, L_ALL,
428     "KLINE over-ruled for %s, client is kline_exempt",
429     get_client_name(client_p, HIDE_IP));
430     continue;
431     }
432    
433 db 141 conf = aconf->conf_ptr;
434 adx 30 ban_them(client_p, conf);
435     continue;
436     }
437    
438     /* if there is a returned struct MatchItem then kill it */
439     if ((conf = find_matching_name_conf(XLINE_TYPE, client_p->info,
440     NULL, NULL, 0)) != NULL ||
441     (conf = find_matching_name_conf(RXLINE_TYPE, client_p->info,
442     NULL, NULL, 0)) != NULL)
443     {
444     ban_them(client_p, conf);
445     continue;
446     }
447     }
448    
449     /* also check the unknowns list for new dlines */
450     DLINK_FOREACH_SAFE(ptr, next_ptr, unknown_list.head)
451     {
452     client_p = ptr->data;
453    
454     if ((aconf = find_dline_conf(&client_p->localClient->ip,
455     client_p->localClient->aftype)))
456     {
457     if (aconf->status & CONF_EXEMPTDLINE)
458     continue;
459    
460     exit_client(client_p, &me, "D-lined");
461     }
462     }
463     }
464    
465     /*
466     * ban_them
467     *
468     * inputs - pointer to client to ban
469     * - pointer to ConfItem
470     * output - NONE
471     * side effects - given client_p is banned
472     */
473     static void
474     ban_them(struct Client *client_p, struct ConfItem *conf)
475     {
476     const char *user_reason = NULL; /* What is sent to user */
477     const char *channel_reason = NULL; /* What is sent to channel */
478     struct AccessItem *aconf = NULL;
479     struct MatchItem *xconf = NULL;
480     const char *type_string = NULL;
481     const char dline_string[] = "D-line";
482     const char kline_string[] = "K-line";
483     const char gline_string[] = "G-line";
484     const char xline_string[] = "X-line";
485    
486     switch (conf->type)
487     {
488     case RKLINE_TYPE:
489     case KLINE_TYPE:
490     type_string = kline_string;
491 db 139 aconf = &conf->conf.AccessItem;
492 adx 30 break;
493     case DLINE_TYPE:
494     type_string = dline_string;
495 db 139 aconf = &conf->conf.AccessItem;
496 adx 30 break;
497     case GLINE_TYPE:
498     type_string = gline_string;
499 db 139 aconf = &conf->conf.AccessItem;
500 adx 30 break;
501     case RXLINE_TYPE:
502     case XLINE_TYPE:
503     type_string = xline_string;
504 db 139 xconf = &conf->conf.MatchItem;
505 adx 30 ++xconf->count;
506     break;
507     default:
508     assert(0);
509     break;
510     }
511    
512     if (ConfigFileEntry.kline_with_reason)
513     {
514     if (aconf != NULL)
515     user_reason = aconf->reason ? aconf->reason : type_string;
516     if (xconf != NULL)
517     user_reason = xconf->reason ? xconf->reason : type_string;
518     }
519     else
520     user_reason = type_string;
521    
522     if (ConfigFileEntry.kline_reason != NULL)
523     channel_reason = ConfigFileEntry.kline_reason;
524     else
525     channel_reason = user_reason;
526    
527     sendto_realops_flags(UMODE_ALL, L_ALL, "%s active for %s",
528     type_string, get_client_name(client_p, HIDE_IP));
529    
530     if (IsClient(client_p))
531     sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP),
532     me.name, client_p->name, user_reason);
533    
534     exit_client(client_p, &me, channel_reason);
535     }
536    
537     /* find_person()
538     *
539     * inputs - pointer to name
540     * output - return client pointer
541     * side effects - find person by (nick)name
542     */
543     struct Client *
544 michael 605 find_person(const struct Client *source_p, const char *name)
545 adx 30 {
546 michael 605 struct Client *target_p = NULL;
547 adx 30
548 michael 605 if (IsDigit(*name) && IsServer(source_p->from))
549     target_p = hash_find_id(name);
550 adx 30 else
551 michael 605 target_p = find_client(name);
552 adx 30
553 michael 605 return (target_p && IsClient(target_p)) ? target_p : NULL;
554 adx 30 }
555    
556     /*
557     * find_chasing - find the client structure for a nick name (user)
558     * using history mechanism if necessary. If the client is not found,
559     * an error message (NO SUCH NICK) is generated. If the client was found
560     * through the history, chasing will be 1 and otherwise 0.
561     */
562     struct Client *
563 michael 605 find_chasing(struct Client *source_p, const char *user, int *chasing)
564 adx 30 {
565 michael 605 struct Client *who = find_person(source_p, user);
566 adx 30
567     if (chasing)
568     *chasing = 0;
569    
570     if (who)
571 michael 450 return who;
572 adx 30
573     if (IsDigit(*user))
574 michael 450 return NULL;
575 adx 30
576 michael 655 if ((who = whowas_get_history(user,
577 adx 30 (time_t)ConfigFileEntry.kill_chase_time_limit))
578     == NULL)
579     {
580     sendto_one(source_p, form_str(ERR_NOSUCHNICK),
581     me.name, source_p->name, user);
582 michael 450 return NULL;
583 adx 30 }
584    
585     if (chasing)
586     *chasing = 1;
587    
588 michael 450 return who;
589 adx 30 }
590    
591     /*
592     * get_client_name - Return the name of the client
593     * for various tracking and
594     * admin purposes. The main purpose of this function is to
595     * return the "socket host" name of the client, if that
596     * differs from the advertised name (other than case).
597     * But, this can be used to any client structure.
598     *
599     * NOTE 1:
600     * Watch out the allocation of "nbuf", if either source_p->name
601     * or source_p->sockhost gets changed into pointers instead of
602     * directly allocated within the structure...
603     *
604     * NOTE 2:
605     * Function return either a pointer to the structure (source_p) or
606     * to internal buffer (nbuf). *NEVER* use the returned pointer
607     * to modify what it points!!!
608     */
609     const char *
610 michael 551 get_client_name(const struct Client *client, int showip)
611 adx 30 {
612     static char nbuf[HOSTLEN * 2 + USERLEN + 5];
613    
614     assert(client != NULL);
615    
616 michael 551 if (!irccmp(client->name, client->host))
617 michael 450 return client->name;
618 adx 30
619     if (ConfigServerHide.hide_server_ips)
620     if (IsServer(client) || IsConnecting(client) || IsHandshake(client))
621     showip = MASK_IP;
622    
623     if (ConfigFileEntry.hide_spoof_ips)
624     if (showip == SHOW_IP && IsIPSpoof(client))
625     showip = MASK_IP;
626    
627     /* And finally, let's get the host information, ip or name */
628     switch (showip)
629     {
630     case SHOW_IP:
631     if (MyConnect(client))
632     {
633     ircsprintf(nbuf, "%s[%s@%s]", client->name, client->username,
634     client->sockhost);
635     break;
636     }
637     case MASK_IP:
638     ircsprintf(nbuf, "%s[%s@255.255.255.255]", client->name,
639     client->username);
640     break;
641     default:
642     ircsprintf(nbuf, "%s[%s@%s]", client->name, client->username,
643     client->host);
644     }
645    
646 michael 450 return nbuf;
647 adx 30 }
648    
649     void
650     free_exited_clients(void)
651     {
652     dlink_node *ptr, *next;
653 michael 688
654 adx 30 DLINK_FOREACH_SAFE(ptr, next, dead_list.head)
655     {
656 michael 688 free_client(ptr->data);
657 adx 30 dlinkDelete(ptr, &dead_list);
658     free_dlink_node(ptr);
659     }
660     }
661    
662     /*
663     * Exit one client, local or remote. Assuming all dependents have
664     * been already removed, and socket closed for local client.
665     *
666     * The only messages generated are QUITs on channels.
667     */
668     static void
669     exit_one_client(struct Client *source_p, const char *quitmsg)
670     {
671     dlink_node *lp = NULL, *next_lp = NULL;
672    
673 michael 529 assert(!IsMe(source_p) && (source_p != &me));
674 adx 30
675 michael 529 if (IsClient(source_p))
676 adx 30 {
677 michael 654 assert(source_p->servptr);
678     assert(source_p->servptr->serv);
679 adx 30
680 michael 688 --Count.total;
681     if (IsOper(source_p))
682     --Count.oper;
683     if (IsInvisible(source_p))
684     --Count.invisi;
685    
686 michael 654 dlinkDelete(&source_p->lnode, &source_p->servptr->serv->client_list);
687    
688 michael 315 /*
689 michael 688 * If a person is on a channel, send a QUIT notice to every
690     * client (person) on the same channel (so that the client
691     * can show the "**signoff" message). (Note: The notice is
692     * to the local clients *only*)
693 michael 315 */
694 adx 30 sendto_common_channels_local(source_p, 0, ":%s!%s@%s QUIT :%s",
695     source_p->name, source_p->username,
696     source_p->host, quitmsg);
697     DLINK_FOREACH_SAFE(lp, next_lp, source_p->channel.head)
698     remove_user_from_channel(lp->data);
699    
700 michael 655 whowas_add_history(source_p, 0);
701     whowas_off_history(source_p);
702 adx 30
703 michael 193 assert(source_p->whowas.head == NULL);
704     assert(source_p->whowas.tail == NULL);
705    
706 michael 655 watch_check_hash(source_p, RPL_LOGOFF);
707 michael 568
708 db 238 /* Do local vs. remote processing here */
709     if (MyConnect(source_p))
710 adx 30 {
711 michael 315 /* Clean up invitefield */
712 michael 316 DLINK_FOREACH_SAFE(lp, next_lp, source_p->localClient->invited.head)
713 michael 315 del_invite(lp->data, source_p);
714    
715 db 238 /* Clean up allow lists */
716     del_all_accepts(source_p);
717     }
718 adx 30 }
719 michael 529 else if (IsServer(source_p))
720     {
721 michael 688 sendto_realops_flags(UMODE_EXTERNAL, L_ALL,
722     "Server %s split from %s",
723     source_p->name, source_p->servptr->name);
724    
725 michael 654 dlinkDelete(&source_p->lnode, &source_p->servptr->serv->server_list);
726 adx 30
727 michael 529 if ((lp = dlinkFindDelete(&global_serv_list, source_p)) != NULL)
728     free_dlink_node(lp);
729     }
730    
731 michael 688 if (splitchecking && !splitmode)
732     check_splitmode(NULL);
733    
734 adx 30 /* Remove source_p from the client lists */
735     if (HasID(source_p))
736     hash_del_id(source_p);
737     if (source_p->name[0])
738     hash_del_client(source_p);
739    
740     if (IsUserHostIp(source_p))
741     delete_user_host(source_p->username, source_p->host, !MyConnect(source_p));
742    
743     /* remove from global client list
744     * NOTE: source_p->node.next cannot be NULL if the client is added
745     * to global_client_list (there is always &me at its end)
746     */
747     if (source_p != NULL && source_p->node.next != NULL)
748     dlinkDelete(&source_p->node, &global_client_list);
749    
750     /* Check to see if the client isn't already on the dead list */
751     assert(dlinkFind(&dead_list, source_p) == NULL);
752    
753     /* add to dead client dlist */
754     SetDead(source_p);
755     dlinkAdd(source_p, make_dlink_node(), &dead_list);
756     }
757    
758     /* Recursively send QUITs and SQUITs for source_p and all its dependent clients
759     * and servers to those servers that need them. A server needs the client
760     * QUITs if it can't figure them out from the SQUIT (ie pre-TS4) or if it
761     * isn't getting the SQUIT because of @#(*&@)# hostmasking. With TS4, once
762     * a link gets a SQUIT, it doesn't need any QUIT/SQUITs for clients depending
763     * on that one -orabidoo
764     *
765     * This is now called on each local server -adx
766     */
767     static void
768     recurse_send_quits(struct Client *original_source_p, struct Client *source_p,
769     struct Client *from, struct Client *to, const char *comment,
770     const char *splitstr, const char *myname)
771     {
772     dlink_node *ptr, *next;
773     struct Client *target_p;
774     int hidden = match(myname, source_p->name);
775    
776     assert(to != source_p); /* should be already removed from serv_list */
777    
778     /* If this server can handle quit storm (QS) removal
779     * of dependents, just send the SQUIT
780     *
781     * Always check *all* dependent servers if some of them are
782     * hidden behind fakename. If so, send out the QUITs -adx
783     */
784     if (hidden || !IsCapable(to, CAP_QS))
785 michael 654 {
786     DLINK_FOREACH_SAFE(ptr, next, source_p->serv->client_list.head)
787 adx 30 {
788     target_p = ptr->data;
789     sendto_one(to, ":%s QUIT :%s", target_p->name, splitstr);
790     }
791 michael 654 }
792 adx 30
793 michael 654 DLINK_FOREACH_SAFE(ptr, next, source_p->serv->server_list.head)
794 adx 30 recurse_send_quits(original_source_p, ptr->data, from, to,
795     comment, splitstr, myname);
796    
797     if (!hidden && ((source_p == original_source_p && to != from) ||
798     !IsCapable(to, CAP_QS)))
799     {
800     /* don't use a prefix here - we have to be 100% sure the message
801     * will be accepted without Unknown prefix etc.. */
802     sendto_one(to, "SQUIT %s :%s", ID_or_name(source_p, to), comment);
803     }
804     }
805    
806     /*
807     * Remove all clients that depend on source_p; assumes all (S)QUITs have
808     * already been sent. we make sure to exit a server's dependent clients
809     * and servers before the server itself; exit_one_client takes care of
810     * actually removing things off llists. tweaked from +CSr31 -orabidoo
811     */
812     static void
813     recurse_remove_clients(struct Client *source_p, const char *quitmsg)
814     {
815 michael 654 dlink_node *ptr = NULL, *next = NULL;
816 adx 30
817 michael 654 DLINK_FOREACH_SAFE(ptr, next, source_p->serv->client_list.head)
818 adx 30 exit_one_client(ptr->data, quitmsg);
819    
820 michael 654 DLINK_FOREACH_SAFE(ptr, next, source_p->serv->server_list.head)
821 adx 30 {
822     recurse_remove_clients(ptr->data, quitmsg);
823     exit_one_client(ptr->data, quitmsg);
824     }
825     }
826    
827     /*
828     ** Remove *everything* that depends on source_p, from all lists, and sending
829     ** all necessary QUITs and SQUITs. source_p itself is still on the lists,
830     ** and its SQUITs have been sent except for the upstream one -orabidoo
831     */
832     static void
833     remove_dependents(struct Client *source_p, struct Client *from,
834     const char *comment, const char *splitstr)
835     {
836     struct Client *to;
837     struct ConfItem *conf;
838 db 126 struct AccessItem *aconf;
839 adx 30 static char myname[HOSTLEN+1];
840     dlink_node *ptr;
841    
842     DLINK_FOREACH(ptr, serv_list.head)
843     {
844     to = ptr->data;
845    
846     if ((conf = to->serv->sconf) != NULL)
847 db 126 {
848 db 139 aconf = &conf->conf.AccessItem;
849 db 126 strlcpy(myname, my_name_for_link(aconf), sizeof(myname));
850     }
851 adx 30 else
852     strlcpy(myname, me.name, sizeof(myname));
853     recurse_send_quits(source_p, source_p, from, to,
854     comment, splitstr, myname);
855     }
856    
857     recurse_remove_clients(source_p, splitstr);
858     }
859    
860     /*
861     * exit_client - exit a client of any type. Generally, you can use
862     * this on any struct Client, regardless of its state.
863     *
864     * Note, you shouldn't exit remote _users_ without first doing
865     * SetKilled and propagating a kill or similar message. However,
866     * it is perfectly correct to call exit_client to force a _server_
867     * quit (either local or remote one).
868     *
869     * inputs: - a client pointer that is going to be exited
870     * - for servers, the second argument is a pointer to who
871     * is firing the server. This side won't get any generated
872     * messages. NEVER NULL!
873     * output: none
874     * side effects: the client is delinked from all lists, disconnected,
875     * and the rest of IRC network is notified of the exit.
876     * Client memory is scheduled to be freed
877     */
878     void
879     exit_client(struct Client *source_p, struct Client *from, const char *comment)
880     {
881 michael 568 dlink_node *m = NULL;
882 adx 30
883     if (MyConnect(source_p))
884     {
885 michael 568 /*
886     * DO NOT REMOVE. exit_client can be called twice after a failed
887 adx 30 * read/write.
888     */
889     if (IsClosing(source_p))
890     return;
891    
892     SetClosing(source_p);
893    
894     if (IsIpHash(source_p))
895     remove_one_ip(&source_p->localClient->ip);
896    
897     delete_auth(source_p);
898    
899 michael 471 if (IsClient(source_p))
900 adx 30 {
901 michael 450 --Count.local;
902 adx 30
903     if (IsOper(source_p))
904     if ((m = dlinkFindDelete(&oper_list, source_p)) != NULL)
905     free_dlink_node(m);
906    
907     dlinkDelete(&source_p->localClient->lclient_node, &local_client_list);
908 michael 688
909 adx 30 if (source_p->localClient->list_task != NULL)
910     free_list_task(source_p->localClient->list_task, source_p);
911 michael 471
912 michael 655 watch_del_watch_list(source_p);
913 adx 30 sendto_realops_flags(UMODE_CCONN, L_ALL, "Client exiting: %s (%s@%s) [%s] [%s]",
914     source_p->name, source_p->username, source_p->host, comment,
915     ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ?
916     "255.255.255.255" : source_p->sockhost);
917     }
918 michael 682 else if (IsServer(source_p))
919 michael 471 {
920 michael 682 if ((m = dlinkFindDelete(&serv_list, source_p)) != NULL)
921     unset_chcap_usage_counts(source_p);
922    
923     --Count.myserver;
924     }
925     else
926     {
927 michael 471 /*
928 michael 682 * This source_p could have status of one of STAT_UNKNOWN,
929     * STAT_CONNECTING or STAT_HANDSHAKE
930 michael 471 * all of which are lumped together into unknown_list
931     *
932     * In all above cases IsRegistered() will not be true.
933     */
934 michael 682 assert(!IsRegistered(source_p));
935 michael 471 dlinkDelete(&source_p->localClient->lclient_node, &unknown_list);
936     }
937 adx 30
938     log_user_exit(source_p);
939    
940     if (!IsDead(source_p))
941     {
942     if (IsServer(source_p))
943     {
944     /* for them, we are exiting the network */
945     sendto_one(source_p, ":%s SQUIT %s :%s",
946     ID_or_name(from, source_p), me.name, comment);
947     }
948    
949     sendto_one(source_p, "ERROR :Closing Link: %s (%s)",
950     source_p->host, comment);
951     }
952    
953     /*
954 michael 688 * Close the Client connection first and mark it so that no
955     * messages are attempted to send to it. Remember it makes
956     * source_p->from == NULL.
957     */
958 adx 30 close_connection(source_p);
959     }
960    
961 michael 529 if (IsClient(source_p) && !IsKilled(source_p))
962 adx 30 {
963 michael 529 sendto_server(from->from, source_p, NULL, CAP_TS6, NOCAPS,
964     ":%s QUIT :%s", ID(source_p), comment);
965     sendto_server(from->from, source_p, NULL, NOCAPS, CAP_TS6,
966     ":%s QUIT :%s", source_p->name, comment);
967     }
968     else if (IsServer(source_p))
969     {
970 adx 30 char splitstr[HOSTLEN + HOSTLEN + 2];
971    
972     /* This shouldn't ever happen */
973     assert(source_p->serv != NULL && source_p->servptr != NULL);
974    
975     if (ConfigServerHide.hide_servers)
976 michael 398 /*
977     * set netsplit message to "*.net *.split" to still show
978 michael 682 * that it's a split, but hide the servers splitting
979 adx 30 */
980     strcpy(splitstr, "*.net *.split");
981     else
982     snprintf(splitstr, sizeof(splitstr), "%s %s",
983     source_p->servptr->name, source_p->name);
984    
985     remove_dependents(source_p, from->from, comment, splitstr);
986    
987 michael 682 if (MyConnect(source_p))
988 adx 30 {
989     sendto_realops_flags(UMODE_ALL, L_ALL,
990     "%s was connected for %d seconds. %llu/%llu sendK/recvK.",
991     source_p->name, (int)(CurrentTime - source_p->firsttime),
992     source_p->localClient->send.bytes >> 10,
993     source_p->localClient->recv.bytes >> 10);
994     ilog(L_NOTICE, "%s was connected for %d seconds. %llu/%llu sendK/recvK.",
995     source_p->name, (int)(CurrentTime - source_p->firsttime),
996     source_p->localClient->send.bytes >> 10,
997     source_p->localClient->recv.bytes >> 10);
998     }
999     }
1000    
1001     /* The client *better* be off all of the lists */
1002     assert(dlinkFind(&unknown_list, source_p) == NULL);
1003     assert(dlinkFind(&local_client_list, source_p) == NULL);
1004     assert(dlinkFind(&serv_list, source_p) == NULL);
1005     assert(dlinkFind(&oper_list, source_p) == NULL);
1006    
1007     exit_one_client(source_p, comment);
1008     }
1009    
1010     /*
1011 adx 68 * close_connection
1012 michael 682 * Close the physical connection. This function sets client_p->from == NULL.
1013 adx 68 */
1014     static void
1015     close_connection(struct Client *client_p)
1016     {
1017     assert(NULL != client_p);
1018    
1019 michael 682 if (!IsDead(client_p))
1020     {
1021     /* attempt to flush any pending dbufs. Evil, but .. -- adrian */
1022     /* there is still a chance that we might send data to this socket
1023     * even if it is marked as blocked (COMM_SELECT_READ handler is called
1024     * before COMM_SELECT_WRITE). Let's try, nothing to lose.. -adx
1025     */
1026     ClearSendqBlocked(client_p);
1027     send_queued_write(client_p);
1028     }
1029    
1030 michael 529 if (IsClient(client_p))
1031 adx 68 {
1032 michael 529 ++ServerStats.is_cl;
1033     ServerStats.is_cbs += client_p->localClient->send.bytes;
1034     ServerStats.is_cbr += client_p->localClient->recv.bytes;
1035     ServerStats.is_cti += CurrentTime - client_p->firsttime;
1036     }
1037     else if (IsServer(client_p))
1038     {
1039 michael 515 ++ServerStats.is_sv;
1040     ServerStats.is_sbs += client_p->localClient->send.bytes;
1041     ServerStats.is_sbr += client_p->localClient->recv.bytes;
1042     ServerStats.is_sti += CurrentTime - client_p->firsttime;
1043 adx 68 }
1044     else
1045 michael 515 ++ServerStats.is_ni;
1046 adx 68
1047     #ifdef HAVE_LIBCRYPTO
1048     if (client_p->localClient->fd.ssl)
1049 michael 452 {
1050     SSL_set_shutdown(client_p->localClient->fd.ssl, SSL_RECEIVED_SHUTDOWN);
1051    
1052     if (!SSL_shutdown(client_p->localClient->fd.ssl))
1053     SSL_shutdown(client_p->localClient->fd.ssl);
1054     }
1055 adx 68 #endif
1056     if (client_p->localClient->fd.flags.open)
1057     fd_close(&client_p->localClient->fd);
1058    
1059     if (HasServlink(client_p))
1060     if (client_p->localClient->ctrlfd.flags.open)
1061     fd_close(&client_p->localClient->ctrlfd);
1062    
1063     dbuf_clear(&client_p->localClient->buf_sendq);
1064     dbuf_clear(&client_p->localClient->buf_recvq);
1065    
1066     MyFree(client_p->localClient->passwd);
1067 adx 365 detach_confs(client_p);
1068 adx 68 client_p->from = NULL; /* ...this should catch them! >:) --msa */
1069     }
1070    
1071     /*
1072     * report_error - report an error from an errno.
1073     * Record error to log and also send a copy to all *LOCAL* opers online.
1074     *
1075     * text is a *format* string for outputing error. It must
1076     * contain only two '%s', the first will be replaced
1077     * by the sockhost from the client_p, and the latter will
1078     * be taken from sys_errlist[errno].
1079     *
1080     * client_p if not NULL, is the *LOCAL* client associated with
1081     * the error.
1082     *
1083     * Cannot use perror() within daemon. stderr is closed in
1084     * ircd and cannot be used. And, worse yet, it might have
1085     * been reassigned to a normal connection...
1086     *
1087     * Actually stderr is still there IFF ircd was run with -s --Rodder
1088     */
1089     void
1090 adx 224 report_error(int level, const char *text, const char *who, int error)
1091 adx 68 {
1092 adx 224 who = (who != NULL) ? who : "";
1093 adx 68
1094     sendto_realops_flags(UMODE_DEBUG, level, text, who, strerror(error));
1095     log_oper_action(LOG_IOERR_TYPE, NULL, "%s %s %s\n", who, text, strerror(error));
1096     ilog(L_ERROR, text, who, strerror(error));
1097     }
1098    
1099     /*
1100 adx 30 * dead_link_on_write - report a write error if not already dead,
1101     * mark it as dead then exit it
1102     */
1103     void
1104     dead_link_on_write(struct Client *client_p, int ierrno)
1105     {
1106     dlink_node *ptr;
1107    
1108     if (IsDefunct(client_p))
1109     return;
1110    
1111     dbuf_clear(&client_p->localClient->buf_recvq);
1112     dbuf_clear(&client_p->localClient->buf_sendq);
1113    
1114     assert(dlinkFind(&abort_list, client_p) == NULL);
1115     ptr = make_dlink_node();
1116     /* don't let exit_aborted_clients() finish yet */
1117     dlinkAddTail(client_p, ptr, &abort_list);
1118    
1119     if (eac_next == NULL)
1120     eac_next = ptr;
1121    
1122     SetDead(client_p); /* You are dead my friend */
1123     }
1124    
1125     /*
1126     * dead_link_on_read - report a read error if not already dead,
1127     * mark it as dead then exit it
1128     */
1129     void
1130     dead_link_on_read(struct Client *client_p, int error)
1131     {
1132 michael 651 char errmsg[IRCD_BUFSIZE];
1133 adx 30 int current_error;
1134    
1135     if (IsDefunct(client_p))
1136     return;
1137    
1138     dbuf_clear(&client_p->localClient->buf_recvq);
1139     dbuf_clear(&client_p->localClient->buf_sendq);
1140    
1141     current_error = get_sockerr(client_p->localClient->fd.fd);
1142    
1143     if (IsServer(client_p) || IsHandshake(client_p))
1144     {
1145     int connected = CurrentTime - client_p->firsttime;
1146    
1147     if (error == 0)
1148     {
1149     /* Admins get the real IP */
1150     sendto_realops_flags(UMODE_ALL, L_ADMIN,
1151     "Server %s closed the connection",
1152     get_client_name(client_p, SHOW_IP));
1153    
1154     /* Opers get a masked IP */
1155     sendto_realops_flags(UMODE_ALL, L_OPER,
1156     "Server %s closed the connection",
1157     get_client_name(client_p, MASK_IP));
1158    
1159     ilog(L_NOTICE, "Server %s closed the connection",
1160     get_client_name(client_p, SHOW_IP));
1161     }
1162     else
1163     {
1164     report_error(L_ADMIN, "Lost connection to %s: %d",
1165     get_client_name(client_p, SHOW_IP), current_error);
1166     report_error(L_OPER, "Lost connection to %s: %d",
1167     get_client_name(client_p, MASK_IP), current_error);
1168     }
1169    
1170     sendto_realops_flags(UMODE_ALL, L_ALL,
1171     "%s had been connected for %d day%s, %2d:%02d:%02d",
1172     client_p->name, connected/86400,
1173     (connected/86400 == 1) ? "" : "s",
1174     (connected % 86400) / 3600, (connected % 3600) / 60,
1175     connected % 60);
1176     }
1177    
1178     if (error == 0)
1179     strlcpy(errmsg, "Remote host closed the connection",
1180     sizeof(errmsg));
1181     else
1182     ircsprintf(errmsg, "Read error: %s",
1183     strerror(current_error));
1184    
1185     exit_client(client_p, &me, errmsg);
1186     }
1187    
1188     void
1189     exit_aborted_clients(void)
1190     {
1191     dlink_node *ptr;
1192     struct Client *target_p;
1193     const char *notice;
1194    
1195     DLINK_FOREACH_SAFE(ptr, eac_next, abort_list.head)
1196     {
1197     target_p = ptr->data;
1198     eac_next = ptr->next;
1199    
1200     if (target_p == NULL)
1201     {
1202     sendto_realops_flags(UMODE_ALL, L_ALL,
1203     "Warning: null client on abort_list!");
1204     dlinkDelete(ptr, &abort_list);
1205     free_dlink_node(ptr);
1206     continue;
1207     }
1208    
1209     dlinkDelete(ptr, &abort_list);
1210    
1211     if (IsSendQExceeded(target_p))
1212     notice = "Max SendQ exceeded";
1213     else
1214     notice = "Write error: connection closed";
1215    
1216     exit_client(target_p, &me, notice);
1217     free_dlink_node(ptr);
1218     }
1219     }
1220    
1221     /*
1222     * accept processing, this adds a form of "caller ID" to ircd
1223     *
1224     * If a client puts themselves into "caller ID only" mode,
1225     * only clients that match a client pointer they have put on
1226     * the accept list will be allowed to message them.
1227     *
1228 db 232 * Diane Bruce, "Dianora" db@db.net
1229 adx 30 */
1230    
1231 michael 235 void
1232 metalrock 362 del_accept(struct Accept *acceptvar, struct Client *client_p)
1233 michael 235 {
1234 metalrock 362 dlinkDelete(&acceptvar->node, &client_p->localClient->acceptlist);
1235 michael 235
1236 metalrock 362 MyFree(acceptvar->nick);
1237     MyFree(acceptvar->user);
1238     MyFree(acceptvar->host);
1239     MyFree(acceptvar);
1240 michael 235 }
1241    
1242     struct Accept *
1243     find_accept(const char *nick, const char *user,
1244     const char *host, struct Client *client_p, int do_match)
1245     {
1246     dlink_node *ptr = NULL;
1247     /* XXX We wouldn't need that if match() would return 0 on match */
1248     int (*cmpfunc)(const char *, const char *) = do_match ? match : irccmp;
1249    
1250     DLINK_FOREACH(ptr, client_p->localClient->acceptlist.head)
1251     {
1252 metalrock 362 struct Accept *acceptvar = ptr->data;
1253 michael 235
1254 metalrock 362 if (cmpfunc(acceptvar->nick, nick) == do_match &&
1255     cmpfunc(acceptvar->user, user) == do_match &&
1256     cmpfunc(acceptvar->host, host) == do_match)
1257     return acceptvar;
1258 michael 235 }
1259    
1260     return NULL;
1261     }
1262    
1263 adx 30 /* accept_message()
1264     *
1265 michael 385 * inputs - pointer to source client
1266 adx 30 * - pointer to target client
1267     * output - 1 if accept this message 0 if not
1268     * side effects - See if source is on target's allow list
1269     */
1270     int
1271 michael 235 accept_message(struct Client *source,
1272     struct Client *target)
1273 adx 30 {
1274 michael 235 dlink_node *ptr = NULL;
1275 adx 30
1276 michael 236 if (source == target || find_accept(source->name, source->username,
1277     source->host, target, 1))
1278 michael 235 return 1;
1279 adx 30
1280 michael 235 if (IsSoftCallerId(target))
1281 adx 30 DLINK_FOREACH(ptr, target->channel.head)
1282 michael 385 if (IsMember(source, ((struct Membership *)ptr->data)->chptr))
1283 michael 235 return 1;
1284 adx 30
1285 michael 235 return 0;
1286 adx 30 }
1287    
1288     /* del_all_accepts()
1289     *
1290     * inputs - pointer to exiting client
1291     * output - NONE
1292 db 232 * side effects - Walk through given clients acceptlist and remove all entries
1293 adx 30 */
1294     void
1295     del_all_accepts(struct Client *client_p)
1296     {
1297 michael 235 dlink_node *ptr = NULL, *next_ptr = NULL;
1298 adx 30
1299 db 232 DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->localClient->acceptlist.head)
1300 michael 235 del_accept(ptr->data, client_p);
1301 adx 30 }
1302    
1303     /* set_initial_nick()
1304     *
1305     * inputs
1306     * output
1307     * side effects -
1308     *
1309     * This function is only called to set up an initially registering
1310     * client.
1311     */
1312     void
1313 michael 457 set_initial_nick(struct Client *source_p, const char *nick)
1314 adx 30 {
1315 michael 237 char buf[USERLEN + 1];
1316 adx 30
1317     /* This had to be copied here to avoid problems.. */
1318     source_p->tsinfo = CurrentTime;
1319 michael 502 source_p->localClient->registration &= ~REG_NEED_NICK;
1320 adx 30
1321     if (source_p->name[0])
1322     hash_del_client(source_p);
1323    
1324     strlcpy(source_p->name, nick, sizeof(source_p->name));
1325     hash_add_client(source_p);
1326    
1327     /* fd_desc is long enough */
1328 db 460 fd_note(&source_p->localClient->fd, "Nick: %s", nick);
1329 adx 30
1330 michael 502 if (!source_p->localClient->registration)
1331 adx 30 {
1332     strlcpy(buf, source_p->username, sizeof(buf));
1333    
1334     /*
1335     * USER already received, now we have NICK.
1336     * *NOTE* For servers "NICK" *must* precede the
1337     * user message (giving USER before NICK is possible
1338     * only for local client connection!). register_user
1339     * may reject the client and call exit_client for it
1340     * --must test this and exit m_nick too!!!
1341     */
1342 michael 458 register_local_user(source_p, buf);
1343 adx 30 }
1344     }
1345    
1346     /* change_local_nick()
1347     *
1348     * inputs - pointer to server
1349     * - pointer to client
1350     * - nick
1351     * output -
1352     * side effects - changes nick of a LOCAL user
1353     */
1354     void
1355     change_local_nick(struct Client *client_p, struct Client *source_p, const char *nick)
1356     {
1357 michael 221 int samenick = 0;
1358 michael 237
1359 adx 30 /*
1360 michael 237 * Client just changing his/her nick. If he/she is
1361     * on a channel, send note of change to all clients
1362     * on that channel. Propagate notice to other servers.
1363     */
1364 adx 30 if ((source_p->localClient->last_nick_change +
1365     ConfigFileEntry.max_nick_time) < CurrentTime)
1366     source_p->localClient->number_of_nick_changes = 0;
1367     source_p->localClient->last_nick_change = CurrentTime;
1368     source_p->localClient->number_of_nick_changes++;
1369    
1370     if ((ConfigFileEntry.anti_nick_flood &&
1371     (source_p->localClient->number_of_nick_changes
1372     <= ConfigFileEntry.max_nick_changes)) ||
1373     !ConfigFileEntry.anti_nick_flood ||
1374     (IsOper(source_p) && ConfigFileEntry.no_oper_flood))
1375     {
1376 michael 221 samenick = !irccmp(source_p->name, nick);
1377     if (!samenick)
1378 adx 30 source_p->tsinfo = CurrentTime;
1379    
1380     /* XXX - the format of this notice should eventually be changed
1381     * to either %s[%s@%s], or even better would be get_client_name() -bill
1382     */
1383     sendto_realops_flags(UMODE_NCHANGE, L_ALL, "Nick change: From %s to %s [%s@%s]",
1384     source_p->name, nick, source_p->username, source_p->host);
1385     sendto_common_channels_local(source_p, 1, ":%s!%s@%s NICK :%s",
1386     source_p->name, source_p->username,
1387     source_p->host, nick);
1388    
1389 michael 655 whowas_add_history(source_p, 1);
1390 michael 511
1391 michael 405 sendto_server(client_p, source_p, NULL, CAP_TS6, NOCAPS,
1392 adx 30 ":%s NICK %s :%lu",
1393     ID(source_p), nick, (unsigned long)source_p->tsinfo);
1394 michael 405 sendto_server(client_p, source_p, NULL, NOCAPS, CAP_TS6,
1395 adx 30 ":%s NICK %s :%lu",
1396     source_p->name, nick, (unsigned long)source_p->tsinfo);
1397     }
1398     else
1399     {
1400     sendto_one(source_p, form_str(ERR_NICKTOOFAST),
1401     me.name, source_p->name, source_p->name,
1402     nick, ConfigFileEntry.max_nick_time);
1403     return;
1404     }
1405    
1406     /* Finally, add to hash */
1407 michael 221 assert(source_p->name[0]);
1408 adx 30
1409 michael 221 hash_del_client(source_p);
1410 michael 511
1411 michael 221 if (!samenick)
1412 michael 655 watch_check_hash(source_p, RPL_LOGOFF);
1413 adx 30 strcpy(source_p->name, nick);
1414     hash_add_client(source_p);
1415    
1416 michael 221 if (!samenick)
1417 michael 655 watch_check_hash(source_p, RPL_LOGON);
1418 adx 30
1419     /* fd_desc is long enough */
1420     fd_note(&client_p->localClient->fd, "Nick: %s", nick);
1421     }
1422 adx 65
1423     /* log_user_exit()
1424     *
1425     * inputs - pointer to connecting client
1426     * output - NONE
1427     * side effects - Current exiting client is logged to
1428     * either SYSLOG or to file.
1429     */
1430     void
1431     log_user_exit(struct Client *source_p)
1432     {
1433     time_t on_for = CurrentTime - source_p->firsttime;
1434     #ifdef SYSLOG_USERS
1435     if (IsClient(source_p))
1436     {
1437     ilog(L_INFO, "%s (%3ld:%02ld:%02ld): %s!%s@%s %llu/%llu\n",
1438     myctime(source_p->firsttime),
1439     (signed long) on_for / 3600,
1440     (signed long) (on_for % 3600)/60,
1441     (signed long) on_for % 60,
1442     source_p->name, source_p->username, source_p->host,
1443     source_p->localClient->send.bytes>>10,
1444     source_p->localClient->recv.bytes>>10);
1445     }
1446     #else
1447     {
1448     char linebuf[BUFSIZ];
1449    
1450     /*
1451     * This conditional makes the logfile active only after
1452     * it's been created - thus logging can be turned off by
1453     * removing the file.
1454     * -Taner
1455     */
1456     if (IsClient(source_p))
1457     {
1458     if (user_log_fb == NULL)
1459     {
1460     if ((ConfigLoggingEntry.userlog[0] != '\0') &&
1461     (user_log_fb = fbopen(ConfigLoggingEntry.userlog, "r")) != NULL)
1462     {
1463     fbclose(user_log_fb);
1464     user_log_fb = fbopen(ConfigLoggingEntry.userlog, "a");
1465     }
1466     }
1467    
1468     if (user_log_fb != NULL)
1469     {
1470     size_t nbytes = ircsprintf(linebuf,
1471     "%s (%3ld:%02ld:%02ld): %s!%s@%s %llu/%llu\n",
1472     myctime(source_p->firsttime),
1473     (signed long) on_for / 3600,
1474     (signed long) (on_for % 3600)/60,
1475     (signed long) on_for % 60,
1476     source_p->name, source_p->username, source_p->host,
1477     source_p->localClient->send.bytes>>10,
1478     source_p->localClient->recv.bytes>>10);
1479     fbputs(linebuf, user_log_fb, nbytes);
1480     }
1481     }
1482     }
1483     #endif
1484     }
1485    
1486    
1487     /* log_oper_action()
1488     *
1489     * inputs - type of oper log entry
1490     * - pointer to oper
1491     * - const char *pattern == format string
1492     * - var args for format string
1493     * output - none
1494     * side effects - corresponding log is written to, if its present.
1495     *
1496     * rewritten sept 5 2005 - Dianora
1497     */
1498     void
1499     log_oper_action(int log_type, const struct Client *source_p,
1500     const char *pattern, ...)
1501     {
1502     va_list args;
1503     char linebuf[IRCD_BUFSIZE];
1504     FBFILE *log_fb;
1505     char *logfile;
1506     const char *log_message;
1507     size_t nbytes;
1508     size_t n_preamble;
1509     char *p;
1510    
1511     switch(log_type)
1512     {
1513     case LOG_OPER_TYPE:
1514     logfile = ConfigLoggingEntry.operlog;
1515     log_message = "OPER";
1516     break;
1517     case LOG_FAILED_OPER_TYPE:
1518     logfile = ConfigLoggingEntry.failed_operlog;
1519     log_message = "FAILED OPER";
1520     break;
1521     case LOG_KLINE_TYPE:
1522     logfile = ConfigLoggingEntry.klinelog;
1523     log_message = "KLINE";
1524     break;
1525     case LOG_RKLINE_TYPE:
1526     logfile = ConfigLoggingEntry.klinelog;
1527     log_message = "RKLINE";
1528     break;
1529     case LOG_DLINE_TYPE:
1530     logfile = ConfigLoggingEntry.klinelog;
1531     log_message = "DLINE";
1532     break;
1533     case LOG_TEMP_DLINE_TYPE:
1534     logfile = ConfigLoggingEntry.klinelog;
1535     log_message = "TEMP DLINE";
1536     break;
1537     case LOG_TEMP_KLINE_TYPE:
1538     logfile = ConfigLoggingEntry.klinelog;
1539     log_message = "TEMP KLINE";
1540     break;
1541     case LOG_GLINE_TYPE:
1542     logfile = ConfigLoggingEntry.glinelog;
1543     log_message = "GLINE";
1544     break;
1545     case LOG_KILL_TYPE:
1546     logfile = ConfigLoggingEntry.killlog;
1547     log_message = "KILL";
1548     break;
1549     case LOG_IOERR_TYPE:
1550     logfile = ConfigLoggingEntry.ioerrlog;
1551     log_message = "IO ERR";
1552     break;
1553     default:
1554     return;
1555     }
1556    
1557     if (*logfile == '\0')
1558     return;
1559    
1560     p = linebuf;
1561     if (source_p != NULL)
1562     {
1563     n_preamble = ircsprintf(linebuf, "%s %s by (%s!%s@%s) :",
1564     myctime(CurrentTime), log_message,
1565     source_p->name, source_p->username, source_p->host);
1566    
1567     }
1568     else
1569     {
1570     n_preamble = ircsprintf(linebuf, "%s %s :",
1571     myctime(CurrentTime), log_message);
1572     }
1573    
1574     p += n_preamble;
1575    
1576     if ((log_fb = fbopen(logfile, "r")) != NULL)
1577     {
1578     fbclose(log_fb);
1579     log_fb = fbopen(logfile, "a");
1580     if (log_fb == NULL)
1581     return;
1582     va_start(args, pattern);
1583     /* XXX add check for IRCD_BUFSIZE-(n_preamble+1) < 0 ? -db */
1584     nbytes = vsnprintf(p, IRCD_BUFSIZE-(n_preamble+1), pattern, args);
1585     nbytes += n_preamble;
1586     va_end(args);
1587     fbputs(linebuf, log_fb, nbytes);
1588     fbclose(log_fb);
1589     }
1590     }

Properties

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