1 /*
2 * bans.c
3 *
4 * This source code implements methods and algorithms used to deal with channel bans.
5 *
6 * written by Joshua J. Drake
7 * copyright (c) 1998
8 *
9 * -= SuckSoft =-
10 */
11
12 #include "irc.h"
13
14 #include "bans.h"
15 #include "channels.h"
16 #include "dma.h"
17 #include "server.h"
18 #include "output.h"
19 #include "ircaux.h"
20 #include "list.h"
21 #include "how_many.h"
22 #include "ninja.h"
23
24 /*
25 * adds a ban to the cached ban list for a channel
26 * accessed via Channel.bans
27 */
28 void
add_ban(Channel * chan,u_char * ban,u_char * owner,u_char * bantime)29 add_ban(Channel *chan, u_char *ban, u_char *owner, u_char *bantime)
30 {
31 Ban *new;
32
33 /* if we have no channel or ban, report so and return */
34 if (!chan || !ban)
35 {
36 put_error("add_ban() called with no channel or ban.");
37 return;
38 }
39
40 /* try to remove the ban specified, if it was found, free the memory used. */
41 if ((new = (Ban *) remove_from_list((List **)&(chan->bans), ban)) != NULL)
42 {
43 dma_Free(&(new->ban));
44 dma_Free(&(new->owner));
45 dma_Free(&new);
46 }
47
48 /* create a new ban entry */
49 new = (Ban *) dma_Malloc(sizeof(Ban));
50 /* pointless.. handled by dma_Malloc()
51 new->ban = NULL;
52 new->owner = NULL;
53 new->time = 0;
54 */
55 if (bantime)
56 new->time = my_atol(bantime);
57 if (owner)
58 dma_strcpy(&(new->owner), owner);
59 dma_strcpy(&(new->ban), ban);
60
61 /* add this new entry to the list. */
62 add_to_list((List **)&(chan->bans), (List *)new);
63 }
64
65 /*
66 * this is done after a special whois is done..
67 * it bans a user
68 */
69 void
ban_queue(WhoisStuff * stuff,u_char * nick,u_char * args)70 ban_queue(WhoisStuff *stuff, u_char *nick, u_char *args)
71 {
72 u_char *foo;
73
74 /* check out the whois reply, make sure it returned something base a ban on. */
75 if (!stuff || !stuff->nick || !nick || strcmp(stuff->user, "<UNKNOWN>") == 0 ||
76 my_stricmp(stuff->nick, nick) || !args)
77 {
78 put_info("%s is not on irc.", nick);
79 return;
80 }
81
82 /* skip over any bullshit characters before the username. */
83 foo = stuff->user;
84 if (foo && *foo && *foo == '~')
85 foo++;
86 if (foo && *foo)
87 foo++;
88
89 /* ban the mask */
90 send_to_server("MODE %s +b *!*%s@%s", args, foo ? foo : empty_string, cluster(stuff->host));
91 }
92
93 /*
94 * this is done after a special whois is done..
95 * it unbans all bans on a channel matching the nick!user@host
96 */
97 void
unban_queue(WhoisStuff * stuff,u_char * nick,u_char * args)98 unban_queue(WhoisStuff *stuff, u_char *nick, u_char *args)
99 {
100 /* check out the whois reply... */
101 if (!stuff || !stuff->nick || !nick || strcmp(stuff->user, "<UNKNOWN>") == 0 ||
102 my_stricmp(stuff->nick, nick) || !args)
103 {
104 put_info("%s is not on irc.", nick);
105 return;
106 }
107
108 /* remove them bans. */
109 remove_matching_bans(stuff->nick, stuff->user, stuff->host, args, 0);
110 }
111
112 /*
113 * remove all bans matching nick!user@host on channel
114 * if quiet, don't talk about the fact that we're doing it..
115 */
116 void
remove_matching_bans(u_char * nick,u_char * user,u_char * host,u_char * channel,int quiet)117 remove_matching_bans(u_char *nick, u_char *user, u_char *host, u_char *channel, int quiet)
118 {
119 Channel *ctmp;
120 Ban *btmp;
121 int found = 0, count = 0, mtch = 0, rmtch = 0;
122 /* int nuhl, nml; */
123 u_char nuh[512], tmpbuf[1024];
124
125 /* if called there are invalid arguments, get out */
126 if (!nick || !channel)
127 return;
128
129 /* try to find the specified channel, if it's not in the list or the user doesn't have
130 * ops on it, get out.
131 */
132 if ((ctmp = lookup_channel(channel, from_server, 0)) == NULL || !(ctmp->status & CHAN_CHOP))
133 {
134 put_info("You don't have access to remove bans from %s", channel);
135 return;
136 }
137
138 /* if a mask was specified, remove bans matching it. */
139 if (my_index(nick, '@') && my_index(nick, '!'))
140 my_strncpy(nuh, nick, sizeof(nuh)-1);
141 else
142 {
143 /* if the user and host aren't there, get out */
144 if (!user || !host)
145 {
146 if (!quiet)
147 put_error("invalid mask: %s", nick);
148 return;
149 }
150 /* otherwise, we will remove bans matching nick!user@host */
151 snprintf(nuh, sizeof(nuh)-1, "%s!%s@%s", nick, user, host);
152 }
153 nuh[sizeof(nuh)-1] = '\0';
154
155 tmpbuf[0] = '\0';
156 /* nuhl = my_strlen(nuh); */
157 /* run through the bans and remove all bans matching the nuh */
158 for (btmp = ctmp->bans; btmp; btmp = btmp->next)
159 {
160 /* if the nuh matches the ban or the ban matches the nuh.. */
161
162 /* nml = my_strlen(btmp->ban); */
163 mtch = match(btmp->ban, nuh);
164 rmtch = match(nuh, btmp->ban);
165 /* put_info("mtch: %d, rmtch: %d", mtch, rmtch); */
166 if (mtch || rmtch)
167 {
168 /* add this ban to the list to be removed. */
169 strmcat(tmpbuf, btmp->ban, sizeof(tmpbuf)-1);
170 strmcat(tmpbuf, " ", sizeof(tmpbuf)-1);
171 count++;
172 }
173 /* only four bans can be removed at a time, so if we have four, we remove them and
174 * reset the list.
175 */
176 if (count == 4)
177 {
178 send_to_server("MODE %s -bbbb %s", ctmp->channel, tmpbuf);
179 tmpbuf[0] = '\0';
180 count = 0;
181 found += 4;
182 }
183 }
184
185 /* if there are any left over, we remove them too. */
186 if (count)
187 {
188 send_to_server("MODE %s -%s %s", ctmp->channel, strfill('b', count), tmpbuf);
189 found += count;
190 }
191
192 /* if we aren't supposed to be quiet, tell how many bans were removed. */
193 if (!quiet)
194 {
195 if (!found)
196 put_info("No bans matching %s were found on %s", nuh, ctmp->channel);
197 }
198 }
199
200 /*
201 * make a nice mask for the hostname passed
202 * ex: elite.net = elite.net
203 * 1.1.1.1 = 1.1.1.*
204 * boom.zoom.com = *.zoom.com
205 * c123459-a.oak1.il.home.com = *.oak*.il.home.com
206 * etc.
207 *
208 * if '@' is in "hn" then it will be replaced by '*@' and
209 * anything before it will be removed...
210 */
211 u_char *
cluster(u_char * hn)212 cluster(u_char *hn)
213 {
214 u_char *ptr = NULL, *ptr2;
215 static u_char cltmp[512];
216 int dots_in_host, ip = 0, clidx = 0;
217
218 /* default to returning '*' */
219 memset(cltmp, 0, sizeof(cltmp));
220
221 /* if there is a hostname, try to mask it */
222 if (hn)
223 {
224 /* got a user name? */
225 ptr2 = strrchr(hn, '@');
226 if (ptr2)
227 {
228 cltmp[clidx++] = '*';
229 *ptr2++ = '\0';
230 if (*hn)
231 {
232 hn++;
233 my_strmcat(cltmp, hn, sizeof(cltmp)-1);
234 clidx += my_strlen(hn);
235 }
236 cltmp[clidx++] = '@';
237 hn = ptr2;
238 }
239
240 /* no more stuff? */
241 if (!hn)
242 my_strmcat(cltmp, "ninja!irc@rulez", sizeof(cltmp)-1);
243 else
244 {
245 dots_in_host = how_many(hn, '.');
246 /* its a hostname! */
247 if (dots_in_host <= 1)
248 my_strmcat(cltmp, hn, sizeof(cltmp)-1);
249 else
250 {
251 dma_strcpy(&ptr, hn);
252 switch (dots_in_host)
253 {
254 case 3:
255 /* if we have an ip address... */
256 if (isdigit(ptr[my_strlen(ptr) - 1]))
257 {
258 /* truncate after the last . to ban class c */
259 ptr2 = my_rindex(ptr, '.');
260 *(ptr2+1) = '\0';
261 my_strmcat(cltmp, ptr, sizeof(cltmp)-1);
262 my_strmcat(cltmp, "*", sizeof(cltmp)-1);
263 ip = 1;
264 break;
265 }
266 default:
267 /* hostname with 3 or more parts */
268 ptr2 = my_index(ptr, '.');
269 my_strmcat(cltmp, "*", sizeof(cltmp)-1);
270 my_strmcat(cltmp, ptr2, sizeof(cltmp)-1);
271 break;
272 }
273 dma_Free(&ptr);
274
275 /* now replace digit strings in non-ips with '*' */
276 if (!ip)
277 {
278 int last_star = 0;
279 u_char *lptr;
280
281 for (ptr2 = cltmp; ptr2 && *ptr2; ptr2++)
282 {
283 /* when we find a digit... */
284 if (isdigit(*ptr2))
285 {
286 /* ..skip to the end of the digits */
287 for (lptr = ptr2; lptr && *lptr && isdigit(*lptr); lptr++);
288
289 /* did we run out of input? */
290 if (!lptr || !*lptr)
291 break;
292
293 /* if there's no '*' on either side,
294 * put a '*' in the place of the first digit
295 */
296 if (!last_star && *lptr != '*')
297 *ptr2++ = '*';
298
299 /* we have a '*' in place, move the rest back */
300 memcpy(ptr2, lptr, MIN(my_strlen(lptr)+1, sizeof(cltmp)));
301 }
302 else if (*ptr2 == '*')
303 last_star = 1;
304 else
305 last_star = 0;
306 }
307 }
308 }
309 }
310 }
311 return cltmp;
312 }
313