]>
Commit | Line | Data |
---|---|---|
1151d736 P |
1 | #include <stdio.h> |
2 | #include <stdlib.h> | |
3 | #include <stdarg.h> | |
4 | #include <string.h> | |
5 | #include <time.h> | |
6 | #include <assert.h> | |
7 | #include <sys/socket.h> | |
8 | #include <netinet/in.h> | |
9 | #include <arpa/inet.h> | |
10 | ||
11 | #include "../control/control.h" | |
12 | #include "../nick/nick.h" | |
13 | #include "../localuser/localuserchannel.h" | |
14 | #include "../core/hooks.h" | |
15 | #include "../server/server.h" | |
16 | #include "../parser/parser.h" | |
17 | #include "../core/schedule.h" | |
18 | #include "../lib/array.h" | |
19 | #include "../lib/base64.h" | |
20 | #include "../lib/irc_string.h" | |
21 | #include "../lib/splitline.h" | |
1ce4eeea | 22 | #include "../core/nsmalloc.h" |
1151d736 P |
23 | |
24 | #include "gline.h" | |
25 | ||
26 | gline* glinelist = 0, *glinelistnonnode = 0; | |
27 | ||
28 | int glinecount = 0; | |
29 | int badchancount = 0; | |
30 | int rnglinecount = 0; | |
1ce4eeea | 31 | int gl_nodeext = -1; |
1151d736 P |
32 | |
33 | /* | |
34 | <prefix> GL <target> [!][+|-|>|<]<mask> [<expiration>] [<lastmod>] | |
35 | [<lifetime>] [:<reason>] | |
36 | ||
37 | */ | |
38 | ||
39 | void _init() { | |
40 | gl_nodeext = registernodeext("gline"); | |
41 | ||
1ce4eeea | 42 | if ( gl_nodeext == -1 ) { |
1151d736 P |
43 | Error("gline", ERR_FATAL, "Could not register a required node extension (gline)"); |
44 | return; | |
45 | } | |
46 | ||
47 | registerserverhandler("GL", &handleglinemsg, 6); | |
48 | ||
49 | /* send reburst command to get glines from before we registered handler */ | |
50 | irc_send("%s RB G", mynumeric->content); | |
51 | } | |
52 | ||
53 | void _fini() { | |
54 | gline *gl, *ngl; | |
55 | ||
56 | deregisterserverhandler("GL", &handleglinemsg); | |
57 | ||
58 | for (gl=glinelist;gl;gl=ngl) { | |
59 | ngl=gl->next; | |
60 | freegline(gl); | |
61 | } | |
62 | glinelist = NULL; | |
63 | ||
1ce4eeea | 64 | if (gl_nodeext != -1) |
1151d736 | 65 | releasenodeext(gl_nodeext); |
1ce4eeea P |
66 | |
67 | nsfreeall(POOL_GLINE); | |
1151d736 P |
68 | } |
69 | ||
70 | int gline_setnick(nick *np, int duration, char *reason ) { | |
71 | ||
72 | } | |
73 | ||
74 | int gline_setnode(patricia_node_t *node ) { | |
75 | ||
76 | } | |
77 | ||
78 | int gline_setmask(char *mask, int duration, char *reason ) { | |
79 | ||
80 | } | |
81 | ||
82 | gline* gline_add(long creatornum, sstring *creator, char *mask, char *reason, time_t expires, time_t lastmod, time_t lifetime) { | |
83 | gline* gl; | |
84 | char glineiddata[1024]; | |
85 | ||
86 | if ( !(gl=gline_processmask(mask))) { /* sets up nick,user,host,node and flags */ | |
87 | /* couldn't process gline mask */ | |
88 | Error("gline", ERR_WARNING, "Tried to add malformed G-Line %s!", mask); | |
89 | return 0; | |
90 | } | |
91 | ||
92 | gl->creator = creator; | |
93 | gl->numeric = creatornum; | |
94 | ||
95 | /* it's not unreasonable to assume gline is active, if we're adding a deactivated gline, we can remove this later */ | |
96 | gl->flags = GLINE_ACTIVE; | |
97 | ||
98 | ||
99 | /* set up gline id */ | |
100 | snprintf(glineiddata, sizeof(glineiddata), "gline %s %s", mask, reason); | |
101 | gl->glineid = crc32(glineiddata); | |
102 | ||
103 | gl->reason = getsstring(reason, 255); /*TODO@@@ */ | |
104 | gl->expires = expires; | |
105 | gl->lastmod = lastmod; | |
106 | gl->lifetime = lifetime; | |
107 | ||
108 | /* Storage of glines */ | |
109 | /* ipbased glines are stored at node->ext[gl_nodeext] | |
110 | * other glines are stored in seperate linked list (for now) */ | |
111 | if (gl->flags & GLINE_IPMASK) { | |
112 | gl->nextbynode = gl->node->exts[gl_nodeext]; | |
113 | gl->node->exts[gl_nodeext] = gl; | |
114 | } else { | |
115 | gl->nextbynonnode = glinelistnonnode; | |
116 | glinelistnonnode = gl; | |
117 | } | |
118 | ||
119 | gl->next = glinelist; | |
120 | glinelist = gl; | |
121 | ||
122 | return gl; | |
123 | } | |
124 | ||
125 | /* returns 1 on success, 0 on a bad mask */ | |
126 | gline* gline_processmask(char *mask) { | |
127 | /* populate gl-> user,host,node,nick and set appropriate flags */ | |
128 | int len; | |
129 | int foundat=-1,foundbang=-1; | |
130 | int foundwild=0; | |
131 | int i; | |
132 | struct irc_in_addr sin; | |
133 | unsigned char bits; | |
134 | gline *gl = NULL; | |
135 | ||
136 | if (!(gl = newgline())) { | |
137 | Error("gline", ERR_ERROR, "Failed to allocate new gline"); | |
138 | return 0; | |
139 | } | |
140 | ||
141 | len=strlen(mask); | |
142 | ||
143 | switch (*mask ) { | |
144 | case '#': | |
145 | case '&': | |
146 | gl->flags |= GLINE_BADCHAN; | |
147 | gl->user = getsstring(mask, CHANNELLEN); | |
148 | return gl; | |
149 | case '$': | |
150 | switch (mask[1]) { | |
151 | case 'R': | |
152 | gl->flags |= GLINE_REALNAME; | |
153 | break; | |
154 | default: | |
155 | Error("gline", ERR_WARNING, "Tried to add malformed G-Line %s!", mask); | |
156 | return 0; | |
157 | } | |
158 | gl->user = getsstring(mask,REALLEN); | |
159 | return gl; | |
160 | default: | |
161 | /* Default case of some host/ip/cidr mask */ | |
162 | for (i=(len-1);i>=0;i--) { | |
163 | if (mask[i]=='@') { | |
164 | /* host */ | |
165 | if ((len-i)-1 > HOSTLEN) { | |
166 | /* host too long */ | |
167 | return 0; | |
168 | } else if (i==(len-1)) { | |
169 | /* no host supplied aka gline ends @ */ | |
170 | return 0; | |
171 | } else if (i==(len-2) && mask[i+1]=='*') { | |
172 | /* Special case: "@*" */ | |
173 | gl->flags |= GLINE_HOSTANY; | |
174 | gl->host=NULL; | |
175 | } else { | |
176 | if (ipmask_parse(&mask[i+1], &sin, &bits) == 0) { | |
177 | /* we have some host string */ | |
178 | gl->host=getsstring(&mask[i+1],HOSTLEN); | |
179 | if (foundwild) { | |
180 | gl->flags |= GLINE_HOSTMASK; | |
181 | } else { | |
182 | gl->flags |= GLINE_HOSTEXACT; | |
183 | } | |
184 | } else { | |
185 | /* we have a / so cidr gline */ | |
186 | Error("gline", ERR_WARNING, "CIDR: %s", &mask[i+1]); | |
187 | gl->node = refnode(iptree, &sin, bits); | |
188 | gl->flags |= GLINE_IPMASK; | |
189 | } | |
190 | } | |
191 | foundat=i; | |
192 | break; | |
193 | } else if (mask[i]=='?' || mask[i]=='*') { | |
194 | if (!foundwild) /* Mark last wildcard in string */ | |
195 | foundwild=i; | |
196 | } | |
197 | } | |
198 | } | |
199 | /*TODO set hostexact/hostmask */ | |
200 | if (foundat<0) { | |
201 | /* If there wasn't an @, this ban matches any host */ | |
202 | gl->host=NULL; | |
203 | gl->flags |= GLINE_HOSTANY; | |
204 | } | |
205 | ||
206 | foundwild=0; | |
207 | ||
208 | for (i=0;i<foundat;i++) { | |
209 | if (mask[i]=='!') { | |
210 | if (i==0) { | |
211 | /* Invalid mask: nick is empty */ | |
212 | gl->flags |= GLINE_NICKNULL; | |
213 | gl->nick=NULL; | |
214 | } else if (i==1 && mask[0]=='*') { | |
215 | /* matches any nick */ | |
216 | gl->flags |= GLINE_NICKANY; | |
217 | gl->nick=NULL; | |
218 | } else { | |
219 | if (i>NICKLEN) { | |
220 | /* too long: just take the first NICKLEN chars */ | |
221 | gl->nick=getsstring(mask,NICKLEN); | |
222 | } else { | |
223 | gl->nick=getsstring(mask,i); | |
224 | } | |
225 | if (foundwild) | |
226 | gl->flags |= GLINE_NICKMASK; | |
227 | else | |
228 | gl->flags |= GLINE_NICKEXACT; | |
229 | } | |
230 | foundbang=i; | |
231 | break; | |
232 | } else if (mask[i]=='?' || mask[i]=='*') { | |
233 | if (i<NICKLEN) { | |
234 | foundwild=1; | |
235 | } | |
236 | } | |
237 | } | |
238 | ||
239 | if (foundbang<0) { | |
240 | /* We didn't find a !, what we do now depends on what happened | |
241 | * with the @ */ | |
242 | if (foundat<0) { | |
243 | /* A gline with no ! or @ is treated as a nick ban only */ | |
244 | /* Note that we've special-cased "*" at the top, so we can only | |
245 | * hit the MASK or EXACT case here. */ | |
246 | if (len>NICKLEN) | |
247 | gl->nick=getsstring(mask,NICKLEN); | |
248 | else | |
249 | gl->nick=getsstring(mask,len); | |
250 | ||
251 | if (foundwild) | |
252 | gl->flags |= GLINE_NICKMASK; | |
253 | else | |
254 | gl->flags |= GLINE_NICKEXACT; | |
255 | ||
256 | gl->flags |= (GLINE_USERANY | GLINE_HOSTANY); | |
257 | gl->host=NULL; | |
258 | gl->user=NULL; | |
259 | } else { | |
260 | /* A gline with @ only is treated as user@host */ | |
261 | gl->nick=NULL; | |
262 | gl->flags |= GLINE_NICKANY; | |
263 | } | |
264 | } | |
265 | ||
266 | if (foundat>=0) { | |
267 | /* We found an @, so everything between foundbang+1 and foundat-1 is supposed to be ident */ | |
268 | /* This is true even if there was no !.. */ | |
269 | if (foundat==(foundbang+1)) { | |
270 | /* empty ident matches nothing */ /*@@@TODO: * for glines? */ | |
271 | gl->flags |= (/*GLINE_INVALID |*/ GLINE_USERNULL); | |
272 | gl->user=NULL; | |
273 | } else if (foundat - foundbang - 1 > USERLEN) { | |
274 | /* It's too long.. */ | |
275 | return 0; | |
276 | } else if ((foundat - foundbang - 1 == 1) && mask[foundbang+1]=='*') { | |
277 | gl->user=NULL; | |
278 | gl->flags |= GLINE_USERANY; | |
279 | } else { | |
280 | gl->user=getsstring(&mask[foundbang+1],(foundat-foundbang-1)); | |
281 | if (strchr(gl->user->content,'*') || strchr(gl->user->content,'?')) | |
282 | gl->flags |= GLINE_USERMASK; | |
283 | else | |
284 | gl->flags |= GLINE_USEREXACT; | |
285 | } | |
286 | /* Username part can't contain an @ */ | |
287 | if (gl->user && strchr(gl->user->content,'@')) { | |
288 | //gl->flags |= CHANBAN_INVALID; | |
289 | } | |
290 | } | |
291 | ||
292 | assert(gl->flags & (GLINE_USEREXACT | GLINE_USERMASK | GLINE_USERANY | GLINE_USERNULL)); | |
293 | assert(gl->flags & (GLINE_NICKEXACT | GLINE_NICKMASK | GLINE_NICKANY | GLINE_NICKNULL)); | |
294 | assert(gl->flags & (GLINE_HOSTEXACT | GLINE_HOSTMASK | GLINE_HOSTANY | GLINE_HOSTNULL | GLINE_IPMASK)); | |
295 | ||
296 | return gl; | |
297 | } | |
298 | ||
299 | gline *gline_find( char *mask) { | |
300 | gline *gl; | |
301 | gline *globalgline; | |
302 | ||
303 | if( !(globalgline=gline_processmask(mask))) { | |
304 | /* gline mask couldn't be processed */ | |
305 | return 0; | |
306 | } | |
307 | ||
308 | if (globalgline->flags & GLINE_IPMASK) { | |
309 | gl = globalgline->node->exts[gl_nodeext]; | |
310 | while (gl) { | |
311 | if ( gline_match( globalgline, gl) ) { | |
312 | freegline(globalgline); | |
313 | return gl; | |
314 | } | |
315 | gl = gl->nextbynode; | |
316 | } | |
317 | } else { | |
318 | gl = glinelist; | |
319 | while (gl) { | |
320 | if ( gline_match( globalgline, gl ) ) { | |
321 | freegline(globalgline); | |
322 | return gl; | |
323 | } | |
324 | gl = gl->nextbynonnode; | |
325 | } | |
326 | } | |
327 | freegline(globalgline); | |
328 | return 0; | |
329 | } | |
330 | ||
331 | /* returns non-zero on match */ | |
332 | int gline_match ( gline *gla, gline *glb) { | |
333 | if ((!gla->nick && glb->nick) || (gla->nick && !glb->nick)) | |
334 | return 0; | |
335 | ||
336 | if (gla->nick && ircd_strcmp(gla->nick->content,glb->nick->content)) | |
337 | return 0; | |
338 | ||
339 | if ((!gla->user && glb->user) || (gla->user && !glb->user)) | |
340 | return 0; | |
341 | ||
342 | if (gla->user && ircd_strcmp(gla->user->content,glb->user->content)) | |
343 | return 0; | |
344 | ||
345 | if ((!gla->host && glb->host) || (gla->host && !glb->host)) | |
346 | return 0; | |
347 | ||
348 | if (gla->host && ircd_strcmp(gla->host->content,glb->host->content)) | |
349 | return 0; | |
350 | ||
351 | /* TODO @@@ match bits flags */ | |
352 | return 1; | |
353 | } | |
354 | ||
355 | void gline_send(gline *gl) { | |
356 | ||
357 | } |