Generate ADC PID more reliably.
[doldaconnect.git] / daemon / fnet-adc.c
1 /*
2  *  Dolda Connect - Modular multiuser Direct Connect-style client
3  *  Copyright (C) 2004 Fredrik Tolf <fredrik@dolda2000.com>
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>
22 #include <fcntl.h>
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"
42 #include <tiger.h>
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
51 struct 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
57 struct qcmd {
58     struct qcmd *next;
59     wchar_t **args;
60 };
61
62 struct qcmdqueue {
63     struct qcmd *f, *l;
64     int size;
65 };
66
67 struct adchub {
68     struct socket *sk;
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;
77     struct wcspair *hubinf;
78     struct qcmdqueue queue;
79 };
80
81 static wchar_t *eoc;
82 /* I've never understood why both of these are necessary, but... */
83 static wchar_t *privid, *cid;
84
85 static 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
125 static void sendeoc(struct socket *sk)
126 {
127     sockqueue(sk, "\n", 1);
128 }
129
130 static 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
156 static 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
172 static struct qcmd *newqcmd(struct qcmdqueue *queue, wchar_t **args)
173 {
174     struct qcmd *new;
175     
176     new = smalloc(sizeof(*new));
177     new->next = NULL;
178     new->args = args;
179     if(queue->l == NULL)
180         queue->f = new;
181     else
182         queue->l->next = new;
183     queue->l = new;
184     queue->size++;
185     return(new);
186 }
187
188 static struct qcmd *ulqcmd(struct qcmdqueue *queue)
189 {
190     struct qcmd *ret;
191     
192     if((ret = queue->f) == NULL)
193         return(NULL);
194     if((queue->f = ret->next) == NULL)
195         queue->l = NULL;
196     queue->size--;
197     return(ret);
198 }
199
200 static 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)
207 #ifdef __GNUC__
208 #define UNUSED __attribute__ ((unused))
209 #else
210 #define UNUSED
211 #endif
212 #define ADC_CMDCOM \
213         struct adchub *hub UNUSED = fn->data; \
214         struct socket *sk UNUSED = hub->sk;
215
216 ADC_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;
238             free(hub->sup[o]);
239             memmove(hub->sup[o], hub->sup[o + 1], parrlen(hub->sup) - o);
240         }
241     }
242 }
243
244 ADC_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
256 ADC_CMDFN(cmd_inf)
257 {
258     ADC_CMDCOM;
259     
260     if(sender == NULL) {
261         
262     }
263 }
264
265 static struct command hubcmds[] = {
266     {L"SUP", 1, 0, cmd_sup},
267     {L"SID", 2, 0, cmd_sid},
268     {L"INF", 0, 0, cmd_inf},
269     {NULL, 0, 0, NULL}
270 };
271
272 static 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;
301             cmd->func(fn, cmdnm, sender, argc, argv);
302             return;
303         }
304     }
305     flog(LOG_DEBUG, "unknown adc command: %ls", qcmd->args[0]);
306 }
307
308 static void hubread(struct socket *sk, struct fnetnode *fn)
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)
318         return;
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);
343                 return;
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));
350                 return;
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
361 static void huberr(struct socket *sk, int err, struct fnetnode *fn)
362 {
363     killfnetnode(fn);
364 }
365
366 static void hubconnect(struct fnetnode *fn, struct socket *sk)
367 {
368     struct adchub *hub;
369     
370     sk->readcb = (void (*)(struct socket *, void *))hubread;
371     sk->errcb = (void (*)(struct socket *, int, void *))huberr;
372     sk->data = fn;
373     
374     hub = smalloc(sizeof(*hub));
375     memset(hub, 0, sizeof(*hub));
376     getsock(hub->sk = sk);
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;
383     sendadc(sk, 0, L"HSUP", L"ADBASE", L"ADTIGR", eoc, NULL);
384 }
385
386 static void hubdestroy(struct fnetnode *fn)
387 {
388     struct adchub *hub;
389     
390     hub = fn->data;
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
399 static void hubkill(struct fnetnode *fn)
400 {
401     struct adchub *hub;
402     
403     hub = fn->data;
404     hub->sk->close = 1;
405 }
406
407 static int hubsetnick(struct fnetnode *fn, wchar_t *newnick)
408 {
409     return(0);
410 }
411
412 static int hubreqconn(struct fnetpeer *peer)
413 {
414     return(0);
415 }
416
417 static struct fnet adcnet_store = {
418     .connect = hubconnect,
419     .destroy = hubdestroy,
420     .kill = hubkill,
421     .setnick = hubsetnick,
422     .reqconn = hubreqconn,
423     .name = L"adc"
424 };
425
426 static struct fnet *adcnet = &adcnet_store;
427
428 static 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;
438         if(fn->fnet != adcnet)
439             continue;
440         if((hub = fn->data) == NULL)
441             continue;
442         if((qcmd = ulqcmd(&hub->queue)) != NULL) {
443             if((hub->sk != NULL) && (hub->sk->state == SOCK_EST))
444                 dispatch(qcmd, fn);
445             freeqcmd(qcmd);
446             ret = 1;
447             break;
448         }
449     }
450     return(ret);
451 }
452
453 static void preinit(int hup)
454 {
455     if(hup)
456         return;
457     regfnet(adcnet);
458 }
459
460 static void makepid(char *idbuf)
461 {
462     int i;
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
483 static int init(int hup)
484 {
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) {
492             makepid(idbuf);
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
514 static void terminate(void)
515 {
516     
517 }
518
519 static struct configvar myvars[] = {
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). */
524     {CONF_VAR_INT, "udpport", {.num = 0}},
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). */
529     {CONF_VAR_INT, "tcpport", {.num = 0}},
530     {CONF_VAR_END}
531 };
532
533 static 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
544 MODULE(me)