]> jfr.im git - irc/quakenet/newserv.git/blob - trusts/data.c
Merge.
[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 id = strtoul(&name[1], NULL, 10);
277 if(!id)
278 return NULL;
279
280 for(tg=tglist;tg;tg=tg->next)
281 if(tg->id == id)
282 return tg;
283 }
284
285 for(tg=tglist;tg;tg=tg->next)
286 if(!match(name, tg->name->content))
287 return tg;
288
289 id = strtoul(name, NULL, 10);
290 if(!id)
291 return NULL;
292
293 /* legacy format */
294 for(tg=tglist;tg;tg=tg->next)
295 if(tg->id == id)
296 return tg;
297
298 return NULL;
299 }
300
301 void th_adjusthosts(trusthost *th, trusthost *superset, trusthost *subset) {
302 /*
303 * First and foremost, CIDR doesn't allow hosts to cross boundaries, i.e. everything with a smaller prefix
304 * is entirely contained with the prefix that is one smaller.
305 * 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
306 * you have two, 0.0.0.64/26 and 0.0.0.128/26.
307 *
308 * This makes the code MUCH easier as the entire thing is one huge set/tree.
309 *
310 * Four cases here:
311 * 1: host isn't covered by any existing hosts.
312 * 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.
313 * 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
314 * (note there might be more than one more specific host, e.g. 0.0.0.1/32 and 0.0.0.2/32).
315 * 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 }.
316 *
317 * CASE 1
318 * ------
319 *
320 * !superset && !subset
321 *
322 * Scan through the host hash and add any clients which match our host, this is exactly the same as case 3
323 * but without needing to check (though checking doesn't hurt), so we'll just use the code for that.
324 *
325 * CASE 2
326 * ------
327 *
328 * superset && !subset
329 *
330 * We have the less specific host in 'superset', we know it is the only one so pull out clients in it's
331 * ->users list matching our new host.
332 * No need to look for extra hosts in the main nick hash as they're all covered already.
333 *
334 * CASE 3
335 * ------
336 *
337 * !superset && subset
338 *
339 * We have one host in 'subset', but there might be more than one, we don't care though!
340 * We can scan the entire host hash and pull out any hosts that match us and don't have
341 * a trust group already, this ignores any with a more specific prefix.
342 *
343 * CASE 4
344 * ------
345 *
346 * superset && subset
347 *
348 * Here we first fix up the ones less specific then us, so we just perform what we did for case 2,
349 * then we perform what we did for case 3.
350 *
351 * So in summary:
352 * CASE 1: DO 3
353 * CASE 2: (work)
354 * CASE 3: (work)
355 * CASE 4: DO 2; DO 3
356 * Or:
357 * if(2 || 4) : DO 2
358 * if(1 || 3 || 4): DO 3
359 */
360
361 /* we let the compiler do the boolean minimisation for clarity reasons */
362
363 if((superset && !subset) || (superset && subset)) { /* cases 2 and 4 */
364 nick *np, *nnp;
365 for(np=superset->users;np;np=nnp) {
366 nnp = nextbytrust(np);
367 if((irc_in_addr_v4_to_int(&np->p_ipaddr) & th->mask) == th->ip) {
368 trusts_lostnick(np, 1);
369 trusts_newnick(np, 1);
370 }
371 }
372 }
373
374 if((!superset && !subset) || (!superset && subset) || (superset && subset)) { /* cases 1, 3 and 4 */
375 nick *np;
376 int i;
377
378 for(i=0;i<NICKHASHSIZE;i++)
379 for(np=nicktable[i];np;np=np->next)
380 if(!gettrusthost(np) && ((irc_in_addr_v4_to_int(&np->p_ipaddr) & th->mask) == th->ip))
381 trusts_newnick(np, 1);
382 }
383 }
384
385 unsigned int nexttgmarker(void) {
386 static unsigned int tgmarker = 0;
387 trustgroup *tg;
388
389 tgmarker++;
390 if(!tgmarker) {
391 /* If we wrapped to zero, zap the marker on all groups */
392 for(tg=tglist;tg;tg=tg->next)
393 tg->marker=0;
394
395 tgmarker++;
396 }
397
398 return tgmarker;
399 }
400
401 unsigned int nextthmarker(void) {
402 static unsigned int thmarker = 0;
403 trustgroup *tg;
404 trusthost *th;
405
406 thmarker++;
407 if(!thmarker) {
408 /* If we wrapped to zero, zap the marker on all hosts */
409 for(tg=tglist;tg;tg=tg->next)
410 for(th=tg->hosts;th;th=th->next)
411 th->marker=0;
412
413 thmarker++;
414 }
415
416 return thmarker;
417 }
418
419 trusthost *th_getbyid(unsigned int id) {
420 trustgroup *tg;
421 trusthost *th;
422
423 for(tg=tglist;tg;tg=tg->next)
424 for(th=tg->hosts;th;th=th->next)
425 if(th->id == id)
426 return th;
427
428 return NULL;
429 }
430
431 int tg_modify(trustgroup *oldtg, trustgroup *newtg) {
432 trustgroup vnewtg;
433
434 memcpy(&vnewtg, oldtg, sizeof(trustgroup));
435
436 /* unfortunately we can't just memcpy the new one over */
437
438 vnewtg.name = getsstring(newtg->name->content, TRUSTNAMELEN);
439 vnewtg.createdby = getsstring(newtg->createdby->content, CREATEDBYLEN);
440 vnewtg.contact = getsstring(newtg->contact->content, CONTACTLEN);
441 vnewtg.comment = getsstring(newtg->comment->content, COMMENTLEN);
442 if(!vnewtg.name || !vnewtg.createdby || !vnewtg.contact || !vnewtg.comment) {
443 freesstring(vnewtg.name);
444 freesstring(vnewtg.createdby);
445 freesstring(vnewtg.contact);
446 freesstring(vnewtg.comment);
447 return 0;
448 }
449
450 /* id remains the same, count/hosts/marker/next/exts are ignored */
451 vnewtg.trustedfor = newtg->trustedfor;
452 vnewtg.mode = newtg->mode;
453 vnewtg.maxperident = newtg->maxperident;
454 vnewtg.maxusage = newtg->maxusage;
455 vnewtg.expires = newtg->expires;
456 vnewtg.lastseen = newtg->lastseen;
457 vnewtg.lastmaxusereset = newtg->lastmaxusereset;
458
459 memcpy(oldtg, &vnewtg, sizeof(trustgroup));
460
461 return 1;
462 }