]> jfr.im git - irc/quakenet/newserv.git/blame - trusts/trusts_slave.c
Stupid off by one bug.
[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"
10#include "../xsb/xsb.h"
11#include "../lib/sha1.h"
12#include "../lib/hmac.h"
13#include "../lib/irc_string.h"
14#include "../core/schedule.h"
15#include "../server/server.h"
35449aa5
CP
16#include "trusts.h"
17
82a316e7
CP
18static int syncing, synced;
19static sstring *masterserver;
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
28static void __abandonreplication(const char *fn, int line, char *error, ...) {
29 va_list ap;
30 char buf[512], buf2[600];
31
32 va_start(ap, error);
33 vsnprintf(buf, sizeof(buf), "%s", ap);
34 va_end(ap);
35
36 snprintf(buf2, sizeof(buf2), "Error replicating (function: %s, line: %d): %s", fn, line, buf);
37
38 Error("trusts_slave", ERR_ERROR, "%s", buf2);
35449aa5 39
82a316e7
CP
40 syncing = 0;
41
42 /* TODO: warn IRC */
35449aa5
CP
43}
44
82a316e7
CP
45#define abandonreplication(x, ...) __abandonreplication(__FUNCTION__, __LINE__, x , # __VA_ARGS__)
46
47void trusts_replication_complete(int error) {
48 if(error) {
49 abandonreplication("final replication stage: error %d", error);
50 return;
51 }
52 Error("trusts_slave", ERR_INFO, "Replication complete!");
53
54 if(!trusts_loaddb()) {
55 abandonreplication("couldn't load database");
35449aa5 56 return;
82a316e7
CP
57 }
58
59 synced = 1;
60}
61
62static char *extractline(char *buf, int reset, int update, int final) {
63 unsigned char n = '\n';
64 int chars = 0;
65 unsigned int lineno, id;
66 static unsigned int curid;
67
68 if(sscanf(buf, "%u %u %n", &id, &lineno, &chars) != 2) {
69 abandonreplication("bad number for sscanf result");
70 return NULL;
71 }
72
73 if(chars <= 0) {
74 abandonreplication("bad number of characters");
75 return NULL;
76 }
77
78 if(reset && (lineno != 1)) {
79 abandonreplication("bad initial line number");
80 return NULL;
81 }
82
83 if(update) {
84 if(reset) {
85 curlineno = 2;
86 curid = id;
87 SHA1Init(&s);
88 } else {
89 /* will happen if two are sent at once, but that's ok */
90 if(id != curid)
91 return NULL;
92
93 if(lineno != curlineno) {
94 abandonreplication("unexpected line number");
95 Error("trusts_slave", ERR_ERROR, "Didn't get expected line number (%u vs. %u).", lineno, curlineno);
96 return NULL;
97 }
98 if(lineno > totallines) {
99 abandonreplication("too many lines");
100 Error("trusts_slave", ERR_ERROR, "Too many lines received!");
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
122 if(argc < 1) {
123 abandonreplication("bad number of args");
124 return CMD_ERROR;
125 }
126
127 buf = extractline(argv[0], 1, 0, 1);
128 if(!buf)
129 return CMD_ERROR;
130
131 if((sscanf(buf, "%u %u", &forced, &totallines) != 2)) {
132 abandonreplication("bad number for sscanf result");
133 return CMD_ERROR;
134 }
135
136 if(totallines < 2) {
137 abandonreplication("bad number of lines");
138 return CMD_ERROR;
139 }
140
141 if(!forced || synced)
142 return CMD_OK;
143
144 if(!extractline(argv[0], 1, 1, 0))
145 return CMD_ERROR;
146
147 trusts_replication_createtables();
148
149 syncing = 1;
150
151 Error("trusts_slave", ERR_INFO, "Replication in progress. . .");
152 return CMD_OK;
153}
154
155/* trdata id lines type data */
156static int xsb_trdata(void *source, int argc, char **argv) {
157 char *buf;
158
159 if(!syncing)
160 return CMD_OK;
161
162 if(argc < 1) {
163 abandonreplication("bad number of args");
164 return CMD_ERROR;
165 }
166
167 buf = extractline(argv[0], 0, 1, 0);
168 if(!buf)
169 return CMD_ERROR;
170
171 if(buf[0] && (buf[1] == ' ')) {
172 if(buf[0] == 'G') {
173 trustgroup tg;
174 if(!parsetg(&buf[2], &tg, 0)) {
175 abandonreplication("bad trustgroup line");
176 Error("trusts_slave", ERR_ERROR, "Bad trustgroup line: %s", buf);
177 return CMD_ERROR;
178 }
179 trustsdb_inserttg("replication_groups", &tg);
180
181 freesstring(tg.name);
182 freesstring(tg.createdby);
183 freesstring(tg.contact);
184 freesstring(tg.comment);
185
186 } else if(buf[0] == 'H') {
187 unsigned int tgid;
188 trusthost th;
189
190 if(!parseth(&buf[2], &th, &tgid, 0)) {
191 abandonreplication("bad trusthost line");
192 Error("trusts_slave", ERR_ERROR, "Bad trusthost line: %s", buf);
193 return CMD_ERROR;
194 }
195 trustsdb_insertth("replication_hosts", &th, tgid);
196 } else {
197 abandonreplication("bad trust type");
198
199 Error("trusts_slave", ERR_ERROR, "Bad trust type: %c", buf[0]);
200 return CMD_ERROR;
201 }
202 } else {
203 abandonreplication("malformed line");
204
205 Error("trusts_slave", ERR_ERROR, "Malformed data line: %s", buf);
206 }
207
208 return CMD_OK;
209}
210
211/* trfini id lines sha */
212static int xsb_trfini(void *source, int argc, char **argv) {
213 char *buf, digestbuf[SHA1_DIGESTSIZE * 2 + 1];
214 unsigned char digest[SHA1_DIGESTSIZE];
215
216 if(!syncing)
217 return CMD_OK;
218
219 if(argc < 1) {
220 abandonreplication("bad number of args");
221 return CMD_ERROR;
222 }
223
224 buf = extractline(argv[0], 0, 1, 1);
225 if(!buf)
226 return CMD_ERROR;
227
228 if((totallines + 1) != curlineno) {
229 abandonreplication("wrong number of lines received");
230 Error("trusts_slave", ERR_ERROR, "Wrong number of lines received (%u vs. %u).", totallines, curlineno - 1);
231 return CMD_ERROR;
232 }
233
234 SHA1Final(digest, &s);
235 if(strcasecmp(hmac_printhex(digest, digestbuf, SHA1_DIGESTSIZE), buf)) {
236 abandonreplication("digest mismatch");
237 Error("trusts_slave", ERR_ERROR, "Digest mismatch.");
238 return CMD_ERROR;
239 }
35449aa5 240
82a316e7
CP
241 Error("trusts_slave", ERR_INFO, "Data verification successful.");
242
243 trusts_replication_swap();
244
245 synced = 1;
246
247 return CMD_OK;
248}
249
250static int xsb_traddgroup(void *source, int argc, char **argv) {
251 trustgroup tg, *otg;
252
253 if(!synced)
254 return CMD_OK;
255
256 if(argc < 1) {
257 abandonreplication("bad number of arguments");
258 return CMD_ERROR;
259 }
260
261 if(!parsetg(argv[0], &tg, 0)) {
262 abandonreplication("bad trustgroup line");
263 Error("trusts_slave", ERR_ERROR, "Bad trustgroup line: %s", argv[0]);
264 return CMD_ERROR;
265 }
266
267 otg = tg_copy(&tg);
268
269 freesstring(tg.name);
270 freesstring(tg.createdby);
271 freesstring(tg.contact);
272 freesstring(tg.comment);
273
274 if(!otg) {
275 abandonreplication("unable to add trustgroup");
276 return CMD_ERROR;
277 }
278
279 return CMD_OK;
280}
281
282static int xsb_traddhost(void *source, int argc, char **argv) {
283 unsigned int tgid;
284 trusthost th;
285
286 if(!synced)
287 return CMD_OK;
288
289 if(argc < 1) {
290 abandonreplication("bad number of arguments");
291 return CMD_ERROR;
292 }
293
294 if(!parseth(argv[0], &th, &tgid, 0)) {
295 abandonreplication("bad trusthost line");
296 Error("trusts_slave", ERR_ERROR, "Bad trusthost line: %s", argv[0]);
297 return CMD_ERROR;
298 }
299
300 th.group = tg_inttotg(tgid);
301 if(!th.group) {
302 abandonreplication("unable to lookup trustgroup");
303 return CMD_ERROR;
304 }
305
306 if(!th_copy(&th)) {
307 abandonreplication("unable to add trusthost");
308 return CMD_ERROR;
309 }
310
311 return CMD_OK;
312}
313
314static int xsb_trdelhost(void *source, int argc, char **argv) {
315 if(!synced)
316 return CMD_OK;
317
318 if(argc < 1) {
319 abandonreplication("bad number of arguments");
320 return CMD_ERROR;
321 }
322
323 return CMD_OK;
324}
325
326static int xsb_trdelgroup(void *source, int argc, char **argv) {
327 if(!synced)
328 return CMD_OK;
329
330 if(argc < 1) {
331 abandonreplication("bad number of arguments");
332 return CMD_ERROR;
333 }
334
335 return CMD_OK;
336}
337
338static int trusts_cmdtrustresync(void *source, int argc, char **argv) {
339 nick *np = source;
340
341 if(syncing) {
342 controlreply(np, "Synchronisation is already in progress.");
343 return CMD_ERROR;
344 }
345
346 synced = 0;
347 xsb_broadcast("trrequestsync", NULL, "%s", "");
348 controlreply(np, "Synchronisation request sent.");
349
350 return CMD_OK;
351}
352
353static int loaded;
354static void *syncsched;
355
356static void checksynced(void *arg) {
357 if(!synced || !syncing)
358 xsb_broadcast("trrequestsync", NULL, "%s", "");
359}
360
361static void __serverlinked(int hooknum, void *arg) {
362 int servernum = (int)arg;
363
364 if(!ircd_strcmp(serverlist[servernum].name->content, masterserver->content)) {
365 syncing = synced = 0;
366 xsb_broadcast("trrequestsync", NULL, "%s", "");
367 }
35449aa5
CP
368}
369
370void _init(void) {
82a316e7 371 sstring *m;
35449aa5 372
82a316e7
CP
373 m = getconfigitem("trusts", "master");
374 if(m && (atoi(m->content) != 0)) {
375 Error("trusts_slave", ERR_ERROR, "Not a slave server, not loaded.");
376 return;
377 }
378
379 masterserver = getcopyconfigitem("trusts", "masterserver", "", 255);
380 if(!masterserver || !masterserver->content || !masterserver->content[0]) {
381 Error("trusts_slave", ERR_ERROR, "No master server defined.");
382 freesstring(masterserver);
383 return;
384 }
385
386 loaded = 1;
387
388 registercontrolhelpcmd("trustresync", NO_DEVELOPER, 0, trusts_cmdtrustresync, "Usage: trustresync");
389
390 xsb_addcommand("trinit", 1, xsb_trinit);
391 xsb_addcommand("trdata", 1, xsb_trdata);
392 xsb_addcommand("trfini", 1, xsb_trfini);
393 xsb_addcommand("traddhost", 1, xsb_traddhost);
394 xsb_addcommand("traddgroup", 1, xsb_traddgroup);
395 xsb_addcommand("trdelhost", 1, xsb_trdelhost);
396 xsb_addcommand("trdelgroup", 1, xsb_trdelgroup);
397
398 registerhook(HOOK_SERVER_LINKED, __serverlinked);
399 syncsched = schedulerecurring(time(NULL)+5, 0, 60, checksynced, NULL);
400
401 if(trusts_fullyonline())
402 xsb_broadcast("trrequestsync", NULL, "%s", "");
35449aa5
CP
403}
404
405void _fini(void) {
82a316e7
CP
406 if(!loaded)
407 return;
408
409 freesstring(masterserver);
410
411 deregistercontrolcmd("trustresync", trusts_cmdtrustresync);
412
413 xsb_delcommand("trinit", xsb_trinit);
414 xsb_delcommand("trdata", xsb_trdata);
415 xsb_delcommand("trfini", xsb_trfini);
416 xsb_delcommand("traddhost", xsb_traddhost);
417 xsb_delcommand("traddgroup", xsb_traddgroup);
418 xsb_delcommand("trdelhost", xsb_trdelhost);
419 xsb_delcommand("trdelgroup", xsb_trdelgroup);
420
421 deregisterhook(HOOK_SERVER_LINKED, __serverlinked);
422
423 deleteschedule(syncsched, checksynced, NULL);
35449aa5 424
82a316e7 425 trusts_closedb(0);
35449aa5 426}