]>
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 CP |
18 | static int syncing, synced; |
19 | static sstring *masterserver; | |
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 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 | ||
47 | void 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 | ||
62 | static 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 */ | |
118 | static 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 */ | |
156 | static 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 */ | |
212 | static 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 | ||
250 | static 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 | ||
282 | static 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 | ||
314 | static 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 | ||
326 | static 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 | ||
be70d6c5 CP |
338 | static int loaded; |
339 | static void *syncsched; | |
340 | ||
341 | static void checksynced(void *arg) { | |
342 | if(!synced || !syncing) | |
343 | xsb_broadcast("trrequestsync", NULL, "%s", ""); | |
344 | } | |
345 | ||
82a316e7 CP |
346 | static int trusts_cmdtrustresync(void *source, int argc, char **argv) { |
347 | nick *np = source; | |
348 | ||
349 | if(syncing) { | |
350 | controlreply(np, "Synchronisation is already in progress."); | |
351 | return CMD_ERROR; | |
352 | } | |
353 | ||
354 | synced = 0; | |
be70d6c5 | 355 | checksynced(NULL); |
82a316e7 CP |
356 | controlreply(np, "Synchronisation request sent."); |
357 | ||
358 | return CMD_OK; | |
359 | } | |
360 | ||
82a316e7 CP |
361 | static 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; | |
be70d6c5 | 366 | checksynced(NULL); |
82a316e7 | 367 | } |
35449aa5 CP |
368 | } |
369 | ||
370 | void _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()) | |
be70d6c5 | 402 | checksynced(NULL); |
35449aa5 CP |
403 | } |
404 | ||
405 | void _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 | } |