2 * ircd-ratbox: A slightly useful ircd.
3 * m_gline.c: Votes towards globally banning a mask.
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
24 * $Id: m_gline.c 3225 2007-03-04 23:42:55Z jilles $
34 #include "irc_string.h"
35 #include "sprintf_irc.h"
41 #include "s_newconf.h"
52 static int mo_gline(struct Client
*, struct Client
*, int, const char **);
53 static int mc_gline(struct Client
*, struct Client
*, int, const char **);
54 static int ms_gline(struct Client
*, struct Client
*, int, const char **);
55 static int mo_ungline(struct Client
*, struct Client
*, int, const char **);
57 struct Message gline_msgtab
= {
58 "GLINE", 0, 0, 0, MFLG_SLOW
,
59 {mg_unreg
, mg_not_oper
, {mc_gline
, 3}, {ms_gline
, 7}, mg_ignore
, {mo_gline
, 3}}
61 struct Message ungline_msgtab
= {
62 "UNGLINE", 0, 0, 0, MFLG_SLOW
,
63 {mg_unreg
, mg_not_oper
, mg_ignore
, mg_ignore
, mg_ignore
, {mo_ungline
, 2}}
66 mapi_clist_av1 gline_clist
[] = { &gline_msgtab
, &ungline_msgtab
, NULL
};
67 DECLARE_MODULE_AV1(gline
, NULL
, NULL
, gline_clist
, NULL
, NULL
, "$Revision: 3225 $");
69 static int majority_gline(struct Client
*source_p
, const char *user
,
70 const char *host
, const char *reason
);
71 static void set_local_gline(struct Client
*source_p
, const char *user
,
72 const char *host
, const char *reason
);
74 static int check_wild_gline(const char *, const char *);
75 static int invalid_gline(struct Client
*, const char *, const char *, char *);
77 static int remove_temp_gline(const char *, const char *);
82 * inputs - The usual for a m_ function
84 * side effects - place a gline if 3 opers agree
87 mo_gline(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
89 const char *user
= NULL
;
90 char *host
= NULL
; /* user and host of GLINE "victim" */
91 char *reason
= NULL
; /* reason for "victims" demise */
95 if(!ConfigFileEntry
.glines
)
97 sendto_one_notice(source_p
, ":GLINE disabled, perhaps you want a clustered or remote KLINE?");
101 if(!IsOperGline(source_p
))
103 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
104 me
.name
, source_p
->name
, "gline");
108 host
= strchr(parv
[1], '@');
110 /* specific user@host */
116 /* gline for "@host", use *@host */
123 /* ok, its not a host.. abort */
124 if(strchr(parv
[1], '.') == NULL
)
126 sendto_one_notice(source_p
, ":Invalid parameters");
131 host
= LOCAL_COPY(parv
[1]);
134 reason
= LOCAL_COPY(parv
[2]);
136 if(invalid_gline(source_p
, user
, host
, reason
))
139 /* Not enough non-wild characters were found, assume they are trying to gline *@*. */
140 if(check_wild_gline(user
, host
))
142 if(MyClient(source_p
))
143 sendto_one_notice(source_p
,
144 ":Please include at least %d non-wildcard characters with the user@host",
145 ConfigFileEntry
.min_nonwildcard
);
149 if((ptr
= strchr(host
, '/')) != NULL
)
152 bitlen
= strtol(++ptr
, NULL
, 10);
155 if(strchr(host
, ':') == NULL
)
157 if(bitlen
< ConfigFileEntry
.gline_min_cidr
)
159 sendto_one_notice(source_p
, ":Cannot set G-Lines with cidr length < %d",
160 ConfigFileEntry
.gline_min_cidr
);
165 else if(bitlen
< ConfigFileEntry
.gline_min_cidr6
)
167 sendto_one_notice(source_p
, ":Cannot set G-Lines with cidr length < %d",
168 ConfigFileEntry
.gline_min_cidr6
);
173 /* inform users about the gline before we call majority_gline()
174 * so already voted comes below gline request --fl
176 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
177 "%s!%s@%s on %s is requesting gline for [%s@%s] [%s]",
178 source_p
->name
, source_p
->username
,
179 source_p
->host
, me
.name
, user
, host
, reason
);
180 ilog(L_GLINE
, "R %s %s %s %s %s %s %s",
181 source_p
->name
, source_p
->username
, source_p
->host
,
182 source_p
->servptr
->name
, user
, host
, reason
);
184 /* If at least 3 opers agree this user should be G lined then do it */
185 majority_gline(source_p
, user
, host
, reason
);
187 /* 4 param version for hyb-7 servers */
188 sendto_server(NULL
, NULL
, CAP_GLN
|CAP_TS6
, NOCAPS
,
189 ":%s GLINE %s %s :%s",
190 use_id(source_p
), user
, host
, reason
);
191 sendto_server(NULL
, NULL
, CAP_GLN
, CAP_TS6
,
192 ":%s GLINE %s %s :%s",
193 source_p
->name
, user
, host
, reason
);
195 /* 8 param for hyb-6 */
196 sendto_server(NULL
, NULL
, NOCAPS
, CAP_GLN
,
197 ":%s GLINE %s %s %s %s %s %s :%s",
198 me
.name
, source_p
->name
, source_p
->username
,
199 source_p
->host
, source_p
->servptr
->name
,
207 mc_gline(struct Client
*client_p
, struct Client
*source_p
,
208 int parc
, const char *parv
[])
210 struct Client
*acptr
;
216 /* hyb6 allows empty gline reasons */
217 if(parc
< 4 || EmptyString(parv
[3]))
224 reason
= LOCAL_COPY(parv
[3]);
226 if(invalid_gline(acptr
, user
, host
, reason
))
229 sendto_server(client_p
, NULL
, CAP_GLN
|CAP_TS6
, NOCAPS
,
230 ":%s GLINE %s %s :%s",
231 use_id(acptr
), user
, host
, reason
);
232 sendto_server(client_p
, NULL
, CAP_GLN
, CAP_TS6
,
233 ":%s GLINE %s %s :%s",
234 acptr
->name
, user
, host
, reason
);
235 sendto_server(client_p
, NULL
, NOCAPS
, CAP_GLN
,
236 ":%s GLINE %s %s %s %s %s %s :%s",
237 acptr
->servptr
->name
, acptr
->name
,
238 acptr
->username
, acptr
->host
,
239 acptr
->servptr
->name
, user
, host
, reason
);
241 if(!ConfigFileEntry
.glines
)
244 /* check theres enough non-wildcard chars */
245 if(check_wild_gline(user
, host
))
247 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
248 "%s!%s@%s on %s is requesting a gline without "
249 "%d non-wildcard characters for [%s@%s] [%s]",
250 acptr
->name
, acptr
->username
,
251 acptr
->host
, acptr
->servptr
->name
,
252 ConfigFileEntry
.min_nonwildcard
,
257 if((ptr
= strchr(host
, '/')) != NULL
)
260 bitlen
= strtol(++ptr
, NULL
, 10);
263 if(strchr(host
, ':') == NULL
)
265 if(bitlen
< ConfigFileEntry
.gline_min_cidr
)
267 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "%s!%s@%s on %s is requesting a "
268 "gline with a cidr mask < %d for [%s@%s] [%s]",
269 acptr
->name
, acptr
->username
, acptr
->host
,
270 acptr
->servptr
->name
,
271 ConfigFileEntry
.gline_min_cidr
,
277 else if(bitlen
< ConfigFileEntry
.gline_min_cidr6
)
279 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "%s!%s@%s on %s is requesting a "
280 "gline with a cidr mask < %d for [%s@%s] [%s]",
281 acptr
->name
, acptr
->username
, acptr
->host
,
282 acptr
->servptr
->name
,
283 ConfigFileEntry
.gline_min_cidr6
,
290 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
291 "%s!%s@%s on %s is requesting gline for [%s@%s] [%s]",
292 acptr
->name
, acptr
->username
, acptr
->host
,
293 acptr
->servptr
->name
, user
, host
, reason
);
295 ilog(L_GLINE
, "R %s %s %s %s %s %s %s",
296 source_p
->name
, source_p
->username
, source_p
->host
,
297 source_p
->servptr
->name
, user
, host
, reason
);
299 /* If at least 3 opers agree this user should be G lined then do it */
300 majority_gline(acptr
, user
, host
, reason
);
308 * inputs - The usual for a m_ function
310 * side effects - attempts to place a gline, if 3 opers agree
313 ms_gline(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
315 struct Client
*acptr
;
320 /* hyb6 allows empty gline reasons */
321 if(parc
< 8 || EmptyString(parv
[7]))
324 /* client doesnt exist.. someones messing */
325 if((acptr
= find_client(parv
[1])) == NULL
)
328 /* client that sent the gline, isnt on the server that sent
329 * the gline out. somethings fucked.
331 if(acptr
->servptr
!= source_p
)
336 reason
= LOCAL_COPY(parv
[7]);
338 if(invalid_gline(acptr
, user
, host
, reason
))
341 sendto_server(client_p
, NULL
, CAP_GLN
|CAP_TS6
, NOCAPS
,
342 ":%s GLINE %s %s :%s",
343 use_id(acptr
), user
, host
, reason
);
344 sendto_server(client_p
, NULL
, CAP_GLN
, CAP_TS6
,
345 ":%s GLINE %s %s :%s",
346 acptr
->name
, user
, host
, reason
);
347 sendto_server(client_p
, NULL
, NOCAPS
, CAP_GLN
,
348 ":%s GLINE %s %s %s %s %s %s :%s",
349 acptr
->servptr
->name
, acptr
->name
,
350 acptr
->username
, acptr
->host
,
351 acptr
->servptr
->name
, user
, host
, reason
);
353 if(!ConfigFileEntry
.glines
)
356 /* check theres enough non-wildcard chars */
357 if(check_wild_gline(user
, host
))
359 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
360 "%s!%s@%s on %s is requesting a gline without "
361 "%d non-wildcard characters for [%s@%s] [%s]",
362 acptr
->name
, acptr
->username
,
363 acptr
->host
, acptr
->servptr
->name
,
364 ConfigFileEntry
.min_nonwildcard
,
369 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
370 "%s!%s@%s on %s is requesting gline for [%s@%s] [%s]",
371 acptr
->name
, acptr
->username
, acptr
->host
,
372 acptr
->servptr
->name
, user
, host
, reason
);
374 ilog(L_GLINE
, "R %s %s %s %s %s %s %s",
375 acptr
->name
, acptr
->username
, acptr
->host
,
376 acptr
->servptr
->name
, user
, host
, reason
);
378 /* If at least 3 opers agree this user should be G lined then do it */
379 majority_gline(acptr
, user
, host
, reason
);
386 * parv[0] = sender nick
387 * parv[1] = gline to remove
390 mo_ungline(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
393 char *h
= LOCAL_COPY(parv
[1]);
397 if(!ConfigFileEntry
.glines
)
399 sendto_one_notice(source_p
, ":UNGLINE disabled, perhaps you want UNKLINE?");
403 if(!IsOperUnkline(source_p
) || !IsOperGline(source_p
))
405 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
406 me
.name
, source_p
->name
, "unkline");
410 if((host
= strchr(h
, '@')) || *h
== '*')
412 /* Explicit user@host mask given */
418 /* check for @host */
435 sendto_one_notice(source_p
, ":Invalid parameters");
439 if(remove_temp_gline(user
, host
))
441 sendto_one_notice(source_p
, ":Un-glined [%s@%s]", user
, host
);
442 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
443 "%s has removed the G-Line for: [%s@%s]",
444 get_oper_name(source_p
), user
, host
);
445 ilog(L_GLINE
, "U %s %s %s %s %s %s",
446 source_p
->name
, source_p
->username
, source_p
->host
,
447 source_p
->servptr
->name
, user
, host
);
451 sendto_one_notice(source_p
, ":No G-Line for %s@%s", user
, host
);
460 * inputs - user, host of gline
461 * output - 1 if not enough non-wildchar char's, 0 if ok
462 * side effects - NONE
465 check_wild_gline(const char *user
, const char *host
)
474 while ((tmpch
= *p
++))
476 if(!IsKWildChar(tmpch
))
478 /* enough of them, break */
479 if(++nonwild
>= ConfigFileEntry
.min_nonwildcard
)
484 if(nonwild
< ConfigFileEntry
.min_nonwildcard
)
486 /* user doesnt, try host */
488 while ((tmpch
= *p
++))
490 if(!IsKWildChar(tmpch
))
491 if(++nonwild
>= ConfigFileEntry
.min_nonwildcard
)
496 if(nonwild
< ConfigFileEntry
.min_nonwildcard
)
504 * inputs - pointer to source client, ident, host and reason
505 * outputs - 1 if invalid, 0 if valid
509 invalid_gline(struct Client
*source_p
, const char *luser
,
510 const char *lhost
, char *lreason
)
512 if(strchr(luser
, '!'))
514 sendto_one_notice(source_p
, ":Invalid character '!' in gline");
518 if(strlen(lreason
) > BANREASONLEN
)
519 lreason
[BANREASONLEN
] = '\0';
527 * inputs - pointer to oper nick/username/host/server,
528 * victim user/host and reason
533 set_local_gline(struct Client
*source_p
, const char *user
,
534 const char *host
, const char *reason
)
536 char buffer
[IRCD_BUFSIZE
];
537 struct ConfItem
*aconf
;
538 const char *current_date
;
542 current_date
= smalldate();
544 my_reason
= LOCAL_COPY(reason
);
547 aconf
->status
= CONF_GLINE
;
548 aconf
->flags
|= CONF_FLAGS_TEMPORARY
;
550 if(strlen(my_reason
) > BANREASONLEN
)
551 my_reason
[BANREASONLEN
-1] = '\0';
553 if((oper_reason
= strchr(my_reason
, '|')) != NULL
)
558 if(!EmptyString(oper_reason
))
559 DupString(aconf
->spasswd
, oper_reason
);
562 ircsnprintf(buffer
, sizeof(buffer
), "%s (%s)", reason
, current_date
);
564 DupString(aconf
->passwd
, buffer
);
565 DupString(aconf
->user
, user
);
566 DupString(aconf
->host
, host
);
567 aconf
->hold
= CurrentTime
+ ConfigFileEntry
.gline_time
;
570 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
571 "%s!%s@%s on %s has triggered gline for [%s@%s] [%s]",
572 source_p
->name
, source_p
->username
,
573 source_p
->host
, source_p
->servptr
->name
,
575 ilog(L_GLINE
, "T %s %s %s %s %s %s %s",
576 source_p
->name
, source_p
->username
, source_p
->host
,
577 source_p
->servptr
->name
, user
, host
, reason
);
584 * input - client doing gline, user, host and reason of gline
585 * output - YES if there are 3 different opers/servers agree, else NO
589 majority_gline(struct Client
*source_p
, const char *user
,
590 const char *host
, const char *reason
)
592 dlink_node
*pending_node
;
593 struct gline_pending
*pending
;
595 /* to avoid desync.. --fl */
596 cleanup_glines(NULL
);
598 /* if its already glined, why bother? :) -- fl_ */
599 if(find_is_glined(host
, user
))
602 DLINK_FOREACH(pending_node
, pending_glines
.head
)
604 pending
= pending_node
->data
;
606 if((irccmp(pending
->user
, user
) == 0) &&
607 (irccmp(pending
->host
, host
) == 0))
609 /* check oper or server hasnt already voted */
610 if(((irccmp(pending
->oper_user1
, source_p
->username
) == 0) ||
611 (irccmp(pending
->oper_host1
, source_p
->host
) == 0)))
613 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "oper has already voted");
616 else if(irccmp(pending
->oper_server1
, source_p
->servptr
->name
) == 0)
618 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "server has already voted");
622 if(pending
->oper_user2
[0] != '\0')
624 /* if two other opers on two different servers have voted yes */
625 if(((irccmp(pending
->oper_user2
, source_p
->username
) == 0) ||
626 (irccmp(pending
->oper_host2
, source_p
->host
) == 0)))
628 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
629 "oper has already voted");
632 else if(irccmp(pending
->oper_server2
, source_p
->servptr
->name
) == 0)
634 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
635 "server has already voted");
639 /* trigger the gline using the original reason --fl */
640 set_local_gline(source_p
, user
, host
,
643 cleanup_glines(NULL
);
648 strlcpy(pending
->oper_nick2
, source_p
->name
,
649 sizeof(pending
->oper_nick2
));
650 strlcpy(pending
->oper_user2
, source_p
->username
,
651 sizeof(pending
->oper_user2
));
652 strlcpy(pending
->oper_host2
, source_p
->host
,
653 sizeof(pending
->oper_host2
));
654 DupString(pending
->reason2
, reason
);
655 pending
->oper_server2
= scache_get_name(source_p
->servptr
->serv
->nameinfo
);
656 pending
->last_gline_time
= CurrentTime
;
657 pending
->time_request2
= CurrentTime
;
663 /* no pending gline, create a new one */
664 pending
= (struct gline_pending
*)
665 MyMalloc(sizeof(struct gline_pending
));
667 strlcpy(pending
->oper_nick1
, source_p
->name
,
668 sizeof(pending
->oper_nick1
));
669 strlcpy(pending
->oper_user1
, source_p
->username
,
670 sizeof(pending
->oper_user1
));
671 strlcpy(pending
->oper_host1
, source_p
->host
,
672 sizeof(pending
->oper_host1
));
674 pending
->oper_server1
= scache_get_name(source_p
->servptr
->serv
->nameinfo
);
676 strlcpy(pending
->user
, user
, sizeof(pending
->user
));
677 strlcpy(pending
->host
, host
, sizeof(pending
->host
));
678 DupString(pending
->reason1
, reason
);
679 pending
->reason2
= NULL
;
681 pending
->last_gline_time
= CurrentTime
;
682 pending
->time_request1
= CurrentTime
;
684 dlinkAddAlloc(pending
, &pending_glines
);
689 /* remove_temp_gline()
691 * inputs - username, hostname to ungline
693 * side effects - tries to ungline anything that matches
696 remove_temp_gline(const char *user
, const char *host
)
698 struct ConfItem
*aconf
;
700 struct irc_sockaddr_storage addr
, caddr
;
704 mtype
= parse_netmask(host
, (struct sockaddr
*)&addr
, &bits
);
706 DLINK_FOREACH(ptr
, glines
.head
)
710 gtype
= parse_netmask(aconf
->host
, (struct sockaddr
*)&caddr
, &cbits
);
712 if(gtype
!= mtype
|| (user
&& irccmp(user
, aconf
->user
)))
717 if(irccmp(aconf
->host
, host
))
720 else if(bits
!= cbits
||
721 !comp_with_mask_sock((struct sockaddr
*)&addr
,
722 (struct sockaddr
*)&caddr
, bits
))
725 dlinkDestroy(ptr
, &glines
);
726 remove_reject_mask(aconf
->user
, aconf
->host
);
727 delete_one_address_conf(aconf
->host
, aconf
);