ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/m_gline.c
Revision: 1618
Committed: Tue Oct 30 21:04:38 2012 UTC (13 years, 11 months ago) by michael
Content type: text/x-csrc
File size: 18439 byte(s)
Log Message:
- Made m_globops() and ms_globops() use sendto_realops_flags()
- Added message-type parameter to sendto_realops_flags() which can be one of
  SEND_NOTICE, SEND_GLOBAL, SEND_LOCOPS
- Forward-port -r1617

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

Properties

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