ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/m_gline.c
Revision: 1646
Committed: Wed Nov 7 21:02:43 2012 UTC (12 years, 9 months ago) by michael
Content type: text/x-csrc
File size: 18353 byte(s)
Log Message:
- First pass of conf parser stabilization/cleanup

File Contents

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

Properties

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