Author: Kev <klmitch@mit.edu>
[ircu2.10.12-pk.git] / ircd / gline.c
1 /*
2  * IRC - Internet Relay Chat, ircd/gline.c
3  * Copyright (C) 1990 Jarkko Oikarinen and
4  *                    University of Oulu, Finland
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 1, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  * $Id$
21  */
22 #include "gline.h"
23 #include "client.h"
24 #include "ircd.h"
25 #include "ircd_alloc.h"
26 #include "ircd_string.h"
27 #include "match.h"
28 #include "numeric.h"
29 #include "s_bsd.h"
30 #include "s_misc.h"
31 #include "send.h"
32 #include "struct.h"
33 #include "sys.h"    /* FALSE bleah */
34
35 #include <assert.h>
36
37 struct Gline* GlobalGlineList  = 0;
38 struct Gline* BadChanGlineList = 0;
39
40 static void
41 canon_userhost(char *userhost, char **user_p, char **host_p, char *def_user)
42 {
43   char *tmp;
44
45   if (!(tmp = strchr(userhost, '@'))) {
46     *user_p = def_user;
47     *host_p = userhost;
48   } else {
49     *user_p = userhost;
50     *(tmp++) = '\0';
51     *host_p = tmp;
52   }
53 }
54
55 static struct Gline *
56 make_gline(char *userhost, char *reason, time_t expire, time_t lastmod,
57            unsigned int flags)
58 {
59   struct Gline *agline;
60   char *user, *host;
61
62   agline = (struct Gline *)MyMalloc(sizeof(struct Gline)); /* alloc memory */
63   assert(0 != agline);
64
65   gline->gl_expire = expire; /* initialize gline... */
66   gline->gl_lastmod = lastmod;
67   gline->gl_flags = flags & GLINE_MASK;
68
69   if (flags & GLINE_BADCHAN) { /* set a BADCHAN gline */
70     DupString(gline->gl_user, userhost); /* first, remember channel */
71     gline->gl_host = 0;
72
73     gline->gl_next = BadChanGlineList; /* then link it into list */
74     gline->gl_prev_p = &BadChanGlineList;
75     if (BadChanGlineList)
76       BadChanGlineList->gl_prev_p = &agline->gl_next;
77     BadChanGlineList = agline;
78   } else {
79     canon_userhost(userhost, &user, &host, "*"); /* find user and host */
80
81     DupString(gline->gl_user, user); /* remember them... */
82     DupString(gline->gl_host, host);
83
84     if (check_if_ipmask(host)) /* mark if it's an IP mask */
85       gline->gl_flags |= GLINE_IPMASK;
86
87     gline->gl_next = GlobalGlineList; /* then link it into list */
88     gline->gl_prev_p = &GlobalGlineList;
89     if (GlobalGlineList)
90       GlobalGlineList->gl_prev_p = &agline->gl_next;
91     GlobalGlineList = agline;
92   }
93
94   return agline;
95 }
96
97 static int
98 do_gline(struct Client *cptr, struct Client *sptr, struct Gline *gline)
99 {
100   struct Client *acptr;
101   int fd, retval = 0, tval;
102
103   if (!GlineIsActive(gline)) /* no action taken on inactive glines */
104     return 0;
105
106   for (fd = HighestFd; fd >= 0; --fd) {
107     /*
108      * get the users!
109      */
110     if ((acptr = LocalClientArray[fd])) {
111       if (!acptr->user)
112         continue;
113
114       if ((GlineIsIpMask(gline) ? match(gline->host, acptr->sock_ip) :
115            match(gline->host, acptr->sockhost)) == 0 &&
116           (!acptr->user->username ||
117            match(gline->name, acptr->user->username) == 0)) {
118         /* ok, here's one that got G-lined */
119         sendto_one(acptr, ":%s %d %s :*** %s.", me.name, ERR_YOUREBANNEDCREEP,
120                    acptr->name, gline->reason);
121
122         /* let the ops know about it */
123         sendto_op_mask(SNO_GLINE, "G-line active for %s",
124                        get_client_name(acptr, FALSE));
125
126         /* and get rid of him */
127         if ((tval = exit_client_msg(cptr, acptr, &me, "G-lined (%s)",
128                                     gline->reason)))
129           retval = tval; /* retain killed status */
130       }
131     }
132   }
133
134   return retval;
135 }
136
137 static void
138 propagate_gline(struct Client *cptr, struct Client *sptr, struct Gline *gline)
139 {
140   if (GlineIsLocal(gline)) /* don't propagate local glines */
141     return;
142
143   if (IsUser(sptr)) { /* select appropriate source */
144     assert(0 != gline->gl_lastmod);
145     sendto_serv_butone(cptr, "%s%s " TOK_GLINE " * %c%s%s%s " TIME_T_FMT " "
146                        TIME_T_FMT " :%s", NumNick(sptr),
147                        GlineIsActive(gline) ? '+' : '-', gline->gl_user,
148                        GlineIsBadChan(gline) ? "" : "@",
149                        GlineIsBadChan(gline) ? "" : gline->gl_host,
150                        gline->gl_expire, gline->gl_lastmod, gline->gl_reason);
151   } else {
152     if (gline->gl_lastmod)
153       sendto_serv_butone(cptr, "%s " TOK_GLINE " * %c%s%s%s " TIME_T_FMT " "
154                          TIME_T_FMT " :%s", NumServ(sptr),
155                          GlineIsActive(gline) ? '+' : '-', gline->gl_user,
156                          GlineIsBadChan(gline) ? "" : "@",
157                          GlineIsBadChan(gline) ? "" : gline->gl_host,
158                          gline->gl_expire, gline->gl_lastmod,
159                          gline->gl_reason);
160     else
161       sendto_serv_butone(cptr, "%s " TOK_GLINE " * %c%s%s%s " TIME_T_FMT
162                          " :%s", NumServ(sptr),
163                          GlineIsActive(gline) ? '+' : '-', gline->gl_user,
164                          GlineIsBadChan(gline) ? "" : "@",
165                          GlineIsBadChan(gline) ? "" : gline->gl_host,
166                          gline->gl_expire, gline->gl_reason);
167   }
168 }
169
170 int 
171 gline_add(struct Client *cptr, struct Client *sptr, char *userhost,
172           char *reason, time_t expire, time_t lastmod, unsigned int flags)
173 {
174   struct Gline *agline;
175
176   assert(0 != userhost);
177   assert(0 != reason);
178
179   /*
180    * You cannot set a negative (or zero) expire time, nor can you set an
181    * expiration time for greater than GLINE_MAX_EXPIRE.
182    */
183   if (!(flags & GLINE_FORCE) && (expire <= 0 || expire > GLINE_MAX_EXPIRE)) {
184     if (!IsServer(sptr) && MyConnect(sptr))
185       send_error_to_client(sptr, ERR_BADEXPIRE, expire);
186     return 0;
187   }
188
189   expire += TStime(); /* convert from lifetime to timestamp */
190
191 #ifdef BADCHAN
192   if (*userhost == '#' || *userhost == '&' || *userhost == '+')
193     flags |= GLINE_BADCHAN;
194 #endif
195
196   /* Inform ops... */
197   sendto_op_mask(SNO_GLINE, "%s adding %s %s for %s, expiring at "
198                  TIME_T_FMT ": %s",
199                  IsServer(sptr) ? sptr->name : sptr->user->server->name,
200                  flags & GLINE_LOCAL ? "local" : "global",
201                  flags & GLINE_BADCHAN ? "BADCHAN" : "GLINE", userhost,
202                  expire, reason);
203
204 #ifdef GPATH
205   /* and log it */
206   if (IsServer(sptr))
207     write_log(GPATH, "# " TIME_T_FMT " %s adding %s %s for %s, expiring at "
208               TIME_T_FMT ": %s\n", TStime(), sptr->name,
209               flags & GLINE_LOCAL ? "local" : "global",
210               flags & GLINE_BADCHAN ? "BADCHAN" : "GLINE", userhost, expire,
211               reason);
212   else
213     write_log(GPATH, "# " TIME_T_FMT " %s!%s@%s adding %s %s for %s, "
214               "expiring at " TIME_T_FMT ": %s\n", TStime(), sptr->name,
215               sptr->user->username, sptr->user->host,
216               flags & GLINE_LOCAL ? "local" : "global",
217               flags & GLINE_BADCHAN ? "BADCHAN" : "GLINE", userhost, expire,
218               reason);
219 #endif /* GPATH */
220
221   /* make the gline */
222   agline = make_gline(userhost, reason, expire, lastmod, flags);
223
224   propagate_gline(cptr, sptr, agline);
225
226   if (GlineIsBadChan(agline))
227     return 0;
228
229 #ifdef GPATH
230   /* this can be inserted into the conf */
231   write_log(GPATH, "%c:%s:%s:%s\n", GlineIsIpMask(agline) ? 'k' : 'K',
232             GlineHost(agline), GlineReason(agline), GlineUser(agline));
233 #endif /* GPATH */
234
235   return do_gline(cptr, sptr, agline); /* knock off users if necessary */
236 }
237
238 int
239 gline_activate(struct Client *cptr, struct Client *sptr, struct Gline *gline,
240                time_t lastmod)
241 {
242   assert(0 != gline);
243
244   gline->gl_flags |= GLINE_ACTIVE;
245   gline->gl_lastmod = lastmod;
246
247   /* Inform ops and log it */
248   sendto_op_mask(SNO_GLINE, "%s activating %s %s for %s%s%s, expiring at "
249                  TIME_T_FMT ": %s",
250                  IsServer(sptr) ? sptr->name : sptr->user->server->name,
251                  GlineIsLocal(gline) ? "local" : "global",
252                  GlineIsBadChan(gline) ? "BADCHAN" : "GLINE",
253                  gline->gl_user, GlineIsBadChan(gline) ? "" : "@",
254                  GlineIsBadChan(gline) ? "" : gline->gl_host, gline->gl_expire,
255                  gline->gl_reason);
256
257 #ifdef GPATH
258   if (IsServer(sptr))
259     write_log(GPATH, "# " TIME_T_FMT " %s activating %s %s for %s%s%s, "
260               "expiring at " TIME_T_FMT ": %s\n", TStime(), sptr->name,
261               GlineIsLocal(gline) ? "local" : "global",
262               GlineIsBadChan(gline) ? "BADCHAN" : "GLINE",
263               gline->gl_user, GlineIsBadChan(gline) ? "" : "@",
264               GlineIsBadChan(gline) ? "" : gline->gl_host, gline->gl_expire,
265               gline->gl_reason);
266   else
267     write_log(GPATH, "# " TIME_T_FMT " %s!%s@%s activating %s %s for "
268               "%s%s%s, expiring at " TIME_T_FMT ": %s\n", TStime(), sptr->name,
269               sptr->user->username, sptr->user->host,
270               GlineIsLocal(gline) ? "local" : "global",
271               GlineIsBadChan(gline) ? "BADCHAN" : "GLINE",
272               gline->gl_user, GlineIsBadChan(gline) ? "" : "@",
273               GlineIsBadChan(gline) ? "" : gline->gl_host, gline->gl_expire,
274               gline->gl_reason);
275 #endif /* GPATH */
276
277   propagate_gline(cptr, sptr, gline);
278
279   return GlineIsBadChan(gline) ? 0 : do_gline(cptr, sptr, gline);
280 }
281
282 int
283 gline_deactivate(struct Client *cptr, struct Client *sptr, struct Gline *gline,
284                  time_t lastmod)
285 {
286   assert(0 != gline);
287
288   gline->gl_flags &= ~GLINE_ACTIVE;
289   gline->gl_lastmod = lastmod;
290
291   /* Inform ops and log it */
292   sendto_op_mask(SNO_GLINE, "%s deactivating %s %s for %s%s%s, expiring at "
293                  TIME_T_FMT ": %s",
294                  IsServer(sptr) ? sptr->name : sptr->user->server->name,
295                  GlineIsLocal(gline) ? "local" : "global",
296                  GlineIsBadChan(gline) ? "BADCHAN" : "GLINE",
297                  gline->gl_user, GlineIsBadChan(gline) ? "" : "@",
298                  GlineIsBadChan(gline) ? "" : gline->gl_host, gline->gl_expire,
299                  gline->gl_reason);
300
301 #ifdef GPATH
302   if (IsServer(sptr))
303     write_log(GPATH, "# " TIME_T_FMT " %s deactivating %s %s for %s%s%s, "
304               "expiring at " TIME_T_FMT ": %s\n", TStime(), sptr->name,
305               GlineIsLocal(gline) ? "local" : "global",
306               GlineIsBadChan(gline) ? "BADCHAN" : "GLINE",
307               gline->gl_user, GlineIsBadChan(gline) ? "" : "@",
308               GlineIsBadChan(gline) ? "" : gline->gl_host, gline->gl_expire,
309               gline->gl_reason);
310   else
311     write_log(GPATH, "# " TIME_T_FMT " %s!%s@%s deactivating %s %s for "
312               "%s%s%s, expiring at " TIME_T_FMT ": %s\n", TStime(), sptr->name,
313               sptr->user->username, sptr->user->host,
314               GlineIsLocal(gline) ? "local" : "global",
315               GlineIsBadChan(gline) ? "BADCHAN" : "GLINE",
316               gline->gl_user, GlineIsBadChan(gline) ? "" : "@",
317               GlineIsBadChan(gline) ? "" : gline->gl_host, gline->gl_expire,
318               gline->gl_reason);
319 #endif /* GPATH */
320
321   propagate_gline(cptr, sptr, gline);
322
323   return 0;
324 }
325
326 struct Gline *
327 gline_find(char *userhost, unsigned int flags)
328 {
329   struct Gline *gline;
330   struct Gline *sgline;
331   char *user, *host, *t_uh;
332
333   if (flags & (GLINE_BADCHAN | GLINE_ANY)) {
334     for (gline = BadChanGlineList; gline; gline = sgline) {
335       sgline = gline->gl_next;
336
337       if (gline->gl_expire <= TStime())
338         gline_free(gline);
339       else if (match(gline->gl_user, userhost) == 0)
340         return gline;
341     }
342   }
343
344   if ((flags & (GLINE_BADCHAN | GLINE_ANY)) == GLINE_BADCHAN)
345     return 0;
346
347   DupString(t_uh, userhost);
348   canon_userhost(t_uh, &user, &host, 0);
349
350   for (gline = GlobalGlineList; gline; gline = sgline) {
351     sgline = gline->gl_next;
352
353     if (gline->gl_expire <= TStime())
354       gline_free(gline);
355     else if (match(gline->host, host) == 0 &&
356              ((!user && ircd_strcmp(gline->user, "*") == 0) ||
357               match(gline->user, user) == 0))
358       break;
359   }
360
361   MyFree(t_uh);
362
363   return gline;
364 }
365
366 struct Gline *
367 gline_lookup(struct Client *cptr)
368 {
369   struct Gline *gline;
370   struct Gline *sgline;
371
372   for (gline = GlobalGlineList; gline; gline = sgline) {
373     sgline = gline->gl_next;
374
375     if (gline->gl_expire <= TStime())
376       gline_free(gline);
377     else if ((GlineIsIpMask(gline) ?
378               match(gline->gl_host, cptr->sock_ip) :
379               match(gline->gl_host, cptr->sockhost)) == 0 &&
380              match(gline->gl_user, cptr->user->username) == 0)
381       return gline;
382   }
383
384   return 0;
385 }
386
387 void
388 gline_free(struct Gline *gline)
389 {
390   assert(0 != gline);
391
392   *gline->gl_prev_p = gline->gl_next; /* squeeze this gline out */
393   if (gline->gl_next)
394     gline->gl_next->gl_prev_p = gline->gl_prev_p;
395
396   MyFree(gline->gl_user); /* free up the memory */
397   if (gline->gl_host)
398     MyFree(gline->gl_host);
399   MyFree(gline->gl_reason);
400   MyFree(gline);
401 }
402
403 void
404 gline_burst(struct Client *cptr)
405 {
406   struct Gline *gline;
407   struct Gline *sgline;
408
409   for (gline = GlobalGlineList; gline; gline = sgline) { /* all glines */
410     sgline = gline->gl_next;
411
412     if (gline->gl_expire <= TStime()) /* expire any that need expiring */
413       gline_free(gline);
414     else if (!GlineIsLocal(gline) && gline->gl_lastmod)
415       sendto_one(cptr, "%s " TOK_GLINE " * %c%s@%s " TIME_T_FMT " " TIME_T_FMT
416                  " :%s", NumServ(&me), GlineIsActive(gline) ? '+' : '-',
417                  gline->gl_user, gline->gl_host, gline->gl_expire,
418                  gline->gl_lastmod, gline->gl_reason);
419   }
420
421   for (gline = BadChanGlineList; gline; gline = sgline) { /* all glines */
422     sgline = gline->gl_next;
423
424     if (gline->gl_expire <= TStime()) /* expire any that need expiring */
425       gline_free(gline);
426     else if (!GlineIsLocal(gline) && gline->gl_lastmod)
427       sendto_one(cptr, "%s " TOK_GLINE " * %c%s " TIME_T_FMT " " TIME_T_FMT
428                  " :%s", NumServ(&me), GlineIsActive(gline) ? '+' : '-',
429                  gline->gl_user, gline->gl_expire, gline->gl_lastmod,
430                  gline->gl_reason);
431   }
432 }
433
434 int
435 gline_resend(struct Client *cptr, struct Gline *gline)
436 {
437   if (GlineIsLocal(gline) || !gline->gl_lastmod)
438     return 0;
439
440   if (GlineIsBadChan(gline))
441     sendto_one(cptr, "%s " TOK_GLINE " * %c%s " TIME_T_FMT " " TIME_T_FMT
442                " :%s", NumServ(&me), GlineIsActive(gline) ? '+' : '-',
443                gline->gl_user, gline->gl_expire, gline->gl_lastmod,
444                gline->gl_reason);
445   else
446     sendto_one(cptr, "%s " TOK_GLINE " * %c%s@%s " TIME_T_FMT " " TIME_T_FMT
447                " :%s", NumServ(&me), GlineIsActive(gline) ? '+' : '-',
448                gline->gl_user, gline->gl_host, gline->gl_expire,
449                gline->gl_lastmod, gline->gl_reason);
450
451   return 0;
452 }
453
454 int
455 gline_list(struct Client *sptr, char *userhost)
456 {
457   struct Gline *gline;
458   struct Gline *sgline;
459
460   if (userhost) {
461     if (!(gline = gline_find(userhost, GLINE_ANY))) { /* no such gline */
462       send_error_to_client(sptr, ERR_NOSUCHGLINE, userhost);
463       return 0;
464     }
465
466     /* send gline information along */
467     sendto_one(sptr, rpl_str(GLIST), me.name, sptr->name, gline->gl_user,
468                GlineIsBadChan(gline) ? "" : "@",
469                GlineIsBadChan(gline) ? "" : gline->gl_host, gline->gl_expire,
470                GlineIsLocal(gline) ? me.name : "*",
471                GlineIsActive(gline) ? '+' : '-', gline->gl_reason);
472   } else {
473     for (gline = GlobalGlineList; gline; gline = sgline) {
474       sgline = gline->gl_next;
475
476       if (gline->gl_expire <= TStime())
477         gline_free(gline);
478       else
479         sendto_one(sptr, rpl_str(GLIST), me.name, sptr->name, gline->gl_user,
480                    "@", gline->gl_host, gline->gl_expire,
481                    GlineIsLocal(gline) ? me.name : "*",
482                    GlineIsActive(gline) ? '+' : '-', gline->gl_reason);
483     }
484
485     for (gline = BadChanGlineList; gline; gline = sgline) {
486       sgline = gline->gl_next;
487
488       if (gline->gl_expire <= TStime())
489         gline_free(gline);
490       else
491         sendto_one(sptr, rpl_str(GLIST), me.name, sptr->name, gline->gl_user,
492                    "", "", gline->gl_expire,
493                    GlineIsLocal(gline) ? me.name : "*",
494                    GlineIsActive(gline) ? '+' : '-', gline->gl_reason);
495     }
496   }
497
498   /* end of gline information */
499   sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, sptr->name);
500   return 0;
501 }
502
503 void
504 gline_stats(struct Client *sptr)
505 {
506   struct Gline *gline;
507   struct Gline *sgline;
508
509   for (gline = GlobalGlineList; gline; gline = sgline) {
510     sgline = gline->gl_next;
511
512     if (gline->gl_expire <= TStime())
513       gline_free(gline);
514     else
515       sendto_one(sptr, rpl_str(RPL_STATSGLINE), me.name, sptr->name, 'G',
516                  gline->gl_user, gline->gl_host, gline->gl_expire,
517                  gline->gl_reason);
518   }
519 }
520
521
522 #if 0 /* forget about it! */
523 struct Gline *make_gline(int is_ipmask, char *host, char *reason,
524                          char *name, time_t expire)
525 {
526   struct Gline *agline;
527
528 #ifdef BADCHAN
529   int gtype = 0;
530   if ('#' == *host || '&' == *host || '+' == *host)
531     gtype = 1; /* BAD CHANNEL GLINE */
532 #endif
533
534   agline = (struct Gline*) MyMalloc(sizeof(struct Gline)); /* alloc memory */
535   assert(0 != agline);
536   DupString(agline->host, host);        /* copy vital information */
537   DupString(agline->reason, reason);
538   DupString(agline->name, name);
539   agline->expire = expire;
540   agline->gflags = GLINE_ACTIVE;        /* gline is active */
541   if (is_ipmask)
542     SetGlineIsIpMask(agline);
543 #ifdef BADCHAN
544   if (gtype)
545   { 
546     agline->next = BadChanGlineList;    /* link it into the list */
547     return (BadChanGlineList = agline);
548   }
549 #endif
550   agline->next = GlobalGlineList;       /* link it into the list */
551   return (GlobalGlineList = agline);
552 }
553
554 struct Gline *find_gline(struct Client *cptr, struct Gline **pgline)
555 {
556   struct Gline* gline = GlobalGlineList;
557   struct Gline* prev = 0;
558
559   while (gline) {
560     /*
561      * look through all glines
562      */
563     if (gline->expire <= TStime()) {
564       /*
565        * handle expired glines
566        */
567       free_gline(gline, prev);
568       gline = prev ? prev->next : GlobalGlineList;
569       if (!gline)
570         break;                  /* gline == NULL means gline == NULL */
571       continue;
572     }
573
574     /* Does gline match? */
575     /* Added a check against the user's IP address as well -Kev */
576     if ((GlineIsIpMask(gline) ?
577         match(gline->host, ircd_ntoa((const char*) &cptr->ip)) :
578         match(gline->host, cptr->sockhost)) == 0 &&
579         match(gline->name, cptr->user->username) == 0) {
580       if (pgline)
581         *pgline = prev; /* If they need it, give them the previous gline
582                                    entry (probably for free_gline, below) */
583       return gline;
584     }
585
586     prev = gline;
587     gline = gline->next;
588   }
589
590   return 0;                  /* found no glines */
591 }
592
593 void free_gline(struct Gline* gline, struct Gline* prev)
594 {
595   assert(0 != gline);
596   if (prev)
597     prev->next = gline->next;   /* squeeze agline out */
598   else { 
599 #ifdef BADCHAN
600     assert(0 != gline->host);
601     if ('#' == *gline->host ||
602         '&' == *gline->host ||
603         '+' == *gline->host) {
604       BadChanGlineList = gline->next;
605     }
606     else
607 #endif
608       GlobalGlineList = gline->next;
609   }
610
611   MyFree(gline->host);  /* and free up the memory */
612   MyFree(gline->reason);
613   MyFree(gline->name);
614   MyFree(gline);
615 }
616
617 void gline_remove_expired(time_t now)
618 {
619   struct Gline* gline;
620   struct Gline* prev = 0;
621   
622   for (gline = GlobalGlineList; gline; gline = gline->next) {
623     if (gline->expire < now) {
624       free_gline(gline, prev);
625       gline = (prev) ? prev : GlobalGlineList;
626       if (!gline)
627         break;
628       continue;
629     }
630     prev = gline;
631   }
632 }
633
634 #ifdef BADCHAN
635 int bad_channel(const char* name)
636
637   struct Gline* agline = BadChanGlineList;
638
639   while (agline)
640   { 
641     if ((agline->gflags & GLINE_ACTIVE) && (agline->expire > TStime()) && 
642          !mmatch(agline->host, name)) { 
643       return 1;
644     }
645     agline = agline->next;
646   }
647   return 0;
648 }
649
650 void bad_channel_remove_expired(time_t now)
651 {
652   struct Gline* gline;
653   struct Gline* prev = 0;
654   
655   for (gline = BadChanGlineList; gline; gline = gline->next) {
656     if (gline->expire < now) {
657       free_gline(gline, prev);
658       gline = (prev) ? prev : BadChanGlineList;
659       if (!gline)
660         break;
661       continue;
662     }
663     prev = gline;
664   }
665 }
666
667 #endif
668
669
670 void add_gline(struct Client *sptr, int ip_mask, char *host, char *comment,
671                char *user, time_t expire, int local)
672 {
673   struct Client *acptr;
674   struct Gline *agline;
675   int fd;
676   int gtype = 0;
677   assert(0 != host);
678
679 #ifdef BADCHAN
680   if ('#' == *host || '&' == *host || '+' == *host)
681     gtype = 1;   /* BAD CHANNEL */
682 #endif
683
684   /* Inform ops */
685   sendto_op_mask(SNO_GLINE,
686       "%s adding %s%s for %s@%s, expiring at " TIME_T_FMT ": %s", sptr->name,
687       local ? "local " : "",
688       gtype ? "BADCHAN" : "GLINE", user, host, expire, comment);
689
690 #ifdef GPATH
691   write_log(GPATH,
692       "# " TIME_T_FMT " %s adding %s %s for %s@%s, expiring at " TIME_T_FMT
693       ": %s\n", TStime(), sptr->name, local ? "local" : "global",
694       gtype ? "BADCHAN" : "GLINE", user, host, expire, comment);
695
696   /* this can be inserted into the conf */
697   if (!gtype)
698     write_log(GPATH, "%c:%s:%s:%s\n", ip_mask ? 'k' : 'K', host, comment, 
699       user);
700 #endif /* GPATH */
701
702   agline = make_gline(ip_mask, host, comment, user, expire);
703   if (local)
704     SetGlineIsLocal(agline);
705
706 #ifdef BADCHAN
707   if (gtype)
708     return;
709 #endif
710
711   for (fd = HighestFd; fd >= 0; --fd) { 
712     /*
713      * get the users!
714      */ 
715     if ((acptr = LocalClientArray[fd])) {
716       if (!acptr->user)
717         continue;
718 #if 0
719       /*
720        * whee!! :)
721        */
722       if (!acptr->user || strlen(acptr->sockhost) > HOSTLEN ||
723           (acptr->user->username ? strlen(acptr->user->username) : 0) > HOSTLEN)
724         continue;               /* these tests right out of
725                                    find_kill for safety's sake */
726 #endif
727
728       if ((GlineIsIpMask(agline) ?  match(agline->host, acptr->sock_ip) :
729           match(agline->host, acptr->sockhost)) == 0 &&
730           (!acptr->user->username ||
731           match(agline->name, acptr->user->username) == 0))
732       {
733
734         /* ok, he was the one that got G-lined */
735         sendto_one(acptr, ":%s %d %s :*** %s.", me.name,
736             ERR_YOUREBANNEDCREEP, acptr->name, agline->reason);
737
738         /* let the ops know about my first kill */
739         sendto_op_mask(SNO_GLINE, "G-line active for %s",
740             get_client_name(acptr, FALSE));
741
742         /* and get rid of him */
743         if (sptr != acptr)
744           exit_client_msg(sptr->from, acptr, &me, "G-lined (%s)", agline->reason);
745       }
746     }
747   }
748 }
749
750 #endif /* 0 */