Generate ADC PID more reliably.
[doldaconnect.git] / daemon / fnet-adc.c
CommitLineData
58e83d6a 1/*
2 * Dolda Connect - Modular multiuser Direct Connect-style client
302a2600 3 * Copyright (C) 2004 Fredrik Tolf <fredrik@dolda2000.com>
58e83d6a 4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18*/
19#include <stdlib.h>
20#include <stdio.h>
21#include <unistd.h>
6adc02a2 22#include <fcntl.h>
58e83d6a 23#include <stdarg.h>
24#include <string.h>
25#include <netinet/in.h>
26#include <arpa/inet.h>
27#include <wctype.h>
28#include <iconv.h>
29#include <errno.h>
30
31#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34#include "filenet.h"
35#include "log.h"
36#include "module.h"
37#include "utils.h"
38#include "client.h"
39#include "transfer.h"
40#include "sysevents.h"
41#include "net.h"
24a794c2 42#include <tiger.h>
58e83d6a 43
44/* Protocol states */
45#define ADC_PROTOCOL 0
46#define ADC_IDENTIFY 1
47#define ADC_VERIFY 2
48#define ADC_NORMAL 3
49#define ADC_DATA 4
50
51struct command {
52 wchar_t *name;
53 int minargs, needsender;
54 void (*func)(struct fnetnode *fn, wchar_t *command, wchar_t *sender, int argc, wchar_t **argv);
55};
56
57struct qcmd {
58 struct qcmd *next;
59 wchar_t **args;
60};
61
ed63a7f8
FT
62struct qcmdqueue {
63 struct qcmd *f, *l;
64 int size;
65};
66
58e83d6a 67struct adchub {
ffa81d5f 68 struct socket *sk;
58e83d6a 69 char *inbuf;
70 size_t inbufdata, inbufsize;
71 wchar_t *sid;
72 wchar_t *cb;
73 size_t cbdata, cbsize;
74 wchar_t **sup;
75 iconv_t ich;
76 int state;
24a794c2 77 struct wcspair *hubinf;
ed63a7f8 78 struct qcmdqueue queue;
58e83d6a 79};
80
81static wchar_t *eoc;
82/* I've never understood why both of these are necessary, but... */
83static wchar_t *privid, *cid;
84
85static wchar_t **parseadc(wchar_t *cmdline)
86{
87 wchar_t **ret;
88 size_t retsize, retdata;
89 wchar_t *p, *p2, *ep;
90 wchar_t r;
91 ssize_t len;
92
93 ret = NULL;
94 retsize = retdata = 0;
95 p = cmdline;
96 do {
97 if((p2 = wcschr(p, L' ')) != NULL)
98 *(p2++) = L'\0';
99 len = wcslen(p);
100 for(ep = p; len > 0; ep++, len--) {
101 if(*ep == L'\\') {
102 if(ep[1] == L's') {
103 r = L' ';
104 } else if(ep[1] == L'n') {
105 r = L'\n';
106 } else if(ep[1] == L'\\') {
107 r = L'\\';
108 } else {
109 memmove(ep, ep + 2, (len -= 2) * sizeof(*ep));
110 ep--;
111 continue;
112 }
113 memmove(ep, ep + 1, --len * sizeof(*ep));
114 *ep = r;
115 }
116 }
117 *ep = L'\0';
118 addtobuf(ret, swcsdup(p));
119 p = p2;
120 } while(p2 != NULL);
121 addtobuf(ret, NULL);
122 return(ret);
123}
124
125static void sendeoc(struct socket *sk)
126{
127 sockqueue(sk, "\n", 1);
128}
129
130static void sendadc1(struct socket *sk, int sep, wchar_t *arg)
131{
132 char *mbsbuf;
133 wchar_t *buf;
134 size_t bufsize, bufdata;
135
136 buf = NULL;
137 bufsize = bufdata = 0;
138 if(sep)
139 addtobuf(buf, L' ');
140 for(; *arg != L'\0'; arg++) {
141 if(*arg == L' ')
142 bufcat(buf, L"\\s", 2);
143 else if(*arg == L'\n')
144 bufcat(buf, L"\\n", 2);
145 else if(*arg == L'\\')
146 bufcat(buf, L"\\\\", 2);
147 else
148 addtobuf(buf, *arg);
149 }
150 addtobuf(buf, L'\0');
151 mbsbuf = icwcstombs(buf, "utf-8");
152 sockqueue(sk, mbsbuf, strlen(mbsbuf));
153 free(mbsbuf);
154}
155
156static void sendadc(struct socket *sk, int sep, ...)
157{
158 va_list args;
159 wchar_t *arg;
160 int i;
161
162 va_start(args, sep);
163 for(i = 0; (arg = va_arg(args, wchar_t *)) != NULL; i++) {
164 if(arg == eoc)
165 sendeoc(sk);
166 else
167 sendadc1(sk, (i == 0)?sep:1, arg);
168 }
169 va_end(args);
170}
171
ed63a7f8 172static struct qcmd *newqcmd(struct qcmdqueue *queue, wchar_t **args)
58e83d6a 173{
174 struct qcmd *new;
175
58e83d6a 176 new = smalloc(sizeof(*new));
177 new->next = NULL;
178 new->args = args;
ed63a7f8
FT
179 if(queue->l == NULL)
180 queue->f = new;
181 else
182 queue->l->next = new;
183 queue->l = new;
184 queue->size++;
58e83d6a 185 return(new);
186}
187
ed63a7f8 188static struct qcmd *ulqcmd(struct qcmdqueue *queue)
58e83d6a 189{
190 struct qcmd *ret;
191
ed63a7f8 192 if((ret = queue->f) == NULL)
58e83d6a 193 return(NULL);
ed63a7f8
FT
194 if((queue->f = ret->next) == NULL)
195 queue->l = NULL;
196 queue->size--;
58e83d6a 197 return(ret);
198}
199
200static void freeqcmd(struct qcmd *qcmd)
201{
202 freeparr(qcmd->args);
203 free(qcmd);
204}
205
206#define ADC_CMDFN(name) static void name(struct fnetnode *fn, wchar_t *command, wchar_t *sender, int argc, wchar_t **argv)
0d6c5363 207#ifdef __GNUC__
9db779f4 208#define UNUSED __attribute__ ((unused))
0d6c5363 209#else
9db779f4 210#define UNUSED
0d6c5363 211#endif
9db779f4 212#define ADC_CMDCOM \
ffa81d5f
FT
213 struct adchub *hub UNUSED = fn->data; \
214 struct socket *sk UNUSED = hub->sk;
58e83d6a 215
216ADC_CMDFN(cmd_sup)
217{
218 ADC_CMDCOM;
219 int i, o, f;
220
221 for(i = 1; i < argc; i++) {
222 if(wcslen(argv[i]) < 3)
223 continue;
224 for(o = 0, f = 0; hub->sup[o]; o++) {
225 if(!wcscmp(argv[i] + 2, hub->sup[o])) {
226 f = 1;
227 break;
228 }
229 }
230 if(!wcsncmp(argv[i], L"AD", 2)) {
231 if(f)
232 continue;
233 hub->sup = srealloc(hub->sup, sizeof(*(hub->sup)) * (o + 1));
234 hub->sup[o] = swcsdup(argv[i] + 2);
235 } else if(!wcsncmp(argv[i], L"RM", 2)) {
236 if(!f)
237 continue;
24a794c2 238 free(hub->sup[o]);
58e83d6a 239 memmove(hub->sup[o], hub->sup[o + 1], parrlen(hub->sup) - o);
240 }
241 }
242}
243
244ADC_CMDFN(cmd_sid)
245{
246 ADC_CMDCOM;
247
248 if(hub->sid != NULL)
249 free(hub->sid);
250 hub->sid = swcsdup(argv[1]);
251 if(hub->state == ADC_PROTOCOL) {
252 hub->state = ADC_IDENTIFY;
253 }
254}
255
24a794c2 256ADC_CMDFN(cmd_inf)
257{
258 ADC_CMDCOM;
259
260 if(sender == NULL) {
261
262 }
263}
264
58e83d6a 265static struct command hubcmds[] = {
266 {L"SUP", 1, 0, cmd_sup},
267 {L"SID", 2, 0, cmd_sid},
24a794c2 268 {L"INF", 0, 0, cmd_inf},
58e83d6a 269 {NULL, 0, 0, NULL}
270};
271
272static void dispatch(struct qcmd *qcmd, struct fnetnode *fn)
273{
274 struct command *cmd;
275 int argc;
276 wchar_t *cmdnm, *sender, **argv;
277
278 if((argc = parrlen(argv = qcmd->args)) < 1)
279 return;
280 cmdnm = *(argv++);
281 argc--;
282 if(wcslen(cmdnm) < 2)
283 return;
284 sender = NULL;
285 if((*cmdnm == L'B') || (*cmdnm == L'F')) {
286 if(argc < 1)
287 return;
288 sender = *(argv++);
289 argc--;
290 } else if((*cmdnm == L'D') || (*cmdnm == L'E')) {
291 if(argc < 2)
292 return;
293 sender = *argv;
294 argv += 2;
295 argc -= 2;
296 }
297 for(cmd = hubcmds; cmd->func != NULL; cmd++) {
298 if(!wcscmp(cmd->name, qcmd->args[0] + 1)) {
299 if(argc < cmd->minargs)
300 return;
6adc02a2 301 cmd->func(fn, cmdnm, sender, argc, argv);
58e83d6a 302 return;
303 }
304 }
305 flog(LOG_DEBUG, "unknown adc command: %ls", qcmd->args[0]);
306}
307
cab0b442 308static void hubread(struct socket *sk, struct fnetnode *fn)
58e83d6a 309{
310 int ret;
311 struct adchub *hub;
312 char *newbuf, *p1, *p2;
313 wchar_t *p;
314 size_t datalen, cblen;
315
316 hub = fn->data;
317 if((newbuf = sockgetinbuf(sk, &datalen)) == NULL)
cab0b442 318 return;
58e83d6a 319 if(hub->inbufdata > 1024)
320 hub->inbufdata = 0;
321 bufcat(hub->inbuf, newbuf, datalen);
322 free(newbuf);
323 /* Memory eating protection */
324 if(hub->cbdata > 65536)
325 hub->cbdata = 0;
326 while(hub->inbufdata > 0) {
327 if(hub->cbdata == hub->cbsize)
328 sizebuf2(hub->cb, hub->cbdata + datalen, 1);
329 p1 = hub->inbuf;
330 p2 = (char *)(hub->cb + hub->cbdata);
331 cblen = sizeof(*(hub->cb)) * (hub->cbsize - hub->cbdata);
332 ret = iconv(hub->ich, &p1, &hub->inbufdata, &p2, &cblen);
333 memmove(hub->inbuf, p1, hub->inbufdata);
334 if(((p2 - ((char *)hub->cb)) % sizeof(*hub->cb)) != 0) {
335 flog(LOG_CRIT, "Spotted a dismembered wchar_t!");
336 abort();
337 }
338 hub->cbdata = hub->cbsize - (cblen / sizeof(*(hub->cb)));
339 if(ret < 0) {
340 if(errno == EILSEQ) {
341 flog(LOG_DEBUG, "adc fnetnode %i sent illegal utf-8 sequence", fn->id);
342 killfnetnode(fn);
cab0b442 343 return;
58e83d6a 344 } else if(errno == EINVAL) {
345 break;
346 } else if(errno == E2BIG) {
347 /* continue; */
348 } else {
349 flog(LOG_WARNING, "bug? iconv returned unexpected error: %s", strerror(errno));
cab0b442 350 return;
58e83d6a 351 }
352 }
353 }
354 while((p = wmemchr(hub->cb, L'\n', hub->cbdata)) != NULL) {
355 *(p++) = L'\0';
356 newqcmd(&hub->queue, parseadc(hub->cb));
357 memmove(hub->cb, p, (hub->cbdata -= (p - hub->cb)) * sizeof(*(hub->cb)));
358 }
359}
360
cab0b442 361static void huberr(struct socket *sk, int err, struct fnetnode *fn)
58e83d6a 362{
363 killfnetnode(fn);
364}
365
ffa81d5f 366static void hubconnect(struct fnetnode *fn, struct socket *sk)
58e83d6a 367{
368 struct adchub *hub;
369
ffa81d5f
FT
370 sk->readcb = (void (*)(struct socket *, void *))hubread;
371 sk->errcb = (void (*)(struct socket *, int, void *))huberr;
372 sk->data = fn;
58e83d6a 373
374 hub = smalloc(sizeof(*hub));
375 memset(hub, 0, sizeof(*hub));
70d8f2f1 376 getsock(hub->sk = sk);
58e83d6a 377 if((hub->ich = iconv_open("wchar_t", "utf-8")) == (iconv_t)-1) {
378 flog(LOG_CRIT, "iconv cannot handle UTF-8: %s", strerror(errno));
379 killfnetnode(fn);
380 return;
381 }
382 fn->data = hub;
6adc02a2 383 sendadc(sk, 0, L"HSUP", L"ADBASE", L"ADTIGR", eoc, NULL);
58e83d6a 384}
385
386static void hubdestroy(struct fnetnode *fn)
387{
388 struct adchub *hub;
389
ffa81d5f 390 hub = fn->data;
58e83d6a 391 iconv_close(hub->ich);
392 if(hub->inbuf != NULL)
393 free(hub->inbuf);
394 if(hub->sup != NULL)
395 freeparr(hub->sup);
396 free(hub);
397}
398
ffa81d5f
FT
399static void hubkill(struct fnetnode *fn)
400{
401 struct adchub *hub;
402
403 hub = fn->data;
404 hub->sk->close = 1;
405}
406
58e83d6a 407static int hubsetnick(struct fnetnode *fn, wchar_t *newnick)
408{
409 return(0);
410}
411
412static int hubreqconn(struct fnetpeer *peer)
413{
414 return(0);
415}
416
3ad44ea7 417static struct fnet adcnet_store = {
58e83d6a 418 .connect = hubconnect,
419 .destroy = hubdestroy,
ffa81d5f 420 .kill = hubkill,
58e83d6a 421 .setnick = hubsetnick,
422 .reqconn = hubreqconn,
423 .name = L"adc"
424};
425
3ad44ea7 426static struct fnet *adcnet = &adcnet_store;
427
58e83d6a 428static int run(void)
429{
430 int ret;
431 struct fnetnode *fn, *nextfn;
432 struct adchub *hub;
433 struct qcmd *qcmd;
434
435 ret = 0;
436 for(fn = fnetnodes; fn != NULL; fn = nextfn) {
437 nextfn = fn->next;
3ad44ea7 438 if(fn->fnet != adcnet)
58e83d6a 439 continue;
440 if((hub = fn->data) == NULL)
441 continue;
442 if((qcmd = ulqcmd(&hub->queue)) != NULL) {
ffa81d5f 443 if((hub->sk != NULL) && (hub->sk->state == SOCK_EST))
58e83d6a 444 dispatch(qcmd, fn);
445 freeqcmd(qcmd);
446 ret = 1;
447 break;
448 }
449 }
450 return(ret);
451}
452
453static void preinit(int hup)
454{
455 if(hup)
456 return;
3ad44ea7 457 regfnet(adcnet);
58e83d6a 458}
459
6adc02a2 460static void makepid(char *idbuf)
58e83d6a 461{
462 int i;
6adc02a2
FT
463 int fd, ret;
464
465 i = 0;
466 if((fd = open("/dev/urandom", O_RDONLY)) >= 0) {
467 for(i = 0; i < 24; i += ret) {
468 if((ret = read(fd, idbuf + i, 24 - i)) <= 0) {
469 flog(LOG_WARNING, "could not read random data from /dev/urandom for ADC PID: %s", (errno == 0)?"EOF":strerror(errno));
470 break;
471 }
472 }
473 close(fd);
474 } else {
475 flog(LOG_WARNING, "could not open /dev/urandom: %s", strerror(errno));
476 }
477 if(i != 24) {
478 for(i = 0; i < sizeof(idbuf); i++)
479 idbuf[i] = rand() % 256;
480 }
481}
482
483static int init(int hup)
484{
58e83d6a 485 char idbuf[24], *id32;
486 struct tigerhash th;
487
488 if(!hup) {
489 eoc = swcsdup(L"");
490
491 if((privid = fetchvar("adc.pid", NULL)) == NULL) {
6adc02a2 492 makepid(idbuf);
58e83d6a 493 id32 = base32encode(idbuf, sizeof(idbuf));
494 id32[39] = 0;
495 privid = icmbstowcs(id32, "us-ascii");
496 free(id32);
497 storevar("adc.pid", privid, sizeof(*privid) * (wcslen(privid) + 1));
498 }
499
500 id32 = base32decode(icswcstombs(privid, "us-ascii", NULL), NULL);
501 inittiger(&th);
502 dotiger(&th, id32, 24);
503 synctiger(&th);
504 free(id32);
505 restiger(&th, idbuf);
506 id32 = base32encode(idbuf, sizeof(idbuf));
507 id32[39] = 0;
508 cid = icmbstowcs(id32, "us-ascii");
509 free(id32);
510 }
511 return(0);
512}
513
514static void terminate(void)
515{
516
517}
518
519static struct configvar myvars[] = {
d9f89ef5 520 /** Specifies a specific UDP port to use for ADC search
521 * results. If left unspecified, a port is allocated
522 * dynamically. Useful for NAT routers (see also the
523 * net.visibleipv4 address for those cases). */
58e83d6a 524 {CONF_VAR_INT, "udpport", {.num = 0}},
d9f89ef5 525 /** Specifies a specific TCP port to use for ADC peer
526 * connections. If left unspecified, a port is allocated
527 * dynamically. Useful for NAT routers (see also the
528 * net.visibleipv4 address for those cases). */
58e83d6a 529 {CONF_VAR_INT, "tcpport", {.num = 0}},
530 {CONF_VAR_END}
531};
532
533static struct module me = {
534 .conf = {
535 .vars = myvars
536 },
537 .preinit = preinit,
538 .init = init,
539 .run = run,
540 .terminate = terminate,
541 .name = "adc"
542};
543
544MODULE(me)