ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.0.x/modules/m_gline.c
Revision: 1871
Committed: Fri Apr 26 08:53:04 2013 UTC (13 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 18349 byte(s)
Log Message:
- Reverted to -r1820; libGeoIP support is sheduled for  8.1

File Contents

# Content
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
47 #define GLINE_NOT_PLACED 0
48 #define GLINE_ALREADY_VOTED -1
49 #define GLINE_PLACED 1
50
51
52 /*! \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
67
68 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 SetConfTemporary(aconf);
78 add_conf_by_address(CONF_GLINE, aconf);
79
80 sendto_realops_flags(UMODE_ALL, L_ALL,
81 "%s added G-Line for [%s@%s] [%s]",
82 get_oper_name(source_p),
83 aconf->user, aconf->host, aconf->reason);
84 ilog(LOG_TYPE_GLINE, "%s added G-Line for [%s@%s] [%s]",
85 get_oper_name(source_p), aconf->user, aconf->host, aconf->reason);
86
87 /* 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 struct irc_ssaddr iphost, *piphost;
100 struct AccessItem *aconf;
101 int t;
102
103 if ((t = parse_netmask(host, &iphost, NULL)) != HM_HOST)
104 {
105 #ifdef IPV6
106 if (t == HM_IPV6)
107 t = AF_INET6;
108 else
109 #endif
110 t = AF_INET;
111 piphost = &iphost;
112 }
113 else
114 {
115 t = 0;
116 piphost = NULL;
117 }
118
119 if ((aconf = find_conf_by_address(host, piphost, CONF_GLINE, t, user, NULL, 0)))
120 {
121 if (IsConfTemporary(aconf))
122 {
123 delete_one_address_conf(host, aconf);
124 return 1;
125 }
126 }
127
128 return 0;
129 }
130
131 /*! \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 *
137 * \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 */
144 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 *
169 * \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 */
181 static int
182 check_majority(const struct Client *source_p, const char *user,
183 const char *host, const char *reason, const int type)
184 {
185 dlink_node *dn_ptr = NULL;
186
187 cleanup_glines(NULL);
188
189 /* 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 {
195 struct gline_pending *gp_ptr = dn_ptr->data;
196
197 if (irccmp(gp_ptr->user, user) ||
198 irccmp(gp_ptr->host, host))
199 continue;
200
201 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 {
208 /* 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 sendto_realops_flags(UMODE_ALL, L_ALL,
219 "%s has removed the G-Line for: [%s@%s]",
220 get_oper_name(source_p), user, host);
221 ilog(LOG_TYPE_GLINE, "%s removed G-Line for [%s@%s]",
222 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 }
232
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 }
247
248 /*
249 * Didn't find this user@host gline in pending gline list
250 * so add it.
251 */
252 add_new_majority(source_p, user, host, reason, type);
253 return GLINE_NOT_PLACED;
254 }
255
256 static void
257 do_sgline(struct Client *source_p, int parc, char *parv[], int prop)
258 {
259 const char *reason = NULL; /* reason for "victims" demise */
260 const char *user = NULL;
261 const char *host = NULL; /* user and host of GLINE "victim" */
262
263 if (!IsClient(source_p))
264 return;
265
266 if (parc != 4 || EmptyString(parv[3]))
267 return;
268
269 assert(source_p->servptr != NULL);
270
271 user = parv[1];
272 host = parv[2];
273 reason = parv[3];
274
275 sendto_server(source_p->from, CAP_GLN|CAP_TS6, NOCAPS,
276 ":%s GLINE %s %s :%s",
277 ID(source_p), user, host, reason);
278 sendto_server(source_p->from, CAP_GLN, CAP_TS6,
279 ":%s GLINE %s %s :%s",
280 source_p->name, user, host, reason);
281
282 if (ConfigFileEntry.glines)
283 {
284 if (!valid_wild_card(source_p, 1, 2, user, host))
285 return;
286
287 if (IsClient(source_p))
288 {
289 const char *p = NULL;
290
291 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 sendto_realops_flags(UMODE_ALL, L_ALL, "%s!%s@%s on %s is requesting "
300 "a GLINE with a CIDR mask < %d for [%s@%s] [%s]",
301 source_p->name, source_p->username, source_p->host,
302 source_p->servptr->name, min_bitlen, user, host, reason);
303 return;
304 }
305 }
306 }
307
308 /* If at least 3 opers agree this user should be G lined then do it */
309 if (check_majority(source_p, user, host, reason, GLINE_PENDING_ADD_TYPE) ==
310 GLINE_ALREADY_VOTED)
311 {
312 sendto_realops_flags(UMODE_ALL, L_ALL, "oper or server has already voted");
313 return;
314 }
315
316 sendto_realops_flags(UMODE_ALL, L_ALL,
317 "%s requesting G-Line for [%s@%s] [%s]",
318 get_oper_name(source_p),
319 user, host, reason);
320 ilog(LOG_TYPE_GLINE, "#gline for %s@%s [%s] requested by %s",
321 user, host, reason, get_oper_name(source_p));
322 }
323 }
324
325
326 /*! \brief GLINE command handler (called by operators)
327 *
328 * \param client_p Pointer to allocated Client struct with physical connection
329 * to this server, i.e. with an open socket connected.
330 * \param source_p Pointer to allocated Client struct from which the message
331 * originally comes from. This can be a local or remote client.
332 * \param parc Integer holding the number of supplied arguments.
333 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
334 * pointers.
335 * \note Valid arguments for this command are:
336 * - parv[0] = sender prefix
337 * - parv[1] = user\@host mask
338 * - parv[2] = reason
339 */
340 static void
341 mo_gline(struct Client *client_p, struct Client *source_p,
342 int parc, char *parv[])
343 {
344 char *user = NULL;
345 char *host = NULL;
346 char *reason = NULL;
347 char *p;
348
349 if (!HasOFlag(source_p, OPER_FLAG_GLINE))
350 {
351 sendto_one(source_p, form_str(ERR_NOPRIVS),
352 me.name, source_p->name, "gline");
353 return;
354 }
355
356 if (!ConfigFileEntry.glines)
357 {
358 sendto_one(source_p, ":%s NOTICE %s :GLINE disabled",
359 me.name, source_p->name);
360 return;
361 }
362
363 if (parse_aline("GLINE", source_p, parc, parv, AWILD,
364 &user, &host, NULL, NULL, &reason) < 0)
365 return;
366
367 if ((p = strchr(host, '/')) != NULL)
368 {
369 int bitlen = strtol(++p, NULL, 10);
370 int min_bitlen = strchr(host, ':') ? ConfigFileEntry.gline_min_cidr6 :
371 ConfigFileEntry.gline_min_cidr;
372 if (bitlen < min_bitlen)
373 {
374 sendto_one(source_p, ":%s NOTICE %s :Cannot set G-Lines with CIDR length < %d",
375 me.name, source_p->name, min_bitlen);
376 return;
377 }
378 }
379
380 /* If at least 3 opers agree this user should be G lined then do it */
381 if (check_majority(source_p, user, host, reason, GLINE_PENDING_ADD_TYPE) ==
382 GLINE_ALREADY_VOTED)
383 {
384 sendto_one(source_p,
385 ":%s NOTICE %s :This server or oper has already voted",
386 me.name, source_p->name);
387 return;
388 }
389
390 /*
391 * call these two functions first so the 'requesting' notice always comes
392 * before the 'has triggered' notice. -bill
393 */
394 sendto_realops_flags(UMODE_ALL, L_ALL,
395 "%s requesting G-Line for [%s@%s] [%s]",
396 get_oper_name(source_p),
397 user, host, reason);
398 ilog(LOG_TYPE_GLINE, "#gline for %s@%s [%s] requested by %s!%s@%s",
399 user, host, reason, source_p->name, source_p->username,
400 source_p->host);
401
402 /* 4 param version for hyb-7 servers */
403 sendto_server(NULL, CAP_GLN|CAP_TS6, NOCAPS,
404 ":%s GLINE %s %s :%s",
405 ID(source_p), user, host, reason);
406 sendto_server(NULL, CAP_GLN, CAP_TS6,
407 ":%s GLINE %s %s :%s",
408 source_p->name, user, host, reason);
409 }
410
411 /* ms_gline()
412 * me_gline()
413 * do_sgline()
414 *
415 * inputs - The usual for a m_ function
416 * output -
417 * side effects -
418 *
419 * Place a G line if 3 opers agree on the identical user@host
420 *
421 * Allow this server to pass along GLINE if received and
422 * GLINES is not defined.
423 *
424 * ENCAP'd GLINES are propagated by encap code.
425 */
426
427 static void
428 ms_gline(struct Client *client_p, struct Client *source_p,
429 int parc, char *parv[])
430 {
431 do_sgline(source_p, parc, parv, 1);
432 }
433
434 static void
435 me_gline(struct Client *client_p, struct Client *source_p,
436 int parc, char *parv[])
437 {
438 do_sgline(source_p, parc, parv, 0);
439 }
440
441 static void
442 do_sungline(struct Client *source_p, const char *user,
443 const char *host, const char *reason, int prop)
444 {
445 assert(source_p->servptr != NULL);
446
447 sendto_realops_flags(UMODE_ALL, L_ALL,
448 "%s requesting UNG-Line for [%s@%s] [%s]",
449 get_oper_name(source_p), user, host, reason);
450 ilog(LOG_TYPE_GLINE, "#ungline for %s@%s [%s] requested by %s",
451 user, host, reason, get_oper_name(source_p));
452
453 /* If at least 3 opers agree this user should be un G lined then do it */
454 if (check_majority(source_p, user, host, reason, GLINE_PENDING_DEL_TYPE) ==
455 GLINE_ALREADY_VOTED)
456 sendto_realops_flags(UMODE_ALL, L_ALL, "oper or server has already voted");
457
458 if (prop)
459 {
460 sendto_server(source_p->from, CAP_ENCAP|CAP_TS6, NOCAPS,
461 ":%s ENCAP * GUNGLINE %s %s :%s",
462 ID(source_p), user, host, reason);
463 sendto_server(source_p->from, CAP_ENCAP, CAP_TS6,
464 ":%s ENCAP * GUNGLINE %s %s :%s",
465 source_p->name, user, host, reason);
466 }
467 }
468
469 /*! \brief GUNGLINE command handler (called in response to an encapsulated
470 * GUNGLINE command)
471 *
472 * \param client_p Pointer to allocated Client struct with physical connection
473 * to this server, i.e. with an open socket connected.
474 * \param source_p Pointer to allocated Client struct from which the message
475 * originally comes from. This can be a local or remote client.
476 * \param parc Integer holding the number of supplied arguments.
477 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
478 * pointers.
479 * \note Valid arguments for this command are:
480 * - parv[0] = sender prefix
481 * - parv[1] = username
482 * - parv[2] = hostname
483 * - parv[3] = reason
484 */
485 static void
486 me_gungline(struct Client *client_p, struct Client *source_p,
487 int parc, char *parv[])
488 {
489 if (ConfigFileEntry.glines)
490 do_sungline(source_p, parv[1], parv[2], parv[3], 0);
491 }
492
493 /*! \brief GUNGLINE command handler (called by operators)
494 *
495 * \param client_p Pointer to allocated Client struct with physical connection
496 * to this server, i.e. with an open socket connected.
497 * \param source_p Pointer to allocated Client struct from which the message
498 * originally comes from. This can be a local or remote client.
499 * \param parc Integer holding the number of supplied arguments.
500 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
501 * pointers.
502 * \note Valid arguments for this command are:
503 * - parv[0] = sender prefix
504 * - parv[1] = user\@host mask
505 * - parv[2] = reason
506 */
507 static void
508 mo_gungline(struct Client *client_p, struct Client *source_p,
509 int parc, char *parv[])
510 {
511 char *user = NULL;
512 char *host = NULL;
513 char *reason = NULL;
514
515 if (!HasOFlag(source_p, OPER_FLAG_GLINE))
516 {
517 sendto_one(source_p, form_str(ERR_NOPRIVS),
518 me.name, source_p->name, "gline");
519 return;
520 }
521
522 if (!ConfigFileEntry.glines)
523 {
524 sendto_one(source_p, ":%s NOTICE %s :GUNGLINE disabled",
525 me.name, source_p->name);
526 return;
527 }
528
529 if (parse_aline("GUNGLINE", source_p, parc, parv, 0, &user,
530 &host, NULL, NULL, &reason) < 0)
531 return;
532
533 do_sungline(source_p, user, host, reason, 1);
534 }
535
536 /*
537 * gline enforces 3 parameters to force operator to give a reason
538 * a gline is not valid with "No reason"
539 * -db
540 */
541 static struct Message gline_msgtab = {
542 "GLINE", 0, 0, 3, MAXPARA, MFLG_SLOW, 0,
543 { m_unregistered, m_not_oper, ms_gline, me_gline, mo_gline, m_ignore }
544 };
545
546 static struct Message ungline_msgtab = {
547 "GUNGLINE", 0, 0, 3, MAXPARA, MFLG_SLOW, 0,
548 { m_unregistered, m_not_oper, m_ignore, me_gungline, mo_gungline, m_ignore }
549 };
550
551 static void
552 module_init(void)
553 {
554 mod_add_cmd(&gline_msgtab);
555 mod_add_cmd(&ungline_msgtab);
556 add_capability("GLN", CAP_GLN, 1);
557 }
558
559 static void
560 module_exit(void)
561 {
562 mod_del_cmd(&gline_msgtab);
563 mod_del_cmd(&ungline_msgtab);
564 delete_capability("GLN");
565 }
566
567 struct module module_entry = {
568 .node = { NULL, NULL, NULL },
569 .name = NULL,
570 .version = "$Revision$",
571 .handle = NULL,
572 .modinit = module_init,
573 .modexit = module_exit,
574 .flags = 0
575 };

Properties

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