]> jfr.im git - irc/quakenet/newserv.git/blob - trusts/trusts_slave.c
Fix timing attacks in HMAC functions.
[irc/quakenet/newserv.git] / trusts / trusts_slave.c
1 #include <stdlib.h>
2 #include <stdarg.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <strings.h>
6 #include "../core/hooks.h"
7 #include "../core/config.h"
8 #include "../core/error.h"
9 #include "../control/control.h"
10 #include "../lib/sha1.h"
11 #include "../lib/hmac.h"
12 #include "../lib/irc_string.h"
13 #include "../core/schedule.h"
14 #include "../server/server.h"
15 #include "../xsb/xsb.h"
16 #include "trusts.h"
17
18 static int syncing, synced;
19 static sstring *smasterserver;
20
21 static unsigned int curlineno, totallines;
22 static SHA1_CTX s;
23
24 void trusts_replication_createtables(void);
25 void trusts_replication_swap(void);
26 void trusts_replication_complete(int);
27
28 static int masterserver(void *source);
29
30 static void __abandonreplication(const char *fn, int line, char *error, ...) {
31 va_list ap;
32 char buf[512], buf2[600];
33
34 va_start(ap, error);
35 vsnprintf(buf, sizeof(buf), error, ap);
36 va_end(ap);
37
38 snprintf(buf2, sizeof(buf2), "Error replicating (function: %s, line: %d): %s", fn, line, buf);
39
40 Error("trusts_slave", ERR_ERROR, "%s", buf2);
41
42 syncing = synced = 0;
43
44 controlwall(NO_DEVELOPER, NL_TRUSTS, "Warning: %s", buf2);
45 }
46
47 #define abandonreplication(x, ...) __abandonreplication(__FUNCTION__, __LINE__, x , # __VA_ARGS__)
48
49 void trusts_replication_complete(int error) {
50 if(error) {
51 abandonreplication("final replication stage: error %d", error);
52 return;
53 }
54 Error("trusts_slave", ERR_INFO, "Replication complete!");
55
56 if(!trusts_loaddb()) {
57 abandonreplication("couldn't load database");
58 return;
59 }
60
61 synced = 1;
62 }
63
64 static char *extractline(char *buf, int reset, int update, int final) {
65 unsigned char n = '\n';
66 int chars = 0;
67 unsigned int lineno, id;
68 static unsigned int curid;
69
70 if(sscanf(buf, "%u %u %n", &id, &lineno, &chars) != 2) {
71 abandonreplication("bad number for sscanf result");
72 return NULL;
73 }
74
75 if(chars <= 0) {
76 abandonreplication("bad number of characters");
77 return NULL;
78 }
79
80 if(reset && (lineno != 1)) {
81 abandonreplication("bad initial line number");
82 return NULL;
83 }
84
85 if(update) {
86 if(reset) {
87 curlineno = 2;
88 curid = id;
89 SHA1Init(&s);
90 } else {
91 /* will happen if two are sent at once, but that's ok */
92 if(id != curid)
93 return NULL;
94
95 if(lineno != curlineno) {
96 abandonreplication("unexpected line number (%u vs. %u)", lineno, curlineno);
97 return NULL;
98 }
99 if(lineno > totallines) {
100 abandonreplication("too many lines");
101 return NULL;
102 }
103
104 curlineno++;
105
106 }
107
108 if(!final) {
109 SHA1Update(&s, (unsigned char *)buf, strlen(buf));
110 SHA1Update(&s, &n, 1);
111 }
112 }
113
114 return &buf[chars];
115 }
116
117 /* trinit id lineno force totallines */
118 static int xsb_trinit(void *source, int argc, char **argv) {
119 char *buf;
120 unsigned int forced;
121
122 if(!masterserver(source))
123 return CMD_ERROR;
124
125 if(argc < 1) {
126 abandonreplication("bad number of args");
127 return CMD_ERROR;
128 }
129
130 buf = extractline(argv[0], 1, 0, 1);
131 if(!buf)
132 return CMD_ERROR;
133
134 if((sscanf(buf, "%u %u", &forced, &totallines) != 2)) {
135 abandonreplication("bad number for sscanf result");
136 return CMD_ERROR;
137 }
138
139 if(totallines < 2) {
140 abandonreplication("bad number of lines");
141 return CMD_ERROR;
142 }
143
144 if(!forced && synced)
145 return CMD_OK;
146
147 if(!extractline(argv[0], 1, 1, 0))
148 return CMD_ERROR;
149
150 trusts_replication_createtables();
151
152 syncing = 1;
153
154 Error("trusts_slave", ERR_INFO, "Replication in progress. . .");
155 return CMD_OK;
156 }
157
158 /* trdata id lines type data */
159 static int xsb_trdata(void *source, int argc, char **argv) {
160 char *buf;
161
162 if(!syncing)
163 return CMD_OK;
164
165 if(!masterserver(source))
166 return CMD_ERROR;
167
168 if(argc < 1) {
169 abandonreplication("bad number of args");
170 return CMD_ERROR;
171 }
172
173 buf = extractline(argv[0], 0, 1, 0);
174 if(!buf)
175 return CMD_ERROR;
176
177 if(buf[0] && (buf[1] == ' ')) {
178 if(buf[0] == 'G') {
179 trustgroup tg;
180 if(!parsetg(&buf[2], &tg, 0)) {
181 abandonreplication("bad trustgroup line: %s", buf);
182 return CMD_ERROR;
183 }
184 trustsdb_inserttg("replication_groups", &tg);
185
186 freesstring(tg.name);
187 freesstring(tg.createdby);
188 freesstring(tg.contact);
189 freesstring(tg.comment);
190
191 } else if(buf[0] == 'H') {
192 unsigned int tgid;
193 trusthost th;
194
195 if(!parseth(&buf[2], &th, &tgid, 0)) {
196 abandonreplication("bad trusthost line: %s", buf);
197 return CMD_ERROR;
198 }
199 trustsdb_insertth("replication_hosts", &th, tgid);
200 } else {
201 abandonreplication("bad trust type: %c", buf[0]);
202
203 return CMD_ERROR;
204 }
205 } else {
206 abandonreplication("malformed line: %s", buf);
207 }
208
209 return CMD_OK;
210 }
211
212 /* trfini id lines sha */
213 static int xsb_trfini(void *source, int argc, char **argv) {
214 char *buf, digestbuf[SHA1_DIGESTSIZE * 2 + 1];
215 unsigned char digest[SHA1_DIGESTSIZE];
216
217 if(!syncing)
218 return CMD_OK;
219
220 if(!masterserver(source))
221 return CMD_ERROR;
222
223 if(argc < 1) {
224 abandonreplication("bad number of args");
225 return CMD_ERROR;
226 }
227
228 buf = extractline(argv[0], 0, 1, 1);
229 if(!buf)
230 return CMD_ERROR;
231
232 if((totallines + 1) != curlineno) {
233 abandonreplication("wrong number of lines received: %u vs. %u", totallines, curlineno - 1);
234 return CMD_ERROR;
235 }
236
237 SHA1Final(digest, &s);
238 if(hmac_strcmp(hmac_printhex(digest, digestbuf, SHA1_DIGESTSIZE), buf)) {
239 abandonreplication("digest mismatch");
240 return CMD_ERROR;
241 }
242
243 Error("trusts_slave", ERR_INFO, "Data verification successful.");
244
245 trusts_replication_swap();
246
247 synced = 1;
248 syncing = 0;
249
250 return CMD_OK;
251 }
252
253 static int xsb_traddgroup(void *source, int argc, char **argv) {
254 trustgroup tg, *otg;
255
256 if(!synced)
257 return CMD_OK;
258
259 if(!masterserver(source))
260 return CMD_ERROR;
261
262 if(argc < 1) {
263 abandonreplication("bad number of arguments");
264 return CMD_ERROR;
265 }
266
267 if(!parsetg(argv[0], &tg, 0)) {
268 abandonreplication("bad trustgroup line: %s", argv[0]);
269 return CMD_ERROR;
270 }
271
272 otg = tg_copy(&tg);
273
274 freesstring(tg.name);
275 freesstring(tg.createdby);
276 freesstring(tg.contact);
277 freesstring(tg.comment);
278
279 if(!otg) {
280 abandonreplication("unable to add trustgroup");
281 return CMD_ERROR;
282 }
283
284 return CMD_OK;
285 }
286
287 static int xsb_traddhost(void *source, int argc, char **argv) {
288 unsigned int tgid;
289 trusthost th;
290
291 if(!synced)
292 return CMD_OK;
293
294 if(!masterserver(source))
295 return CMD_ERROR;
296
297 if(argc < 1) {
298 abandonreplication("bad number of arguments");
299 return CMD_ERROR;
300 }
301
302 if(!parseth(argv[0], &th, &tgid, 0)) {
303 abandonreplication("bad trusthost line: %s", argv[0]);
304 return CMD_ERROR;
305 }
306
307 th.group = tg_getbyid(tgid);
308 if(!th.group) {
309 abandonreplication("unable to lookup trustgroup");
310 return CMD_ERROR;
311 }
312
313 if(!th_copy(&th)) {
314 abandonreplication("unable to add trusthost");
315 return CMD_ERROR;
316 }
317
318 return CMD_OK;
319 }
320
321 static int xsb_trdelhost(void *source, int argc, char **argv) {
322 unsigned int id;
323 trusthost *th;
324
325 if(!synced)
326 return CMD_OK;
327
328 if(!masterserver(source))
329 return CMD_ERROR;
330
331 if(argc < 1) {
332 abandonreplication("bad number of arguments");
333 return CMD_ERROR;
334 }
335
336 id = strtoul(argv[0], NULL, 10);
337 if(!id) {
338 abandonreplication("unable to convert id to integer");
339 return CMD_ERROR;
340 }
341
342 th = th_getbyid(id);
343 if(!th) {
344 abandonreplication("unable to lookup id");
345 return CMD_ERROR;
346 }
347
348 th_delete(th);
349
350 return CMD_OK;
351 }
352
353 static int xsb_trdelgroup(void *source, int argc, char **argv) {
354 unsigned int id;
355 trustgroup *tg;
356
357 if(!synced)
358 return CMD_OK;
359
360 if(!masterserver(source))
361 return CMD_ERROR;
362
363 if(argc < 1) {
364 abandonreplication("bad number of arguments");
365 return CMD_ERROR;
366 }
367
368 id = strtoul(argv[0], NULL, 10);
369 if(!id) {
370 abandonreplication("unable to convert id to integer");
371 return CMD_ERROR;
372 }
373
374 tg = tg_getbyid(id);
375 if(!tg) {
376 abandonreplication("unable to lookup id");
377 return CMD_ERROR;
378 }
379
380 tg_delete(tg);
381
382 return CMD_OK;
383 }
384
385 static int xsb_trmodifygroup(void *source, int argc, char **argv) {
386 trustgroup tg, *otg;
387
388 if(!synced)
389 return CMD_OK;
390
391 if(!masterserver(source))
392 return CMD_ERROR;
393
394 if(argc < 1) {
395 abandonreplication("bad number of arguments");
396 return CMD_ERROR;
397 }
398
399 if(!parsetg(argv[0], &tg, 0)) {
400 abandonreplication("bad trustgroup line: %s", argv[0]);
401 return CMD_ERROR;
402 }
403
404 otg = tg_getbyid(tg.id);
405
406 if(otg && !tg_modify(otg, &tg)) {
407 abandonreplication("unable to modify database");
408 return CMD_ERROR;
409 }
410
411 freesstring(tg.name);
412 freesstring(tg.createdby);
413 freesstring(tg.contact);
414 freesstring(tg.comment);
415
416 if(!otg) {
417 abandonreplication("unable to lookup id");
418 return CMD_ERROR;
419 }
420
421 tg_update(otg);
422
423 return CMD_OK;
424 }
425
426 static int loaded, masternumeric = -1;
427 static void *syncsched;
428
429 static int masterserver(void *source) {
430 nick *np = source;
431 int home = homeserver(np->numeric);
432
433 if(home < 0)
434 return 0;
435
436 if(home != masternumeric) {
437 Error("trusts_slave", ERR_WARNING, "Command from server that isn't a master: %s", serverlist[home].name->content);
438 return 0;
439 }
440
441 return 1;
442 }
443
444 static void checksynced(void *arg) {
445 if(!synced && !syncing)
446 xsb_broadcast("trrequeststart", NULL, "%s", "");
447 }
448
449 static int trusts_cmdtrustresync(void *source, int argc, char **argv) {
450 nick *np = source;
451
452 syncing = synced = 0;
453
454 checksynced(NULL);
455 controlreply(np, "Synchronisation request sent.");
456
457 return CMD_OK;
458 }
459
460 static void __serverlinked(int hooknum, void *arg) {
461 int servernum = (int)(long)arg;
462
463 if(!ircd_strcmp(serverlist[servernum].name->content, smasterserver->content)) {
464 masternumeric = servernum;
465 syncing = synced = 0;
466 checksynced(NULL);
467 }
468 }
469
470 void _init(void) {
471 sstring *m;
472
473 m = getconfigitem("trusts", "master");
474 if(m && (atoi(m->content) != 0)) {
475 Error("trusts_slave", ERR_ERROR, "Not a slave server, not loaded.");
476 return;
477 }
478
479 smasterserver = getcopyconfigitem("trusts", "masterserver", "", 255);
480 if(!smasterserver || !smasterserver->content || !smasterserver->content[0]) {
481 Error("trusts_slave", ERR_ERROR, "No master server defined.");
482 freesstring(smasterserver);
483 return;
484 }
485
486 masternumeric = findserver(smasterserver->content);
487
488 loaded = 1;
489
490 registercontrolhelpcmd("trustresync", NO_DEVELOPER, 0, trusts_cmdtrustresync, "Usage: trustresync");
491
492 xsb_addcommand("trinit", 1, xsb_trinit);
493 xsb_addcommand("trdata", 1, xsb_trdata);
494 xsb_addcommand("trfini", 1, xsb_trfini);
495 xsb_addcommand("traddhost", 1, xsb_traddhost);
496 xsb_addcommand("traddgroup", 1, xsb_traddgroup);
497 xsb_addcommand("trdelhost", 1, xsb_trdelhost);
498 xsb_addcommand("trdelgroup", 1, xsb_trdelgroup);
499 xsb_addcommand("trmodifygroup", 1, xsb_trmodifygroup);
500
501 registerhook(HOOK_SERVER_LINKED, __serverlinked);
502 syncsched = schedulerecurring(time(NULL)+5, 0, 60, checksynced, NULL);
503
504 if(trusts_fullyonline())
505 checksynced(NULL);
506 }
507
508 void _fini(void) {
509 if(!loaded)
510 return;
511
512 freesstring(smasterserver);
513
514 deregistercontrolcmd("trustresync", trusts_cmdtrustresync);
515
516 xsb_delcommand("trinit", xsb_trinit);
517 xsb_delcommand("trdata", xsb_trdata);
518 xsb_delcommand("trfini", xsb_trfini);
519 xsb_delcommand("traddhost", xsb_traddhost);
520 xsb_delcommand("traddgroup", xsb_traddgroup);
521 xsb_delcommand("trdelhost", xsb_trdelhost);
522 xsb_delcommand("trdelgroup", xsb_trdelgroup);
523 xsb_delcommand("trmodifygroup", xsb_trmodifygroup);
524
525 deregisterhook(HOOK_SERVER_LINKED, __serverlinked);
526
527 deleteschedule(syncsched, checksynced, NULL);
528
529 trusts_closedb(0);
530 }