]> jfr.im git - irc/quakenet/newserv.git/blame - trusts/trusts_management.c
Implement removing TGs and THs.
[irc/quakenet/newserv.git] / trusts / trusts_management.c
CommitLineData
35449aa5
CP
1#include <stdio.h>
2#include <string.h>
3#include "../control/control.h"
4#include "../lib/irc_string.h"
5#include "../lib/strlfunc.h"
82a316e7 6#include "../core/config.h"
2ab0a1e7 7#include "../lib/stringbuf.h"
35449aa5
CP
8#include "trusts.h"
9
10static void registercommands(int, void *);
11static void deregistercommands(int, void *);
12
2ab0a1e7
CP
13typedef int (*trustmodificationfn)(trustgroup *, char *arg);
14
15struct trustmodification {
1d9ccd69 16 char name[50];
2ab0a1e7
CP
17 trustmodificationfn fn;
18};
19
35449aa5
CP
20static int trusts_cmdtrustadd(void *source, int cargc, char **cargv) {
21 trustgroup *tg;
22 nick *sender = source;
23 char *host;
24 uint32_t ip, mask;
25 trusthost *th, *superset, *subset;
26
27 if(cargc < 2)
28 return CMD_USAGE;
29
30 tg = tg_strtotg(cargv[0]);
31 if(!tg) {
32 controlreply(sender, "Couldn't look up trustgroup.");
33 return CMD_ERROR;
34 }
35
36 host = cargv[1];
37 if(!trusts_str2cidr(host, &ip, &mask)) {
38 controlreply(sender, "Invalid host.");
39 return CMD_ERROR;
40 }
41
42 /* OKAY! Lots of checking here!
43 *
44 * Need to check:
45 * - host isn't already covered by given group (reject if it is)
46 * - host doesn't already exist exactly already (reject if it does)
47 * - host is more specific than an existing one (warn if it is, fix up later)
48 * - host is less specific than an existing one (warn if it is, don't need to do anything special)
49 */
50
51 for(th=tg->hosts;th;th=th->next) {
52 if(th->ip == (ip & th->mask)) {
53 controlreply(sender, "This host (or part of it) is already covered in the given group.");
54 return CMD_ERROR;
55 }
56 }
57
58 if(th_getbyhostandmask(ip, mask)) {
59 controlreply(sender, "This host already exists in another group with the same mask.");
60 return CMD_ERROR;
61 }
62
63 /* this function will set both to NULL if it's equal, hence the check above */
64 th_getsuperandsubsets(ip, mask, &superset, &subset);
65 if(superset) {
66 /* a superset exists for us, we will be more specific than one existing host */
67
68 controlreply(sender, "Warning: this host already exists in another group, but this new host will override it as it has a smaller prefix.");
69 }
70 if(subset) {
71 /* a subset of us exists, we will be less specific than some existing hosts */
72
73 controlreply(sender, "Warning: this host already exists in at least one other group, the new host has a larger prefix and therefore will not override those hosts.");
74 }
75 if(superset || subset)
76 controlreply(sender, "Adding anyway...");
77
78 th = th_new(tg, host);
79 if(!th) {
80 controlreply(sender, "An error occured adding the host to the group.");
81 return CMD_ERROR;
82 }
83
84 controlreply(sender, "Host added.");
82a316e7
CP
85 triggerhook(HOOK_TRUSTS_ADDHOST, th);
86
7e11a2c6 87 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTADD'ed host %s to group '%s'", controlid(sender), host, th->group->name->content);
35449aa5
CP
88
89 return CMD_OK;
90}
91
92static int trusts_cmdtrustgroupadd(void *source, int cargc, char **cargv) {
93 nick *sender = source;
94 char *name, *contact, *comment, createdby[ACCOUNTLEN + 2];
95 unsigned int howmany, maxperident, enforceident;
96 time_t howlong;
82a316e7 97 trustgroup *tg, itg;
35449aa5
CP
98
99 if(cargc < 6)
100 return CMD_USAGE;
101
102 name = cargv[0];
103 howmany = strtoul(cargv[1], NULL, 10);
2ab0a1e7 104 if(!howmany || (howmany > MAXTRUSTEDFOR)) {
35449aa5
CP
105 controlreply(sender, "Bad value maximum number of clients.");
106 return CMD_ERROR;
107 }
108
109 howlong = durationtolong(cargv[2]);
2ab0a1e7 110 if((howlong <= 0) || (howlong > MAXDURATION)) {
35449aa5
CP
111 controlreply(sender, "Invalid duration supplied.");
112 return CMD_ERROR;
113 }
114
115 maxperident = strtoul(cargv[3], NULL, 10);
2ab0a1e7 116 if(!howmany || (maxperident > MAXPERIDENT)) {
35449aa5
CP
117 controlreply(sender, "Bad value for max per ident.");
118 return CMD_ERROR;
119 }
120
121 if(cargv[4][0] != '1' && cargv[4][0] != '0') {
122 controlreply(sender, "Bad value for enforce ident (use 0 or 1).");
123 return CMD_ERROR;
124 }
125 enforceident = cargv[4][0] == '1';
126
127 contact = cargv[5];
128
129 if(cargc < 7) {
130 comment = "(no comment)";
131 } else {
132 comment = cargv[6];
133 }
134
135 /* don't allow #id or id forms */
136 if((name[0] == '#') || strtoul(name, NULL, 10)) {
137 controlreply(sender, "Invalid trustgroup name.");
138 return CMD_ERROR;
139 }
140
141 tg = tg_strtotg(name);
142 if(tg) {
143 controlreply(sender, "A group with that name already exists");
144 return CMD_ERROR;
145 }
146
147 snprintf(createdby, sizeof(createdby), "#%s", sender->authname);
148
82a316e7
CP
149 itg.trustedfor = howmany;
150 itg.mode = enforceident;
151 itg.maxperident = maxperident;
152 itg.expires = howlong + time(NULL);
1f685425 153 itg.createdby = getsstring(createdby, CREATEDBYLEN);
82a316e7
CP
154 itg.contact = getsstring(contact, CONTACTLEN);
155 itg.comment = getsstring(comment, COMMENTLEN);
156 itg.name = getsstring(name, TRUSTNAMELEN);
157
158 if(itg.createdby && itg.contact && itg.comment && itg.name) {
159 tg = tg_new(&itg);
160 } else {
161 tg = NULL;
162 }
163
164 freesstring(itg.createdby);
165 freesstring(itg.comment);
166 freesstring(itg.name);
167 freesstring(itg.contact);
168
35449aa5
CP
169 if(!tg) {
170 controlreply(sender, "An error occured adding the trustgroup.");
171 return CMD_ERROR;
172 }
173
174 controlreply(sender, "Group added.");
82a316e7
CP
175 triggerhook(HOOK_TRUSTS_ADDGROUP, tg);
176
7e11a2c6 177 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTGROUPADD'ed '%s'", controlid(sender), tg->name->content);
35449aa5
CP
178
179 return CMD_OK;
180}
181
2ab0a1e7
CP
182static int trusts_cmdtrustgroupdel(void *source, int cargc, char **cargv) {
183 trustgroup *tg;
184 nick *sender = source;
185
186 if(cargc < 1)
187 return CMD_USAGE;
188
189 tg = tg_strtotg(cargv[0]);
190 if(!tg) {
191 controlreply(sender, "Couldn't look up trustgroup.");
192 return CMD_ERROR;
193 }
194
195 if(tg->hosts) {
196 controlreply(sender, "Delete all hosts before deleting the group.");
197 return CMD_ERROR;
198 }
199
7e11a2c6
CP
200 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTGROUPDEL'ed '%s'.", controlid(sender), tg->name->content);
201
2ab0a1e7
CP
202 triggerhook(HOOK_TRUSTS_DELGROUP, tg);
203 tg_delete(tg);
204 controlreply(sender, "Group deleted.");
205
2ab0a1e7
CP
206 return CMD_OK;
207}
208
209static int trusts_cmdtrustdel(void *source, int cargc, char **cargv) {
210 trustgroup *tg;
211 trusthost *th;
212 uint32_t ip, mask;
213 nick *sender = source;
7e11a2c6 214 char *host;
2ab0a1e7
CP
215
216 if(cargc < 2)
217 return CMD_USAGE;
218
219 tg = tg_strtotg(cargv[0]);
220 if(!tg) {
221 controlreply(sender, "Couldn't look up trustgroup.");
222 return CMD_ERROR;
223 }
224
7e11a2c6
CP
225 host = cargv[1];
226 if(!trusts_str2cidr(host, &ip, &mask)) {
2ab0a1e7
CP
227 controlreply(sender, "Invalid IP/mask.");
228 return CMD_ERROR;
229 }
230
231 for(th=tg->hosts;th;th=th->next)
232 if((th->ip == ip) && (th->mask == mask))
233 break;
234
235 if(!th) {
236 controlreply(sender, "Couldn't find that host in that group.");
237 return CMD_ERROR;
238 }
239
240 triggerhook(HOOK_TRUSTS_DELHOST, th);
241 th_delete(th);
242 controlreply(sender, "Host deleted.");
243
7e11a2c6 244 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTDEL'ed %s from group '%s'.", controlid(sender), host, tg->name->content);
2ab0a1e7 245
7e11a2c6 246 return CMD_OK;
2ab0a1e7
CP
247}
248
249static int modifycomment(trustgroup *tg, char *comment) {
250 sstring *n = getsstring(comment, COMMENTLEN);
251 if(!n)
252 return 0;
253
254 freesstring(tg->comment);
255 tg->comment = n;
256
257 return 1;
258}
259
260static int modifycontact(trustgroup *tg, char *contact) {
261 sstring *n = getsstring(contact, CONTACTLEN);
262 if(!n)
263 return 0;
264
265 freesstring(tg->contact);
266 tg->contact = n;
267
268 return 1;
269}
270
271static int modifytrustedfor(trustgroup *tg, char *num) {
272 unsigned int trustedfor = strtoul(num, NULL, 10);
273
274 if(trustedfor > MAXTRUSTEDFOR)
275 return 0;
276
277 tg->trustedfor = trustedfor;
278
279 return 1;
280}
281
1f685425
CP
282static int modifymaxperident(trustgroup *tg, char *num) {
283 unsigned int maxperident = strtoul(num, NULL, 10);
2ab0a1e7 284
1f685425 285 if(maxperident > MAXPERIDENT)
2ab0a1e7
CP
286 return 0;
287
1f685425 288 tg->maxperident = maxperident;
2ab0a1e7
CP
289
290 return 1;
291}
292
293static int modifyenforceident(trustgroup *tg, char *num) {
294 if(num[0] == '1') {
295 tg->mode = 1;
296 } else if(num[0] == '0') {
297 tg->mode = 0;
298 } else {
299 return 0;
300 }
301
302 return 1;
303}
304
305static int modifyexpires(trustgroup *tg, char *expires) {
306 int howlong = durationtolong(expires);
307
308 if((howlong <= 0) || (howlong > MAXDURATION))
309 return 0;
310
311 tg->expires = time(NULL) + howlong;
312
313 return 1;
314}
315
1d9ccd69
CP
316static array trustmods_a;
317static struct trustmodification *trustmods;
2ab0a1e7
CP
318
319static int trusts_cmdtrustgroupmodify(void *source, int cargc, char **cargv) {
320 trustgroup *tg;
321 nick *sender = source;
322 char *what, *to, validfields[512];
2ab0a1e7
CP
323 int i;
324 StringBuf b;
2ab0a1e7
CP
325
326 if(cargc < 3)
327 return CMD_USAGE;
328
329 tg = tg_strtotg(cargv[0]);
330 if(!tg) {
331 controlreply(sender, "Couldn't look up trustgroup.");
332 return CMD_ERROR;
333 }
334
335 what = cargv[1];
336 to = cargv[2];
337
338 sbinit(&b, validfields, sizeof(validfields));
1d9ccd69
CP
339 for(i=0;i<trustmods_a.cursi;i++) {
340 if(!strcmp(what, trustmods[i].name)) {
341 if(!(trustmods[i].fn)(tg, to)) {
2ab0a1e7
CP
342 controlreply(sender, "An error occured changing that property, check the syntax.");
343 return CMD_ERROR;
344 }
345 break;
346 }
347
348 if(i > 0)
349 sbaddstr(&b, ", ");
1d9ccd69 350 sbaddstr(&b, trustmods[i].name);
2ab0a1e7
CP
351 }
352
1d9ccd69 353 if(i == trustmods_a.cursi) {
2ab0a1e7
CP
354 sbterminate(&b);
355 controlreply(sender, "No such field, valid fields are: %s", validfields);
356 return CMD_ERROR;
357 }
358
359 triggerhook(HOOK_TRUSTS_MODIFYGROUP, tg);
360 tg_update(tg);
361 controlreply(sender, "Group modified.");
362
7e11a2c6
CP
363 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTMODIFIED'ed group '%s' (field: %s, value: %s)", controlid(sender), tg->name->content, what, to);
364
2ab0a1e7
CP
365 return CMD_OK;
366}
367
35449aa5
CP
368static int commandsregistered;
369
370static void registercommands(int hooknum, void *arg) {
371 if(commandsregistered)
372 return;
373 commandsregistered = 1;
374
375 registercontrolhelpcmd("trustgroupadd", NO_OPER, 6, trusts_cmdtrustgroupadd, "Usage: trustgroupadd <name> <howmany> <howlong> <maxperident> <enforceident> <contact> ?comment?");
376 registercontrolhelpcmd("trustadd", NO_OPER, 2, trusts_cmdtrustadd, "Usage: trustadd <#id|name|id> <host>");
2ab0a1e7
CP
377 registercontrolhelpcmd("trustgroupdel", NO_OPER, 1, trusts_cmdtrustgroupdel, "Usage: trustgroupdel <#id|name|id>");
378 registercontrolhelpcmd("trustdel", NO_OPER, 2, trusts_cmdtrustdel, "Usage: trustdel <#id|name|id> <ip/mask>");
379 registercontrolhelpcmd("trustgroupmodify", NO_OPER, 3, trusts_cmdtrustgroupmodify, "Usage: trustgroupmodify <#id|name|id> <field> <new value>");
35449aa5
CP
380}
381
382static void deregistercommands(int hooknum, void *arg) {
383 if(!commandsregistered)
384 return;
385 commandsregistered = 0;
386
387 deregistercontrolcmd("trustgroupadd", trusts_cmdtrustgroupadd);
388 deregistercontrolcmd("trustadd", trusts_cmdtrustadd);
2ab0a1e7
CP
389 deregistercontrolcmd("trustgroupdel", trusts_cmdtrustgroupdel);
390 deregistercontrolcmd("trustdel", trusts_cmdtrustdel);
391 deregistercontrolcmd("trustgroupmodify", trusts_cmdtrustgroupmodify);
35449aa5
CP
392}
393
82a316e7
CP
394static int loaded;
395
1d9ccd69
CP
396#define _ms_(x) (struct trustmodification){ .name = # x, .fn = modify ## x }
397#define MS(x) { int slot = array_getfreeslot(&trustmods_a); trustmods = (struct trustmodification *)trustmods_a.content; memcpy(&trustmods[slot], &_ms_(x), sizeof(struct trustmodification)); }
398
399static void setupmods(void) {
400 MS(expires);
401 MS(enforceident);
402 MS(maxperident);
403 MS(contact);
404 MS(comment);
405 MS(trustedfor);
406}
407
35449aa5 408void _init(void) {
82a316e7
CP
409 sstring *m;
410
1d9ccd69
CP
411 array_init(&trustmods_a, sizeof(struct trustmodification));
412 setupmods();
413
82a316e7
CP
414 m = getconfigitem("trusts", "master");
415 if(!m || (atoi(m->content) != 1)) {
416 Error("trusts_management", ERR_ERROR, "Not a master server, not loaded.");
417 return;
418 }
419
420 loaded = 1;
421
35449aa5
CP
422 registerhook(HOOK_TRUSTS_DB_LOADED, registercommands);
423 registerhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
424
425 if(trustsdbloaded)
426 registercommands(0, NULL);
427}
428
429void _fini(void) {
1d9ccd69
CP
430 array_free(&trustmods_a);
431
82a316e7
CP
432 if(!loaded)
433 return;
434
35449aa5
CP
435 deregisterhook(HOOK_TRUSTS_DB_LOADED, registercommands);
436 deregisterhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
437
438 deregistercommands(0, NULL);
439}