]> jfr.im git - irc/quakenet/newserv.git/blame - trusts/trusts_slave.c
O has stupid #'s.
[irc/quakenet/newserv.git] / trusts / trusts_slave.c
CommitLineData
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 18static int syncing, synced;
e854b1bf 19static sstring *smasterserver;
82a316e7
CP
20
21static unsigned int curlineno, totallines;
22static SHA1_CTX s;
23
24void trusts_replication_createtables(void);
25void trusts_replication_swap(void);
26void trusts_replication_complete(int);
27
e854b1bf
CP
28static int masterserver(void *source);
29
82a316e7
CP
30static 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
82a316e7
CP
42 syncing = 0;
43
44 /* TODO: warn IRC */
35449aa5
CP
45}
46
82a316e7
CP
47#define abandonreplication(x, ...) __abandonreplication(__FUNCTION__, __LINE__, x , # __VA_ARGS__)
48
49void 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
64static 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 */
118static 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 */
159static 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 */
213static 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);
238 if(strcasecmp(hmac_printhex(digest, digestbuf, SHA1_DIGESTSIZE), buf)) {
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
253static 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
287static 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
307 th.group = tg_inttotg(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
321static int xsb_trdelhost(void *source, int argc, char **argv) {
322 if(!synced)
323 return CMD_OK;
324
e854b1bf
CP
325 if(!masterserver(source))
326 return CMD_ERROR;
327
82a316e7
CP
328 if(argc < 1) {
329 abandonreplication("bad number of arguments");
330 return CMD_ERROR;
331 }
332
333 return CMD_OK;
334}
335
336static int xsb_trdelgroup(void *source, int argc, char **argv) {
337 if(!synced)
338 return CMD_OK;
339
e854b1bf
CP
340 if(!masterserver(source))
341 return CMD_ERROR;
342
82a316e7
CP
343 if(argc < 1) {
344 abandonreplication("bad number of arguments");
345 return CMD_ERROR;
346 }
347
348 return CMD_OK;
349}
350
e854b1bf 351static int loaded, masternumeric = -1;
be70d6c5
CP
352static void *syncsched;
353
e854b1bf
CP
354static int masterserver(void *source) {
355 nick *np = source;
356 int home = homeserver(np->numeric);
357
358 if(home < 0)
359 return 0;
360
361 if(home != masternumeric) {
362 Error("trusts_slave", ERR_WARNING, "Command from server that isn't a master: %s", serverlist[home].name->content);
363 return 0;
364 }
365
366 return 1;
367}
368
be70d6c5 369static void checksynced(void *arg) {
e854b1bf
CP
370 if(!synced && !syncing)
371 xsb_broadcast("trrequeststart", NULL, "%s", "");
be70d6c5
CP
372}
373
82a316e7
CP
374static int trusts_cmdtrustresync(void *source, int argc, char **argv) {
375 nick *np = source;
376
e854b1bf 377 syncing = synced = 0;
82a316e7 378
be70d6c5 379 checksynced(NULL);
82a316e7
CP
380 controlreply(np, "Synchronisation request sent.");
381
382 return CMD_OK;
383}
384
82a316e7 385static void __serverlinked(int hooknum, void *arg) {
e854b1bf 386 int servernum = (int)(long)arg;
82a316e7 387
e854b1bf
CP
388 if(!ircd_strcmp(serverlist[servernum].name->content, smasterserver->content)) {
389 masternumeric = servernum;
82a316e7 390 syncing = synced = 0;
be70d6c5 391 checksynced(NULL);
82a316e7 392 }
35449aa5
CP
393}
394
395void _init(void) {
82a316e7 396 sstring *m;
35449aa5 397
82a316e7
CP
398 m = getconfigitem("trusts", "master");
399 if(m && (atoi(m->content) != 0)) {
400 Error("trusts_slave", ERR_ERROR, "Not a slave server, not loaded.");
401 return;
402 }
403
e854b1bf
CP
404 smasterserver = getcopyconfigitem("trusts", "masterserver", "", 255);
405 if(!smasterserver || !smasterserver->content || !smasterserver->content[0]) {
82a316e7 406 Error("trusts_slave", ERR_ERROR, "No master server defined.");
e854b1bf 407 freesstring(smasterserver);
82a316e7
CP
408 return;
409 }
410
f139c388
CP
411 masternumeric = findserver(smasterserver->content);
412
82a316e7
CP
413 loaded = 1;
414
415 registercontrolhelpcmd("trustresync", NO_DEVELOPER, 0, trusts_cmdtrustresync, "Usage: trustresync");
416
417 xsb_addcommand("trinit", 1, xsb_trinit);
418 xsb_addcommand("trdata", 1, xsb_trdata);
419 xsb_addcommand("trfini", 1, xsb_trfini);
420 xsb_addcommand("traddhost", 1, xsb_traddhost);
421 xsb_addcommand("traddgroup", 1, xsb_traddgroup);
422 xsb_addcommand("trdelhost", 1, xsb_trdelhost);
423 xsb_addcommand("trdelgroup", 1, xsb_trdelgroup);
424
425 registerhook(HOOK_SERVER_LINKED, __serverlinked);
426 syncsched = schedulerecurring(time(NULL)+5, 0, 60, checksynced, NULL);
427
428 if(trusts_fullyonline())
be70d6c5 429 checksynced(NULL);
35449aa5
CP
430}
431
432void _fini(void) {
82a316e7
CP
433 if(!loaded)
434 return;
435
e854b1bf 436 freesstring(smasterserver);
82a316e7
CP
437
438 deregistercontrolcmd("trustresync", trusts_cmdtrustresync);
439
440 xsb_delcommand("trinit", xsb_trinit);
441 xsb_delcommand("trdata", xsb_trdata);
442 xsb_delcommand("trfini", xsb_trfini);
443 xsb_delcommand("traddhost", xsb_traddhost);
444 xsb_delcommand("traddgroup", xsb_traddgroup);
445 xsb_delcommand("trdelhost", xsb_trdelhost);
446 xsb_delcommand("trdelgroup", xsb_trdelgroup);
447
448 deregisterhook(HOOK_SERVER_LINKED, __serverlinked);
449
450 deleteschedule(syncsched, checksynced, NULL);
35449aa5 451
82a316e7 452 trusts_closedb(0);
35449aa5 453}