ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/modules/m_gline.c
Revision: 32
Committed: Sun Oct 2 20:41:23 2005 UTC (18 years, 5 months ago) by knight
Content type: text/x-csrc
File size: 19600 byte(s)
Log Message:
- svn:keywords

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * m_gline.c: Votes towards globally banning a mask.
4 *
5 * Copyright (C) 2002 by the past and present ircd coders, and others.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 * $Id$
23 */
24
25 #include "stdinc.h"
26 #include "tools.h"
27 #include "handlers.h"
28 #include "s_gline.h"
29 #include "channel.h"
30 #include "client.h"
31 #include "common.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 "fdlist.h"
38 #include "s_bsd.h"
39 #include "s_conf.h"
40 #include "s_misc.h"
41 #include "send.h"
42 #include "msg.h"
43 #include "fileio.h"
44 #include "s_serv.h"
45 #include "hash.h"
46 #include "parse.h"
47 #include "modules.h"
48 #include "list.h"
49 #include "s_log.h"
50
51 #define GLINE_NOT_PLACED 0
52 #ifdef GLINE_VOTING
53 #define GLINE_ALREADY_VOTED -1
54 #endif /* GLINE_VOTING */
55 #define GLINE_PLACED 1
56
57 extern dlink_list gdeny_items;
58
59 /* internal functions */
60 static void set_local_gline(const struct Client *,
61 const char *, const char *, const char *);
62
63 #ifdef GLINE_VOTING
64 static int check_majority_gline(const struct Client *,
65 const char *, const char *, const char *);
66
67 static void add_new_majority_gline(const struct Client *,
68 const char *, const char *, const char *);
69 #endif /* GLINE_VOTING */
70
71 static void do_sgline(struct Client *, struct Client *, int, char **, int);
72
73 static void me_gline(struct Client *, struct Client *, int, char **);
74 static void ms_gline(struct Client *, struct Client *, int, char **);
75 static void mo_gline(struct Client *, struct Client *, int, char **);
76 static void mo_ungline(struct Client *, struct Client *, int, char **);
77
78 /*
79 * gline enforces 3 parameters to force operator to give a reason
80 * a gline is not valid with "No reason"
81 * -db
82 */
83 struct Message gline_msgtab = {
84 "GLINE", 0, 0, 3, 0, MFLG_SLOW, 0,
85 {m_unregistered, m_not_oper, ms_gline, me_gline, mo_gline, m_ignore}
86 };
87
88 struct Message ungline_msgtab = {
89 "UNGLINE", 0, 0, 2, 0, MFLG_SLOW, 0,
90 {m_unregistered, m_not_oper, m_error, m_ignore, mo_ungline, m_ignore}
91 };
92
93 #ifndef STATIC_MODULES
94 void
95 _modinit(void)
96 {
97 mod_add_cmd(&gline_msgtab);
98 mod_add_cmd(&ungline_msgtab);
99 add_capability("GLN", CAP_GLN, 1);
100 }
101
102 void
103 _moddeinit(void)
104 {
105 mod_del_cmd(&gline_msgtab);
106 mod_del_cmd(&ungline_msgtab);
107 delete_capability("GLN");
108 }
109
110 const char *_version = "$Revision$";
111 #endif
112
113 /* mo_gline()
114 *
115 * inputs - The usual for a m_ function
116 * output -
117 * side effects -
118 *
119 * Place a G line if 3 opers agree on the identical user@host
120 *
121 */
122 /* Allow this server to pass along GLINE if received and
123 * GLINES is not defined.
124 *
125 */
126
127 static void
128 mo_gline(struct Client *client_p, struct Client *source_p,
129 int parc, char *parv[])
130 {
131 char *user = NULL;
132 char *host = NULL; /* user and host of GLINE "victim" */
133 char *reason = NULL; /* reason for "victims" demise */
134 char *p;
135
136 if (!ConfigFileEntry.glines)
137 {
138 sendto_one(source_p, ":%s NOTICE %s :GLINE disabled",
139 me.name, source_p->name);
140 return;
141 }
142
143 if (!IsOperGline(source_p))
144 {
145 sendto_one(source_p, form_str(ERR_NOPRIVS),
146 me.name, source_p->name, "gline");
147 return;
148 }
149
150 if (parse_aline("GLINE", source_p, parc, parv,
151 AWILD, &user, &host, NULL, NULL, &reason) < 0)
152 return;
153
154 if ((p = strchr(host, '/')) != NULL)
155 {
156 int bitlen = strtol(++p, NULL, 10);
157 int min_bitlen = strchr(host, ':') ? ConfigFileEntry.gline_min_cidr6 :
158 ConfigFileEntry.gline_min_cidr;
159 if (bitlen < min_bitlen)
160 {
161 sendto_one(source_p, ":%s NOTICE %s :Cannot set G-Lines with CIDR length < %d",
162 me.name, source_p->name, min_bitlen);
163 return;
164 }
165 }
166
167 #ifdef GLINE_VOTING
168 /* If at least 3 opers agree this user should be G lined then do it */
169 if (check_majority_gline(source_p, user, host, reason) ==
170 GLINE_ALREADY_VOTED)
171 {
172 sendto_one(source_p,
173 ":%s NOTICE %s :This server or oper has already voted",
174 me.name, source_p->name);
175 return;
176 }
177
178 /* call these two functions first so the 'requesting' notice always comes
179 * before the 'has triggered' notice. -bill
180 */
181 sendto_realops_flags(UMODE_ALL, L_ALL,
182 "%s requesting G-Line for [%s@%s] [%s]",
183 get_oper_name(source_p),
184 user, host, reason);
185 ilog(L_TRACE, "#gline for %s@%s [%s] requested by %s!%s@%s",
186 user, host, reason, source_p->name, source_p->username,
187 source_p->host);
188
189 set_local_gline(source_p, user, host, reason);
190 #else
191 set_local_gline(source_p, user, host, reason);
192 #endif /* GLINE_VOTING */
193
194 /* 4 param version for hyb-7 servers */
195 sendto_server(NULL, source_p, NULL, CAP_GLN|CAP_TS6, NOCAPS,
196 LL_ICLIENT, ":%s GLINE %s %s :%s",
197 ID(source_p), user, host, reason);
198 sendto_server(NULL, source_p, NULL, CAP_GLN, CAP_TS6,
199 LL_ICLIENT, ":%s GLINE %s %s :%s",
200 source_p->name, user, host, reason);
201
202 /* 8 param for hyb-6 */
203 sendto_server(NULL, NULL, NULL, CAP_TS6, CAP_GLN, NOFLAGS,
204 ":%s GLINE %s %s %s %s %s %s :%s",
205 ID(&me),
206 ID(source_p), source_p->username,
207 source_p->host, source_p->servptr->name, user, host,
208 reason);
209 sendto_server(NULL, NULL, NULL, NOCAPS, CAP_GLN|CAP_TS6, NOFLAGS,
210 ":%s GLINE %s %s %s %s %s %s :%s",
211 me.name, source_p->name, source_p->username,
212 source_p->host, source_p->servptr->name, user, host,
213 reason);
214 }
215
216 /* ms_gline()
217 * me_gline()
218 * do_sgline()
219 *
220 * inputs - The usual for a m_ function
221 * output -
222 * side effects -
223 *
224 * Place a G line if 3 opers agree on the identical user@host
225 *
226 * Allow this server to pass along GLINE if received and
227 * GLINES is not defined.
228 *
229 * ENCAP'd GLINES are propagated by encap code.
230 */
231
232 static void
233 ms_gline(struct Client *client_p, struct Client *source_p,
234 int parc, char *parv[])
235 {
236 do_sgline(client_p, source_p, parc, parv, 1);
237 }
238
239 static void
240 me_gline(struct Client *client_p, struct Client *source_p,
241 int parc, char *parv[])
242 {
243 do_sgline(client_p, source_p, parc, parv, 0);
244 }
245
246 static void
247 do_sgline(struct Client *client_p, struct Client *source_p,
248 int parc, char *parv[], int prop)
249 {
250 const char *reason = NULL; /* reason for "victims" demise */
251 char *user = NULL;
252 char *host = NULL; /* user and host of GLINE "victim" */
253 int var_offset, logged = 0;
254 dlink_node *ptr;
255 struct ConfItem *conf;
256 struct AccessItem *aconf;
257
258 /* hyb-7 style gline (post beta3) */
259 if (parc == 4 && IsClient(source_p))
260 var_offset = 0;
261 /* or it's a hyb-6 style */
262 else if (parc == 8 && IsServer(source_p))
263 {
264 var_offset = 4;
265
266 /*
267 * if we are dealing with an old style formatted gline,
268 * the gline message is originating from the oper's server,
269 * so we update source_p to point to the oper now, so that
270 * logging works down the line. -bill
271 */
272 if ((source_p = find_person(client_p, parv[1])) == NULL)
273 return;
274
275 if (irccmp(parv[2], source_p->username) != 0 ||
276 irccmp(parv[3], source_p->host) != 0 ||
277 irccmp(parv[4], source_p->servptr->name) != 0)
278 {
279 /*
280 * at this point we know one of the parameters provided by
281 * the h6 server was faulty. bail out.
282 */
283 return;
284 }
285 }
286 /* none of the above */
287 else
288 return;
289
290 assert(source_p->servptr != NULL);
291
292 user = parv[++var_offset];
293 host = parv[++var_offset];
294 reason = parv[++var_offset];
295
296 var_offset = 0;
297
298 DLINK_FOREACH(ptr, gdeny_items.head)
299 {
300 conf = ptr->data;
301 aconf = (struct AccessItem *)map_to_conf(conf);
302
303 if (match(conf->name, source_p->servptr->name) &&
304 match(aconf->user, source_p->username) &&
305 match(aconf->host, source_p->host))
306 {
307 var_offset = aconf->flags;
308 break;
309 }
310 }
311
312 if (prop && !(var_offset & GDENY_BLOCK))
313 {
314 sendto_server(client_p, source_p->servptr, NULL, CAP_GLN, NOCAPS, LL_ICLIENT,
315 ":%s GLINE %s %s :%s",
316 source_p->name, user, host, reason);
317 /* hyb-6 version to the rest */
318 sendto_server(client_p, NULL, NULL, NOCAPS, CAP_GLN, NOFLAGS,
319 ":%s GLINE %s %s %s %s %s %s :%s",
320 source_p->servptr->name,
321 source_p->name, source_p->username, source_p->host,
322 source_p->servptr->name,
323 user, host, reason);
324 }
325 else if (ConfigFileEntry.gline_logging & GDENY_BLOCK && ServerInfo.hub)
326 {
327 sendto_realops_flags(UMODE_ALL, L_ALL, "Blocked G-Line %s requested on [%s@%s] [%s]",
328 get_oper_name(source_p), user, host, reason);
329 ilog(L_TRACE, "Blocked G-Line %s requested on [%s@%s] [%s]",
330 get_oper_name(source_p), user, host, reason);
331 logged = 1;
332 }
333
334
335 if (var_offset & GDENY_REJECT)
336 {
337 if (ConfigFileEntry.gline_logging & GDENY_REJECT && !logged)
338 {
339 sendto_realops_flags(UMODE_ALL, L_ALL, "Rejected G-Line %s requested on [%s@%s] [%s]",
340 get_oper_name(source_p), user, host, reason);
341 ilog(L_TRACE, "Rejected G-Line %s requested on [%s@%s] [%s]",
342 get_oper_name(source_p), user, host, reason);
343 }
344 return;
345 }
346
347 if (ConfigFileEntry.glines)
348 {
349 if (!valid_wild_card(source_p, YES, 2, user, host))
350 return;
351
352 if (IsClient(source_p))
353 {
354 const char *p = NULL;
355 if ((p = strchr(host, '/')))
356 {
357 int bitlen = strtol(++p, NULL, 10);
358 int min_bitlen = strchr(host, ':') ? ConfigFileEntry.gline_min_cidr6 :
359 ConfigFileEntry.gline_min_cidr;
360
361 if (bitlen < min_bitlen)
362 {
363 sendto_realops_flags(UMODE_ALL, L_ALL, "%s!%s@%s on %s is requesting "
364 "a GLINE with a CIDR mask < %d for [%s@%s] [%s]",
365 source_p->name, source_p->username, source_p->host,
366 source_p->servptr->name, min_bitlen, user, host, reason);
367 return;
368 }
369 }
370 }
371
372 #ifdef GLINE_VOTING
373 sendto_realops_flags(UMODE_ALL, L_ALL,
374 "%s requesting G-Line for [%s@%s] [%s]",
375 get_oper_name(source_p),
376 user, host, reason);
377
378 /* If at least 3 opers agree this user should be G lined then do it */
379 if (check_majority_gline(source_p, user, host, reason) ==
380 GLINE_ALREADY_VOTED)
381 {
382 sendto_realops_flags(UMODE_ALL, L_ALL, "oper or server has already voted");
383 return;
384 }
385
386 ilog(L_TRACE, "#gline for %s@%s [%s] requested by %s",
387 user, host, reason, get_oper_name(source_p));
388
389 set_local_gline(source_p, user, host, reason);
390 #else
391 set_local_gline(source_p, user, host, reason);
392 #endif /* GLINE_VOTING */
393
394 }
395 }
396
397 /* set_local_gline()
398 *
399 * inputs - pointer to client struct of oper
400 * - pointer to victim user
401 * - pointer to victim host
402 * - pointer reason
403 * output - NONE
404 * side effects -
405 */
406 static void
407 set_local_gline(const struct Client *source_p, const char *user,
408 const char *host, const char *reason)
409 {
410 char buffer[IRCD_BUFSIZE];
411 struct ConfItem *conf;
412 struct AccessItem *aconf;
413 const char *current_date;
414 time_t cur_time;
415
416 set_time();
417 cur_time = CurrentTime;
418
419 current_date = smalldate(cur_time);
420 conf = make_conf_item(GLINE_TYPE);
421 aconf = (struct AccessItem *)map_to_conf(conf);
422
423 ircsprintf(buffer, "%s (%s)", reason, current_date);
424 DupString(aconf->reason, buffer);
425 DupString(aconf->user, user);
426 DupString(aconf->host, host);
427
428 aconf->hold = CurrentTime + ConfigFileEntry.gline_time;
429 add_temp_line(conf);
430
431 sendto_realops_flags(UMODE_ALL, L_ALL,
432 "%s added G-Line for [%s@%s] [%s]",
433 get_oper_name(source_p),
434 aconf->user, aconf->host, aconf->reason);
435 ilog(L_TRACE, "%s added G-Line for [%s@%s] [%s]",
436 get_oper_name(source_p), aconf->user, aconf->host, aconf->reason);
437 log_oper_action(LOG_GLINE_TYPE, source_p, "[%s@%s] [%s]\n",
438 aconf->user, aconf->host, aconf->reason);
439 /* Now, activate gline against current online clients */
440 rehashed_klines = 1;
441 }
442
443 #ifdef GLINE_VOTING
444 /* add_new_majority_gline()
445 *
446 * inputs - operator requesting gline
447 * - username covered by the gline
448 * - hostname covered by the gline
449 * - reason for the gline
450 * output - NONE
451 * side effects -
452 * This function is called once a majority of opers
453 * have agreed on a gline, and it can be placed. The
454 * information about an operator being passed to us
455 * happens to be the operator who pushed us over the
456 * "majority" level needed. See check_majority_gline()
457 * for more information.
458 */
459 static void
460 add_new_majority_gline(const struct Client *source_p,
461 const char *user, const char *host, const char *reason)
462 {
463 struct gline_pending *pending = MyMalloc(sizeof(struct gline_pending));
464
465 strlcpy(pending->oper_nick1, source_p->name, sizeof(pending->oper_nick1));
466 strlcpy(pending->oper_user1, source_p->username, sizeof(pending->oper_user1));
467 strlcpy(pending->oper_host1, source_p->host, sizeof(pending->oper_host1));
468
469 strlcpy(pending->oper_server1, source_p->servptr->name, sizeof(pending->oper_server1));
470
471 strlcpy(pending->user, user, sizeof(pending->user));
472 strlcpy(pending->host, host, sizeof(pending->host));
473 strlcpy(pending->reason1, reason, sizeof(pending->reason1));
474
475 pending->last_gline_time = CurrentTime;
476 pending->time_request1 = CurrentTime;
477
478 dlinkAdd(pending, &pending->node, &pending_glines);
479 }
480
481 /* check_majority_gline()
482 *
483 * inputs - source, user, host, reason
484 *
485 * output - one of three results
486 *
487 * GLINE_ALREADY_VOTED - returned if oper/server has already voted
488 * GLINE_PLACED - returned if this triggers a gline
489 * GLINE_NOT_PLACED - returned if not triggered
490 *
491 * Side effects -
492 * See if there is a majority agreement on a GLINE on the given user
493 * There must be at least 3 different opers agreeing on this GLINE
494 *
495 */
496 static int
497 check_majority_gline(const struct Client *source_p,
498 const char *user, const char *host, const char *reason)
499 {
500 dlink_node *pending_node;
501 struct gline_pending *gline_pending_ptr;
502
503 /* if its already glined, why bother? :) -- fl_ */
504 if (find_is_glined(host, user))
505 return(GLINE_NOT_PLACED);
506
507 /* special case condition where there are no pending glines */
508 if (dlink_list_length(&pending_glines) == 0) /* first gline request placed */
509 {
510 add_new_majority_gline(source_p, user, host, reason);
511 return(GLINE_NOT_PLACED);
512 }
513
514 DLINK_FOREACH(pending_node, pending_glines.head)
515 {
516 gline_pending_ptr = pending_node->data;
517
518 if ((irccmp(gline_pending_ptr->user, user) == 0) &&
519 (irccmp(gline_pending_ptr->host, host) == 0))
520 {
521 if (((irccmp(gline_pending_ptr->oper_user1, source_p->username) == 0) ||
522 (irccmp(gline_pending_ptr->oper_host1, source_p->host) == 0)) ||
523 (irccmp(gline_pending_ptr->oper_server1, source_p->servptr->name) == 0))
524 {
525 return(GLINE_ALREADY_VOTED);
526 }
527
528 if (gline_pending_ptr->oper_user2[0] != '\0')
529 {
530 /* if two other opers on two different servers have voted yes */
531
532 if(((irccmp(gline_pending_ptr->oper_user2, source_p->username)==0) ||
533 (irccmp(gline_pending_ptr->oper_host2, source_p->host)==0)) ||
534 (irccmp(gline_pending_ptr->oper_server2, source_p->servptr->name)==0))
535 {
536 return(GLINE_ALREADY_VOTED);
537 }
538
539 /* trigger the gline using the original reason --fl */
540 set_local_gline(source_p, user, host, gline_pending_ptr->reason1);
541 cleanup_glines(NULL);
542 return(GLINE_PLACED);
543 }
544 else
545 {
546 strlcpy(gline_pending_ptr->oper_nick2, source_p->name,
547 sizeof(gline_pending_ptr->oper_nick2));
548 strlcpy(gline_pending_ptr->oper_user2, source_p->username,
549 sizeof(gline_pending_ptr->oper_user2));
550 strlcpy(gline_pending_ptr->oper_host2, source_p->host,
551 sizeof(gline_pending_ptr->oper_host2));
552 strlcpy(gline_pending_ptr->reason2, reason,
553 sizeof(gline_pending_ptr->reason2));
554 strlcpy(gline_pending_ptr->oper_server2, source_p->servptr->name,
555 sizeof(gline_pending_ptr->oper_server2));
556 gline_pending_ptr->last_gline_time = CurrentTime;
557 gline_pending_ptr->time_request2 = CurrentTime;
558 return(GLINE_NOT_PLACED);
559 }
560 }
561 }
562
563 /* Didn't find this user@host gline in pending gline list
564 * so add it.
565 */
566 add_new_majority_gline(source_p, user, host, reason);
567 return(GLINE_NOT_PLACED);
568 }
569 #endif /* GLINE_VOTING */
570
571 static int
572 remove_gline_match(const char *user, const char *host)
573 {
574 struct AccessItem *aconf;
575 dlink_node *ptr = NULL;
576 struct irc_ssaddr addr, caddr;
577 int nm_t, cnm_t, bits, cbits;
578
579 nm_t = parse_netmask(host, &addr, &bits);
580
581 DLINK_FOREACH(ptr, temporary_glines.head)
582 {
583 aconf = map_to_conf(ptr->data);
584 cnm_t = parse_netmask(aconf->host, &caddr, &cbits);
585
586 if (cnm_t != nm_t || irccmp(user, aconf->user))
587 continue;
588
589 if ((nm_t == HM_HOST && !irccmp(aconf->host, host)) ||
590 (nm_t == HM_IPV4 && bits == cbits && match_ipv4(&addr, &caddr, bits))
591 #ifdef IPV6
592 || (nm_t == HM_IPV6 && bits == cbits && match_ipv6(&addr, &caddr, bits))
593 #endif
594 )
595 {
596 dlinkDelete(ptr, &temporary_glines);
597 delete_one_address_conf(aconf->host, aconf);
598 return(1);
599 }
600 }
601
602 return(0);
603 }
604
605 /*
606 ** m_ungline
607 ** added May 29th 2000 by Toby Verrall <toot@melnet.co.uk>
608 ** added to hybrid-7 7/11/2000 --is
609 **
610 ** parv[0] = sender nick
611 ** parv[1] = gline to remove
612 */
613 static void
614 mo_ungline(struct Client *client_p, struct Client *source_p,
615 int parc, char *parv[])
616 {
617 char *user, *host;
618
619 if (!ConfigFileEntry.glines)
620 {
621 sendto_one(source_p, ":%s NOTICE %s :UNGLINE disabled",
622 me.name, source_p->name);
623 return;
624 }
625
626 if (!IsOperUnkline(source_p) || !IsOperGline(source_p))
627 {
628 sendto_one(source_p, form_str(ERR_NOPRIVS),
629 me.name, source_p->name, "gline");
630 return;
631 }
632
633 if (parse_aline("UNGLINE", source_p, parc, parv,
634 0, &user, &host, NULL, NULL, NULL) < 0)
635 return;
636
637 if (remove_gline_match(user, host))
638 {
639 sendto_one(source_p, ":%s NOTICE %s :G-Line for [%s@%s] is removed",
640 me.name, source_p->name, user, host);
641 sendto_realops_flags(UMODE_ALL, L_ALL,
642 "%s has removed the G-Line for: [%s@%s]",
643 get_oper_name(source_p), user, host);
644 ilog(L_NOTICE, "%s removed G-Line for [%s@%s]",
645 get_oper_name(source_p), user, host);
646 }
647 else
648 {
649 sendto_one(source_p, ":%s NOTICE %s :No G-Line for %s@%s",
650 me.name, source_p->name, user, host);
651 }
652 }

Properties

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