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