ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/m_gline.c
Revision: 3504
Committed: Sat May 10 19:51:29 2014 UTC (11 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 17612 byte(s)
Log Message:
- Renamed MyMalloc() to MyCalloc()

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2014 ircd-hybrid development team
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/GUNGLINE command.
24 * \version $Id$
25 */
26
27 #include "stdinc.h"
28 #include "list.h"
29 #include "gline.h"
30 #include "client.h"
31 #include "irc_string.h"
32 #include "ircd.h"
33 #include "conf.h"
34 #include "hostmask.h"
35 #include "numeric.h"
36 #include "misc.h"
37 #include "send.h"
38 #include "server.h"
39 #include "parse.h"
40 #include "modules.h"
41 #include "log.h"
42 #include "conf_db.h"
43 #include "memory.h"
44
45 #define GLINE_NOT_PLACED 0
46 #define GLINE_ALREADY_VOTED -1
47 #define GLINE_PLACED 1
48
49
50 static void
51 check_gline(struct AddressRec *arec)
52 {
53 dlink_node *ptr = NULL, *ptr_next = NULL;
54
55 DLINK_FOREACH_SAFE(ptr, ptr_next, local_client_list.head)
56 {
57 struct Client *client_p = ptr->data;
58
59 if (IsDead(client_p))
60 continue;
61
62 if (match(arec->username, client_p->username))
63 continue;
64
65 switch (arec->masktype)
66 {
67 case HM_IPV4:
68 if (client_p->localClient->aftype == AF_INET)
69 if (match_ipv4(&client_p->localClient->ip, &arec->Mask.ipa.addr, arec->Mask.ipa.bits))
70 conf_try_ban(client_p, arec->conf);
71 break;
72 case HM_IPV6:
73 if (client_p->localClient->aftype == AF_INET6)
74 if (match_ipv6(&client_p->localClient->ip, &arec->Mask.ipa.addr, arec->Mask.ipa.bits))
75 conf_try_ban(client_p, arec->conf);
76 break;
77 default: /* HM_HOST */
78 if (!match(arec->Mask.hostname, client_p->host))
79 conf_try_ban(client_p, arec->conf);
80 break;
81 }
82 }
83 }
84
85 /*! \brief Adds a GLINE to the configuration subsystem.
86 *
87 * \param source_p Operator requesting gline
88 * \param user Username covered by the gline
89 * \param host Hostname covered by the gline
90 * \param reason Reason for the gline
91 */
92 static void
93 set_local_gline(const struct Client *source_p, const char *user,
94 const char *host, const char *reason)
95 {
96 char buffer[IRCD_BUFSIZE];
97 struct MaskItem *conf = conf_make(CONF_GLINE);
98
99 snprintf(buffer, sizeof(buffer), "%s (%s)", reason, smalldate(0));
100 conf->reason = xstrdup(buffer);
101 conf->user = xstrdup(user);
102 conf->host = xstrdup(host);
103
104 conf->setat = CurrentTime;
105 conf->until = CurrentTime + ConfigFileEntry.gline_time;
106 SetConfDatabase(conf);
107
108 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
109 "%s added G-Line for [%s@%s] [%s]",
110 get_oper_name(source_p),
111 conf->user, conf->host, conf->reason);
112 ilog(LOG_TYPE_GLINE, "%s added G-Line for [%s@%s] [%s]",
113 get_oper_name(source_p), conf->user, conf->host, conf->reason);
114
115 check_gline(add_conf_by_address(CONF_GLINE, conf));
116 }
117
118 /*! \brief Removes a GLINE from the configuration subsystem.
119 *
120 * \param user Username covered by the gline
121 * \param host Hostname covered by the gline
122 */
123 static int
124 remove_gline_match(const char *user, const char *host)
125 {
126 struct irc_ssaddr iphost, *piphost;
127 struct MaskItem *conf;
128 int t = 0;
129 int aftype = 0;
130
131 if ((t = parse_netmask(host, &iphost, NULL)) != HM_HOST)
132 {
133 #ifdef IPV6
134 if (t == HM_IPV6)
135 aftype = AF_INET6;
136 else
137 #endif
138 aftype = AF_INET;
139 piphost = &iphost;
140 }
141 else
142 piphost = NULL;
143
144 if ((conf = find_conf_by_address(host, piphost, CONF_GLINE, aftype, user, NULL, 0)))
145 {
146 if (IsConfDatabase(conf))
147 {
148 delete_one_address_conf(host, conf);
149 return 1;
150 }
151 }
152
153 return 0;
154 }
155
156 /*! \brief This function is called once a majority of opers have agreed on a
157 * GLINE/GUNGLINE, and it can be placed. The information about an
158 * operator being passed to us happens to be the operator who pushed us
159 * over the "majority" level needed. See check_majority() for more
160 * information.
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 static void
170 add_new_majority(const struct Client *source_p, const char *user,
171 const char *host, const char *reason, const unsigned int type)
172 {
173 struct gline_pending *pending = MyCalloc(sizeof(struct gline_pending));
174
175 strlcpy(pending->vote_1.oper_nick, source_p->name, sizeof(pending->vote_1.oper_nick));
176 strlcpy(pending->vote_1.oper_user, source_p->username, sizeof(pending->vote_1.oper_user));
177 strlcpy(pending->vote_1.oper_host, source_p->host, sizeof(pending->vote_1.oper_host));
178 strlcpy(pending->vote_1.oper_server, source_p->servptr->name, sizeof(pending->vote_1.oper_server));
179
180 strlcpy(pending->user, user, sizeof(pending->user));
181 strlcpy(pending->host, host, sizeof(pending->host));
182 strlcpy(pending->vote_1.reason, reason, sizeof(pending->vote_1.reason));
183
184 pending->last_gline_time = CurrentTime;
185 pending->vote_1.time_request = CurrentTime;
186
187 dlinkAdd(pending, &pending->node, &pending_glines[type]);
188 }
189
190 /*! \brief See if there is a majority agreement on a GLINE on the given user.
191 * There must be at least 3 different opers agreeing on this
192 * GLINE/GUNGLINE
193 *
194 * \param source_p Operator requesting gline
195 * \param user Username covered by the gline
196 * \param host Hostname covered by the gline
197 * \param reason Reason for the gline
198 * \param type Valid values are either GLINE_PENDING_ADD_TYPE, or
199 * GLINE_PENDING_DEL_TYPE
200 *
201 * \return
202 * - GLINE_ALREADY_VOTED returned if oper/server has already voted
203 * - GLINE_PLACED returned if this triggers a gline
204 * - GLINE_NOT_PLACED returned if not triggered
205 */
206 static int
207 check_majority(const struct Client *source_p, const char *user,
208 const char *host, const char *reason, const int type)
209 {
210 dlink_node *dn_ptr = NULL;
211
212 cleanup_glines(NULL);
213
214 /* if its already glined, why bother? :) -- fl_ */
215 if ((type == GLINE_PENDING_ADD_TYPE) && find_is_glined(host, user))
216 return GLINE_NOT_PLACED;
217
218 DLINK_FOREACH(dn_ptr, pending_glines[type].head)
219 {
220 struct gline_pending *gp_ptr = dn_ptr->data;
221
222 if (irccmp(gp_ptr->user, user) ||
223 irccmp(gp_ptr->host, host))
224 continue;
225
226 if ((!irccmp(gp_ptr->vote_1.oper_user, source_p->username) &&
227 !irccmp(gp_ptr->vote_1.oper_host, source_p->host)) ||
228 !irccmp(gp_ptr->vote_1.oper_server, source_p->servptr->name))
229 return GLINE_ALREADY_VOTED;
230
231 if (gp_ptr->vote_2.oper_user[0] != '\0')
232 {
233 /* if two other opers on two different servers have voted yes */
234 if ((!irccmp(gp_ptr->vote_2.oper_user, source_p->username) &&
235 !irccmp(gp_ptr->vote_2.oper_host, source_p->host)) ||
236 !irccmp(gp_ptr->vote_2.oper_server, source_p->servptr->name))
237 return GLINE_ALREADY_VOTED;
238
239 if (type == GLINE_PENDING_DEL_TYPE)
240 {
241 if (remove_gline_match(user, host))
242 {
243 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
244 "%s has removed the G-Line for: [%s@%s]",
245 get_oper_name(source_p), user, host);
246 ilog(LOG_TYPE_GLINE, "%s removed G-Line for [%s@%s]",
247 get_oper_name(source_p), user, host);
248 }
249 }
250 else
251 /* trigger the gline using the original reason --fl */
252 set_local_gline(source_p, user, host, gp_ptr->vote_1.reason);
253
254 cleanup_glines(gp_ptr);
255 return GLINE_PLACED;
256 }
257
258 strlcpy(gp_ptr->vote_2.oper_nick, source_p->name,
259 sizeof(gp_ptr->vote_2.oper_nick));
260 strlcpy(gp_ptr->vote_2.oper_user, source_p->username,
261 sizeof(gp_ptr->vote_2.oper_user));
262 strlcpy(gp_ptr->vote_2.oper_host, source_p->host,
263 sizeof(gp_ptr->vote_2.oper_host));
264 strlcpy(gp_ptr->vote_2.reason, reason,
265 sizeof(gp_ptr->vote_2.reason));
266 strlcpy(gp_ptr->vote_2.oper_server, source_p->servptr->name,
267 sizeof(gp_ptr->vote_2.oper_server));
268 gp_ptr->last_gline_time = CurrentTime;
269 gp_ptr->vote_2.time_request = CurrentTime;
270 return GLINE_NOT_PLACED;
271 }
272
273 /*
274 * Didn't find this user@host gline in pending gline list
275 * so add it.
276 */
277 add_new_majority(source_p, user, host, reason, type);
278 return GLINE_NOT_PLACED;
279 }
280
281 /*! \brief GLINE command handler
282 *
283 * \param source_p Pointer to allocated Client struct from which the message
284 * originally comes from. This can be a local or remote client.
285 * \param parc Integer holding the number of supplied arguments.
286 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
287 * pointers.
288 * \note Valid arguments for this command are:
289 * - parv[0] = command
290 * - parv[1] = user mask
291 * - parv[2] = host mask
292 * - parv[3] = reason
293 */
294 static int
295 ms_gline(struct Client *source_p, int parc, char *parv[])
296 {
297 const char *reason = NULL; /* reason for "victims" demise */
298 const char *user = NULL;
299 const char *host = NULL; /* user and host of GLINE "victim" */
300 const char *p = NULL;
301
302 if (!IsClient(source_p))
303 return 0;
304
305 if (parc != 4 || EmptyString(parv[3]))
306 return 0;
307
308 assert(source_p->servptr != NULL);
309
310 user = parv[1];
311 host = parv[2];
312 reason = parv[3];
313
314 sendto_server(source_p, CAP_GLN, NOCAPS, ":%s GLINE %s %s :%s",
315 source_p->id, user, host, reason);
316
317 if (!ConfigFileEntry.glines)
318 return 0;
319
320 if (!valid_wild_card(source_p, 1, 2, user, host))
321 return 0;
322
323 if ((p = strchr(host, '/')))
324 {
325 int bitlen = strtol(++p, NULL, 10);
326 int min_bitlen = strchr(host, ':') ? ConfigFileEntry.gline_min_cidr6 :
327 ConfigFileEntry.gline_min_cidr;
328
329 if (bitlen < min_bitlen)
330 {
331 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
332 "%s is requesting a GLINE with a CIDR mask < %d for [%s@%s] [%s]",
333 get_oper_name(source_p), min_bitlen,
334 user, host, reason);
335 return 0;
336 }
337 }
338
339 /* If at least 3 opers agree this user should be G lined then do it */
340 if (check_majority(source_p, user, host, reason, GLINE_PENDING_ADD_TYPE) ==
341 GLINE_ALREADY_VOTED)
342 {
343 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
344 "oper or server has already voted");
345 return 0;
346 }
347
348 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
349 "%s requesting G-Line for [%s@%s] [%s]",
350 get_oper_name(source_p),
351 user, host, reason);
352 ilog(LOG_TYPE_GLINE, "G-Line for [%s@%s] [%s] requested by %s",
353 user, host, reason, get_oper_name(source_p));
354 return 0;
355 }
356
357 /*! \brief GLINE command handler
358 *
359 * \param source_p Pointer to allocated Client struct from which the message
360 * originally comes from. This can be a local or remote client.
361 * \param parc Integer holding the number of supplied arguments.
362 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
363 * pointers.
364 * \note Valid arguments for this command are:
365 * - parv[0] = command
366 * - parv[1] = user\@host mask
367 * - parv[2] = reason
368 */
369 static int
370 mo_gline(struct Client *source_p, int parc, char *parv[])
371 {
372 char *user = NULL;
373 char *host = NULL;
374 char *reason = NULL;
375 char *p;
376
377 if (!HasOFlag(source_p, OPER_FLAG_GLINE))
378 {
379 sendto_one_numeric(source_p, &me, ERR_NOPRIVS, "gline");
380 return 0;
381 }
382
383 if (!ConfigFileEntry.glines)
384 {
385 sendto_one_notice(source_p, &me, ":GLINE disabled");
386 return 0;
387 }
388
389 if (parse_aline("GLINE", source_p, parc, parv, AWILD,
390 &user, &host, NULL, NULL, &reason) < 0)
391 return 0;
392
393 if ((p = strchr(host, '/')) != NULL)
394 {
395 int bitlen = strtol(++p, NULL, 10);
396 int min_bitlen = strchr(host, ':') ? ConfigFileEntry.gline_min_cidr6 :
397 ConfigFileEntry.gline_min_cidr;
398 if (bitlen < min_bitlen)
399 {
400 sendto_one_notice(source_p, &me, ":Cannot set G-Lines with CIDR length < %d",
401 min_bitlen);
402 return 0;
403 }
404 }
405
406 /* If at least 3 opers agree this user should be G lined then do it */
407 if (check_majority(source_p, user, host, reason, GLINE_PENDING_ADD_TYPE) ==
408 GLINE_ALREADY_VOTED)
409 {
410 sendto_one_notice(source_p, &me, ":This server or oper has already voted");
411 return 0;
412 }
413
414 /*
415 * call these two functions first so the 'requesting' notice always comes
416 * before the 'has triggered' notice. -bill
417 */
418 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
419 "%s requesting G-Line for [%s@%s] [%s]",
420 get_oper_name(source_p),
421 user, host, reason);
422 ilog(LOG_TYPE_GLINE, "G-Line for [%s@%s] [%s] requested by %s",
423 user, host, reason, get_oper_name(source_p));
424
425 sendto_server(NULL, CAP_GLN, NOCAPS, ":%s GLINE %s %s :%s",
426 source_p->id, user, host, reason);
427 return 0;
428 }
429
430 static void
431 do_sungline(struct Client *source_p, const char *user,
432 const char *host, const char *reason, int prop)
433 {
434 assert(source_p->servptr != NULL);
435
436 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
437 "%s requesting UNG-Line for [%s@%s] [%s]",
438 get_oper_name(source_p), user, host, reason);
439 ilog(LOG_TYPE_GLINE, "UNG-Line for [%s@%s] [%s] requested by %s",
440 user, host, reason, get_oper_name(source_p));
441
442 /* If at least 3 opers agree this user should be un G lined then do it */
443 if (check_majority(source_p, user, host, reason, GLINE_PENDING_DEL_TYPE) ==
444 GLINE_ALREADY_VOTED)
445 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
446 "oper or server has already voted");
447
448 if (prop)
449 {
450 sendto_server(source_p, CAP_ENCAP, NOCAPS,
451 ":%s ENCAP * GUNGLINE %s %s :%s",
452 source_p->id, user, host, reason);
453 }
454 }
455
456 /*! \brief GUNGLINE command handler
457 *
458 * \param source_p Pointer to allocated Client struct from which the message
459 * originally comes from. This can be a local or remote client.
460 * \param parc Integer holding the number of supplied arguments.
461 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
462 * pointers.
463 * \note Valid arguments for this command are:
464 * - parv[0] = command
465 * - parv[1] = user mask
466 * - parv[2] = host mask
467 * - parv[3] = reason
468 */
469 static int
470 me_gungline(struct Client *source_p, int parc, char *parv[])
471 {
472 if (ConfigFileEntry.glines)
473 do_sungline(source_p, parv[1], parv[2], parv[3], 0);
474 return 0;
475 }
476
477 /*! \brief GUNGLINE command handler
478 *
479 * \param source_p Pointer to allocated Client struct from which the message
480 * originally comes from. This can be a local or remote client.
481 * \param parc Integer holding the number of supplied arguments.
482 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
483 * pointers.
484 * \note Valid arguments for this command are:
485 * - parv[0] = command
486 * - parv[1] = user\@host mask
487 * - parv[2] = reason
488 */
489 static int
490 mo_gungline(struct Client *source_p, int parc, char *parv[])
491 {
492 char *user = NULL;
493 char *host = NULL;
494 char *reason = NULL;
495
496 if (!HasOFlag(source_p, OPER_FLAG_GLINE))
497 {
498 sendto_one_numeric(source_p, &me, ERR_NOPRIVS, "gline");
499 return 0;
500 }
501
502 if (!ConfigFileEntry.glines)
503 {
504 sendto_one_notice(source_p, &me, ":GUNGLINE disabled");
505 return 0;
506 }
507
508 if (parse_aline("GUNGLINE", source_p, parc, parv, 0, &user,
509 &host, NULL, NULL, &reason) < 0)
510 return 0;
511
512 do_sungline(source_p, user, host, reason, 1);
513 return 0;
514 }
515
516 /*
517 * gline enforces 3 parameters to force operator to give a reason
518 * a gline is not valid with "No reason"
519 * -db
520 */
521 static struct Message gline_msgtab =
522 {
523 "GLINE", 0, 0, 3, MAXPARA, MFLG_SLOW, 0,
524 { m_unregistered, m_not_oper, ms_gline, m_ignore, mo_gline, m_ignore }
525 };
526
527 static struct Message ungline_msgtab =
528 {
529 "GUNGLINE", 0, 0, 3, MAXPARA, MFLG_SLOW, 0,
530 { m_unregistered, m_not_oper, m_ignore, me_gungline, mo_gungline, m_ignore }
531 };
532
533 static void
534 module_init(void)
535 {
536 mod_add_cmd(&gline_msgtab);
537 mod_add_cmd(&ungline_msgtab);
538 add_capability("GLN", CAP_GLN, 1);
539 }
540
541 static void
542 module_exit(void)
543 {
544 mod_del_cmd(&gline_msgtab);
545 mod_del_cmd(&ungline_msgtab);
546 delete_capability("GLN");
547 }
548
549 struct module module_entry =
550 {
551 .node = { NULL, NULL, NULL },
552 .name = NULL,
553 .version = "$Revision$",
554 .handle = NULL,
555 .modinit = module_init,
556 .modexit = module_exit,
557 .flags = 0
558 };

Properties

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