/[svn]/ircd-hybrid/trunk/modules/m_gline.c
ViewVC logotype

Annotation of /ircd-hybrid/trunk/modules/m_gline.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1625 - (hide annotations)
Thu Nov 1 13:49:25 2012 UTC (7 years, 10 months ago) by michael
File MIME type: text/x-chdr
File size: 18332 byte(s)
- dbs are now periodically flushed on disc every 5 minutes

1 adx 30 /*
2     * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3     *
4     * Copyright (C) 2002 by the past and present ircd coders, and others.
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 2 of the License, or
9     * (at your option) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19     * USA
20     */
21    
22 michael 1008 /*! \file m_gline.c
23     * \brief Includes required functions for processing the GLINE command.
24     * \version $Id$
25     */
26    
27 adx 30 #include "stdinc.h"
28 michael 1011 #include "list.h"
29 adx 30 #include "s_gline.h"
30     #include "channel.h"
31     #include "client.h"
32     #include "irc_string.h"
33     #include "sprintf_irc.h"
34     #include "ircd.h"
35     #include "hostmask.h"
36     #include "numeric.h"
37     #include "s_bsd.h"
38 michael 1309 #include "conf.h"
39 adx 30 #include "s_misc.h"
40     #include "send.h"
41     #include "s_serv.h"
42     #include "hash.h"
43     #include "parse.h"
44     #include "modules.h"
45 michael 1309 #include "log.h"
46 michael 1622 #include "conf_db.h"
47 adx 30
48     #define GLINE_NOT_PLACED 0
49     #define GLINE_ALREADY_VOTED -1
50     #define GLINE_PLACED 1
51    
52    
53 michael 1009 /*! \brief Adds a GLINE to the configuration subsystem.
54     *
55     * \param source_p Operator requesting gline
56     * \param user Username covered by the gline
57     * \param host Hostname covered by the gline
58     * \param reason Reason for the gline
59     */
60     static void
61     set_local_gline(const struct Client *source_p, const char *user,
62     const char *host, const char *reason)
63     {
64     char buffer[IRCD_BUFSIZE];
65 michael 1622 struct AccessItem *aconf = map_to_conf(make_conf_item(GLINE_TYPE));
66 michael 1008
67 michael 1009 snprintf(buffer, sizeof(buffer), "%s (%s)", reason, smalldate(CurrentTime));
68     DupString(aconf->reason, buffer);
69     DupString(aconf->user, user);
70     DupString(aconf->host, host);
71    
72 michael 1622 aconf->setat = CurrentTime;
73 michael 1009 aconf->hold = CurrentTime + ConfigFileEntry.gline_time;
74 michael 1369 SetConfTemporary(aconf);
75 michael 1009
76 michael 1618 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
77 michael 1009 "%s added G-Line for [%s@%s] [%s]",
78     get_oper_name(source_p),
79     aconf->user, aconf->host, aconf->reason);
80 michael 1247 ilog(LOG_TYPE_GLINE, "%s added G-Line for [%s@%s] [%s]",
81 michael 1009 get_oper_name(source_p), aconf->user, aconf->host, aconf->reason);
82 michael 1247
83 michael 1622 add_conf_by_address(CONF_GLINE, aconf);
84 michael 1009 rehashed_klines = 1;
85     }
86    
87     /*! \brief Removes a GLINE from the configuration subsystem.
88     *
89     * \param user Username covered by the gline
90     * \param host Hostname covered by the gline
91     */
92     static int
93     remove_gline_match(const char *user, const char *host)
94     {
95 michael 1369 struct irc_ssaddr iphost, *piphost;
96 michael 1009 struct AccessItem *aconf;
97 michael 1369 int t;
98 michael 1009
99 michael 1369 if ((t = parse_netmask(host, &iphost, NULL)) != HM_HOST)
100 michael 1009 {
101     #ifdef IPV6
102 michael 1369 if (t == HM_IPV6)
103     t = AF_INET6;
104     else
105 michael 1009 #endif
106 michael 1369 t = AF_INET;
107     piphost = &iphost;
108     }
109     else
110     {
111     t = 0;
112     piphost = NULL;
113     }
114    
115 michael 1371 if ((aconf = find_conf_by_address(host, piphost, CONF_GLINE, t, user, NULL, 0)))
116 michael 1369 {
117 michael 1622 delete_one_address_conf(host, aconf);
118     return 1;
119 michael 1009 }
120    
121     return 0;
122     }
123    
124 michael 1008 /*! \brief This function is called once a majority of opers have agreed on a
125     * GLINE/GUNGLINE, and it can be placed. The information about an
126     * operator being passed to us happens to be the operator who pushed us
127     * over the "majority" level needed. See check_majority() for more
128     * information.
129 adx 30 *
130 michael 1008 * \param source_p Operator requesting gline
131     * \param user Username covered by the gline
132     * \param host Hostname covered by the gline
133     * \param reason Reason for the gline
134     * \param type Valid values are either GLINE_PENDING_ADD_TYPE, or
135     * GLINE_PENDING_DEL_TYPE
136 adx 30 */
137 michael 1008 static void
138     add_new_majority(const struct Client *source_p, const char *user,
139     const char *host, const char *reason, const unsigned int type)
140     {
141     struct gline_pending *pending = MyMalloc(sizeof(struct gline_pending));
142    
143     strlcpy(pending->vote_1.oper_nick, source_p->name, sizeof(pending->vote_1.oper_nick));
144     strlcpy(pending->vote_1.oper_user, source_p->username, sizeof(pending->vote_1.oper_user));
145     strlcpy(pending->vote_1.oper_host, source_p->host, sizeof(pending->vote_1.oper_host));
146     strlcpy(pending->vote_1.oper_server, source_p->servptr->name, sizeof(pending->vote_1.oper_server));
147    
148     strlcpy(pending->user, user, sizeof(pending->user));
149     strlcpy(pending->host, host, sizeof(pending->host));
150     strlcpy(pending->vote_1.reason, reason, sizeof(pending->vote_1.reason));
151    
152     pending->last_gline_time = CurrentTime;
153     pending->vote_1.time_request = CurrentTime;
154    
155     dlinkAdd(pending, &pending->node, &pending_glines[type]);
156     }
157    
158     /*! \brief See if there is a majority agreement on a GLINE on the given user.
159     * There must be at least 3 different opers agreeing on this
160     * GLINE/GUNGLINE
161 adx 30 *
162 michael 1008 * \param source_p Operator requesting gline
163     * \param user Username covered by the gline
164     * \param host Hostname covered by the gline
165     * \param reason Reason for the gline
166     * \param type Valid values are either GLINE_PENDING_ADD_TYPE, or
167     * GLINE_PENDING_DEL_TYPE
168     *
169     * \return
170     * - GLINE_ALREADY_VOTED returned if oper/server has already voted
171     * - GLINE_PLACED returned if this triggers a gline
172     * - GLINE_NOT_PLACED returned if not triggered
173 adx 30 */
174 michael 1008 static int
175     check_majority(const struct Client *source_p, const char *user,
176     const char *host, const char *reason, const int type)
177 adx 30 {
178 michael 1008 dlink_node *dn_ptr = NULL;
179 adx 30
180 michael 1008 cleanup_glines(NULL);
181 adx 30
182 michael 1008 /* if its already glined, why bother? :) -- fl_ */
183     if ((type == GLINE_PENDING_ADD_TYPE) && find_is_glined(host, user))
184     return GLINE_NOT_PLACED;
185    
186     DLINK_FOREACH(dn_ptr, pending_glines[type].head)
187 adx 30 {
188 michael 1008 struct gline_pending *gp_ptr = dn_ptr->data;
189 adx 30
190 michael 1008 if (irccmp(gp_ptr->user, user) ||
191     irccmp(gp_ptr->host, host))
192     continue;
193 adx 30
194 michael 1008 if ((!irccmp(gp_ptr->vote_1.oper_user, source_p->username) &&
195     !irccmp(gp_ptr->vote_1.oper_host, source_p->host)) ||
196     !irccmp(gp_ptr->vote_1.oper_server, source_p->servptr->name))
197     return GLINE_ALREADY_VOTED;
198    
199     if (gp_ptr->vote_2.oper_user[0] != '\0')
200 adx 30 {
201 michael 1008 /* if two other opers on two different servers have voted yes */
202     if ((!irccmp(gp_ptr->vote_2.oper_user, source_p->username) &&
203     !irccmp(gp_ptr->vote_2.oper_host, source_p->host)) ||
204     !irccmp(gp_ptr->vote_2.oper_server, source_p->servptr->name))
205     return GLINE_ALREADY_VOTED;
206    
207     if (type == GLINE_PENDING_DEL_TYPE)
208     {
209     if (remove_gline_match(user, host))
210     {
211 michael 1618 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
212 michael 1008 "%s has removed the G-Line for: [%s@%s]",
213     get_oper_name(source_p), user, host);
214 michael 1247 ilog(LOG_TYPE_GLINE, "%s removed G-Line for [%s@%s]",
215 michael 1008 get_oper_name(source_p), user, host);
216     }
217     }
218     else
219     /* trigger the gline using the original reason --fl */
220     set_local_gline(source_p, user, host, gp_ptr->vote_1.reason);
221    
222     cleanup_glines(gp_ptr);
223     return GLINE_PLACED;
224 adx 30 }
225 michael 1008
226     strlcpy(gp_ptr->vote_2.oper_nick, source_p->name,
227     sizeof(gp_ptr->vote_2.oper_nick));
228     strlcpy(gp_ptr->vote_2.oper_user, source_p->username,
229     sizeof(gp_ptr->vote_2.oper_user));
230     strlcpy(gp_ptr->vote_2.oper_host, source_p->host,
231     sizeof(gp_ptr->vote_2.oper_host));
232     strlcpy(gp_ptr->vote_2.reason, reason,
233     sizeof(gp_ptr->vote_2.reason));
234     strlcpy(gp_ptr->vote_2.oper_server, source_p->servptr->name,
235     sizeof(gp_ptr->vote_2.oper_server));
236     gp_ptr->last_gline_time = CurrentTime;
237     gp_ptr->vote_2.time_request = CurrentTime;
238     return GLINE_NOT_PLACED;
239 adx 30 }
240    
241 michael 552 /*
242 michael 1008 * Didn't find this user@host gline in pending gline list
243     * so add it.
244 adx 30 */
245 michael 1008 add_new_majority(source_p, user, host, reason, type);
246     return GLINE_NOT_PLACED;
247 adx 30 }
248    
249     static void
250 michael 1008 do_sgline(struct Client *source_p, int parc, char *parv[], int prop)
251 adx 30 {
252     const char *reason = NULL; /* reason for "victims" demise */
253 michael 1463 const char *user = NULL;
254     const char *host = NULL; /* user and host of GLINE "victim" */
255 adx 30
256 michael 1482 if (!IsClient(source_p))
257     return;
258 adx 30
259 michael 1482 if (parc != 4 || EmptyString(parv[3]))
260     return;
261    
262 adx 30 assert(source_p->servptr != NULL);
263    
264 michael 1482 user = parv[1];
265     host = parv[2];
266     reason = parv[3];
267 adx 30
268 michael 1474 sendto_server(source_p->from, CAP_GLN|CAP_TS6, NOCAPS,
269 michael 1459 ":%s GLINE %s %s :%s",
270 michael 1463 ID(source_p), user, host, reason);
271 michael 1474 sendto_server(source_p->from, CAP_GLN, CAP_TS6,
272 michael 1463 ":%s GLINE %s %s :%s",
273 michael 1459 source_p->name, user, host, reason);
274 michael 1463
275 adx 30 if (ConfigFileEntry.glines)
276     {
277 michael 1243 if (!valid_wild_card(source_p, 1, 2, user, host))
278 adx 30 return;
279    
280     if (IsClient(source_p))
281     {
282     const char *p = NULL;
283 michael 958
284 adx 30 if ((p = strchr(host, '/')))
285     {
286     int bitlen = strtol(++p, NULL, 10);
287     int min_bitlen = strchr(host, ':') ? ConfigFileEntry.gline_min_cidr6 :
288     ConfigFileEntry.gline_min_cidr;
289    
290     if (bitlen < min_bitlen)
291     {
292 michael 1618 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
293     "%s is requesting a GLINE with a CIDR mask < %d for [%s@%s] [%s]",
294     get_oper_name(source_p), min_bitlen,
295     user, host, reason);
296 adx 30 return;
297     }
298     }
299     }
300    
301     /* If at least 3 opers agree this user should be G lined then do it */
302 michael 988 if (check_majority(source_p, user, host, reason, GLINE_PENDING_ADD_TYPE) ==
303 adx 30 GLINE_ALREADY_VOTED)
304     {
305 michael 1618 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
306     "oper or server has already voted");
307 adx 30 return;
308     }
309    
310 michael 1618 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
311 michael 554 "%s requesting G-Line for [%s@%s] [%s]",
312     get_oper_name(source_p),
313     user, host, reason);
314 michael 1247 ilog(LOG_TYPE_GLINE, "#gline for %s@%s [%s] requested by %s",
315 adx 30 user, host, reason, get_oper_name(source_p));
316     }
317     }
318    
319 michael 1008
320     /*! \brief GLINE command handler (called by operators)
321 adx 30 *
322 michael 1008 * \param client_p Pointer to allocated Client struct with physical connection
323     * to this server, i.e. with an open socket connected.
324     * \param source_p Pointer to allocated Client struct from which the message
325     * originally comes from. This can be a local or remote client.
326     * \param parc Integer holding the number of supplied arguments.
327     * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
328     * pointers.
329     * \note Valid arguments for this command are:
330     * - parv[0] = sender prefix
331     * - parv[1] = user\@host mask
332     * - parv[2] = reason
333 adx 30 */
334     static void
335 michael 1008 mo_gline(struct Client *client_p, struct Client *source_p,
336     int parc, char *parv[])
337 adx 30 {
338 michael 1008 char *user = NULL;
339     char *host = NULL;
340     char *reason = NULL;
341     char *p;
342 adx 30
343 michael 1463 if (!HasOFlag(source_p, OPER_FLAG_GLINE))
344 michael 1008 {
345 michael 1463 sendto_one(source_p, form_str(ERR_NOPRIVS),
346     me.name, source_p->name, "gline");
347 michael 1008 return;
348     }
349 adx 30
350 michael 1463 if (!ConfigFileEntry.glines)
351 michael 1008 {
352 michael 1463 sendto_one(source_p, ":%s NOTICE %s :GLINE disabled",
353     me.name, source_p->name);
354 michael 1008 return;
355     }
356 adx 30
357 michael 1008 if (parse_aline("GLINE", source_p, parc, parv, AWILD,
358     &user, &host, NULL, NULL, &reason) < 0)
359     return;
360 adx 30
361 michael 1008 if ((p = strchr(host, '/')) != NULL)
362 adx 30 {
363 michael 1008 int bitlen = strtol(++p, NULL, 10);
364     int min_bitlen = strchr(host, ':') ? ConfigFileEntry.gline_min_cidr6 :
365     ConfigFileEntry.gline_min_cidr;
366     if (bitlen < min_bitlen)
367 adx 30 {
368 michael 1008 sendto_one(source_p, ":%s NOTICE %s :Cannot set G-Lines with CIDR length < %d",
369     me.name, source_p->name, min_bitlen);
370     return;
371 michael 957 }
372 adx 30 }
373 michael 1008
374     /* If at least 3 opers agree this user should be G lined then do it */
375     if (check_majority(source_p, user, host, reason, GLINE_PENDING_ADD_TYPE) ==
376     GLINE_ALREADY_VOTED)
377     {
378     sendto_one(source_p,
379     ":%s NOTICE %s :This server or oper has already voted",
380     me.name, source_p->name);
381     return;
382     }
383 adx 30
384 michael 957 /*
385 michael 1008 * call these two functions first so the 'requesting' notice always comes
386     * before the 'has triggered' notice. -bill
387 adx 30 */
388 michael 1618 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
389 michael 1008 "%s requesting G-Line for [%s@%s] [%s]",
390     get_oper_name(source_p),
391     user, host, reason);
392 michael 1247 ilog(LOG_TYPE_GLINE, "#gline for %s@%s [%s] requested by %s!%s@%s",
393 michael 1008 user, host, reason, source_p->name, source_p->username,
394     source_p->host);
395 adx 30
396 michael 1008 /* 4 param version for hyb-7 servers */
397 michael 1474 sendto_server(NULL, CAP_GLN|CAP_TS6, NOCAPS,
398 michael 1008 ":%s GLINE %s %s :%s",
399     ID(source_p), user, host, reason);
400 michael 1474 sendto_server(NULL, CAP_GLN, CAP_TS6,
401 michael 1008 ":%s GLINE %s %s :%s",
402     source_p->name, user, host, reason);
403 adx 30 }
404    
405 michael 1008 /* ms_gline()
406     * me_gline()
407     * do_sgline()
408 db 937 *
409     * inputs - The usual for a m_ function
410     * output -
411     * side effects -
412     *
413 michael 1008 * Place a G line if 3 opers agree on the identical user@host
414 db 937 *
415 michael 1008 * Allow this server to pass along GLINE if received and
416     * GLINES is not defined.
417     *
418     * ENCAP'd GLINES are propagated by encap code.
419 db 937 */
420    
421     static void
422 michael 1008 ms_gline(struct Client *client_p, struct Client *source_p,
423     int parc, char *parv[])
424 db 937 {
425 michael 1008 do_sgline(source_p, parc, parv, 1);
426 db 937 }
427    
428     static void
429 michael 1008 me_gline(struct Client *client_p, struct Client *source_p,
430     int parc, char *parv[])
431     {
432     do_sgline(source_p, parc, parv, 0);
433     }
434    
435     static void
436 michael 1006 do_sungline(struct Client *source_p, const char *user,
437     const char *host, const char *reason, int prop)
438 db 937 {
439     assert(source_p->servptr != NULL);
440    
441 michael 1618 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
442 michael 957 "%s requesting UNG-Line for [%s@%s] [%s]",
443 michael 1006 get_oper_name(source_p), user, host, reason);
444 michael 1247 ilog(LOG_TYPE_GLINE, "#ungline for %s@%s [%s] requested by %s",
445 michael 957 user, host, reason, get_oper_name(source_p));
446 db 937
447 michael 957 /* If at least 3 opers agree this user should be un G lined then do it */
448 michael 958 if (check_majority(source_p, user, host, reason, GLINE_PENDING_DEL_TYPE) ==
449 michael 957 GLINE_ALREADY_VOTED)
450 michael 1618 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
451     "oper or server has already voted");
452 michael 1006
453     if (prop)
454     {
455 michael 1474 sendto_server(source_p->from, CAP_ENCAP|CAP_TS6, NOCAPS,
456 michael 1006 ":%s ENCAP * GUNGLINE %s %s :%s",
457     ID(source_p), user, host, reason);
458 michael 1474 sendto_server(source_p->from, CAP_ENCAP, CAP_TS6,
459 michael 1006 ":%s ENCAP * GUNGLINE %s %s :%s",
460     source_p->name, user, host, reason);
461     }
462 db 937 }
463    
464 michael 1008 /*! \brief GUNGLINE command handler (called in response to an encapsulated
465     * GUNGLINE command)
466 db 937 *
467 michael 1008 * \param client_p Pointer to allocated Client struct with physical connection
468     * to this server, i.e. with an open socket connected.
469     * \param source_p Pointer to allocated Client struct from which the message
470     * originally comes from. This can be a local or remote client.
471     * \param parc Integer holding the number of supplied arguments.
472     * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
473     * pointers.
474     * \note Valid arguments for this command are:
475     * - parv[0] = sender prefix
476     * - parv[1] = username
477     * - parv[2] = hostname
478     * - parv[3] = reason
479 db 937 */
480 michael 1008 static void
481     me_gungline(struct Client *client_p, struct Client *source_p,
482     int parc, char *parv[])
483     {
484     if (ConfigFileEntry.glines)
485     do_sungline(source_p, parv[1], parv[2], parv[3], 0);
486     }
487    
488     /*! \brief GUNGLINE command handler (called by operators)
489 db 937 *
490 michael 1008 * \param client_p Pointer to allocated Client struct with physical connection
491     * to this server, i.e. with an open socket connected.
492     * \param source_p Pointer to allocated Client struct from which the message
493     * originally comes from. This can be a local or remote client.
494     * \param parc Integer holding the number of supplied arguments.
495     * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
496     * pointers.
497     * \note Valid arguments for this command are:
498     * - parv[0] = sender prefix
499     * - parv[1] = user\@host mask
500     * - parv[2] = reason
501 db 937 */
502     static void
503 db 940 mo_gungline(struct Client *client_p, struct Client *source_p,
504 michael 957 int parc, char *parv[])
505 db 937 {
506     char *user = NULL;
507 michael 1008 char *host = NULL;
508     char *reason = NULL;
509 db 937
510 michael 1463 if (!HasOFlag(source_p, OPER_FLAG_GLINE))
511 db 937 {
512 michael 1463 sendto_one(source_p, form_str(ERR_NOPRIVS),
513     me.name, source_p->name, "gline");
514 db 937 return;
515     }
516    
517 michael 1463 if (!ConfigFileEntry.glines)
518 db 937 {
519 michael 1463 sendto_one(source_p, ":%s NOTICE %s :GUNGLINE disabled",
520     me.name, source_p->name);
521 db 937 return;
522     }
523    
524 michael 957 if (parse_aline("GUNGLINE", source_p, parc, parv, 0, &user,
525     &host, NULL, NULL, &reason) < 0)
526 db 937 return;
527    
528 michael 1006 do_sungline(source_p, user, host, reason, 1);
529 db 937 }
530 michael 1230
531     /*
532     * gline enforces 3 parameters to force operator to give a reason
533     * a gline is not valid with "No reason"
534     * -db
535     */
536     static struct Message gline_msgtab = {
537     "GLINE", 0, 0, 3, MAXPARA, MFLG_SLOW, 0,
538     { m_unregistered, m_not_oper, ms_gline, me_gline, mo_gline, m_ignore }
539     };
540    
541     static struct Message ungline_msgtab = {
542     "GUNGLINE", 0, 0, 3, MAXPARA, MFLG_SLOW, 0,
543     { m_unregistered, m_not_oper, m_ignore, me_gungline, mo_gungline, m_ignore }
544     };
545    
546     static void
547     module_init(void)
548     {
549     mod_add_cmd(&gline_msgtab);
550     mod_add_cmd(&ungline_msgtab);
551     add_capability("GLN", CAP_GLN, 1);
552     }
553    
554     static void
555     module_exit(void)
556     {
557     mod_del_cmd(&gline_msgtab);
558     mod_del_cmd(&ungline_msgtab);
559     delete_capability("GLN");
560     }
561    
562     struct module module_entry = {
563     .node = { NULL, NULL, NULL },
564     .name = NULL,
565     .version = "$Revision$",
566     .handle = NULL,
567     .modinit = module_init,
568     .modexit = module_exit,
569     .flags = 0
570     };

Properties

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

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28