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 $
33 #include "irc_string.h"
34 #include "sprintf_irc.h"
39 #include "s_newconf.h"
50 static int mo_gline(struct Client
*, struct Client
*, int, const char **);
51 static int mc_gline(struct Client
*, struct Client
*, int, const char **);
52 static int ms_gline(struct Client
*, struct Client
*, int, const char **);
53 static int mo_ungline(struct Client
*, struct Client
*, int, const char **);
55 struct Message gline_msgtab
= {
56 "GLINE", 0, 0, 0, MFLG_SLOW
,
57 {mg_unreg
, mg_not_oper
, {mc_gline
, 3}, {ms_gline
, 7}, mg_ignore
, {mo_gline
, 3}}
59 struct Message ungline_msgtab
= {
60 "UNGLINE", 0, 0, 0, MFLG_SLOW
,
61 {mg_unreg
, mg_not_oper
, mg_ignore
, mg_ignore
, mg_ignore
, {mo_ungline
, 2}}
64 mapi_clist_av1 gline_clist
[] = { &gline_msgtab
, &ungline_msgtab
, NULL
};
65 DECLARE_MODULE_AV1(gline
, NULL
, NULL
, gline_clist
, NULL
, NULL
, "$Revision: 3225 $");
67 static int majority_gline(struct Client
*source_p
, const char *user
,
68 const char *host
, const char *reason
);
69 static void set_local_gline(struct Client
*source_p
, const char *user
,
70 const char *host
, const char *reason
);
72 static int check_wild_gline(const char *, const char *);
73 static int invalid_gline(struct Client
*, const char *, const char *, char *);
75 static int remove_temp_gline(const char *, const char *);
80 * inputs - The usual for a m_ function
82 * side effects - place a gline if 3 opers agree
85 mo_gline(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
87 const char *user
= NULL
;
88 char *host
= NULL
; /* user and host of GLINE "victim" */
89 char *reason
= NULL
; /* reason for "victims" demise */
93 if(!ConfigFileEntry
.glines
)
95 sendto_one_notice(source_p
, ":GLINE disabled, perhaps you want a clustered or remote KLINE?");
99 if(!IsOperGline(source_p
))
101 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
102 me
.name
, source_p
->name
, "gline");
106 host
= strchr(parv
[1], '@');
108 /* specific user@host */
114 /* gline for "@host", use *@host */
121 /* ok, its not a host.. abort */
122 if(strchr(parv
[1], '.') == NULL
)
124 sendto_one_notice(source_p
, ":Invalid parameters");
129 host
= LOCAL_COPY(parv
[1]);
132 reason
= LOCAL_COPY(parv
[2]);
134 if(invalid_gline(source_p
, user
, host
, reason
))
137 /* Not enough non-wild characters were found, assume they are trying to gline *@*. */
138 if(check_wild_gline(user
, host
))
140 if(MyClient(source_p
))
141 sendto_one_notice(source_p
,
142 ":Please include at least %d non-wildcard characters with the user@host",
143 ConfigFileEntry
.min_nonwildcard
);
147 if((ptr
= strchr(host
, '/')) != NULL
)
150 bitlen
= strtol(++ptr
, NULL
, 10);
153 if(strchr(host
, ':') == NULL
)
155 if(bitlen
< ConfigFileEntry
.gline_min_cidr
)
157 sendto_one_notice(source_p
, ":Cannot set G-Lines with cidr length < %d",
158 ConfigFileEntry
.gline_min_cidr
);
163 else if(bitlen
< ConfigFileEntry
.gline_min_cidr6
)
165 sendto_one_notice(source_p
, ":Cannot set G-Lines with cidr length < %d",
166 ConfigFileEntry
.gline_min_cidr6
);
171 /* inform users about the gline before we call majority_gline()
172 * so already voted comes below gline request --fl
174 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
175 "%s!%s@%s on %s is requesting gline for [%s@%s] [%s]",
176 source_p
->name
, source_p
->username
,
177 source_p
->host
, me
.name
, user
, host
, reason
);
178 ilog(L_GLINE
, "R %s %s %s %s %s %s %s",
179 source_p
->name
, source_p
->username
, source_p
->host
,
180 source_p
->servptr
->name
, user
, host
, reason
);
182 /* If at least 3 opers agree this user should be G lined then do it */
183 majority_gline(source_p
, user
, host
, reason
);
185 /* 4 param version for hyb-7 servers */
186 sendto_server(NULL
, NULL
, CAP_GLN
|CAP_TS6
, NOCAPS
,
187 ":%s GLINE %s %s :%s",
188 use_id(source_p
), user
, host
, reason
);
189 sendto_server(NULL
, NULL
, CAP_GLN
, CAP_TS6
,
190 ":%s GLINE %s %s :%s",
191 source_p
->name
, user
, host
, reason
);
193 /* 8 param for hyb-6 */
194 sendto_server(NULL
, NULL
, NOCAPS
, CAP_GLN
,
195 ":%s GLINE %s %s %s %s %s %s :%s",
196 me
.name
, source_p
->name
, source_p
->username
,
197 source_p
->host
, source_p
->servptr
->name
,
205 mc_gline(struct Client
*client_p
, struct Client
*source_p
,
206 int parc
, const char *parv
[])
208 struct Client
*acptr
;
214 /* hyb6 allows empty gline reasons */
215 if(parc
< 4 || EmptyString(parv
[3]))
222 reason
= LOCAL_COPY(parv
[3]);
224 if(invalid_gline(acptr
, user
, host
, reason
))
227 sendto_server(client_p
, NULL
, CAP_GLN
|CAP_TS6
, NOCAPS
,
228 ":%s GLINE %s %s :%s",
229 use_id(acptr
), user
, host
, reason
);
230 sendto_server(client_p
, NULL
, CAP_GLN
, CAP_TS6
,
231 ":%s GLINE %s %s :%s",
232 acptr
->name
, user
, host
, reason
);
233 sendto_server(client_p
, NULL
, NOCAPS
, CAP_GLN
,
234 ":%s GLINE %s %s %s %s %s %s :%s",
235 acptr
->servptr
->name
, acptr
->name
,
236 acptr
->username
, acptr
->host
,
237 acptr
->servptr
->name
, user
, host
, reason
);
239 if(!ConfigFileEntry
.glines
)
242 /* check theres enough non-wildcard chars */
243 if(check_wild_gline(user
, host
))
245 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
246 "%s!%s@%s on %s is requesting a gline without "
247 "%d non-wildcard characters for [%s@%s] [%s]",
248 acptr
->name
, acptr
->username
,
249 acptr
->host
, acptr
->servptr
->name
,
250 ConfigFileEntry
.min_nonwildcard
,
255 if((ptr
= strchr(host
, '/')) != NULL
)
258 bitlen
= strtol(++ptr
, NULL
, 10);
261 if(strchr(host
, ':') == NULL
)
263 if(bitlen
< ConfigFileEntry
.gline_min_cidr
)
265 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "%s!%s@%s on %s is requesting a "
266 "gline with a cidr mask < %d for [%s@%s] [%s]",
267 acptr
->name
, acptr
->username
, acptr
->host
,
268 acptr
->servptr
->name
,
269 ConfigFileEntry
.gline_min_cidr
,
275 else if(bitlen
< ConfigFileEntry
.gline_min_cidr6
)
277 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "%s!%s@%s on %s is requesting a "
278 "gline with a cidr mask < %d for [%s@%s] [%s]",
279 acptr
->name
, acptr
->username
, acptr
->host
,
280 acptr
->servptr
->name
,
281 ConfigFileEntry
.gline_min_cidr6
,
288 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
289 "%s!%s@%s on %s is requesting gline for [%s@%s] [%s]",
290 acptr
->name
, acptr
->username
, acptr
->host
,
291 acptr
->servptr
->name
, user
, host
, reason
);
293 ilog(L_GLINE
, "R %s %s %s %s %s %s %s",
294 source_p
->name
, source_p
->username
, source_p
->host
,
295 source_p
->servptr
->name
, user
, host
, reason
);
297 /* If at least 3 opers agree this user should be G lined then do it */
298 majority_gline(acptr
, user
, host
, reason
);
306 * inputs - The usual for a m_ function
308 * side effects - attempts to place a gline, if 3 opers agree
311 ms_gline(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
313 struct Client
*acptr
;
318 /* hyb6 allows empty gline reasons */
319 if(parc
< 8 || EmptyString(parv
[7]))
322 /* client doesnt exist.. someones messing */
323 if((acptr
= find_client(parv
[1])) == NULL
)
326 /* client that sent the gline, isnt on the server that sent
327 * the gline out. somethings fucked.
329 if(acptr
->servptr
!= source_p
)
334 reason
= LOCAL_COPY(parv
[7]);
336 if(invalid_gline(acptr
, user
, host
, reason
))
339 sendto_server(client_p
, NULL
, CAP_GLN
|CAP_TS6
, NOCAPS
,
340 ":%s GLINE %s %s :%s",
341 use_id(acptr
), user
, host
, reason
);
342 sendto_server(client_p
, NULL
, CAP_GLN
, CAP_TS6
,
343 ":%s GLINE %s %s :%s",
344 acptr
->name
, user
, host
, reason
);
345 sendto_server(client_p
, NULL
, NOCAPS
, CAP_GLN
,
346 ":%s GLINE %s %s %s %s %s %s :%s",
347 acptr
->servptr
->name
, acptr
->name
,
348 acptr
->username
, acptr
->host
,
349 acptr
->servptr
->name
, user
, host
, reason
);
351 if(!ConfigFileEntry
.glines
)
354 /* check theres enough non-wildcard chars */
355 if(check_wild_gline(user
, host
))
357 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
358 "%s!%s@%s on %s is requesting a gline without "
359 "%d non-wildcard characters for [%s@%s] [%s]",
360 acptr
->name
, acptr
->username
,
361 acptr
->host
, acptr
->servptr
->name
,
362 ConfigFileEntry
.min_nonwildcard
,
367 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
368 "%s!%s@%s on %s is requesting gline for [%s@%s] [%s]",
369 acptr
->name
, acptr
->username
, acptr
->host
,
370 acptr
->servptr
->name
, user
, host
, reason
);
372 ilog(L_GLINE
, "R %s %s %s %s %s %s %s",
373 acptr
->name
, acptr
->username
, acptr
->host
,
374 acptr
->servptr
->name
, user
, host
, reason
);
376 /* If at least 3 opers agree this user should be G lined then do it */
377 majority_gline(acptr
, user
, host
, reason
);
384 * parv[0] = sender nick
385 * parv[1] = gline to remove
388 mo_ungline(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
391 char *h
= LOCAL_COPY(parv
[1]);
395 if(!ConfigFileEntry
.glines
)
397 sendto_one_notice(source_p
, ":UNGLINE disabled, perhaps you want UNKLINE?");
401 if(!IsOperUnkline(source_p
) || !IsOperGline(source_p
))
403 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
404 me
.name
, source_p
->name
, "unkline");
408 if((host
= strchr(h
, '@')) || *h
== '*')
410 /* Explicit user@host mask given */
416 /* check for @host */
433 sendto_one_notice(source_p
, ":Invalid parameters");
437 if(remove_temp_gline(user
, host
))
439 sendto_one_notice(source_p
, ":Un-glined [%s@%s]", user
, host
);
440 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
441 "%s has removed the G-Line for: [%s@%s]",
442 get_oper_name(source_p
), user
, host
);
443 ilog(L_GLINE
, "U %s %s %s %s %s %s",
444 source_p
->name
, source_p
->username
, source_p
->host
,
445 source_p
->servptr
->name
, user
, host
);
449 sendto_one_notice(source_p
, ":No G-Line for %s@%s", user
, host
);
458 * inputs - user, host of gline
459 * output - 1 if not enough non-wildchar char's, 0 if ok
460 * side effects - NONE
463 check_wild_gline(const char *user
, const char *host
)
472 while ((tmpch
= *p
++))
474 if(!IsKWildChar(tmpch
))
476 /* enough of them, break */
477 if(++nonwild
>= ConfigFileEntry
.min_nonwildcard
)
482 if(nonwild
< ConfigFileEntry
.min_nonwildcard
)
484 /* user doesnt, try host */
486 while ((tmpch
= *p
++))
488 if(!IsKWildChar(tmpch
))
489 if(++nonwild
>= ConfigFileEntry
.min_nonwildcard
)
494 if(nonwild
< ConfigFileEntry
.min_nonwildcard
)
502 * inputs - pointer to source client, ident, host and reason
503 * outputs - 1 if invalid, 0 if valid
507 invalid_gline(struct Client
*source_p
, const char *luser
,
508 const char *lhost
, char *lreason
)
510 if(strchr(luser
, '!'))
512 sendto_one_notice(source_p
, ":Invalid character '!' in gline");
516 if(strlen(lreason
) > BANREASONLEN
)
517 lreason
[BANREASONLEN
] = '\0';
525 * inputs - pointer to oper nick/username/host/server,
526 * victim user/host and reason
531 set_local_gline(struct Client
*source_p
, const char *user
,
532 const char *host
, const char *reason
)
534 char buffer
[IRCD_BUFSIZE
];
535 struct ConfItem
*aconf
;
536 const char *current_date
;
540 current_date
= smalldate();
542 my_reason
= LOCAL_COPY(reason
);
545 aconf
->status
= CONF_GLINE
;
546 aconf
->flags
|= CONF_FLAGS_TEMPORARY
;
548 if(strlen(my_reason
) > BANREASONLEN
)
549 my_reason
[BANREASONLEN
-1] = '\0';
551 if((oper_reason
= strchr(my_reason
, '|')) != NULL
)
556 if(!EmptyString(oper_reason
))
557 DupString(aconf
->spasswd
, oper_reason
);
560 rb_snprintf(buffer
, sizeof(buffer
), "%s (%s)", reason
, current_date
);
562 DupString(aconf
->passwd
, buffer
);
563 DupString(aconf
->user
, user
);
564 DupString(aconf
->host
, host
);
565 aconf
->hold
= CurrentTime
+ ConfigFileEntry
.gline_time
;
568 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
569 "%s!%s@%s on %s has triggered gline for [%s@%s] [%s]",
570 source_p
->name
, source_p
->username
,
571 source_p
->host
, source_p
->servptr
->name
,
573 ilog(L_GLINE
, "T %s %s %s %s %s %s %s",
574 source_p
->name
, source_p
->username
, source_p
->host
,
575 source_p
->servptr
->name
, user
, host
, reason
);
582 * input - client doing gline, user, host and reason of gline
583 * output - YES if there are 3 different opers/servers agree, else NO
587 majority_gline(struct Client
*source_p
, const char *user
,
588 const char *host
, const char *reason
)
590 rb_dlink_node
*pending_node
;
591 struct gline_pending
*pending
;
593 /* to avoid desync.. --fl */
594 cleanup_glines(NULL
);
596 /* if its already glined, why bother? :) -- fl_ */
597 if(find_is_glined(host
, user
))
600 RB_DLINK_FOREACH(pending_node
, pending_glines
.head
)
602 pending
= pending_node
->data
;
604 if((irccmp(pending
->user
, user
) == 0) &&
605 (irccmp(pending
->host
, host
) == 0))
607 /* check oper or server hasnt already voted */
608 if(((irccmp(pending
->oper_user1
, source_p
->username
) == 0) ||
609 (irccmp(pending
->oper_host1
, source_p
->host
) == 0)))
611 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "oper has already voted");
614 else if(irccmp(pending
->oper_server1
, source_p
->servptr
->name
) == 0)
616 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "server has already voted");
620 if(pending
->oper_user2
[0] != '\0')
622 /* if two other opers on two different servers have voted yes */
623 if(((irccmp(pending
->oper_user2
, source_p
->username
) == 0) ||
624 (irccmp(pending
->oper_host2
, source_p
->host
) == 0)))
626 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
627 "oper has already voted");
630 else if(irccmp(pending
->oper_server2
, source_p
->servptr
->name
) == 0)
632 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
633 "server has already voted");
637 /* trigger the gline using the original reason --fl */
638 set_local_gline(source_p
, user
, host
,
641 cleanup_glines(NULL
);
646 strlcpy(pending
->oper_nick2
, source_p
->name
,
647 sizeof(pending
->oper_nick2
));
648 strlcpy(pending
->oper_user2
, source_p
->username
,
649 sizeof(pending
->oper_user2
));
650 strlcpy(pending
->oper_host2
, source_p
->host
,
651 sizeof(pending
->oper_host2
));
652 DupString(pending
->reason2
, reason
);
653 pending
->oper_server2
= scache_get_name(source_p
->servptr
->serv
->nameinfo
);
654 pending
->last_gline_time
= CurrentTime
;
655 pending
->time_request2
= CurrentTime
;
661 /* no pending gline, create a new one */
662 pending
= (struct gline_pending
*)
663 MyMalloc(sizeof(struct gline_pending
));
665 strlcpy(pending
->oper_nick1
, source_p
->name
,
666 sizeof(pending
->oper_nick1
));
667 strlcpy(pending
->oper_user1
, source_p
->username
,
668 sizeof(pending
->oper_user1
));
669 strlcpy(pending
->oper_host1
, source_p
->host
,
670 sizeof(pending
->oper_host1
));
672 pending
->oper_server1
= scache_get_name(source_p
->servptr
->serv
->nameinfo
);
674 strlcpy(pending
->user
, user
, sizeof(pending
->user
));
675 strlcpy(pending
->host
, host
, sizeof(pending
->host
));
676 DupString(pending
->reason1
, reason
);
677 pending
->reason2
= NULL
;
679 pending
->last_gline_time
= CurrentTime
;
680 pending
->time_request1
= CurrentTime
;
682 rb_dlinkAddAlloc(pending
, &pending_glines
);
687 /* remove_temp_gline()
689 * inputs - username, hostname to ungline
691 * side effects - tries to ungline anything that matches
694 remove_temp_gline(const char *user
, const char *host
)
696 struct ConfItem
*aconf
;
698 struct irc_sockaddr_storage addr
, caddr
;
702 mtype
= parse_netmask(host
, (struct sockaddr
*)&addr
, &bits
);
704 RB_DLINK_FOREACH(ptr
, glines
.head
)
708 gtype
= parse_netmask(aconf
->host
, (struct sockaddr
*)&caddr
, &cbits
);
710 if(gtype
!= mtype
|| (user
&& irccmp(user
, aconf
->user
)))
715 if(irccmp(aconf
->host
, host
))
718 else if(bits
!= cbits
||
719 !comp_with_mask_sock((struct sockaddr
*)&addr
,
720 (struct sockaddr
*)&caddr
, bits
))
723 rb_dlinkDestroy(ptr
, &glines
);
724 remove_reject_mask(aconf
->user
, aconf
->host
);
725 delete_one_address_conf(aconf
->host
, aconf
);