]> jfr.im git - irc/quakenet/newserv.git/blob - trusts/data.c
LUA: add irc_localwallops andirc_localwallusers commands.
[irc/quakenet/newserv.git] / trusts / data.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdio.h>
4
5 #include "../lib/sstring.h"
6 #include "../core/hooks.h"
7 #include "../core/nsmalloc.h"
8 #include "../lib/irc_string.h"
9 #include "trusts.h"
10
11 trustgroup *tglist;
12
13 void th_dbupdatecounts(trusthost *);
14 void tg_dbupdatecounts(trustgroup *);
15
16 static trusthost *th_getnextchildbyhost(trusthost *, trusthost *);
17
18 void trusts_freeall(void) {
19 trustgroup *tg, *ntg;
20 trusthost *th, *nth;
21
22 for(tg=tglist;tg;tg=ntg) {
23 ntg = tg->next;
24 for(th=tg->hosts;th;th=nth) {
25 nth = th->next;
26
27 th_free(th);
28 }
29
30 tg_free(tg, 1);
31 }
32
33 tglist = NULL;
34 }
35
36 trustgroup *tg_getbyid(unsigned int id) {
37 trustgroup *tg;
38
39 for(tg=tglist;tg;tg=tg->next)
40 if(tg->id == id)
41 return tg;
42
43 return NULL;
44 }
45
46 void th_free(trusthost *th) {
47 triggerhook(HOOK_TRUSTS_LOSTHOST, th);
48
49 nsfree(POOL_TRUSTS, th);
50 }
51
52 static void th_updatechildren(trusthost *th) {
53 trusthost *nth = NULL;
54
55 th->children = NULL;
56
57 for(;;) {
58 nth = th_getnextchildbyhost(th, nth);
59 if(!nth)
60 break;
61
62 nth->nextbychild = th->children;
63 th->children = nth;
64 }
65 }
66
67 void th_linktree(void) {
68 trustgroup *tg;
69 trusthost *th;
70
71 /* ugh */
72 for(tg=tglist;tg;tg=tg->next)
73 for(th=tg->hosts;th;th=th->next)
74 th->parent = th_getsmallestsupersetbyhost(th->ip, th->mask);
75
76 for(tg=tglist;tg;tg=tg->next)
77 for(th=tg->hosts;th;th=th->next)
78 if(th->parent)
79 th_updatechildren(th->parent);
80 }
81
82 trusthost *th_add(trusthost *ith) {
83 trusthost *th;
84
85 th = nsmalloc(POOL_TRUSTS, sizeof(trusthost));
86 if(!th)
87 return NULL;
88
89 memcpy(th, ith, sizeof(trusthost));
90
91 th->users = NULL;
92 th->count = 0;
93
94 th->parent = NULL;
95 th->children = NULL;
96
97 th->marker = 0;
98
99 th->next = th->group->hosts;
100 th->group->hosts = th;
101
102 return th;
103 }
104
105 void tg_free(trustgroup *tg, int created) {
106 if(created)
107 triggerhook(HOOK_TRUSTS_LOSTGROUP, tg);
108
109 freesstring(tg->name);
110 freesstring(tg->createdby);
111 freesstring(tg->contact);
112 freesstring(tg->comment);
113 nsfree(POOL_TRUSTS, tg);
114 }
115
116 trustgroup *tg_add(trustgroup *itg) {
117 trustgroup *tg = nsmalloc(POOL_TRUSTS, sizeof(trustgroup));
118 if(!tg)
119 return NULL;
120
121 memcpy(tg, itg, sizeof(trustgroup));
122
123 tg->name = getsstring(tg->name->content, TRUSTNAMELEN);
124 tg->createdby = getsstring(tg->createdby->content, CREATEDBYLEN);
125 tg->contact = getsstring(tg->contact->content, CONTACTLEN);
126 tg->comment = getsstring(tg->comment->content, COMMENTLEN);
127 if(!tg->name || !tg->createdby || !tg->contact || !tg->comment) {
128 tg_free(tg, 0);
129 return NULL;
130 }
131
132 tg->hosts = NULL;
133 tg->marker = 0;
134 tg->count = 0;
135
136 memset(tg->exts, 0, sizeof(tg->exts));
137
138 tg->next = tglist;
139 tglist = tg;
140
141 triggerhook(HOOK_TRUSTS_NEWGROUP, tg);
142
143 return tg;
144 }
145
146 trusthost *th_getbyhost(uint32_t ip) {
147 trustgroup *tg;
148 trusthost *th, *result = NULL;
149 uint32_t mask;
150
151 for(tg=tglist;tg;tg=tg->next) {
152 for(th=tg->hosts;th;th=th->next) {
153 if((ip & th->mask) == th->ip) {
154 if(!result || (th->mask > mask)) {
155 mask = th->mask;
156 result = th;
157 }
158 }
159 }
160 }
161
162 return result;
163 }
164
165 trusthost *th_getbyhostandmask(uint32_t ip, uint32_t mask) {
166 trustgroup *tg;
167 trusthost *th;
168
169 for(tg=tglist;tg;tg=tg->next)
170 for(th=tg->hosts;th;th=th->next)
171 if((th->ip == ip) && (th->mask == mask))
172 return th;
173
174 return NULL;
175 }
176
177 /* returns the ip with the smallest prefix that is still a superset of the given host */
178 trusthost *th_getsmallestsupersetbyhost(uint32_t ip, uint32_t mask) {
179 trustgroup *tg;
180 trusthost *th, *result = NULL;
181 uint32_t smask;
182
183 for(tg=tglist;tg;tg=tg->next) {
184 for(th=tg->hosts;th;th=th->next) {
185 if(th->ip == (ip & th->mask)) {
186 if((th->mask < mask) && (!result || (th->mask > smask))) {
187 smask = th->mask;
188 result = th;
189 }
190 }
191 }
192 }
193
194 return result;
195 }
196
197 /* returns the first ip that is a subset it comes across */
198 trusthost *th_getsubsetbyhost(uint32_t ip, uint32_t mask) {
199 trustgroup *tg;
200 trusthost *th;
201
202 for(tg=tglist;tg;tg=tg->next)
203 for(th=tg->hosts;th;th=th->next)
204 if((th->ip & mask) == ip)
205 if(th->mask > mask)
206 return th;
207
208 return NULL;
209 }
210
211 /* NOT reentrant obviously */
212 static trusthost *th_getnextchildbyhost(trusthost *orig, trusthost *th) {
213 if(!th) {
214 trustgroup *tg;
215
216 tg = tglist;
217 for(tg=tglist;tg;tg=tg->next) {
218 th = tg->hosts;
219 if(th)
220 break;
221 }
222
223 /* INVARIANT: tg => th */
224 if(!tg)
225 return NULL;
226
227 if(th->parent == orig)
228 return th;
229 }
230
231 for(;;) {
232 if(th->next) {
233 th = th->next;
234 } else {
235 if(!th->group->next)
236 return NULL;
237 th = th->group->next->hosts;
238 }
239
240 if(th->parent == orig)
241 return th;
242 }
243 }
244
245 void th_getsuperandsubsets(uint32_t ip, uint32_t mask, trusthost **superset, trusthost **subset) {
246 *superset = th_getsmallestsupersetbyhost(ip, mask);
247 *subset = th_getsubsetbyhost(ip, mask);
248 }
249
250 void trusts_flush(void (*thflush)(trusthost *), void (*tgflush)(trustgroup *)) {
251 trustgroup *tg;
252 trusthost *th;
253 time_t t = time(NULL);
254
255 for(tg=tglist;tg;tg=tg->next) {
256 if(tg->count > 0)
257 tg->lastseen = t;
258
259 tgflush(tg);
260
261 for(th=tg->hosts;th;th=th->next) {
262 if(th->count > 0)
263 th->lastseen = t;
264
265 thflush(th);
266 }
267 }
268 }
269
270 trustgroup *tg_strtotg(char *name) {
271 unsigned long id;
272 trustgroup *tg;
273
274 /* legacy format */
275 if(name[0] == '#') {
276 char *endp;
277 id = strtoul(&name[1], &endp, 10);
278 if(!id || *endp)
279 return NULL;
280
281 return tg_getbyid(id);
282 }
283
284 for(tg=tglist;tg;tg=tg->next)
285 if(!strcmp(name, tg->name->content))
286 return tg;
287
288 return NULL;
289 }
290
291 void th_adjusthosts(trusthost *th, trusthost *superset, trusthost *subset) {
292 /*
293 * First and foremost, CIDR doesn't allow hosts to cross boundaries, i.e. everything with a smaller prefix
294 * is entirely contained with the prefix that is one smaller.
295 * e.g. 0.0.0.0/23, 0.0.0.128/23, you can't have a single prefix for 0.0.0.64-0.0.0.192, instead
296 * you have two, 0.0.0.64/26 and 0.0.0.128/26.
297 *
298 * This makes the code MUCH easier as the entire thing is one huge set/tree.
299 *
300 * Four cases here:
301 * 1: host isn't covered by any existing hosts.
302 * 2: host is covered by a less specific one only, e.g. adding 0.0.0.1/32, while 0.0.0.0/24 already exists.
303 * 3: host is covered by a more specific one only, e.g. adding 0.0.0.0/24 while 0.0.0.1/32 already exists
304 * (note there might be more than one more specific host, e.g. 0.0.0.1/32 and 0.0.0.2/32).
305 * 4: covered by more and less specific cases, e.g. adding 0.0.0.0/24 to: { 0.0.0.1/32, 0.0.0.2/32, 0.0.0.0/16 }.
306 *
307 * CASE 1
308 * ------
309 *
310 * !superset && !subset
311 *
312 * Scan through the host hash and add any clients which match our host, this is exactly the same as case 3
313 * but without needing to check (though checking doesn't hurt), so we'll just use the code for that.
314 *
315 * CASE 2
316 * ------
317 *
318 * superset && !subset
319 *
320 * We have the less specific host in 'superset', we know it is the only one so pull out clients in it's
321 * ->users list matching our new host.
322 * No need to look for extra hosts in the main nick hash as they're all covered already.
323 *
324 * CASE 3
325 * ------
326 *
327 * !superset && subset
328 *
329 * We have one host in 'subset', but there might be more than one, we don't care though!
330 * We can scan the entire host hash and pull out any hosts that match us and don't have
331 * a trust group already, this ignores any with a more specific prefix.
332 *
333 * CASE 4
334 * ------
335 *
336 * superset && subset
337 *
338 * Here we first fix up the ones less specific then us, so we just perform what we did for case 2,
339 * then we perform what we did for case 3.
340 *
341 * So in summary:
342 * CASE 1: DO 3
343 * CASE 2: (work)
344 * CASE 3: (work)
345 * CASE 4: DO 2; DO 3
346 * Or:
347 * if(2 || 4) : DO 2
348 * if(1 || 3 || 4): DO 3
349 */
350
351 /* we let the compiler do the boolean minimisation for clarity reasons */
352
353 if((superset && !subset) || (superset && subset)) { /* cases 2 and 4 */
354 nick *np, *nnp;
355 for(np=superset->users;np;np=nnp) {
356 nnp = nextbytrust(np);
357 if((irc_in_addr_v4_to_int(&np->p_ipaddr) & th->mask) == th->ip) {
358 trusts_lostnick(np, 1);
359 trusts_newnick(np, 1);
360 }
361 }
362 }
363
364 if((!superset && !subset) || (!superset && subset) || (superset && subset)) { /* cases 1, 3 and 4 */
365 nick *np;
366 int i;
367
368 for(i=0;i<NICKHASHSIZE;i++)
369 for(np=nicktable[i];np;np=np->next)
370 if(!gettrusthost(np) && ((irc_in_addr_v4_to_int(&np->p_ipaddr) & th->mask) == th->ip))
371 trusts_newnick(np, 1);
372 }
373 }
374
375 unsigned int nexttgmarker(void) {
376 static unsigned int tgmarker = 0;
377 trustgroup *tg;
378
379 tgmarker++;
380 if(!tgmarker) {
381 /* If we wrapped to zero, zap the marker on all groups */
382 for(tg=tglist;tg;tg=tg->next)
383 tg->marker=0;
384
385 tgmarker++;
386 }
387
388 return tgmarker;
389 }
390
391 unsigned int nextthmarker(void) {
392 static unsigned int thmarker = 0;
393 trustgroup *tg;
394 trusthost *th;
395
396 thmarker++;
397 if(!thmarker) {
398 /* If we wrapped to zero, zap the marker on all hosts */
399 for(tg=tglist;tg;tg=tg->next)
400 for(th=tg->hosts;th;th=th->next)
401 th->marker=0;
402
403 thmarker++;
404 }
405
406 return thmarker;
407 }
408
409 trusthost *th_getbyid(unsigned int id) {
410 trustgroup *tg;
411 trusthost *th;
412
413 for(tg=tglist;tg;tg=tg->next)
414 for(th=tg->hosts;th;th=th->next)
415 if(th->id == id)
416 return th;
417
418 return NULL;
419 }
420
421 int tg_modify(trustgroup *oldtg, trustgroup *newtg) {
422 trustgroup vnewtg;
423
424 memcpy(&vnewtg, oldtg, sizeof(trustgroup));
425
426 /* unfortunately we can't just memcpy the new one over */
427
428 vnewtg.name = getsstring(newtg->name->content, TRUSTNAMELEN);
429 vnewtg.createdby = getsstring(newtg->createdby->content, CREATEDBYLEN);
430 vnewtg.contact = getsstring(newtg->contact->content, CONTACTLEN);
431 vnewtg.comment = getsstring(newtg->comment->content, COMMENTLEN);
432 if(!vnewtg.name || !vnewtg.createdby || !vnewtg.contact || !vnewtg.comment) {
433 freesstring(vnewtg.name);
434 freesstring(vnewtg.createdby);
435 freesstring(vnewtg.contact);
436 freesstring(vnewtg.comment);
437 return 0;
438 }
439
440 /* id remains the same, count/hosts/marker/next/exts are ignored */
441 vnewtg.trustedfor = newtg->trustedfor;
442 vnewtg.mode = newtg->mode;
443 vnewtg.maxperident = newtg->maxperident;
444 vnewtg.maxusage = newtg->maxusage;
445 vnewtg.expires = newtg->expires;
446 vnewtg.lastseen = newtg->lastseen;
447 vnewtg.lastmaxusereset = newtg->lastmaxusereset;
448
449 memcpy(oldtg, &vnewtg, sizeof(trustgroup));
450
451 return 1;
452 }