ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.1.x/modules/m_gline.c
Revision: 2862
Committed: Sat Jan 18 20:17:59 2014 UTC (10 years, 2 months ago) by michael
Content type: text/x-csrc
File size: 18876 byte(s)
Log Message:
- m_gline.c:ms_gline(): improved readability. Removed extranous IsClient() test.

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

Properties

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