]>
Commit | Line | Data |
---|---|---|
82a316e7 CP |
1 | #include <stdlib.h> |
2 | #include <stdarg.h> | |
3 | #include <stdio.h> | |
4 | #include <string.h> | |
5 | #include <strings.h> | |
35449aa5 | 6 | #include "../core/hooks.h" |
82a316e7 CP |
7 | #include "../core/config.h" |
8 | #include "../core/error.h" | |
9 | #include "../control/control.h" | |
82a316e7 CP |
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" | |
be70d6c5 | 15 | #include "../xsb/xsb.h" |
35449aa5 CP |
16 | #include "trusts.h" |
17 | ||
82a316e7 | 18 | static int syncing, synced; |
e854b1bf | 19 | static sstring *smasterserver; |
82a316e7 CP |
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 | ||
e854b1bf CP |
28 | static int masterserver(void *source); |
29 | ||
82a316e7 CP |
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); | |
e854b1bf | 35 | vsnprintf(buf, sizeof(buf), error, ap); |
82a316e7 CP |
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); | |
35449aa5 | 41 | |
f803c9ca | 42 | syncing = synced = 0; |
82a316e7 | 43 | |
2ab0a1e7 | 44 | controlwall(NO_DEVELOPER, NL_TRUSTS, "Warning: %s", buf2); |
35449aa5 CP |
45 | } |
46 | ||
82a316e7 CP |
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"); | |
35449aa5 | 58 | return; |
82a316e7 CP |
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) { | |
e854b1bf | 96 | abandonreplication("unexpected line number (%u vs. %u)", lineno, curlineno); |
82a316e7 CP |
97 | return NULL; |
98 | } | |
99 | if(lineno > totallines) { | |
100 | abandonreplication("too many lines"); | |
82a316e7 CP |
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 | ||
e854b1bf CP |
122 | if(!masterserver(source)) |
123 | return CMD_ERROR; | |
124 | ||
82a316e7 CP |
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 | ||
e854b1bf | 144 | if(!forced && synced) |
82a316e7 CP |
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 | ||
e854b1bf CP |
165 | if(!masterserver(source)) |
166 | return CMD_ERROR; | |
167 | ||
82a316e7 CP |
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)) { | |
e854b1bf | 181 | abandonreplication("bad trustgroup line: %s", buf); |
82a316e7 CP |
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)) { | |
e854b1bf | 196 | abandonreplication("bad trusthost line: %s", buf); |
82a316e7 CP |
197 | return CMD_ERROR; |
198 | } | |
199 | trustsdb_insertth("replication_hosts", &th, tgid); | |
200 | } else { | |
e854b1bf | 201 | abandonreplication("bad trust type: %c", buf[0]); |
82a316e7 | 202 | |
82a316e7 CP |
203 | return CMD_ERROR; |
204 | } | |
205 | } else { | |
e854b1bf | 206 | abandonreplication("malformed line: %s", buf); |
82a316e7 CP |
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 | ||
e854b1bf CP |
220 | if(!masterserver(source)) |
221 | return CMD_ERROR; | |
222 | ||
82a316e7 CP |
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) { | |
e854b1bf | 233 | abandonreplication("wrong number of lines received: %u vs. %u", totallines, curlineno - 1); |
82a316e7 CP |
234 | return CMD_ERROR; |
235 | } | |
236 | ||
237 | SHA1Final(digest, &s); | |
0bd91417 | 238 | if(hmac_strcmp(hmac_printhex(digest, digestbuf, SHA1_DIGESTSIZE), buf)) { |
82a316e7 | 239 | abandonreplication("digest mismatch"); |
82a316e7 CP |
240 | return CMD_ERROR; |
241 | } | |
35449aa5 | 242 | |
82a316e7 CP |
243 | Error("trusts_slave", ERR_INFO, "Data verification successful."); |
244 | ||
245 | trusts_replication_swap(); | |
246 | ||
247 | synced = 1; | |
e854b1bf | 248 | syncing = 0; |
82a316e7 CP |
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 | ||
e854b1bf CP |
259 | if(!masterserver(source)) |
260 | return CMD_ERROR; | |
261 | ||
82a316e7 CP |
262 | if(argc < 1) { |
263 | abandonreplication("bad number of arguments"); | |
264 | return CMD_ERROR; | |
265 | } | |
266 | ||
267 | if(!parsetg(argv[0], &tg, 0)) { | |
e854b1bf | 268 | abandonreplication("bad trustgroup line: %s", argv[0]); |
82a316e7 CP |
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 | ||
e854b1bf CP |
294 | if(!masterserver(source)) |
295 | return CMD_ERROR; | |
296 | ||
82a316e7 CP |
297 | if(argc < 1) { |
298 | abandonreplication("bad number of arguments"); | |
299 | return CMD_ERROR; | |
300 | } | |
301 | ||
302 | if(!parseth(argv[0], &th, &tgid, 0)) { | |
e854b1bf | 303 | abandonreplication("bad trusthost line: %s", argv[0]); |
82a316e7 CP |
304 | return CMD_ERROR; |
305 | } | |
306 | ||
2ab0a1e7 | 307 | th.group = tg_getbyid(tgid); |
82a316e7 CP |
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) { | |
2ab0a1e7 CP |
322 | unsigned int id; |
323 | trusthost *th; | |
324 | ||
82a316e7 CP |
325 | if(!synced) |
326 | return CMD_OK; | |
327 | ||
e854b1bf CP |
328 | if(!masterserver(source)) |
329 | return CMD_ERROR; | |
330 | ||
82a316e7 CP |
331 | if(argc < 1) { |
332 | abandonreplication("bad number of arguments"); | |
333 | return CMD_ERROR; | |
334 | } | |
335 | ||
2ab0a1e7 CP |
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 | ||
82a316e7 CP |
350 | return CMD_OK; |
351 | } | |
352 | ||
353 | static int xsb_trdelgroup(void *source, int argc, char **argv) { | |
2ab0a1e7 CP |
354 | unsigned int id; |
355 | trustgroup *tg; | |
356 | ||
82a316e7 CP |
357 | if(!synced) |
358 | return CMD_OK; | |
359 | ||
e854b1bf CP |
360 | if(!masterserver(source)) |
361 | return CMD_ERROR; | |
362 | ||
82a316e7 CP |
363 | if(argc < 1) { |
364 | abandonreplication("bad number of arguments"); | |
365 | return CMD_ERROR; | |
366 | } | |
367 | ||
2ab0a1e7 CP |
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 | ||
82a316e7 CP |
423 | return CMD_OK; |
424 | } | |
425 | ||
e854b1bf | 426 | static int loaded, masternumeric = -1; |
be70d6c5 CP |
427 | static void *syncsched; |
428 | ||
e854b1bf CP |
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 | ||
be70d6c5 | 444 | static void checksynced(void *arg) { |
e854b1bf CP |
445 | if(!synced && !syncing) |
446 | xsb_broadcast("trrequeststart", NULL, "%s", ""); | |
be70d6c5 CP |
447 | } |
448 | ||
82a316e7 CP |
449 | static int trusts_cmdtrustresync(void *source, int argc, char **argv) { |
450 | nick *np = source; | |
451 | ||
e854b1bf | 452 | syncing = synced = 0; |
82a316e7 | 453 | |
be70d6c5 | 454 | checksynced(NULL); |
82a316e7 CP |
455 | controlreply(np, "Synchronisation request sent."); |
456 | ||
457 | return CMD_OK; | |
458 | } | |
459 | ||
82a316e7 | 460 | static void __serverlinked(int hooknum, void *arg) { |
e854b1bf | 461 | int servernum = (int)(long)arg; |
82a316e7 | 462 | |
e854b1bf CP |
463 | if(!ircd_strcmp(serverlist[servernum].name->content, smasterserver->content)) { |
464 | masternumeric = servernum; | |
82a316e7 | 465 | syncing = synced = 0; |
be70d6c5 | 466 | checksynced(NULL); |
82a316e7 | 467 | } |
35449aa5 CP |
468 | } |
469 | ||
470 | void _init(void) { | |
82a316e7 | 471 | sstring *m; |
35449aa5 | 472 | |
82a316e7 CP |
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 | ||
e854b1bf CP |
479 | smasterserver = getcopyconfigitem("trusts", "masterserver", "", 255); |
480 | if(!smasterserver || !smasterserver->content || !smasterserver->content[0]) { | |
82a316e7 | 481 | Error("trusts_slave", ERR_ERROR, "No master server defined."); |
e854b1bf | 482 | freesstring(smasterserver); |
82a316e7 CP |
483 | return; |
484 | } | |
485 | ||
f139c388 CP |
486 | masternumeric = findserver(smasterserver->content); |
487 | ||
82a316e7 CP |
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); | |
2ab0a1e7 | 499 | xsb_addcommand("trmodifygroup", 1, xsb_trmodifygroup); |
82a316e7 CP |
500 | |
501 | registerhook(HOOK_SERVER_LINKED, __serverlinked); | |
502 | syncsched = schedulerecurring(time(NULL)+5, 0, 60, checksynced, NULL); | |
503 | ||
504 | if(trusts_fullyonline()) | |
be70d6c5 | 505 | checksynced(NULL); |
35449aa5 CP |
506 | } |
507 | ||
508 | void _fini(void) { | |
82a316e7 CP |
509 | if(!loaded) |
510 | return; | |
511 | ||
e854b1bf | 512 | freesstring(smasterserver); |
82a316e7 CP |
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); | |
2ab0a1e7 | 523 | xsb_delcommand("trmodifygroup", xsb_trmodifygroup); |
82a316e7 CP |
524 | |
525 | deregisterhook(HOOK_SERVER_LINKED, __serverlinked); | |
526 | ||
527 | deleteschedule(syncsched, checksynced, NULL); | |
35449aa5 | 528 | |
82a316e7 | 529 | trusts_closedb(0); |
35449aa5 | 530 | } |