]> jfr.im git - irc/quakenet/newserv.git/blob - trusts/trusts_management.c
PQSQL: show the error message on query error.
[irc/quakenet/newserv.git] / trusts / trusts_management.c
1 #include <stdio.h>
2 #include <string.h>
3 #include "../control/control.h"
4 #include "../lib/irc_string.h"
5 #include "../lib/strlfunc.h"
6 #include "../core/config.h"
7 #include "../lib/stringbuf.h"
8 #include "trusts.h"
9
10 static void registercommands(int, void *);
11 static void deregistercommands(int, void *);
12
13 typedef int (*trustmodificationfn)(trustgroup *, char *arg);
14
15 struct trustmodification {
16 char name[50];
17 trustmodificationfn fn;
18 };
19
20 static 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.");
85 triggerhook(HOOK_TRUSTS_ADDHOST, th);
86
87 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTADD'ed host %s to group '%s'", controlid(sender), host, th->group->name->content);
88
89 return CMD_OK;
90 }
91
92 static 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;
97 trustgroup *tg, itg;
98
99 if(cargc < 6)
100 return CMD_USAGE;
101
102 name = cargv[0];
103 howmany = strtoul(cargv[1], NULL, 10);
104 if(!howmany || (howmany > MAXTRUSTEDFOR)) {
105 controlreply(sender, "Bad value maximum number of clients.");
106 return CMD_ERROR;
107 }
108
109 howlong = durationtolong(cargv[2]);
110 if((howlong <= 0) || (howlong > MAXDURATION)) {
111 controlreply(sender, "Invalid duration supplied.");
112 return CMD_ERROR;
113 }
114
115 maxperident = strtoul(cargv[3], NULL, 10);
116 if(!howmany || (maxperident > MAXPERIDENT)) {
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
149 itg.trustedfor = howmany;
150 itg.mode = enforceident;
151 itg.maxperident = maxperident;
152 itg.expires = howlong + time(NULL);
153 itg.createdby = getsstring(createdby, CREATEDBYLEN);
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
169 if(!tg) {
170 controlreply(sender, "An error occured adding the trustgroup.");
171 return CMD_ERROR;
172 }
173
174 controlreply(sender, "Group added.");
175 triggerhook(HOOK_TRUSTS_ADDGROUP, tg);
176
177 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTGROUPADD'ed '%s'", controlid(sender), tg->name->content);
178
179 return CMD_OK;
180 }
181
182 static 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
200 controlreply(sender, "TODO: NOT IMPLEMENTED");
201
202 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTGROUPDEL'ed '%s'.", controlid(sender), tg->name->content);
203
204 triggerhook(HOOK_TRUSTS_DELGROUP, tg);
205 tg_delete(tg);
206 controlreply(sender, "Group deleted.");
207
208 return CMD_OK;
209 }
210
211 static int trusts_cmdtrustdel(void *source, int cargc, char **cargv) {
212 trustgroup *tg;
213 trusthost *th;
214 uint32_t ip, mask;
215 nick *sender = source;
216 char *host;
217
218 if(cargc < 2)
219 return CMD_USAGE;
220
221 tg = tg_strtotg(cargv[0]);
222 if(!tg) {
223 controlreply(sender, "Couldn't look up trustgroup.");
224 return CMD_ERROR;
225 }
226
227 host = cargv[1];
228 if(!trusts_str2cidr(host, &ip, &mask)) {
229 controlreply(sender, "Invalid IP/mask.");
230 return CMD_ERROR;
231 }
232
233 for(th=tg->hosts;th;th=th->next)
234 if((th->ip == ip) && (th->mask == mask))
235 break;
236
237 if(!th) {
238 controlreply(sender, "Couldn't find that host in that group.");
239 return CMD_ERROR;
240 }
241
242 controlreply(sender, "TODO: NOT IMPLEMENTED");
243
244 triggerhook(HOOK_TRUSTS_DELHOST, th);
245 th_delete(th);
246 controlreply(sender, "Host deleted.");
247
248 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTDEL'ed %s from group '%s'.", controlid(sender), host, tg->name->content);
249
250 return CMD_OK;
251 }
252
253 static int modifycomment(trustgroup *tg, char *comment) {
254 sstring *n = getsstring(comment, COMMENTLEN);
255 if(!n)
256 return 0;
257
258 freesstring(tg->comment);
259 tg->comment = n;
260
261 return 1;
262 }
263
264 static int modifycontact(trustgroup *tg, char *contact) {
265 sstring *n = getsstring(contact, CONTACTLEN);
266 if(!n)
267 return 0;
268
269 freesstring(tg->contact);
270 tg->contact = n;
271
272 return 1;
273 }
274
275 static int modifytrustedfor(trustgroup *tg, char *num) {
276 unsigned int trustedfor = strtoul(num, NULL, 10);
277
278 if(trustedfor > MAXTRUSTEDFOR)
279 return 0;
280
281 tg->trustedfor = trustedfor;
282
283 return 1;
284 }
285
286 static int modifymaxperident(trustgroup *tg, char *num) {
287 unsigned int maxperident = strtoul(num, NULL, 10);
288
289 if(maxperident > MAXPERIDENT)
290 return 0;
291
292 tg->maxperident = maxperident;
293
294 return 1;
295 }
296
297 static int modifyenforceident(trustgroup *tg, char *num) {
298 if(num[0] == '1') {
299 tg->mode = 1;
300 } else if(num[0] == '0') {
301 tg->mode = 0;
302 } else {
303 return 0;
304 }
305
306 return 1;
307 }
308
309 static int modifyexpires(trustgroup *tg, char *expires) {
310 int howlong = durationtolong(expires);
311
312 if((howlong <= 0) || (howlong > MAXDURATION))
313 return 0;
314
315 tg->expires = time(NULL) + howlong;
316
317 return 1;
318 }
319
320 static array trustmods_a;
321 static struct trustmodification *trustmods;
322
323 static int trusts_cmdtrustgroupmodify(void *source, int cargc, char **cargv) {
324 trustgroup *tg;
325 nick *sender = source;
326 char *what, *to, validfields[512];
327 int i;
328 StringBuf b;
329
330 if(cargc < 3)
331 return CMD_USAGE;
332
333 tg = tg_strtotg(cargv[0]);
334 if(!tg) {
335 controlreply(sender, "Couldn't look up trustgroup.");
336 return CMD_ERROR;
337 }
338
339 what = cargv[1];
340 to = cargv[2];
341
342 sbinit(&b, validfields, sizeof(validfields));
343 for(i=0;i<trustmods_a.cursi;i++) {
344 if(!strcmp(what, trustmods[i].name)) {
345 if(!(trustmods[i].fn)(tg, to)) {
346 controlreply(sender, "An error occured changing that property, check the syntax.");
347 return CMD_ERROR;
348 }
349 break;
350 }
351
352 if(i > 0)
353 sbaddstr(&b, ", ");
354 sbaddstr(&b, trustmods[i].name);
355 }
356
357 if(i == trustmods_a.cursi) {
358 sbterminate(&b);
359 controlreply(sender, "No such field, valid fields are: %s", validfields);
360 return CMD_ERROR;
361 }
362
363 triggerhook(HOOK_TRUSTS_MODIFYGROUP, tg);
364 tg_update(tg);
365 controlreply(sender, "Group modified.");
366
367 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTMODIFIED'ed group '%s' (field: %s, value: %s)", controlid(sender), tg->name->content, what, to);
368
369 return CMD_OK;
370 }
371
372 static int commandsregistered;
373
374 static void registercommands(int hooknum, void *arg) {
375 if(commandsregistered)
376 return;
377 commandsregistered = 1;
378
379 registercontrolhelpcmd("trustgroupadd", NO_OPER, 6, trusts_cmdtrustgroupadd, "Usage: trustgroupadd <name> <howmany> <howlong> <maxperident> <enforceident> <contact> ?comment?");
380 registercontrolhelpcmd("trustadd", NO_OPER, 2, trusts_cmdtrustadd, "Usage: trustadd <#id|name|id> <host>");
381 registercontrolhelpcmd("trustgroupdel", NO_OPER, 1, trusts_cmdtrustgroupdel, "Usage: trustgroupdel <#id|name|id>");
382 registercontrolhelpcmd("trustdel", NO_OPER, 2, trusts_cmdtrustdel, "Usage: trustdel <#id|name|id> <ip/mask>");
383 registercontrolhelpcmd("trustgroupmodify", NO_OPER, 3, trusts_cmdtrustgroupmodify, "Usage: trustgroupmodify <#id|name|id> <field> <new value>");
384 }
385
386 static void deregistercommands(int hooknum, void *arg) {
387 if(!commandsregistered)
388 return;
389 commandsregistered = 0;
390
391 deregistercontrolcmd("trustgroupadd", trusts_cmdtrustgroupadd);
392 deregistercontrolcmd("trustadd", trusts_cmdtrustadd);
393 deregistercontrolcmd("trustgroupdel", trusts_cmdtrustgroupdel);
394 deregistercontrolcmd("trustdel", trusts_cmdtrustdel);
395 deregistercontrolcmd("trustgroupmodify", trusts_cmdtrustgroupmodify);
396 }
397
398 static int loaded;
399
400 #define _ms_(x) (struct trustmodification){ .name = # x, .fn = modify ## x }
401 #define MS(x) { int slot = array_getfreeslot(&trustmods_a); trustmods = (struct trustmodification *)trustmods_a.content; memcpy(&trustmods[slot], &_ms_(x), sizeof(struct trustmodification)); }
402
403 static void setupmods(void) {
404 MS(expires);
405 MS(enforceident);
406 MS(maxperident);
407 MS(contact);
408 MS(comment);
409 MS(trustedfor);
410 }
411
412 void _init(void) {
413 sstring *m;
414
415 array_init(&trustmods_a, sizeof(struct trustmodification));
416 setupmods();
417
418 m = getconfigitem("trusts", "master");
419 if(!m || (atoi(m->content) != 1)) {
420 Error("trusts_management", ERR_ERROR, "Not a master server, not loaded.");
421 return;
422 }
423
424 loaded = 1;
425
426 registerhook(HOOK_TRUSTS_DB_LOADED, registercommands);
427 registerhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
428
429 if(trustsdbloaded)
430 registercommands(0, NULL);
431 }
432
433 void _fini(void) {
434 array_free(&trustmods_a);
435
436 if(!loaded)
437 return;
438
439 deregisterhook(HOOK_TRUSTS_DB_LOADED, registercommands);
440 deregisterhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
441
442 deregistercommands(0, NULL);
443 }