ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/branches/newio/src/client.c
Revision: 2428
Committed: Wed Jul 31 15:31:20 2013 UTC (13 years, 2 months ago) by michael
Content type: text/x-csrc
File size: 36746 byte(s)
Log Message:
- ioengine changes as of 31JUL13

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 michael 1011 #include "list.h"
27 adx 30 #include "client.h"
28     #include "channel_mode.h"
29 michael 2392 #include "ioengine.h"
30 adx 30 #include "hash.h"
31     #include "irc_string.h"
32     #include "ircd.h"
33     #include "s_gline.h"
34     #include "numeric.h"
35     #include "packet.h"
36     #include "s_auth.h"
37     #include "s_bsd.h"
38 michael 1309 #include "conf.h"
39     #include "log.h"
40 adx 30 #include "s_misc.h"
41     #include "s_serv.h"
42     #include "send.h"
43     #include "whowas.h"
44     #include "s_user.h"
45     #include "dbuf.h"
46     #include "memory.h"
47 michael 1654 #include "mempool.h"
48 adx 30 #include "hostmask.h"
49     #include "listener.h"
50     #include "irc_res.h"
51     #include "userhost.h"
52 michael 876 #include "watch.h"
53 michael 1783 #include "rng_mt.h"
54 michael 2406 #include "xsnprintf.h"
55 adx 30
56 michael 2406
57 adx 30 /* Pointer to beginning of Client list */
58     dlink_list global_client_list = {NULL, NULL, 0};
59     /* unknown/client pointer lists */
60     dlink_list unknown_list = {NULL, NULL, 0};
61     dlink_list local_client_list = {NULL, NULL, 0};
62     dlink_list serv_list = {NULL, NULL, 0};
63     dlink_list global_serv_list = {NULL, NULL, 0};
64     dlink_list oper_list = {NULL, NULL, 0};
65    
66    
67 michael 2414 static struct Timer ping_timer; /**< Timer structure for check_pings() */
68 michael 1654 static mp_pool_t *client_pool = NULL;
69     static mp_pool_t *lclient_pool = NULL;
70 adx 30
71 michael 2414 static void check_pings(struct Event *);
72 michael 1632 static void ban_them(struct Client *, struct MaskItem *);
73 adx 30
74    
75 michael 1798 /* client_init()
76 adx 30 *
77     * inputs - NONE
78     * output - NONE
79     * side effects - initialize client free memory
80     */
81     void
82 michael 1798 client_init(void)
83 adx 30 {
84 michael 1654 client_pool = mp_pool_new(sizeof(struct Client), MP_CHUNK_SIZE_CLIENT);
85 michael 2388 lclient_pool = mp_pool_new(sizeof(struct Connection), MP_CHUNK_SIZE_LCLIENT);
86 michael 2414 timer_add(timer_init(&ping_timer), check_pings, 0, TT_RELATIVE, 1);
87 adx 30 }
88    
89 michael 2396 /** Allocate a new Client structure.
90     * If #clientFreeList != NULL, use the head of that list.
91     * Otherwise, allocate a new structure.
92     * @return Newly allocated Client.
93 adx 30 */
94 michael 2396 static struct Client *
95     alloc_client(void)
96 adx 30 {
97 michael 1654 struct Client *client_p = mp_pool_get(client_pool);
98 adx 30
99 michael 1654 memset(client_p, 0, sizeof(*client_p));
100 michael 2406 return client_p;
101 michael 2396 }
102 michael 1654
103 michael 2396 /** Release a Client structure by prepending it to #clientFreeList.
104 michael 2406 * @param[in] client_p Client that is no longer being used.
105 michael 2396 */
106     static void
107     dealloc_client(struct Client *client_p)
108     {
109     assert(!client_p->localClient);
110     mp_pool_release(client_p);
111     }
112    
113     /** Allocate a new Connection structure.
114     * If #connectionFreeList != NULL, use the head of that list.
115     * Otherwise, allocate a new structure.
116     * @return Newly allocated Connection.
117     */
118     static struct Connection *
119     alloc_connection(void)
120     {
121     struct Connection *con = mp_pool_get(lclient_pool);
122    
123     memset(con, 0, sizeof(*con));
124 michael 2406 timer_init(&con->proc);
125 michael 2396
126     return con;
127     }
128    
129     /** Release a Connection and all memory associated with it.
130     * The connection's DNS reply field is freed, its file descriptor is
131     * closed, its msgq and sendq are cleared, and its associated Listener
132     * is dereferenced. Then it is prepended to #connectionFreeList.
133     * @param[in] con Connection to free.
134     */
135     static void
136     dealloc_connection(struct Connection *con)
137     {
138     assert(!t_active(&con->proc));
139     assert(!t_onqueue(&con->proc));
140    
141 michael 2406 if (s_fd(&con->socket) > -1)
142     close(s_fd(&con->socket));
143 michael 2396
144     MsgQClear(&con->sendQ);
145     client_drop_sendq(con);
146     DBufClear(&con->recvQ);
147    
148     if (con->listener)
149 michael 2406 listener_release(con->listener);
150 michael 2396
151     mp_pool_release(con);
152     }
153    
154     /** Allocate a new client and initialize it.
155     * If \a from == NULL, initialize the fields for a local client,
156     * including allocating a Connection for him; otherwise initialize the
157     * fields for a remote client..
158     * @param[in] from Server connection that introduced the client (or
159     * NULL).
160     * @param[in] status Initial Client::cli_status value.
161     * @return Newly allocated and initialized Client.
162     */
163     struct Client *
164 michael 2406 make_client(struct Client *from)
165 michael 2396 {
166     struct Client *client_p = alloc_client();
167    
168     if (!from)
169 adx 30 {
170 michael 2396 /* Local client, allocate a struct Connection */
171     struct Connection *con = alloc_connection();
172 michael 1654
173 michael 2406 s_fd(&con->socket) = -1;
174 michael 2396 con->since = CurrentTime;
175     con->lasttime = CurrentTime;
176     con->firsttime = CurrentTime;
177     con->registration = REG_INIT;
178 michael 2414 con->client_p = client_p;
179 michael 2396 client_p->localClient = con;
180     client_p->from = client_p; /* 'from' of local client is self! */
181 michael 1654
182 adx 30 /* as good a place as any... */
183 michael 1126 dlinkAdd(client_p, &client_p->localClient->lclient_node, &unknown_list);
184 adx 30 }
185     else
186 michael 2396 client_p->from = from; /* 'from' of local client is self! */
187 adx 30
188 michael 1360 client_p->idhnext = client_p;
189 adx 30 client_p->hnext = client_p;
190     client_p->status = STAT_UNKNOWN;
191     strcpy(client_p->username, "unknown");
192 michael 1559 strcpy(client_p->svid, "0");
193 adx 30
194     return client_p;
195     }
196    
197 michael 2396 /** Release a Connection.
198     * @param[in] con Connection to free.
199     */
200     void
201     free_connection(struct Connection *con)
202     {
203     if (!con)
204     return;
205    
206     assert(!con->from);
207    
208     dealloc_connection(con); /* Deallocate the connection */
209     }
210    
211     /** Release a Client.
212     * In addition to the cleanup done by dealloc_client(), this will free
213     * any pending auth request, free the connection for local clients,
214     * and delete the processing timer for the client.
215     * @param[in] client_p Client to free.
216     */
217     void
218     free_client(struct Client *client_p)
219     {
220 michael 2414 assert(client_p);
221 michael 2396 assert(client_p != &me);
222     assert(client_p->hnext == client_p);
223     assert(client_p->idhnext == client_p);
224     assert(client_p->channel.head == NULL);
225     assert(dlink_list_length(&client_p->channel) == 0);
226     assert(dlink_list_length(&client_p->whowas) == 0);
227     assert(!IsServer(client_p) || (IsServer(client_p) && client_p->serv));
228    
229 michael 2414 MyFree(client_p->serv);
230     MyFree(client_p->certfp);
231    
232 michael 2396 if (client_p->from == client_p)
233     {
234     /* In other words, we're local */
235     client_p->from = NULL;
236    
237 michael 2414 MyFree(client_p->localClient->response);
238     MyFree(client_p->localClient->auth_oper);
239    
240 michael 2396 if (client_p->localClient->auth)
241     {
242 michael 2406 destroy_auth_request(client_p->localClient->auth, 0);
243 michael 2396 client_p->localClient->auth = NULL;
244     }
245    
246 michael 2414 /* Timer must be marked as not active */
247 michael 2396 if (!client_p->localClient->freeflag && !t_active(&client_p->localClient->proc))
248     dealloc_connection(client_p->localClient); /* Connection not open anymore */
249     else
250     {
251 michael 2414 if (s_fd(&client_p->localClient->socket) > -1 &&
252 michael 2396 (client_p->localClient->freeflag & FREEFLAG_SOCKET))
253     socket_del(&client_p->localClient->socket); /* Queue a socket delete */
254     if (client_p->localClient->freeflag & FREEFLAG_TIMER)
255     timer_del(&client_p->localClient->proc); /* Queue a timer delete */
256     }
257     }
258    
259 michael 2406 client_p->localClient = NULL;
260 michael 2396 dealloc_client(client_p); /* Actually destroy the client */
261     }
262    
263 michael 2406 /** Link \a client_p into #GlobalClientList.
264     * @param[in] client_p Client to link into the global list.
265 michael 2396 */
266     void
267     add_client_to_list(struct Client *client_p)
268     {
269     /*
270     * Since we always insert new clients to the top of the list,
271     * this should mean the "me" is the bottom most item in the list.
272     * XXX - don't always count on the above, things change
273     */
274 michael 2406 dlinkAdd(client_p, &client_p->node, &global_client_list);
275 michael 2396 }
276    
277     /** Remove \a client_p from lists that it is a member of.
278 michael 2406 * Specifically, this delinks \a client_p from #GlobalClientList, updates
279 michael 2396 * the whowas history list, frees its Client::cli_user and
280     * Client::cli_serv fields, and finally calls free_client() on it.
281 michael 2406 * @param[in] client_p Client to remove from lists and free.
282 michael 2396 */
283     void
284     remove_client_from_list(struct Client *client_p)
285     {
286     assert(!IsMe(client_p));
287    
288     /*
289 michael 2406 * Only try remove client_p from the list if it IS in the list.
290     * cli_next(client_p) cannot be NULL here, as &me is always the end
291 michael 2396 * the list, and we never remove &me. -GW
292     */
293 michael 2406 dlinkDelete(&client_p->node, &global_client_list);
294 michael 2396
295 michael 2406 free_client(client_p);
296 michael 2396 }
297    
298 michael 2407 /** Remove a connection from the list of connections with queued data.
299     * @param[in] con Connection with no queued data.
300     */
301     void
302     client_drop_sendq(struct Connection *con)
303     {
304     if (con->con_prev)
305     {
306     /* On the queued data list... */
307     if (con->con_next)
308     con->con_next->con_prev = con->con_prev;
309     *con->con_prev = con->con_next;
310    
311     con->con_next = NULL;
312     con->con_prev = NULL;
313     }
314     }
315    
316     /** Add a connection to the list of connections with queued data.
317     * @param[in] con Connection with queued data.
318     * @param[in,out] con_p Previous pointer to next connection.
319     */
320     void
321     client_add_sendq(struct Connection *con, struct Connection **con_p)
322     {
323     if (!con->con_prev)
324     {
325     /* Not on the queued data list yet... */
326     con->con_prev = con_p;
327     con->con_next = *con_p;
328    
329     if (*con_p)
330     (*con_p)->con_prev = &con->con_next;
331     *con_p = con;
332     }
333     }
334    
335 michael 2414 /** Check for clients that have not sent a ping response recently.
336     * Reschedules itself to run again at the appropriate time.
337     * @param[in] ev Timer event (ignored).
338 adx 30 */
339     static void
340 michael 2414 check_pings(struct Event *ev)
341 michael 2345 {
342 michael 1644 dlink_node *ptr = NULL, *next_ptr = NULL;
343 michael 2414 int expire = 0;
344 michael 2428 int next_check = CurrentTime + DEFAULT_PINGFREQUENCY;
345 michael 2414 int max_ping = 0;
346 adx 30
347 michael 2428 assert(ET_EXPIRE == ev_type(ev));
348     assert(0 != ev_timer(ev));
349    
350 michael 2414 DLINK_FOREACH_SAFE(ptr, next_ptr, connection_list.head)
351 adx 30 {
352 michael 1644 struct Client *client_p = ptr->data;
353 adx 30
354 michael 2414 assert(client_p != &me);
355    
356     /* Remove dead clients. */
357 adx 30 if (IsDead(client_p))
358     {
359 michael 2419 exit_client(client_p, client_p, &me, client_p->info);
360 michael 2345 continue;
361 adx 30 }
362    
363     if (!IsRegistered(client_p))
364 michael 2414 max_ping = CONNECTTIMEOUT;
365 adx 30 else
366 michael 2414 max_ping = get_client_ping(&client_p->localClient->confs);
367 adx 30
368 michael 2414 /*
369     * Ok, the thing that will happen most frequently, is that someone will
370     * have sent something recently. Cover this first for speed.
371     * --
372     * If it's an unregistered client and hasn't managed to register within
373     * max_ping then it's obviously having problems (broken client) or it's
374     * just up to no good, so we won't skip it, even if its been sending
375     * data to us.
376     * -- hikari
377     */
378     if ((CurrentTime - client_p->localClient->lasttime < max_ping) && IsRegistered(client_p))
379 adx 30 {
380 michael 2414 expire = client_p->localClient->lasttime + max_ping;
381     if (expire < next_check)
382     next_check = expire;
383     continue;
384     }
385    
386     /*
387     * Unregistered clients pingout after max_ping seconds, they don't
388     * get given a second chance - if they were then people could not quite
389     * finish registration and hold resources without being subject to k/g
390     * lines
391     */
392     if (!IsRegistered(client_p))
393     {
394     assert(!IsServer(client_p));
395     if ((CurrentTime - client_p->localClient->firsttime >= max_ping))
396 adx 30 {
397 michael 2419 exit_client(client_p, client_p, &me, "Registration timed out");
398 michael 2414 continue;
399     }
400     else
401     {
402 michael 2182 /*
403 michael 2414 * OK, they still have enough time left, so we'll just skip to the
404     * next client. Set the next check to be when their time is up, if
405     * that's before the currently scheduled next check -- hikari
406 michael 2182 */
407 michael 2414 expire = client_p->localClient->firsttime + max_ping;
408     if (expire < next_check)
409     next_check = expire;
410     continue;
411 adx 30 }
412 michael 2414 }
413    
414     /* Quit the client after max_ping*2 - they should have answered by now */
415     if (CurrentTime - client_p->localClient->lasttime >= (max_ping * 2))
416     {
417     /* If it was a server, then tell ops about it. */
418     if (IsServer(client_p) || IsConnecting(client_p) || IsHandshake(client_p))
419 adx 30 {
420 michael 2414 sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
421     "No response from %s, closing link",
422     get_client_name(client_p, HIDE_IP));
423     sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
424     "No response from %s, closing link",
425     get_client_name(client_p, MASK_IP));
426     ilog(LOG_TYPE_IRCD, "No response from %s, closing link",
427     get_client_name(client_p, HIDE_IP));
428     }
429 michael 650
430 michael 2419 exit_client_msg(client_p, client_p, &me, "Ping timeout: %d seconds",
431 michael 2414 (int)(CurrentTime - client_p->localClient->lasttime));
432     continue;
433 adx 30 }
434    
435 michael 2414 if (!IsPingSent(client_p))
436     {
437     /*
438     * If we haven't PINGed the connection and we haven't heard from it in a
439     * while, PING it to make sure it is still alive.
440     */
441     SetPingSent(client_p);
442 adx 30
443 michael 2414 /* If we're late in noticing don't hold it against them :) */
444     client_p->localClient->lasttime = CurrentTime - max_ping;
445     sendto_one(client_p, "PING :%s", ID_or_name(&me, client_p));
446     }
447 adx 30
448 michael 2414 expire = client_p->localClient->lasttime + max_ping * 2;
449     if (expire < next_check)
450     next_check = expire;
451 adx 30 }
452 michael 2414
453     assert(next_check >= CurrentTime);
454    
455     timer_add(&ping_timer, check_pings, 0, TT_ABSOLUTE, next_check);
456 adx 30 }
457    
458     /* check_conf_klines()
459     *
460     * inputs - NONE
461     * output - NONE
462     * side effects - Check all connections for a pending kline against the
463     * client, exit the client if a kline matches.
464     */
465 michael 2345 void
466 adx 30 check_conf_klines(void)
467 michael 2345 {
468 adx 30 struct Client *client_p = NULL; /* current local client_p being examined */
469 michael 1632 struct MaskItem *conf = NULL;
470 adx 30 dlink_node *ptr, *next_ptr;
471    
472     DLINK_FOREACH_SAFE(ptr, next_ptr, local_client_list.head)
473     {
474     client_p = ptr->data;
475    
476     /* If a client is already being exited
477     */
478     if (IsDead(client_p) || !IsClient(client_p))
479     continue;
480    
481 michael 1632 if ((conf = find_dline_conf(&client_p->localClient->ip,
482 adx 30 client_p->localClient->aftype)) != NULL)
483     {
484 michael 1636 if (conf->type == CONF_EXEMPT)
485 michael 2182 continue;
486 adx 30
487     ban_them(client_p, conf);
488     continue; /* and go examine next fd/client_p */
489     }
490    
491 michael 1632 if (ConfigFileEntry.glines && (conf = find_gline(client_p)))
492 adx 30 {
493     if (IsExemptKline(client_p) ||
494     IsExemptGline(client_p))
495     {
496 michael 1618 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
497 adx 30 "GLINE over-ruled for %s, client is %sline_exempt",
498     get_client_name(client_p, HIDE_IP), IsExemptKline(client_p) ? "k" : "g");
499     continue;
500     }
501    
502     ban_them(client_p, conf);
503 michael 2345 /* and go examine next fd/client_p */
504 adx 30 continue;
505 michael 2345 }
506 adx 30
507 michael 2345 if ((conf = find_kill(client_p)) != NULL)
508 adx 30 {
509     if (IsExemptKline(client_p))
510     {
511 michael 1618 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
512 adx 30 "KLINE over-ruled for %s, client is kline_exempt",
513     get_client_name(client_p, HIDE_IP));
514     continue;
515     }
516    
517     ban_them(client_p, conf);
518 michael 2345 continue;
519 adx 30 }
520    
521 michael 1632 if ((conf = find_matching_name_conf(CONF_XLINE, client_p->info,
522 michael 1921 NULL, NULL, 0)))
523 adx 30 {
524     ban_them(client_p, conf);
525     continue;
526     }
527     }
528    
529     /* also check the unknowns list for new dlines */
530     DLINK_FOREACH_SAFE(ptr, next_ptr, unknown_list.head)
531     {
532     client_p = ptr->data;
533    
534 michael 1632 if ((conf = find_dline_conf(&client_p->localClient->ip,
535     client_p->localClient->aftype)))
536 adx 30 {
537 michael 1636 if (conf->type == CONF_EXEMPT)
538 adx 30 continue;
539    
540 michael 2419 exit_client(client_p, client_p, &me, "D-lined");
541 adx 30 }
542     }
543     }
544    
545     /*
546     * ban_them
547     *
548     * inputs - pointer to client to ban
549 michael 1632 * - pointer to MaskItem
550 adx 30 * output - NONE
551     * side effects - given client_p is banned
552     */
553     static void
554 michael 1632 ban_them(struct Client *client_p, struct MaskItem *conf)
555 adx 30 {
556 michael 2182 const char *user_reason = NULL; /* What is sent to user */
557 adx 30 const char *type_string = NULL;
558     const char dline_string[] = "D-line";
559     const char kline_string[] = "K-line";
560     const char gline_string[] = "G-line";
561     const char xline_string[] = "X-line";
562    
563     switch (conf->type)
564     {
565 michael 1632 case CONF_KLINE:
566 adx 30 type_string = kline_string;
567     break;
568 michael 1632 case CONF_DLINE:
569 adx 30 type_string = dline_string;
570     break;
571 michael 1632 case CONF_GLINE:
572 adx 30 type_string = gline_string;
573     break;
574 michael 1632 case CONF_XLINE:
575 adx 30 type_string = xline_string;
576 michael 1632 ++conf->count;
577 adx 30 break;
578     default:
579     assert(0);
580     break;
581     }
582    
583 michael 1632 user_reason = conf->reason ? conf->reason : type_string;
584 adx 30
585 michael 1618 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "%s active for %s",
586 adx 30 type_string, get_client_name(client_p, HIDE_IP));
587    
588     if (IsClient(client_p))
589 michael 1834 sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP),
590 michael 2182 me.name, client_p->name, user_reason);
591 adx 30
592 michael 2419 exit_client(client_p, client_p, &me, user_reason);
593 adx 30 }
594    
595     /* update_client_exit_stats()
596     *
597     * input - pointer to client
598     * output - NONE
599 michael 2345 * side effects -
600 adx 30 */
601     static void
602     update_client_exit_stats(struct Client *client_p)
603     {
604 michael 1143 if (IsClient(client_p))
605 adx 30 {
606 michael 1013 assert(Count.total > 0);
607 adx 30 --Count.total;
608 michael 1219 if (HasUMode(client_p, UMODE_OPER))
609 adx 30 --Count.oper;
610 michael 1219 if (HasUMode(client_p, UMODE_INVISIBLE))
611 adx 30 --Count.invisi;
612     }
613 michael 1143 else if (IsServer(client_p))
614 michael 1618 sendto_realops_flags(UMODE_EXTERNAL, L_ALL, SEND_NOTICE,
615     "Server %s split from %s",
616 michael 1143 client_p->name, client_p->servptr->name);
617 adx 30
618     if (splitchecking && !splitmode)
619     check_splitmode(NULL);
620     }
621    
622     /* find_person()
623     *
624     * inputs - pointer to name
625     * output - return client pointer
626     * side effects - find person by (nick)name
627     */
628     struct Client *
629     find_person(const struct Client *client_p, const char *name)
630     {
631 michael 1564 struct Client *c2ptr = NULL;
632 adx 30
633     if (IsDigit(*name))
634     {
635     if ((c2ptr = hash_find_id(name)) != NULL)
636     {
637     /* invisible users shall not be found by UID guessing */
638 michael 1564 if (HasUMode(c2ptr, UMODE_INVISIBLE))
639     if (!IsServer(client_p) && !HasFlag(client_p, FLAGS_SERVICE))
640     c2ptr = NULL;
641 adx 30 }
642     }
643     else
644 michael 1169 c2ptr = hash_find_client(name);
645 adx 30
646     return ((c2ptr != NULL && IsClient(c2ptr)) ? c2ptr : NULL);
647     }
648    
649     /*
650 michael 2345 * find_chasing - find the client structure for a nick name (user)
651     * using history mechanism if necessary. If the client is not found,
652 adx 30 * an error message (NO SUCH NICK) is generated. If the client was found
653     * through the history, chasing will be 1 and otherwise 0.
654     */
655     struct Client *
656     find_chasing(struct Client *client_p, struct Client *source_p, const char *user, int *chasing)
657     {
658     struct Client *who = find_person(client_p, user);
659    
660     if (chasing)
661     *chasing = 0;
662    
663     if (who)
664 michael 1169 return who;
665 adx 30
666     if (IsDigit(*user))
667 michael 1169 return NULL;
668 adx 30
669 michael 2300 if ((who = whowas_get_history(user,
670 michael 2182 (time_t)ConfigFileEntry.kill_chase_time_limit))
671     == NULL)
672 adx 30 {
673 michael 1834 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
674 adx 30 me.name, source_p->name, user);
675 michael 1169 return NULL;
676 adx 30 }
677    
678     if (chasing)
679     *chasing = 1;
680    
681 michael 1169 return who;
682 adx 30 }
683    
684     /*
685     * get_client_name - Return the name of the client
686     * for various tracking and
687     * admin purposes. The main purpose of this function is to
688     * return the "socket host" name of the client, if that
689     * differs from the advertised name (other than case).
690     * But, this can be used to any client structure.
691     *
692     * NOTE 1:
693     * Watch out the allocation of "nbuf", if either source_p->name
694     * or source_p->sockhost gets changed into pointers instead of
695     * directly allocated within the structure...
696     *
697     * NOTE 2:
698     * Function return either a pointer to the structure (source_p) or
699     * to internal buffer (nbuf). *NEVER* use the returned pointer
700     * to modify what it points!!!
701     */
702     const char *
703 michael 1328 get_client_name(const struct Client *client, enum addr_mask_type type)
704 adx 30 {
705     static char nbuf[HOSTLEN * 2 + USERLEN + 5];
706    
707     assert(client != NULL);
708    
709 michael 2345 if (!MyConnect(client))
710 michael 1124 return client->name;
711 adx 30
712 michael 1340 if (IsServer(client) || IsConnecting(client) || IsHandshake(client))
713     {
714     if (!irccmp(client->name, client->host))
715     return client->name;
716     else if (ConfigServerHide.hide_server_ips)
717 michael 1328 type = MASK_IP;
718 michael 1340 }
719 adx 30
720     if (ConfigFileEntry.hide_spoof_ips)
721 michael 1328 if (type == SHOW_IP && IsIPSpoof(client))
722     type = MASK_IP;
723 adx 30
724     /* And finally, let's get the host information, ip or name */
725 michael 1328 switch (type)
726 adx 30 {
727     case SHOW_IP:
728 michael 1339 snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
729     client->name,
730     client->username, client->sockhost);
731     break;
732 adx 30 case MASK_IP:
733 michael 1339 if (client->localClient->aftype == AF_INET)
734     snprintf(nbuf, sizeof(nbuf), "%s[%s@255.255.255.255]",
735     client->name, client->username);
736     else
737     snprintf(nbuf, sizeof(nbuf), "%s[%s@ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]",
738     client->name, client->username);
739 adx 30 break;
740     default:
741 michael 1124 snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
742     client->name,
743     client->username, client->host);
744 adx 30 }
745    
746 michael 1124 return nbuf;
747 adx 30 }
748    
749     /*
750     * Exit one client, local or remote. Assuming all dependents have
751     * been already removed, and socket closed for local client.
752     *
753     * The only messages generated are QUITs on channels.
754     */
755     static void
756     exit_one_client(struct Client *source_p, const char *quitmsg)
757     {
758     dlink_node *lp = NULL, *next_lp = NULL;
759    
760     assert(!IsMe(source_p));
761    
762 michael 1118 if (IsClient(source_p))
763 adx 30 {
764     if (source_p->servptr->serv != NULL)
765 michael 889 dlinkDelete(&source_p->lnode, &source_p->servptr->serv->client_list);
766 adx 30
767 michael 1118 /*
768     * If a person is on a channel, send a QUIT notice
769     * to every client (person) on the same channel (so
770     * that the client can show the "**signoff" message).
771     * (Note: The notice is to the local clients *only*)
772     */
773 michael 1734 sendto_common_channels_local(source_p, 0, 0, ":%s!%s@%s QUIT :%s",
774 adx 30 source_p->name, source_p->username,
775     source_p->host, quitmsg);
776     DLINK_FOREACH_SAFE(lp, next_lp, source_p->channel.head)
777     remove_user_from_channel(lp->data);
778    
779 michael 2300 whowas_add_history(source_p, 0);
780     whowas_off_history(source_p);
781 adx 30
782 michael 876 watch_check_hash(source_p, RPL_LOGOFF);
783    
784 michael 889 if (MyConnect(source_p))
785 adx 30 {
786 michael 317 /* Clean up invitefield */
787     DLINK_FOREACH_SAFE(lp, next_lp, source_p->localClient->invited.head)
788     del_invite(lp->data, source_p);
789 michael 887
790     del_all_accepts(source_p);
791 michael 317 }
792 adx 30 }
793 michael 1118 else if (IsServer(source_p))
794     {
795     dlinkDelete(&source_p->lnode, &source_p->servptr->serv->server_list);
796 adx 30
797 michael 1118 if ((lp = dlinkFindDelete(&global_serv_list, source_p)) != NULL)
798     free_dlink_node(lp);
799     }
800    
801 adx 30 /* Remove source_p from the client lists */
802     if (HasID(source_p))
803     hash_del_id(source_p);
804     if (source_p->name[0])
805     hash_del_client(source_p);
806    
807     if (IsUserHostIp(source_p))
808     delete_user_host(source_p->username, source_p->host, !MyConnect(source_p));
809    
810     update_client_exit_stats(source_p);
811    
812 michael 2406 remove_client_from_list(source_p);
813 adx 30 }
814    
815     /* Recursively send QUITs and SQUITs for source_p and all its dependent clients
816     * and servers to those servers that need them. A server needs the client
817     * QUITs if it can't figure them out from the SQUIT (ie pre-TS4) or if it
818     * isn't getting the SQUIT because of @#(*&@)# hostmasking. With TS4, once
819     * a link gets a SQUIT, it doesn't need any QUIT/SQUITs for clients depending
820     * on that one -orabidoo
821     *
822     * This is now called on each local server -adx
823     */
824     static void
825     recurse_send_quits(struct Client *original_source_p, struct Client *source_p,
826     struct Client *from, struct Client *to, const char *comment,
827 michael 1118 const char *splitstr)
828 adx 30 {
829     dlink_node *ptr, *next;
830     struct Client *target_p;
831    
832     assert(to != source_p); /* should be already removed from serv_list */
833    
834     /* If this server can handle quit storm (QS) removal
835     * of dependents, just send the SQUIT
836     */
837 michael 1529 if (!IsCapable(to, CAP_QS))
838 michael 889 DLINK_FOREACH_SAFE(ptr, next, source_p->serv->client_list.head)
839 adx 30 {
840     target_p = ptr->data;
841     sendto_one(to, ":%s QUIT :%s", target_p->name, splitstr);
842     }
843    
844 michael 889 DLINK_FOREACH_SAFE(ptr, next, source_p->serv->server_list.head)
845 adx 30 recurse_send_quits(original_source_p, ptr->data, from, to,
846 michael 1118 comment, splitstr);
847 adx 30
848 michael 1529 if ((source_p == original_source_p && to != from) ||
849     !IsCapable(to, CAP_QS))
850 adx 30 {
851     /* don't use a prefix here - we have to be 100% sure the message
852     * will be accepted without Unknown prefix etc.. */
853     sendto_one(to, "SQUIT %s :%s", ID_or_name(source_p, to), comment);
854     }
855     }
856    
857 michael 2345 /*
858 adx 30 * Remove all clients that depend on source_p; assumes all (S)QUITs have
859 michael 2345 * already been sent. we make sure to exit a server's dependent clients
860     * and servers before the server itself; exit_one_client takes care of
861 adx 30 * actually removing things off llists. tweaked from +CSr31 -orabidoo
862     */
863     static void
864     recurse_remove_clients(struct Client *source_p, const char *quitmsg)
865     {
866     dlink_node *ptr, *next;
867    
868 michael 889 DLINK_FOREACH_SAFE(ptr, next, source_p->serv->client_list.head)
869 adx 30 exit_one_client(ptr->data, quitmsg);
870    
871 michael 889 DLINK_FOREACH_SAFE(ptr, next, source_p->serv->server_list.head)
872 adx 30 {
873     recurse_remove_clients(ptr->data, quitmsg);
874     exit_one_client(ptr->data, quitmsg);
875     }
876     }
877    
878     /*
879     ** Remove *everything* that depends on source_p, from all lists, and sending
880     ** all necessary QUITs and SQUITs. source_p itself is still on the lists,
881     ** and its SQUITs have been sent except for the upstream one -orabidoo
882     */
883     static void
884     remove_dependents(struct Client *source_p, struct Client *from,
885     const char *comment, const char *splitstr)
886     {
887 michael 1118 dlink_node *ptr = NULL;
888 adx 30
889     DLINK_FOREACH(ptr, serv_list.head)
890 michael 1118 recurse_send_quits(source_p, source_p, from, ptr->data,
891     comment, splitstr);
892 adx 30
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 michael 1219 * AddFlag(x, FLAGS_KILLED) and propagating a kill or similar message.
902     * However, it is perfectly correct to call exit_client to force a _server_
903 adx 30 * 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 michael 2408 int
915 michael 2419 exit_client(struct Client *client_p, struct Client *source_p, struct Client *from, const char *comment)
916 adx 30 {
917 michael 1118 dlink_node *m = NULL;
918 adx 30
919     if (MyConnect(source_p))
920     {
921     SetClosing(source_p);
922    
923     if (IsIpHash(source_p))
924     remove_one_ip(&source_p->localClient->ip);
925    
926 michael 1571 /*
927     * This source_p could have status of one of STAT_UNKNOWN, STAT_CONNECTING
928 adx 30 * STAT_HANDSHAKE or STAT_UNKNOWN
929     * all of which are lumped together into unknown_list
930     *
931     * In all above cases IsRegistered() will not be true.
932     */
933     if (!IsRegistered(source_p))
934     {
935 michael 1126 assert(dlinkFind(&unknown_list, source_p));
936    
937     dlinkDelete(&source_p->localClient->lclient_node, &unknown_list);
938 adx 30 }
939     else if (IsClient(source_p))
940     {
941 michael 1247 time_t on_for = CurrentTime - source_p->localClient->firsttime;
942 michael 1013 assert(Count.local > 0);
943 adx 30 Count.local--;
944    
945 michael 1219 if (HasUMode(source_p, UMODE_OPER))
946 adx 30 if ((m = dlinkFindDelete(&oper_list, source_p)) != NULL)
947     free_dlink_node(m);
948    
949 michael 1126 assert(dlinkFind(&local_client_list, source_p));
950 adx 30 dlinkDelete(&source_p->localClient->lclient_node, &local_client_list);
951 michael 1126
952 adx 30 if (source_p->localClient->list_task != NULL)
953     free_list_task(source_p->localClient->list_task, source_p);
954    
955 michael 876 watch_del_watch_list(source_p);
956 michael 1618 sendto_realops_flags(UMODE_CCONN, L_ALL, SEND_NOTICE,
957     "Client exiting: %s (%s@%s) [%s] [%s]",
958 adx 30 source_p->name, source_p->username, source_p->host, comment,
959     ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ?
960     "255.255.255.255" : source_p->sockhost);
961 michael 1247 ilog(LOG_TYPE_USER, "%s (%3u:%02u:%02u): %s!%s@%s %llu/%llu",
962     myctime(source_p->localClient->firsttime), (unsigned int)(on_for / 3600),
963     (unsigned int)((on_for % 3600)/60), (unsigned int)(on_for % 60),
964     source_p->name, source_p->username, source_p->host,
965     source_p->localClient->send.bytes>>10,
966     source_p->localClient->recv.bytes>>10);
967 adx 30 }
968 michael 1571 else if (IsServer(source_p))
969 adx 30 {
970 michael 1571 assert(Count.myserver > 0);
971     --Count.myserver;
972 adx 30
973 michael 1571 assert(dlinkFind(&serv_list, source_p));
974     dlinkDelete(&source_p->localClient->lclient_node, &serv_list);
975     unset_chcap_usage_counts(source_p);
976 adx 30 }
977    
978     if (!IsDead(source_p))
979     {
980     if (IsServer(source_p))
981     {
982     /* for them, we are exiting the network */
983     sendto_one(source_p, ":%s SQUIT %s :%s",
984 michael 2182 ID_or_name(from, source_p), me.name, comment);
985 adx 30 }
986    
987     sendto_one(source_p, "ERROR :Closing Link: %s (%s)",
988     source_p->host, comment);
989     }
990    
991     /*
992     ** Currently only server connections can have
993     ** depending remote clients here, but it does no
994     ** harm to check for all local clients. In
995     ** future some other clients than servers might
996     ** have remotes too...
997     **
998     ** Close the Client connection first and mark it
999     ** so that no messages are attempted to send to it.
1000     ** Remember it makes source_p->from == NULL.
1001     */
1002     close_connection(source_p);
1003     }
1004 michael 1991 else if (IsClient(source_p) && HasFlag(source_p->servptr, FLAGS_EOB))
1005 michael 1976 sendto_realops_flags(UMODE_FARCONNECT, L_ALL, SEND_NOTICE,
1006     "Client exiting at %s: %s (%s@%s) [%s]",
1007     source_p->servptr->name, source_p->name,
1008     source_p->username, source_p->host, comment);
1009 adx 30
1010     if (IsServer(source_p))
1011     {
1012     char splitstr[HOSTLEN + HOSTLEN + 2];
1013    
1014     /* This shouldn't ever happen */
1015     assert(source_p->serv != NULL && source_p->servptr != NULL);
1016    
1017     if (ConfigServerHide.hide_servers)
1018 michael 887 /*
1019 michael 2345 * Set netsplit message to "*.net *.split" to still show
1020 adx 30 * that its a split, but hide the servers splitting
1021     */
1022     strcpy(splitstr, "*.net *.split");
1023     else
1024     snprintf(splitstr, sizeof(splitstr), "%s %s",
1025     source_p->servptr->name, source_p->name);
1026    
1027     remove_dependents(source_p, from->from, comment, splitstr);
1028    
1029     if (source_p->servptr == &me)
1030     {
1031 michael 1618 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
1032 adx 30 "%s was connected for %d seconds. %llu/%llu sendK/recvK.",
1033 michael 1241 source_p->name, (int)(CurrentTime - source_p->localClient->firsttime),
1034 adx 30 source_p->localClient->send.bytes >> 10,
1035     source_p->localClient->recv.bytes >> 10);
1036 michael 1247 ilog(LOG_TYPE_IRCD, "%s was connected for %d seconds. %llu/%llu sendK/recvK.",
1037 michael 2345 source_p->name, (int)(CurrentTime - source_p->localClient->firsttime),
1038 adx 30 source_p->localClient->send.bytes >> 10,
1039     source_p->localClient->recv.bytes >> 10);
1040     }
1041     }
1042 michael 1219 else if (IsClient(source_p) && !HasFlag(source_p, FLAGS_KILLED))
1043 adx 30 {
1044 michael 2419 sendto_server(client_p, CAP_TS6, NOCAPS,
1045 adx 30 ":%s QUIT :%s", ID(source_p), comment);
1046 michael 2419 sendto_server(client_p, NOCAPS, CAP_TS6,
1047 adx 30 ":%s QUIT :%s", source_p->name, comment);
1048     }
1049    
1050     /* The client *better* be off all of the lists */
1051     assert(dlinkFind(&unknown_list, source_p) == NULL);
1052     assert(dlinkFind(&local_client_list, source_p) == NULL);
1053     assert(dlinkFind(&serv_list, source_p) == NULL);
1054     assert(dlinkFind(&oper_list, source_p) == NULL);
1055    
1056     exit_one_client(source_p, comment);
1057 michael 2419 return (client_p == source_p) ? CPTR_KILLED : 0;
1058 adx 30 }
1059    
1060 michael 2389 /**
1061     * Exit client with formatted va_list message.
1062     * Thin wrapper around exit_client().
1063     * @param cptr Connection being processed.
1064     * @param bcptr Connection being closed.
1065     * @param sptr Connection who asked to close the victim.
1066     * @param pattern Format string for message.
1067     * @param vl Stdargs argument list.
1068     * @return Has a tail call to exit_client().
1069     */
1070     /* added 25-9-94 by Run */
1071     int
1072 michael 2419 vexit_client_msg(struct Client *client_p, struct Client *source_p,
1073     struct Client *from,
1074 michael 2389 const char *pattern, va_list vl)
1075     {
1076     char msgbuf[IRCD_BUFSIZE];
1077    
1078 michael 2419 xvsnprintf(NULL, msgbuf, sizeof(msgbuf), pattern, vl);
1079     return exit_client(client_p, source_p, from, msgbuf);
1080 michael 2389 }
1081    
1082     /**
1083     * Exit client with formatted message using a variable-length argument list.
1084     * Thin wrapper around exit_client().
1085     * @param cptr Connection being processed.
1086     * @param bcptr Connection being closed.
1087     * @param sptr Connection who asked to close the victim.
1088     * @param pattern Format string for message.
1089     * @return Has a tail call to exit_client().
1090     */
1091     int
1092 michael 2419 exit_client_msg(struct Client *client_p, struct Client *source_p,
1093     struct Client *from,
1094 michael 2389 const char *pattern, ...)
1095     {
1096     va_list vl;
1097     char msgbuf[IRCD_BUFSIZE];
1098    
1099     va_start(vl, pattern);
1100 michael 2419 xvsnprintf(NULL, msgbuf, sizeof(msgbuf), pattern, vl);
1101 michael 2389 va_end(vl);
1102    
1103 michael 2419 return exit_client(client_p, source_p, from, msgbuf);
1104 michael 2389 }
1105    
1106 adx 30 /*
1107     * accept processing, this adds a form of "caller ID" to ircd
1108 michael 887 *
1109 adx 30 * If a client puts themselves into "caller ID only" mode,
1110 michael 887 * only clients that match a client pointer they have put on
1111 adx 30 * the accept list will be allowed to message them.
1112     *
1113 michael 887 * Diane Bruce, "Dianora" db@db.net
1114 adx 30 */
1115    
1116 michael 887 void
1117     del_accept(struct split_nuh_item *accept_p, struct Client *client_p)
1118 adx 30 {
1119 michael 887 dlinkDelete(&accept_p->node, &client_p->localClient->acceptlist);
1120 adx 30
1121 michael 887 MyFree(accept_p->nickptr);
1122     MyFree(accept_p->userptr);
1123     MyFree(accept_p->hostptr);
1124     MyFree(accept_p);
1125     }
1126 adx 30
1127 michael 887 struct split_nuh_item *
1128     find_accept(const char *nick, const char *user,
1129 michael 2363 const char *host, struct Client *client_p,
1130     int (*cmpfunc)(const char *, const char *))
1131 michael 887 {
1132     dlink_node *ptr = NULL;
1133 adx 30
1134 michael 887 DLINK_FOREACH(ptr, client_p->localClient->acceptlist.head)
1135 adx 30 {
1136 michael 887 struct split_nuh_item *accept_p = ptr->data;
1137    
1138 michael 1652 if (!cmpfunc(accept_p->nickptr, nick) &&
1139     !cmpfunc(accept_p->userptr, user) &&
1140     !cmpfunc(accept_p->hostptr, host))
1141 michael 887 return accept_p;
1142 adx 30 }
1143    
1144 michael 887 return NULL;
1145 adx 30 }
1146    
1147 michael 887 /* accept_message()
1148 adx 30 *
1149 michael 887 * inputs - pointer to source client
1150     * - pointer to target client
1151     * output - 1 if accept this message 0 if not
1152     * side effects - See if source is on target's allow list
1153 adx 30 */
1154 michael 887 int
1155     accept_message(struct Client *source,
1156     struct Client *target)
1157 adx 30 {
1158 michael 887 dlink_node *ptr = NULL;
1159 adx 30
1160 michael 887 if (source == target || find_accept(source->name, source->username,
1161 michael 2363 source->host, target, match))
1162 michael 887 return 1;
1163 adx 30
1164 michael 1219 if (HasUMode(target, UMODE_SOFTCALLERID))
1165 michael 887 DLINK_FOREACH(ptr, target->channel.head)
1166     if (IsMember(source, ((struct Membership *)ptr->data)->chptr))
1167     return 1;
1168 adx 30
1169 michael 887 return 0;
1170 adx 30 }
1171    
1172     /* del_all_accepts()
1173     *
1174 michael 887 * inputs - pointer to exiting client
1175     * output - NONE
1176     * side effects - Walk through given clients acceptlist and remove all entries
1177 adx 30 */
1178     void
1179     del_all_accepts(struct Client *client_p)
1180     {
1181 michael 887 dlink_node *ptr = NULL, *next_ptr = NULL;
1182 adx 30
1183 michael 887 DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->localClient->acceptlist.head)
1184     del_accept(ptr->data, client_p);
1185 adx 30 }
1186 michael 1783
1187     unsigned int
1188     idle_time_get(const struct Client *source_p, const struct Client *target_p)
1189     {
1190     unsigned int idle = 0;
1191     unsigned int min_idle = 0;
1192     unsigned int max_idle = 0;
1193 michael 1847 const struct ClassItem *class = get_class_ptr(&target_p->localClient->confs);
1194 michael 1783
1195 michael 1785 if (!(class->flags & CLASS_FLAGS_FAKE_IDLE) || target_p == source_p)
1196 michael 1783 return CurrentTime - target_p->localClient->last_privmsg;
1197     if (HasUMode(source_p, UMODE_OPER) &&
1198 michael 1785 !(class->flags & CLASS_FLAGS_HIDE_IDLE_FROM_OPERS))
1199 michael 1783 return CurrentTime - target_p->localClient->last_privmsg;
1200    
1201     min_idle = class->min_idle;
1202     max_idle = class->max_idle;
1203    
1204     if (min_idle == max_idle)
1205     return min_idle;
1206    
1207     if (class->flags & CLASS_FLAGS_RANDOM_IDLE)
1208     idle = genrand_int32();
1209     else
1210     idle = CurrentTime - target_p->localClient->last_privmsg;
1211    
1212     if (max_idle == 0)
1213     idle = 0;
1214     else
1215     idle %= max_idle;
1216    
1217     if (idle < min_idle)
1218     idle = min_idle + (idle % (max_idle - min_idle));
1219    
1220     return idle;
1221     }

Properties

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