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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1644 - (show annotations)
Tue Nov 6 22:20:16 2012 UTC (7 years, 7 months ago) by michael
File MIME type: text/x-chdr
File size: 18356 byte(s)
- More config subsystem cleanups

1 /*
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 /*! \file m_gline.c
23 * \brief Includes required functions for processing the GLINE command.
24 * \version $Id$
25 */
26
27 #include "stdinc.h"
28 #include "list.h"
29 #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 "conf.h"
36 #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 #include "log.h"
46 #include "conf_db.h"
47
48 #define GLINE_NOT_PLACED 0
49 #define GLINE_ALREADY_VOTED -1
50 #define GLINE_PLACED 1
51
52
53 /*! \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 struct MaskItem *conf = conf_make(CONF_GLINE);
66
67 snprintf(buffer, sizeof(buffer), "%s (%s)", reason, smalldate(CurrentTime));
68 DupString(conf->reason, buffer);
69 DupString(conf->user, user);
70 DupString(conf->host, host);
71
72 conf->setat = CurrentTime;
73 conf->hold = CurrentTime + ConfigFileEntry.gline_time;
74 SetConfDatabase(conf);
75
76 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
77 "%s added G-Line for [%s@%s] [%s]",
78 get_oper_name(source_p),
79 conf->user, conf->host, conf->reason);
80 ilog(LOG_TYPE_GLINE, "%s added G-Line for [%s@%s] [%s]",
81 get_oper_name(source_p), conf->user, conf->host, conf->reason);
82
83 add_conf_by_address(CONF_GLINE, conf);
84 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 struct irc_ssaddr iphost, *piphost;
96 struct MaskItem *conf;
97 int t = 0;
98 int aftype = 0;
99
100 if ((t = parse_netmask(host, &iphost, NULL)) != HM_HOST)
101 {
102 #ifdef IPV6
103 if (t == HM_IPV6)
104 aftype = AF_INET6;
105 else
106 #endif
107 aftype = AF_INET;
108 piphost = &iphost;
109 }
110 else
111 piphost = NULL;
112
113 if ((conf = find_conf_by_address(host, piphost, CONF_GLINE, aftype, user, NULL, 0)))
114 {
115 if (IsConfDatabase(conf))
116 {
117 delete_one_address_conf(host, conf);
118 return 1;
119 }
120 }
121
122 return 0;
123 }
124
125 /*! \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 *
131 * \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 */
138 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 *
163 * \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 */
175 static int
176 check_majority(const struct Client *source_p, const char *user,
177 const char *host, const char *reason, const int type)
178 {
179 dlink_node *dn_ptr = NULL;
180
181 cleanup_glines(NULL);
182
183 /* 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 {
189 struct gline_pending *gp_ptr = dn_ptr->data;
190
191 if (irccmp(gp_ptr->user, user) ||
192 irccmp(gp_ptr->host, host))
193 continue;
194
195 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 {
202 /* 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 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
213 "%s has removed the G-Line for: [%s@%s]",
214 get_oper_name(source_p), user, host);
215 ilog(LOG_TYPE_GLINE, "%s removed G-Line for [%s@%s]",
216 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 }
226
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 }
241
242 /*
243 * Didn't find this user@host gline in pending gline list
244 * so add it.
245 */
246 add_new_majority(source_p, user, host, reason, type);
247 return GLINE_NOT_PLACED;
248 }
249
250 static void
251 do_sgline(struct Client *source_p, int parc, char *parv[], int prop)
252 {
253 const char *reason = NULL; /* reason for "victims" demise */
254 const char *user = NULL;
255 const char *host = NULL; /* user and host of GLINE "victim" */
256
257 if (!IsClient(source_p))
258 return;
259
260 if (parc != 4 || EmptyString(parv[3]))
261 return;
262
263 assert(source_p->servptr != NULL);
264
265 user = parv[1];
266 host = parv[2];
267 reason = parv[3];
268
269 sendto_server(source_p->from, CAP_GLN|CAP_TS6, NOCAPS,
270 ":%s GLINE %s %s :%s",
271 ID(source_p), user, host, reason);
272 sendto_server(source_p->from, CAP_GLN, CAP_TS6,
273 ":%s GLINE %s %s :%s",
274 source_p->name, user, host, reason);
275
276 if (ConfigFileEntry.glines)
277 {
278 if (!valid_wild_card(source_p, 1, 2, user, host))
279 return;
280
281 if (IsClient(source_p))
282 {
283 const char *p = NULL;
284
285 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 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 return;
298 }
299 }
300 }
301
302 /* If at least 3 opers agree this user should be G lined then do it */
303 if (check_majority(source_p, user, host, reason, GLINE_PENDING_ADD_TYPE) ==
304 GLINE_ALREADY_VOTED)
305 {
306 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
307 "oper or server has already voted");
308 return;
309 }
310
311 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
312 "%s requesting G-Line for [%s@%s] [%s]",
313 get_oper_name(source_p),
314 user, host, reason);
315 ilog(LOG_TYPE_GLINE, "#gline for %s@%s [%s] requested by %s",
316 user, host, reason, get_oper_name(source_p));
317 }
318 }
319
320
321 /*! \brief GLINE command handler (called by operators)
322 *
323 * \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 */
335 static void
336 mo_gline(struct Client *client_p, struct Client *source_p,
337 int parc, char *parv[])
338 {
339 char *user = NULL;
340 char *host = NULL;
341 char *reason = NULL;
342 char *p;
343
344 if (!HasOFlag(source_p, OPER_FLAG_GLINE))
345 {
346 sendto_one(source_p, form_str(ERR_NOPRIVS),
347 me.name, source_p->name, "gline");
348 return;
349 }
350
351 if (!ConfigFileEntry.glines)
352 {
353 sendto_one(source_p, ":%s NOTICE %s :GLINE disabled",
354 me.name, source_p->name);
355 return;
356 }
357
358 if (parse_aline("GLINE", source_p, parc, parv, AWILD,
359 &user, &host, NULL, NULL, &reason) < 0)
360 return;
361
362 if ((p = strchr(host, '/')) != NULL)
363 {
364 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 {
369 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 }
373 }
374
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
385 /*
386 * call these two functions first so the 'requesting' notice always comes
387 * before the 'has triggered' notice. -bill
388 */
389 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
390 "%s requesting G-Line for [%s@%s] [%s]",
391 get_oper_name(source_p),
392 user, host, reason);
393 ilog(LOG_TYPE_GLINE, "#gline for %s@%s [%s] requested by %s!%s@%s",
394 user, host, reason, source_p->name, source_p->username,
395 source_p->host);
396
397 /* 4 param version for hyb-7 servers */
398 sendto_server(NULL, CAP_GLN|CAP_TS6, NOCAPS,
399 ":%s GLINE %s %s :%s",
400 ID(source_p), user, host, reason);
401 sendto_server(NULL, CAP_GLN, CAP_TS6,
402 ":%s GLINE %s %s :%s",
403 source_p->name, user, host, reason);
404 }
405
406 /* ms_gline()
407 * me_gline()
408 * do_sgline()
409 *
410 * inputs - The usual for a m_ function
411 * output -
412 * side effects -
413 *
414 * Place a G line if 3 opers agree on the identical user@host
415 *
416 * 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 */
421
422 static void
423 ms_gline(struct Client *client_p, struct Client *source_p,
424 int parc, char *parv[])
425 {
426 do_sgline(source_p, parc, parv, 1);
427 }
428
429 static void
430 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 do_sungline(struct Client *source_p, const char *user,
438 const char *host, const char *reason, int prop)
439 {
440 assert(source_p->servptr != NULL);
441
442 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
443 "%s requesting UNG-Line for [%s@%s] [%s]",
444 get_oper_name(source_p), user, host, reason);
445 ilog(LOG_TYPE_GLINE, "#ungline for %s@%s [%s] requested by %s",
446 user, host, reason, get_oper_name(source_p));
447
448 /* If at least 3 opers agree this user should be un G lined then do it */
449 if (check_majority(source_p, user, host, reason, GLINE_PENDING_DEL_TYPE) ==
450 GLINE_ALREADY_VOTED)
451 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
452 "oper or server has already voted");
453
454 if (prop)
455 {
456 sendto_server(source_p->from, CAP_ENCAP|CAP_TS6, NOCAPS,
457 ":%s ENCAP * GUNGLINE %s %s :%s",
458 ID(source_p), user, host, reason);
459 sendto_server(source_p->from, CAP_ENCAP, CAP_TS6,
460 ":%s ENCAP * GUNGLINE %s %s :%s",
461 source_p->name, user, host, reason);
462 }
463 }
464
465 /*! \brief GUNGLINE command handler (called in response to an encapsulated
466 * GUNGLINE command)
467 *
468 * \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 */
481 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 *
491 * \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 */
503 static void
504 mo_gungline(struct Client *client_p, struct Client *source_p,
505 int parc, char *parv[])
506 {
507 char *user = NULL;
508 char *host = NULL;
509 char *reason = NULL;
510
511 if (!HasOFlag(source_p, OPER_FLAG_GLINE))
512 {
513 sendto_one(source_p, form_str(ERR_NOPRIVS),
514 me.name, source_p->name, "gline");
515 return;
516 }
517
518 if (!ConfigFileEntry.glines)
519 {
520 sendto_one(source_p, ":%s NOTICE %s :GUNGLINE disabled",
521 me.name, source_p->name);
522 return;
523 }
524
525 if (parse_aline("GUNGLINE", source_p, parc, parv, 0, &user,
526 &host, NULL, NULL, &reason) < 0)
527 return;
528
529 do_sungline(source_p, user, host, reason, 1);
530 }
531
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

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