2 #include "../irc/irc.h"
3 #include "../lib/version.h"
4 #include "../lib/irc_string.h"
5 #include "../channel/channel.h"
6 #include "../bans/bans.h"
7 #include "../control/control.h"
8 #include "../localuser/localuser.h"
9 #include "../localuser/localuserchannel.h"
15 int ircdbanned(nick
*n
, channel
*c
);
17 static chanban
*nickbanned2(nick
*np
, channel
*cp
, int visibleonly
) {
20 for (cbp
=cp
->bans
;cbp
;cbp
=cbp
->next
) {
21 if (nickmatchban(np
,cbp
,visibleonly
))
28 void be_onjoin(int hooknum
, void *arg
) {
29 void **arglist
= (void **)arg
;
30 channel
*c
= ((channel
*)arglist
[0]);
31 nick
*np
= arglist
[1];
33 /* Verify both are valid */
37 /* Services, opers and extended opers can bypass bans */
38 if (IsService(np
) || IsOper(np
) || IsXOper(np
) || NickOnServiceServer(np
))
41 int ircd_banned
= ircdbanned(np
, c
);
42 chanban
*ns_banned
= nickbanned2(np
, c
, 0);
45 Error("banevade", ERR_INFO
, "Ban status ircd_banned=%d newserv_banned=%s", ircd_banned
, (ns_banned
? "here" : "(null)"));
48 /* If we're not considered banned as per the ircd code,
49 but banned according to newserv - trigger the hook */
50 if(!ircd_banned
&& ns_banned
) {
51 /* We kinda dont need this hook anymore - but we'll trigger it anyway for future scripts/modules */
52 triggerhook(HOOK_CHANNEL_JOIN_BYPASS_BAN
, arg
);
54 channel
*cp
= findchannel("#qnet.banevade");
56 controlchanmsg(cp
, "banevade: bad user in %s: %s!%s@%s vs. %s", c
->index
->name
->content
, np
->nick
, np
->ident
, np
->host
->name
->content
, bantostring(ns_banned
));
59 /* Reset host to [cc].HIS_HIDDENHOST */
60 char host
[HOSTLEN
+1] = "";
61 snprintf(host
, sizeof(host
), "%s.%s", np
->authname
, HIS_HIDDENHOST
);
63 /* I didnt find a function for this, so we're doing it R A W */
64 irc_send("%s SH %s %s %s", mynumeric
->content
, longtonumeric(np
->numeric
, 5), np
->ident
, host
);
66 /* Also remove them from the channel they're not supposed to be in */
67 /* We're gonna go with the generic default-Q-kick-reason since we don't know the real reason for the kick */
68 localkickuser(NULL
, c
, np
, "Banned.");
70 /* Honest to god, this should never happen since the IRCD is in a state where it
71 * checks EITHER the sethost or the authname. So people shouldn't be able to avoid bans
72 * unauthed. But we still need to handle it, incase shit hits the fan. */
74 /* User has a spoofed host but isn't authed, most likely a s:line (for some reason I want to write an s:line). Send them flying. */
75 /* We're not gonna kill the user because they'll most likely just reconnect and rejoin, causing a buttload of spam. */
76 /* So just trigger an extra line of spam into qnet.banevade so we'll investigate manually! */
77 //killuser(NULL, np, "Please don't avoid bans on QuakeNet");
79 /* Also send an additional spam line to the amazing OGs in qnet.banevade */
80 if(cp
) controlchanmsg(cp
, "banevade: user %s appears to be un-authed, this might be a s:line!", np
->nick
);
86 registerhook(HOOK_CHANNEL_JOIN
, &be_onjoin
);
87 registerhook(HOOK_CHANNEL_CREATE
, &be_onjoin
);
91 deregisterhook(HOOK_CHANNEL_JOIN
, &be_onjoin
);
92 deregisterhook(HOOK_CHANNEL_CREATE
, &be_onjoin
);
95 /* This code is based on snircd 1.3.4a, which has the bug where authed users with +h
96 could bypass *!*@[account].users.quakenet.org bans.
97 It has been somewhat rewritten to fit the NewServ ban flags and structure
100 /* The ircd checks 4 things:
102 * The clients nick!username (where username is current, original usernames are not checked)
103 * The clients real ip towards IP bans
104 * The real host (if client is using a cloaked host)
105 * The current host of the client
107 * This causes the bug that [account].HIS_HIDDENHOST is never checked towards the banlist
108 * if they have +h set.
109 * We need to replicate that check in this code
113 #define IFNULLELSE(x, y) (x ? y : "(null)")
116 int ircdbanned(nick
*n
, channel
*c
) {
117 char *nick
= n
->nick
;
118 char *ident
= n
->ident
;
119 char tmphost
[HOSTLEN
+ 1];
123 /* Here is the bug in the ircd.
124 * In a perfect world we'd have one more variable to save both sethost and authhost
128 else if (IsSetHost(n
))
129 sr
= n
->sethost
->content
;
131 snprintf(tmphost
, sizeof(tmphost
), "%s.%s", n
->authname
, HIS_HIDDENHOST
);
136 Error("banevade", ERR_INFO
, "---------------------------");
137 Error("banevade", ERR_INFO
, "User %s has joined %s.", nick
, c
->index
->name
->content
);
138 Error("banevade", ERR_INFO
, "We will be checking the following:");
139 Error("banevade", ERR_INFO
, " nick=%s ident=%s iphost=%s sr=%s host=%s", nick
, ident
, IPtostr(n
->ipaddress
), IFNULLELSE(sr
, sr
), n
->host
->name
->content
);
142 /* Walk through ban list. */
143 for (cb
= c
->bans
; cb
; cb
= cb
->next
) {
145 Error("banevade", ERR_INFO
, "Ban for: %s!%s@%s", IFNULLELSE(cb
->nick
, cb
->nick
->content
), IFNULLELSE(cb
->user
, cb
->user
->content
), IFNULLELSE(cb
->host
, cb
->host
->content
));
148 /* Compare nick and user portion of ban. */
150 banlist->banstr[banlist->nu_len] = '\0';
151 res = match(banlist->banstr, nu);
152 banlist->banstr[banlist->nu_len] = '@';
155 /* Our code - since we don't save nick!user in our ban structure - we need to check it using other tools!
156 * I've only used match2strings, I've not used the flags for CHANBAN_NICKEXACT etc.
157 * The only issue I could think of is the lack of irc_compare for {[]} etc.
158 * But the ircd uses match, so I went with this to be somewhat 1:1 close to it.
159 * Give me a poke if you want this to be more like nickbanned() with those checks.
162 if(!match2strings(cb
->nick
->content
, nick
)) {
164 Error("banevade", ERR_INFO
, " nick is present but not matching");
170 if(!match2strings(cb
->user
->content
, ident
)) {
172 Error("banevade", ERR_INFO
, " user is present but not matching");
178 /* Compare host portion of ban. */
180 if (!((cb->flags & BAN_IPMASK)
181 && ipmask_check(&cli_ip(cptr), &cb->address, cb->addrbits))
182 && match(hostmask, cli_user(cptr)->host)
183 && !(sr && !match(hostmask, sr)))
188 /* Check current host */
189 !match2strings(cb
->host
->content
, n
->host
->name
->content
)
190 /* Check IP if ip-ban */
191 && !((cb
->flags
& CHANBAN_IP
) && ipmask_check(&(n
->ipnode
->prefix
->sin
), &(cb
->ipaddr
), cb
->prefixlen
))
192 /* Check our real host (if +h/+x) */
193 && !(sr
&& match2strings(cb
->host
->content
, sr
))
196 Error("banevade", ERR_INFO
, " host is present but not matching.");
202 /* If we got this far, everything that exists in the ban matches! */
204 Error("banevade", ERR_INFO
, " -- Ban appears to hit the user.");