ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/modules/m_gline.c
Revision: 190
Committed: Sun Oct 23 22:06:17 2005 UTC (18 years, 5 months ago) by adx
Content type: text/x-csrc
File size: 19437 byte(s)
Log Message:
* prototypes are now prefixed with either nothing or EXTERN
  (meaning it's an ircd.dll API)
* dynamic modules now work on win32.

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

Properties

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