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