ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/modules/m_gline.c
Revision: 190
Committed: Sun Oct 23 22:06:17 2005 UTC (20 years, 9 months ago) by adx
Content type: text/x-csrc
File size: 19437 byte(s)
Log Message:
* prototypes are now prefixed with either nothing or EXTERN
  (meaning it's an ircd.dll API)
* dynamic modules now work on win32.

File Contents

# User Rev Content
1 adx 30 /*
2     * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3     * m_gline.c: Votes towards globally banning a mask.
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 "handlers.h"
27     #include "s_gline.h"
28     #include "channel.h"
29     #include "client.h"
30     #include "common.h"
31     #include "ircd.h"
32     #include "hostmask.h"
33     #include "numeric.h"
34     #include "s_conf.h"
35 db 91 #include "parse_aline.h"
36 adx 30 #include "send.h"
37     #include "msg.h"
38     #include "s_serv.h"
39     #include "hash.h"
40     #include "parse.h"
41     #include "modules.h"
42    
43     #define GLINE_NOT_PLACED 0
44     #ifdef GLINE_VOTING
45     #define GLINE_ALREADY_VOTED -1
46     #endif /* GLINE_VOTING */
47     #define GLINE_PLACED 1
48    
49 adx 190 EXTERN dlink_list gdeny_items;
50 adx 30
51     /* internal functions */
52     static void set_local_gline(const struct Client *,
53     const char *, const char *, const char *);
54    
55     #ifdef GLINE_VOTING
56     static int check_majority_gline(const struct Client *,
57     const char *, const char *, const char *);
58    
59     static void add_new_majority_gline(const struct Client *,
60     const char *, const char *, const char *);
61     #endif /* GLINE_VOTING */
62    
63     static void do_sgline(struct Client *, struct Client *, int, char **, int);
64    
65     static void me_gline(struct Client *, struct Client *, int, char **);
66     static void ms_gline(struct Client *, struct Client *, int, char **);
67     static void mo_gline(struct Client *, struct Client *, int, char **);
68     static void mo_ungline(struct Client *, struct Client *, int, char **);
69    
70     /*
71     * gline enforces 3 parameters to force operator to give a reason
72     * a gline is not valid with "No reason"
73     * -db
74     */
75     struct Message gline_msgtab = {
76     "GLINE", 0, 0, 3, 0, MFLG_SLOW, 0,
77     {m_unregistered, m_not_oper, ms_gline, me_gline, mo_gline, m_ignore}
78     };
79    
80     struct Message ungline_msgtab = {
81     "UNGLINE", 0, 0, 2, 0, MFLG_SLOW, 0,
82     {m_unregistered, m_not_oper, m_error, m_ignore, mo_ungline, m_ignore}
83     };
84    
85     #ifndef STATIC_MODULES
86     void
87     _modinit(void)
88     {
89     mod_add_cmd(&gline_msgtab);
90     mod_add_cmd(&ungline_msgtab);
91     add_capability("GLN", CAP_GLN, 1);
92     }
93    
94     void
95     _moddeinit(void)
96     {
97     mod_del_cmd(&gline_msgtab);
98     mod_del_cmd(&ungline_msgtab);
99     delete_capability("GLN");
100     }
101    
102 knight 31 const char *_version = "$Revision$";
103 adx 30 #endif
104    
105     /* mo_gline()
106     *
107     * inputs - The usual for a m_ function
108     * output -
109     * side effects -
110     *
111     * Place a G line if 3 opers agree on the identical user@host
112     *
113     */
114     /* Allow this server to pass along GLINE if received and
115     * GLINES is not defined.
116     *
117     */
118    
119     static void
120     mo_gline(struct Client *client_p, struct Client *source_p,
121     int parc, char *parv[])
122     {
123     char *user = NULL;
124     char *host = NULL; /* user and host of GLINE "victim" */
125     char *reason = NULL; /* reason for "victims" demise */
126     char *p;
127    
128     if (!ConfigFileEntry.glines)
129     {
130     sendto_one(source_p, ":%s NOTICE %s :GLINE disabled",
131     me.name, source_p->name);
132     return;
133     }
134    
135     if (!IsOperGline(source_p))
136     {
137     sendto_one(source_p, form_str(ERR_NOPRIVS),
138     me.name, source_p->name, "gline");
139     return;
140     }
141    
142     if (parse_aline("GLINE", source_p, parc, parv,
143     AWILD, &user, &host, NULL, NULL, &reason) < 0)
144     return;
145    
146     if ((p = strchr(host, '/')) != NULL)
147     {
148     int bitlen = strtol(++p, NULL, 10);
149     int min_bitlen = strchr(host, ':') ? ConfigFileEntry.gline_min_cidr6 :
150     ConfigFileEntry.gline_min_cidr;
151     if (bitlen < min_bitlen)
152     {
153     sendto_one(source_p, ":%s NOTICE %s :Cannot set G-Lines with CIDR length < %d",
154     me.name, source_p->name, min_bitlen);
155     return;
156     }
157     }
158    
159     #ifdef GLINE_VOTING
160     /* If at least 3 opers agree this user should be G lined then do it */
161     if (check_majority_gline(source_p, user, host, reason) ==
162     GLINE_ALREADY_VOTED)
163     {
164     sendto_one(source_p,
165     ":%s NOTICE %s :This server or oper has already voted",
166     me.name, source_p->name);
167     return;
168     }
169    
170     /* call these two functions first so the 'requesting' notice always comes
171     * before the 'has triggered' notice. -bill
172     */
173     sendto_realops_flags(UMODE_ALL, L_ALL,
174     "%s requesting G-Line for [%s@%s] [%s]",
175     get_oper_name(source_p),
176     user, host, reason);
177     ilog(L_TRACE, "#gline for %s@%s [%s] requested by %s!%s@%s",
178     user, host, reason, source_p->name, source_p->username,
179     source_p->host);
180    
181     set_local_gline(source_p, user, host, reason);
182     #else
183     set_local_gline(source_p, user, host, reason);
184     #endif /* GLINE_VOTING */
185    
186     /* 4 param version for hyb-7 servers */
187     sendto_server(NULL, source_p, NULL, CAP_GLN|CAP_TS6, NOCAPS,
188     LL_ICLIENT, ":%s GLINE %s %s :%s",
189     ID(source_p), user, host, reason);
190     sendto_server(NULL, source_p, NULL, CAP_GLN, CAP_TS6,
191     LL_ICLIENT, ":%s GLINE %s %s :%s",
192     source_p->name, user, host, reason);
193    
194     /* 8 param for hyb-6 */
195     sendto_server(NULL, NULL, NULL, CAP_TS6, CAP_GLN, NOFLAGS,
196     ":%s GLINE %s %s %s %s %s %s :%s",
197     ID(&me),
198     ID(source_p), source_p->username,
199     source_p->host, source_p->servptr->name, user, host,
200     reason);
201     sendto_server(NULL, NULL, NULL, NOCAPS, CAP_GLN|CAP_TS6, NOFLAGS,
202     ":%s GLINE %s %s %s %s %s %s :%s",
203     me.name, source_p->name, source_p->username,
204     source_p->host, source_p->servptr->name, user, host,
205     reason);
206     }
207    
208     /* ms_gline()
209     * me_gline()
210     * do_sgline()
211     *
212     * inputs - The usual for a m_ function
213     * output -
214     * side effects -
215     *
216     * Place a G line if 3 opers agree on the identical user@host
217     *
218     * Allow this server to pass along GLINE if received and
219     * GLINES is not defined.
220     *
221     * ENCAP'd GLINES are propagated by encap code.
222     */
223    
224     static void
225     ms_gline(struct Client *client_p, struct Client *source_p,
226     int parc, char *parv[])
227     {
228     do_sgline(client_p, source_p, parc, parv, 1);
229     }
230    
231     static void
232     me_gline(struct Client *client_p, struct Client *source_p,
233     int parc, char *parv[])
234     {
235     do_sgline(client_p, source_p, parc, parv, 0);
236     }
237    
238     static void
239     do_sgline(struct Client *client_p, struct Client *source_p,
240     int parc, char *parv[], int prop)
241     {
242     const char *reason = NULL; /* reason for "victims" demise */
243     char *user = NULL;
244     char *host = NULL; /* user and host of GLINE "victim" */
245     int var_offset, logged = 0;
246     dlink_node *ptr;
247     struct ConfItem *conf;
248     struct AccessItem *aconf;
249    
250     /* hyb-7 style gline (post beta3) */
251     if (parc == 4 && IsClient(source_p))
252     var_offset = 0;
253     /* or it's a hyb-6 style */
254     else if (parc == 8 && IsServer(source_p))
255     {
256     var_offset = 4;
257    
258     /*
259     * if we are dealing with an old style formatted gline,
260     * the gline message is originating from the oper's server,
261     * so we update source_p to point to the oper now, so that
262     * logging works down the line. -bill
263     */
264     if ((source_p = find_person(client_p, parv[1])) == NULL)
265     return;
266    
267     if (irccmp(parv[2], source_p->username) != 0 ||
268     irccmp(parv[3], source_p->host) != 0 ||
269     irccmp(parv[4], source_p->servptr->name) != 0)
270     {
271     /*
272     * at this point we know one of the parameters provided by
273     * the h6 server was faulty. bail out.
274     */
275     return;
276     }
277     }
278     /* none of the above */
279     else
280     return;
281    
282     assert(source_p->servptr != NULL);
283    
284     user = parv[++var_offset];
285     host = parv[++var_offset];
286     reason = parv[++var_offset];
287    
288     var_offset = 0;
289    
290     DLINK_FOREACH(ptr, gdeny_items.head)
291     {
292     conf = ptr->data;
293 db 139 aconf = &conf->conf.AccessItem;
294 adx 30
295     if (match(conf->name, source_p->servptr->name) &&
296     match(aconf->user, source_p->username) &&
297     match(aconf->host, source_p->host))
298     {
299     var_offset = aconf->flags;
300     break;
301     }
302     }
303    
304     if (prop && !(var_offset & GDENY_BLOCK))
305     {
306     sendto_server(client_p, source_p->servptr, NULL, CAP_GLN, NOCAPS, LL_ICLIENT,
307     ":%s GLINE %s %s :%s",
308     source_p->name, user, host, reason);
309     /* hyb-6 version to the rest */
310     sendto_server(client_p, NULL, NULL, NOCAPS, CAP_GLN, NOFLAGS,
311     ":%s GLINE %s %s %s %s %s %s :%s",
312     source_p->servptr->name,
313     source_p->name, source_p->username, source_p->host,
314     source_p->servptr->name,
315     user, host, reason);
316     }
317     else if (ConfigFileEntry.gline_logging & GDENY_BLOCK && ServerInfo.hub)
318     {
319     sendto_realops_flags(UMODE_ALL, L_ALL, "Blocked G-Line %s requested on [%s@%s] [%s]",
320     get_oper_name(source_p), user, host, reason);
321     ilog(L_TRACE, "Blocked G-Line %s requested on [%s@%s] [%s]",
322     get_oper_name(source_p), user, host, reason);
323     logged = 1;
324     }
325    
326    
327     if (var_offset & GDENY_REJECT)
328     {
329     if (ConfigFileEntry.gline_logging & GDENY_REJECT && !logged)
330     {
331     sendto_realops_flags(UMODE_ALL, L_ALL, "Rejected G-Line %s requested on [%s@%s] [%s]",
332     get_oper_name(source_p), user, host, reason);
333     ilog(L_TRACE, "Rejected G-Line %s requested on [%s@%s] [%s]",
334     get_oper_name(source_p), user, host, reason);
335     }
336     return;
337     }
338    
339     if (ConfigFileEntry.glines)
340     {
341     if (!valid_wild_card(source_p, YES, 2, user, host))
342     return;
343    
344     if (IsClient(source_p))
345     {
346     const char *p = NULL;
347     if ((p = strchr(host, '/')))
348     {
349     int bitlen = strtol(++p, NULL, 10);
350     int min_bitlen = strchr(host, ':') ? ConfigFileEntry.gline_min_cidr6 :
351     ConfigFileEntry.gline_min_cidr;
352    
353     if (bitlen < min_bitlen)
354     {
355     sendto_realops_flags(UMODE_ALL, L_ALL, "%s!%s@%s on %s is requesting "
356     "a GLINE with a CIDR mask < %d for [%s@%s] [%s]",
357     source_p->name, source_p->username, source_p->host,
358     source_p->servptr->name, min_bitlen, user, host, reason);
359     return;
360     }
361     }
362     }
363    
364     #ifdef GLINE_VOTING
365     sendto_realops_flags(UMODE_ALL, L_ALL,
366     "%s requesting G-Line for [%s@%s] [%s]",
367     get_oper_name(source_p),
368     user, host, reason);
369    
370     /* If at least 3 opers agree this user should be G lined then do it */
371     if (check_majority_gline(source_p, user, host, reason) ==
372     GLINE_ALREADY_VOTED)
373     {
374     sendto_realops_flags(UMODE_ALL, L_ALL, "oper or server has already voted");
375     return;
376     }
377    
378     ilog(L_TRACE, "#gline for %s@%s [%s] requested by %s",
379     user, host, reason, get_oper_name(source_p));
380    
381     set_local_gline(source_p, user, host, reason);
382     #else
383     set_local_gline(source_p, user, host, reason);
384     #endif /* GLINE_VOTING */
385    
386     }
387     }
388    
389     /* set_local_gline()
390     *
391     * inputs - pointer to client struct of oper
392     * - pointer to victim user
393     * - pointer to victim host
394     * - pointer reason
395     * output - NONE
396     * side effects -
397     */
398     static void
399     set_local_gline(const struct Client *source_p, const char *user,
400     const char *host, const char *reason)
401     {
402     char buffer[IRCD_BUFSIZE];
403     struct ConfItem *conf;
404     struct AccessItem *aconf;
405     const char *current_date;
406     time_t cur_time;
407    
408     set_time();
409     cur_time = CurrentTime;
410    
411     current_date = smalldate(cur_time);
412     conf = make_conf_item(GLINE_TYPE);
413 db 139 aconf = &conf->conf.AccessItem;
414 adx 30
415     ircsprintf(buffer, "%s (%s)", reason, current_date);
416     DupString(aconf->reason, buffer);
417     DupString(aconf->user, user);
418     DupString(aconf->host, host);
419    
420     aconf->hold = CurrentTime + ConfigFileEntry.gline_time;
421     add_temp_line(conf);
422    
423     sendto_realops_flags(UMODE_ALL, L_ALL,
424     "%s added G-Line for [%s@%s] [%s]",
425     get_oper_name(source_p),
426     aconf->user, aconf->host, aconf->reason);
427     ilog(L_TRACE, "%s added G-Line for [%s@%s] [%s]",
428     get_oper_name(source_p), aconf->user, aconf->host, aconf->reason);
429     log_oper_action(LOG_GLINE_TYPE, source_p, "[%s@%s] [%s]\n",
430     aconf->user, aconf->host, aconf->reason);
431     /* Now, activate gline against current online clients */
432     rehashed_klines = 1;
433     }
434    
435     #ifdef GLINE_VOTING
436     /* add_new_majority_gline()
437     *
438     * inputs - operator requesting gline
439     * - username covered by the gline
440     * - hostname covered by the gline
441     * - reason for the gline
442     * output - NONE
443     * side effects -
444     * This function is called once a majority of opers
445     * have agreed on a gline, and it can be placed. The
446     * information about an operator being passed to us
447     * happens to be the operator who pushed us over the
448     * "majority" level needed. See check_majority_gline()
449     * for more information.
450     */
451     static void
452     add_new_majority_gline(const struct Client *source_p,
453     const char *user, const char *host, const char *reason)
454     {
455     struct gline_pending *pending = MyMalloc(sizeof(struct gline_pending));
456    
457     strlcpy(pending->oper_nick1, source_p->name, sizeof(pending->oper_nick1));
458     strlcpy(pending->oper_user1, source_p->username, sizeof(pending->oper_user1));
459     strlcpy(pending->oper_host1, source_p->host, sizeof(pending->oper_host1));
460    
461     strlcpy(pending->oper_server1, source_p->servptr->name, sizeof(pending->oper_server1));
462    
463     strlcpy(pending->user, user, sizeof(pending->user));
464     strlcpy(pending->host, host, sizeof(pending->host));
465     strlcpy(pending->reason1, reason, sizeof(pending->reason1));
466    
467     pending->last_gline_time = CurrentTime;
468     pending->time_request1 = CurrentTime;
469    
470     dlinkAdd(pending, &pending->node, &pending_glines);
471     }
472    
473     /* check_majority_gline()
474     *
475     * inputs - source, user, host, reason
476     *
477     * output - one of three results
478     *
479     * GLINE_ALREADY_VOTED - returned if oper/server has already voted
480     * GLINE_PLACED - returned if this triggers a gline
481     * GLINE_NOT_PLACED - returned if not triggered
482     *
483     * Side effects -
484     * See if there is a majority agreement on a GLINE on the given user
485     * There must be at least 3 different opers agreeing on this GLINE
486     *
487     */
488     static int
489     check_majority_gline(const struct Client *source_p,
490     const char *user, const char *host, const char *reason)
491     {
492     dlink_node *pending_node;
493     struct gline_pending *gline_pending_ptr;
494    
495     /* if its already glined, why bother? :) -- fl_ */
496     if (find_is_glined(host, user))
497     return(GLINE_NOT_PLACED);
498    
499     /* special case condition where there are no pending glines */
500     if (dlink_list_length(&pending_glines) == 0) /* first gline request placed */
501     {
502     add_new_majority_gline(source_p, user, host, reason);
503     return(GLINE_NOT_PLACED);
504     }
505    
506     DLINK_FOREACH(pending_node, pending_glines.head)
507     {
508     gline_pending_ptr = pending_node->data;
509    
510     if ((irccmp(gline_pending_ptr->user, user) == 0) &&
511     (irccmp(gline_pending_ptr->host, host) == 0))
512     {
513     if (((irccmp(gline_pending_ptr->oper_user1, source_p->username) == 0) ||
514     (irccmp(gline_pending_ptr->oper_host1, source_p->host) == 0)) ||
515     (irccmp(gline_pending_ptr->oper_server1, source_p->servptr->name) == 0))
516     {
517     return(GLINE_ALREADY_VOTED);
518     }
519    
520     if (gline_pending_ptr->oper_user2[0] != '\0')
521     {
522     /* if two other opers on two different servers have voted yes */
523    
524     if(((irccmp(gline_pending_ptr->oper_user2, source_p->username)==0) ||
525     (irccmp(gline_pending_ptr->oper_host2, source_p->host)==0)) ||
526     (irccmp(gline_pending_ptr->oper_server2, source_p->servptr->name)==0))
527     {
528     return(GLINE_ALREADY_VOTED);
529     }
530    
531     /* trigger the gline using the original reason --fl */
532     set_local_gline(source_p, user, host, gline_pending_ptr->reason1);
533     cleanup_glines(NULL);
534     return(GLINE_PLACED);
535     }
536     else
537     {
538     strlcpy(gline_pending_ptr->oper_nick2, source_p->name,
539     sizeof(gline_pending_ptr->oper_nick2));
540     strlcpy(gline_pending_ptr->oper_user2, source_p->username,
541     sizeof(gline_pending_ptr->oper_user2));
542     strlcpy(gline_pending_ptr->oper_host2, source_p->host,
543     sizeof(gline_pending_ptr->oper_host2));
544     strlcpy(gline_pending_ptr->reason2, reason,
545     sizeof(gline_pending_ptr->reason2));
546     strlcpy(gline_pending_ptr->oper_server2, source_p->servptr->name,
547     sizeof(gline_pending_ptr->oper_server2));
548     gline_pending_ptr->last_gline_time = CurrentTime;
549     gline_pending_ptr->time_request2 = CurrentTime;
550     return(GLINE_NOT_PLACED);
551     }
552     }
553     }
554    
555     /* Didn't find this user@host gline in pending gline list
556     * so add it.
557     */
558     add_new_majority_gline(source_p, user, host, reason);
559     return(GLINE_NOT_PLACED);
560     }
561     #endif /* GLINE_VOTING */
562    
563     static int
564     remove_gline_match(const char *user, const char *host)
565     {
566     struct AccessItem *aconf;
567     dlink_node *ptr = NULL;
568     struct irc_ssaddr addr, caddr;
569     int nm_t, cnm_t, bits, cbits;
570    
571     nm_t = parse_netmask(host, &addr, &bits);
572    
573     DLINK_FOREACH(ptr, temporary_glines.head)
574     {
575 db 139 aconf = &((struct ConfItem *)(ptr->data))->conf.AccessItem;
576 adx 30 cnm_t = parse_netmask(aconf->host, &caddr, &cbits);
577    
578     if (cnm_t != nm_t || irccmp(user, aconf->user))
579     continue;
580    
581     if ((nm_t == HM_HOST && !irccmp(aconf->host, host)) ||
582     (nm_t == HM_IPV4 && bits == cbits && match_ipv4(&addr, &caddr, bits))
583     #ifdef IPV6
584     || (nm_t == HM_IPV6 && bits == cbits && match_ipv6(&addr, &caddr, bits))
585     #endif
586     )
587     {
588     dlinkDelete(ptr, &temporary_glines);
589     delete_one_address_conf(aconf->host, aconf);
590     return(1);
591     }
592     }
593    
594     return(0);
595     }
596    
597     /*
598     ** m_ungline
599     ** added May 29th 2000 by Toby Verrall <toot@melnet.co.uk>
600     ** added to hybrid-7 7/11/2000 --is
601     **
602     ** parv[0] = sender nick
603     ** parv[1] = gline to remove
604     */
605     static void
606     mo_ungline(struct Client *client_p, struct Client *source_p,
607     int parc, char *parv[])
608     {
609     char *user, *host;
610    
611     if (!ConfigFileEntry.glines)
612     {
613     sendto_one(source_p, ":%s NOTICE %s :UNGLINE disabled",
614     me.name, source_p->name);
615     return;
616     }
617    
618     if (!IsOperUnkline(source_p) || !IsOperGline(source_p))
619     {
620     sendto_one(source_p, form_str(ERR_NOPRIVS),
621     me.name, source_p->name, "gline");
622     return;
623     }
624    
625     if (parse_aline("UNGLINE", source_p, parc, parv,
626     0, &user, &host, NULL, NULL, NULL) < 0)
627     return;
628    
629     if (remove_gline_match(user, host))
630     {
631     sendto_one(source_p, ":%s NOTICE %s :G-Line for [%s@%s] is removed",
632     me.name, source_p->name, user, host);
633     sendto_realops_flags(UMODE_ALL, L_ALL,
634     "%s has removed the G-Line for: [%s@%s]",
635     get_oper_name(source_p), user, host);
636     ilog(L_NOTICE, "%s removed G-Line for [%s@%s]",
637     get_oper_name(source_p), user, host);
638     }
639     else
640     {
641     sendto_one(source_p, ":%s NOTICE %s :No G-Line for %s@%s",
642     me.name, source_p->name, user, host);
643     }
644     }

Properties

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