ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/m_gline.c
Revision: 4545
Committed: Fri Aug 22 08:46:13 2014 UTC (11 years ago) by michael
Content type: text/x-csrc
File size: 17492 byte(s)
Log Message:
- Implemented pseudo {} blocks (service aliases)
- Fixed compile warnings with -Wmissing-field-initializers

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 + ConfigGeneral.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 if (t == HM_IPV6)
134 aftype = AF_INET6;
135 else
136 aftype = AF_INET;
137 piphost = &iphost;
138 }
139 else
140 piphost = NULL;
141
142 if ((conf = find_conf_by_address(host, piphost, CONF_GLINE, aftype, user, NULL, 0)))
143 {
144 if (IsConfDatabase(conf))
145 {
146 delete_one_address_conf(host, conf);
147 return 1;
148 }
149 }
150
151 return 0;
152 }
153
154 /*! \brief This function is called once a majority of opers have agreed on a
155 * GLINE/GUNGLINE, and it can be placed. The information about an
156 * operator being passed to us happens to be the operator who pushed us
157 * over the "majority" level needed. See check_majority() for more
158 * information.
159 *
160 * \param source_p Operator requesting gline
161 * \param user Username covered by the gline
162 * \param host Hostname covered by the gline
163 * \param reason Reason for the gline
164 * \param type Valid values are either GLINE_PENDING_ADD_TYPE, or
165 * GLINE_PENDING_DEL_TYPE
166 */
167 static void
168 add_new_majority(const struct Client *source_p, const char *user,
169 const char *host, const char *reason, const unsigned int type)
170 {
171 struct gline_pending *pending = MyCalloc(sizeof(struct gline_pending));
172
173 strlcpy(pending->vote_1.oper_nick, source_p->name, sizeof(pending->vote_1.oper_nick));
174 strlcpy(pending->vote_1.oper_user, source_p->username, sizeof(pending->vote_1.oper_user));
175 strlcpy(pending->vote_1.oper_host, source_p->host, sizeof(pending->vote_1.oper_host));
176 strlcpy(pending->vote_1.oper_server, source_p->servptr->name, sizeof(pending->vote_1.oper_server));
177
178 strlcpy(pending->user, user, sizeof(pending->user));
179 strlcpy(pending->host, host, sizeof(pending->host));
180 strlcpy(pending->vote_1.reason, reason, sizeof(pending->vote_1.reason));
181
182 pending->last_gline_time = CurrentTime;
183 pending->vote_1.time_request = CurrentTime;
184
185 dlinkAdd(pending, &pending->node, &pending_glines[type]);
186 }
187
188 /*! \brief See if there is a majority agreement on a GLINE on the given user.
189 * There must be at least 3 different opers agreeing on this
190 * GLINE/GUNGLINE
191 *
192 * \param source_p Operator requesting gline
193 * \param user Username covered by the gline
194 * \param host Hostname covered by the gline
195 * \param reason Reason for the gline
196 * \param type Valid values are either GLINE_PENDING_ADD_TYPE, or
197 * GLINE_PENDING_DEL_TYPE
198 *
199 * \return
200 * - GLINE_ALREADY_VOTED returned if oper/server has already voted
201 * - GLINE_PLACED returned if this triggers a gline
202 * - GLINE_NOT_PLACED returned if not triggered
203 */
204 static int
205 check_majority(const struct Client *source_p, const char *user,
206 const char *host, const char *reason, const int type)
207 {
208 dlink_node *dn_ptr = NULL;
209
210 cleanup_glines(NULL);
211
212 /* if its already glined, why bother? :) -- fl_ */
213 if ((type == GLINE_PENDING_ADD_TYPE) && find_is_glined(host, user))
214 return GLINE_NOT_PLACED;
215
216 DLINK_FOREACH(dn_ptr, pending_glines[type].head)
217 {
218 struct gline_pending *gp_ptr = dn_ptr->data;
219
220 if (irccmp(gp_ptr->user, user) ||
221 irccmp(gp_ptr->host, host))
222 continue;
223
224 if ((!irccmp(gp_ptr->vote_1.oper_user, source_p->username) &&
225 !irccmp(gp_ptr->vote_1.oper_host, source_p->host)) ||
226 !irccmp(gp_ptr->vote_1.oper_server, source_p->servptr->name))
227 return GLINE_ALREADY_VOTED;
228
229 if (gp_ptr->vote_2.oper_user[0])
230 {
231 /* if two other opers on two different servers have voted yes */
232 if ((!irccmp(gp_ptr->vote_2.oper_user, source_p->username) &&
233 !irccmp(gp_ptr->vote_2.oper_host, source_p->host)) ||
234 !irccmp(gp_ptr->vote_2.oper_server, source_p->servptr->name))
235 return GLINE_ALREADY_VOTED;
236
237 if (type == GLINE_PENDING_DEL_TYPE)
238 {
239 if (remove_gline_match(user, host))
240 {
241 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
242 "%s has removed the G-Line for: [%s@%s]",
243 get_oper_name(source_p), user, host);
244 ilog(LOG_TYPE_GLINE, "%s removed G-Line for [%s@%s]",
245 get_oper_name(source_p), user, host);
246 }
247 }
248 else
249 /* trigger the gline using the original reason --fl */
250 set_local_gline(source_p, user, host, gp_ptr->vote_1.reason);
251
252 cleanup_glines(gp_ptr);
253 return GLINE_PLACED;
254 }
255
256 strlcpy(gp_ptr->vote_2.oper_nick, source_p->name,
257 sizeof(gp_ptr->vote_2.oper_nick));
258 strlcpy(gp_ptr->vote_2.oper_user, source_p->username,
259 sizeof(gp_ptr->vote_2.oper_user));
260 strlcpy(gp_ptr->vote_2.oper_host, source_p->host,
261 sizeof(gp_ptr->vote_2.oper_host));
262 strlcpy(gp_ptr->vote_2.reason, reason,
263 sizeof(gp_ptr->vote_2.reason));
264 strlcpy(gp_ptr->vote_2.oper_server, source_p->servptr->name,
265 sizeof(gp_ptr->vote_2.oper_server));
266 gp_ptr->last_gline_time = CurrentTime;
267 gp_ptr->vote_2.time_request = CurrentTime;
268 return GLINE_NOT_PLACED;
269 }
270
271 /*
272 * Didn't find this user@host gline in pending gline list
273 * so add it.
274 */
275 add_new_majority(source_p, user, host, reason, type);
276 return GLINE_NOT_PLACED;
277 }
278
279 /*! \brief GLINE command handler
280 *
281 * \param source_p Pointer to allocated Client struct from which the message
282 * originally comes from. This can be a local or remote client.
283 * \param parc Integer holding the number of supplied arguments.
284 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
285 * pointers.
286 * \note Valid arguments for this command are:
287 * - parv[0] = command
288 * - parv[1] = user mask
289 * - parv[2] = host mask
290 * - parv[3] = reason
291 */
292 static int
293 ms_gline(struct Client *source_p, int parc, char *parv[])
294 {
295 const char *reason = NULL; /* reason for "victims" demise */
296 const char *user = NULL;
297 const char *host = NULL; /* user and host of GLINE "victim" */
298 const char *p = NULL;
299
300 if (!IsClient(source_p))
301 return 0;
302
303 if (parc != 4 || EmptyString(parv[3]))
304 return 0;
305
306 user = parv[1];
307 host = parv[2];
308 reason = parv[3];
309
310 sendto_server(source_p, CAP_GLN, NOCAPS, ":%s GLINE %s %s :%s",
311 source_p->id, user, host, reason);
312
313 if (!ConfigGeneral.glines)
314 return 0;
315
316 if (!valid_wild_card(source_p, 1, 2, user, host))
317 return 0;
318
319 if ((p = strchr(host, '/')))
320 {
321 int bitlen = strtol(++p, NULL, 10);
322 int min_bitlen = strchr(host, ':') ? ConfigGeneral.gline_min_cidr6 :
323 ConfigGeneral.gline_min_cidr;
324
325 if (bitlen < min_bitlen)
326 {
327 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
328 "%s is requesting a GLINE with a CIDR mask < %d for [%s@%s] [%s]",
329 get_oper_name(source_p), min_bitlen,
330 user, host, reason);
331 return 0;
332 }
333 }
334
335 /* If at least 3 opers agree this user should be G lined then do it */
336 if (check_majority(source_p, user, host, reason, GLINE_PENDING_ADD_TYPE) ==
337 GLINE_ALREADY_VOTED)
338 {
339 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
340 "oper or server has already voted");
341 return 0;
342 }
343
344 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
345 "%s requesting G-Line for [%s@%s] [%s]",
346 get_oper_name(source_p),
347 user, host, reason);
348 ilog(LOG_TYPE_GLINE, "G-Line for [%s@%s] [%s] requested by %s",
349 user, host, reason, get_oper_name(source_p));
350 return 0;
351 }
352
353 /*! \brief GLINE command handler
354 *
355 * \param source_p Pointer to allocated Client struct from which the message
356 * originally comes from. This can be a local or remote client.
357 * \param parc Integer holding the number of supplied arguments.
358 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
359 * pointers.
360 * \note Valid arguments for this command are:
361 * - parv[0] = command
362 * - parv[1] = user\@host mask
363 * - parv[2] = reason
364 */
365 static int
366 mo_gline(struct Client *source_p, int parc, char *parv[])
367 {
368 char *user = NULL;
369 char *host = NULL;
370 char *reason = NULL;
371 char *p;
372
373 if (!HasOFlag(source_p, OPER_FLAG_GLINE))
374 {
375 sendto_one_numeric(source_p, &me, ERR_NOPRIVS, "gline");
376 return 0;
377 }
378
379 if (!ConfigGeneral.glines)
380 {
381 sendto_one_notice(source_p, &me, ":GLINE disabled");
382 return 0;
383 }
384
385 if (parse_aline("GLINE", source_p, parc, parv, AWILD,
386 &user, &host, NULL, NULL, &reason) < 0)
387 return 0;
388
389 if ((p = strchr(host, '/')))
390 {
391 int bitlen = strtol(++p, NULL, 10);
392 int min_bitlen = strchr(host, ':') ? ConfigGeneral.gline_min_cidr6 :
393 ConfigGeneral.gline_min_cidr;
394 if (bitlen < min_bitlen)
395 {
396 sendto_one_notice(source_p, &me, ":Cannot set G-Lines with CIDR length < %d",
397 min_bitlen);
398 return 0;
399 }
400 }
401
402 /* If at least 3 opers agree this user should be G lined then do it */
403 if (check_majority(source_p, user, host, reason, GLINE_PENDING_ADD_TYPE) ==
404 GLINE_ALREADY_VOTED)
405 {
406 sendto_one_notice(source_p, &me, ":This server or oper has already voted");
407 return 0;
408 }
409
410 /*
411 * call these two functions first so the 'requesting' notice always comes
412 * before the 'has triggered' notice. -bill
413 */
414 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
415 "%s requesting G-Line for [%s@%s] [%s]",
416 get_oper_name(source_p),
417 user, host, reason);
418 ilog(LOG_TYPE_GLINE, "G-Line for [%s@%s] [%s] requested by %s",
419 user, host, reason, get_oper_name(source_p));
420
421 sendto_server(NULL, CAP_GLN, NOCAPS, ":%s GLINE %s %s :%s",
422 source_p->id, user, host, reason);
423 return 0;
424 }
425
426 static void
427 do_sungline(struct Client *source_p, const char *user,
428 const char *host, const char *reason, int prop)
429 {
430 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
431 "%s requesting UNG-Line for [%s@%s] [%s]",
432 get_oper_name(source_p), user, host, reason);
433 ilog(LOG_TYPE_GLINE, "UNG-Line for [%s@%s] [%s] requested by %s",
434 user, host, reason, get_oper_name(source_p));
435
436 /* If at least 3 opers agree this user should be un G lined then do it */
437 if (check_majority(source_p, user, host, reason, GLINE_PENDING_DEL_TYPE) ==
438 GLINE_ALREADY_VOTED)
439 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
440 "oper or server has already voted");
441
442 if (prop)
443 {
444 sendto_server(source_p, CAP_ENCAP, NOCAPS,
445 ":%s ENCAP * GUNGLINE %s %s :%s",
446 source_p->id, user, host, reason);
447 }
448 }
449
450 /*! \brief GUNGLINE command handler
451 *
452 * \param source_p Pointer to allocated Client struct from which the message
453 * originally comes from. This can be a local or remote client.
454 * \param parc Integer holding the number of supplied arguments.
455 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
456 * pointers.
457 * \note Valid arguments for this command are:
458 * - parv[0] = command
459 * - parv[1] = user mask
460 * - parv[2] = host mask
461 * - parv[3] = reason
462 */
463 static int
464 me_gungline(struct Client *source_p, int parc, char *parv[])
465 {
466 if (ConfigGeneral.glines)
467 do_sungline(source_p, parv[1], parv[2], parv[3], 0);
468 return 0;
469 }
470
471 /*! \brief GUNGLINE command handler
472 *
473 * \param source_p Pointer to allocated Client struct from which the message
474 * originally comes from. This can be a local or remote client.
475 * \param parc Integer holding the number of supplied arguments.
476 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
477 * pointers.
478 * \note Valid arguments for this command are:
479 * - parv[0] = command
480 * - parv[1] = user\@host mask
481 * - parv[2] = reason
482 */
483 static int
484 mo_gungline(struct Client *source_p, int parc, char *parv[])
485 {
486 char *user = NULL;
487 char *host = NULL;
488 char *reason = NULL;
489
490 if (!HasOFlag(source_p, OPER_FLAG_GLINE))
491 {
492 sendto_one_numeric(source_p, &me, ERR_NOPRIVS, "gline");
493 return 0;
494 }
495
496 if (!ConfigGeneral.glines)
497 {
498 sendto_one_notice(source_p, &me, ":GUNGLINE disabled");
499 return 0;
500 }
501
502 if (parse_aline("GUNGLINE", source_p, parc, parv, 0, &user,
503 &host, NULL, NULL, &reason) < 0)
504 return 0;
505
506 do_sungline(source_p, user, host, reason, 1);
507 return 0;
508 }
509
510 /*
511 * gline enforces 3 parameters to force operator to give a reason
512 * a gline is not valid with "No reason"
513 * -db
514 */
515 static struct Message gline_msgtab =
516 {
517 "GLINE", NULL, 0, 0, 3, MAXPARA, MFLG_SLOW, 0,
518 { m_unregistered, m_not_oper, ms_gline, m_ignore, mo_gline, m_ignore }
519 };
520
521 static struct Message ungline_msgtab =
522 {
523 "GUNGLINE", NULL, 0, 0, 3, MAXPARA, MFLG_SLOW, 0,
524 { m_unregistered, m_not_oper, m_ignore, me_gungline, mo_gungline, m_ignore }
525 };
526
527 static void
528 module_init(void)
529 {
530 mod_add_cmd(&gline_msgtab);
531 mod_add_cmd(&ungline_msgtab);
532 add_capability("GLN", CAP_GLN, 1);
533 }
534
535 static void
536 module_exit(void)
537 {
538 mod_del_cmd(&gline_msgtab);
539 mod_del_cmd(&ungline_msgtab);
540 delete_capability("GLN");
541 }
542
543 struct module module_entry =
544 {
545 .node = { NULL, NULL, NULL },
546 .name = NULL,
547 .version = "$Revision$",
548 .handle = NULL,
549 .modinit = module_init,
550 .modexit = module_exit,
551 .flags = 0
552 };

Properties

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