A DynamicLookupCommand exiting with 10 is treated like an empty server stanza.
[libradsec.git] / radsecproxy.c
1 /*
2  * Copyright (C) 2006-2009 Stig Venaas <venaas@uninett.no>
3  * Copyright (C) 2010, 2011 NORDUnet A/S
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  */
9
10 /* Code contributions from:
11  *
12  * Arne Schwabe <schwabe at uni-paderborn.de>
13  * Maja Wolniewicz <mgw@umk.pl>
14  * Simon Leinen <simon.leinen@switch.ch>
15  * Stefan Winter <stefan.winter@restena.lu>
16  */
17
18 /* For UDP there is one server instance consisting of udpserverrd and udpserverth
19  *              rd is responsible for init and launching wr
20  * For TLS there is a server instance that launches tlsserverrd for each TLS peer
21  *          each tlsserverrd launches tlsserverwr
22  * For each UDP/TLS peer there is clientrd and clientwr, clientwr is responsible
23  *          for init and launching rd
24  *
25  * serverrd will receive a request, processes it and puts it in the requestq of
26  *          the appropriate clientwr
27  * clientwr monitors its requestq and sends requests
28  * clientrd looks for responses, processes them and puts them in the replyq of
29  *          the peer the request came from
30  * serverwr monitors its reply and sends replies
31  *
32  * In addition to the main thread, we have:
33  * If UDP peers are configured, there will be 2 + 2 * #peers UDP threads
34  * If TLS peers are configured, there will initially be 2 * #peers TLS threads
35  * For each TLS peer connecting to us there will be 2 more TLS threads
36  *       This is only for connected peers
37  * Example: With 3 UDP peers and 30 TLS peers, there will be a max of
38  *          1 + (2 + 2 * 3) + (2 * 30) + (2 * 30) = 129 threads
39  */
40
41 /* Bugs:
42  * May segfault when dtls connections go down? More testing needed
43  * Remove expired stuff from clients request list?
44  * Multiple outgoing connections if not enough IDs? (multiple servers per conf?)
45  * Useful for TCP accounting? Now we require separate server config for alt port
46  */
47
48 #include <signal.h>
49 #include <sys/socket.h>
50 #include <netinet/in.h>
51 #include <netdb.h>
52 #include <string.h>
53 #include <unistd.h>
54 #include <limits.h>
55 #ifdef SYS_SOLARIS9
56 #include <fcntl.h>
57 #endif
58 #include <sys/time.h>
59 #include <sys/types.h>
60 #include <ctype.h>
61 #include <sys/wait.h>
62 #include <arpa/inet.h>
63 #include <regex.h>
64 #include <libgen.h>
65 #include <pthread.h>
66 #include <errno.h>
67 #include <openssl/ssl.h>
68 #include <openssl/rand.h>
69 #include <openssl/err.h>
70 #include <openssl/md5.h>
71 #include "debug.h"
72 #include "hash.h"
73 #include "util.h"
74 #include "hostport.h"
75 #include "radsecproxy.h"
76 #include "udp.h"
77 #include "tcp.h"
78 #include "tls.h"
79 #include "dtls.h"
80 #if defined(WANT_FTICKS)
81 #include "fticks.h"
82 #endif
83
84 static struct options options;
85 static struct list *clconfs, *srvconfs;
86 static struct list *realms;
87 static struct hash *rewriteconfs;
88
89 static pthread_mutex_t *ssl_locks = NULL;
90 static long *ssl_lock_count;
91 extern int optind;
92 extern char *optarg;
93 static const struct protodefs *protodefs[RAD_PROTOCOUNT];
94
95 /* minimum required declarations to avoid reordering code */
96 struct realm *adddynamicrealmserver(struct realm *realm, char *id);
97 int dynamicconfig(struct server *server);
98 int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val);
99 void freerealm(struct realm *realm);
100 void freeclsrvconf(struct clsrvconf *conf);
101 void freerq(struct request *rq);
102 void freerqoutdata(struct rqout *rqout);
103 void rmclientrq(struct request *rq, uint8_t id);
104
105 static const struct protodefs *(*protoinits[])(uint8_t) = { udpinit, tlsinit, tcpinit, dtlsinit };
106
107 uint8_t protoname2int(const char *name) {
108     uint8_t i;
109
110     for (i = 0; i < RAD_PROTOCOUNT; i++)
111         if (protodefs[i] && protodefs[i]->name && !strcasecmp(protodefs[i]->name, name))
112             return i;
113     return 255;
114 }
115
116 /* callbacks for making OpenSSL thread safe */
117 unsigned long ssl_thread_id() {
118     return (unsigned long)pthread_self();
119 }
120
121 void ssl_locking_callback(int mode, int type, const char *file, int line) {
122     if (mode & CRYPTO_LOCK) {
123         pthread_mutex_lock(&ssl_locks[type]);
124         ssl_lock_count[type]++;
125     } else
126         pthread_mutex_unlock(&ssl_locks[type]);
127 }
128
129 /* returns 1 if the len first bits are equal, else 0 */
130 int prefixmatch(void *a1, void *a2, uint8_t len) {
131     static uint8_t mask[] = { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
132     uint8_t r, l = len / 8;
133     if (l && memcmp(a1, a2, l))
134         return 0;
135     r = len % 8;
136     if (!r)
137         return 1;
138     return (((uint8_t *)a1)[l] & mask[r]) == (((uint8_t *)a2)[l] & mask[r]);
139 }
140
141 /* returns next config with matching address, or NULL */
142 struct clsrvconf *find_conf(uint8_t type, struct sockaddr *addr, struct list *confs, struct list_node **cur, uint8_t server_p) {
143     struct list_node *entry;
144     struct clsrvconf *conf;
145
146     for (entry = (cur && *cur ? list_next(*cur) : list_first(confs)); entry; entry = list_next(entry)) {
147         conf = (struct clsrvconf *)entry->data;
148         if (conf->type == type && addressmatches(conf->hostports, addr, server_p)) {
149             if (cur)
150                 *cur = entry;
151             return conf;
152         }
153     }
154     return NULL;
155 }
156
157 struct clsrvconf *find_clconf(uint8_t type, struct sockaddr *addr, struct list_node **cur) {
158     return find_conf(type, addr, clconfs, cur, 0);
159 }
160
161 struct clsrvconf *find_srvconf(uint8_t type, struct sockaddr *addr, struct list_node **cur) {
162     return find_conf(type, addr, srvconfs, cur, 1);
163 }
164
165 /* returns next config of given type, or NULL */
166 struct clsrvconf *find_clconf_type(uint8_t type, struct list_node **cur) {
167     struct list_node *entry;
168     struct clsrvconf *conf;
169
170     for (entry = (cur && *cur ? list_next(*cur) : list_first(clconfs)); entry; entry = list_next(entry)) {
171         conf = (struct clsrvconf *)entry->data;
172         if (conf->type == type) {
173             if (cur)
174                 *cur = entry;
175             return conf;
176         }
177     }
178     return NULL;
179 }
180
181 struct gqueue *newqueue() {
182     struct gqueue *q;
183
184     q = malloc(sizeof(struct gqueue));
185     if (!q)
186         debugx(1, DBG_ERR, "malloc failed");
187     q->entries = list_create();
188     if (!q->entries)
189         debugx(1, DBG_ERR, "malloc failed");
190     pthread_mutex_init(&q->mutex, NULL);
191     pthread_cond_init(&q->cond, NULL);
192     return q;
193 }
194
195 void removequeue(struct gqueue *q) {
196     struct list_node *entry;
197
198     if (!q)
199         return;
200     pthread_mutex_lock(&q->mutex);
201     for (entry = list_first(q->entries); entry; entry = list_next(entry))
202         freerq((struct request *)entry);
203     list_destroy(q->entries);
204     pthread_cond_destroy(&q->cond);
205     pthread_mutex_unlock(&q->mutex);
206     pthread_mutex_destroy(&q->mutex);
207     free(q);
208 }
209
210 void freebios(struct gqueue *q) {
211     BIO *bio;
212
213     pthread_mutex_lock(&q->mutex);
214     while ((bio = (BIO *)list_shift(q->entries)))
215         BIO_free(bio);
216     pthread_mutex_unlock(&q->mutex);
217     removequeue(q);
218 }
219
220 struct client *addclient(struct clsrvconf *conf, uint8_t lock) {
221     struct client *new = malloc(sizeof(struct client));
222
223     if (!new) {
224         debug(DBG_ERR, "malloc failed");
225         return NULL;
226     }
227
228     if (lock)
229         pthread_mutex_lock(conf->lock);
230     if (!conf->clients) {
231         conf->clients = list_create();
232         if (!conf->clients) {
233             if (lock)
234                 pthread_mutex_unlock(conf->lock);
235             debug(DBG_ERR, "malloc failed");
236             return NULL;
237         }
238     }
239
240     memset(new, 0, sizeof(struct client));
241     new->conf = conf;
242     if (conf->pdef->addclient)
243         conf->pdef->addclient(new);
244     else
245         new->replyq = newqueue();
246     list_push(conf->clients, new);
247     if (lock)
248         pthread_mutex_unlock(conf->lock);
249     return new;
250 }
251
252 void removeclientrqs_sendrq_freeserver_lock(uint8_t wantlock) {
253     static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
254
255     if (wantlock)
256         pthread_mutex_lock(&lock);
257     else
258         pthread_mutex_unlock(&lock);
259 }
260
261 void removeclientrqs(struct client *client) {
262     struct request *rq;
263     struct rqout *rqout;
264     int i;
265
266     removeclientrqs_sendrq_freeserver_lock(1);
267     for (i = 0; i < MAX_REQUESTS; i++) {
268         rq = client->rqs[i];
269         if (!rq)
270             continue;
271         if (rq->to) {
272             rqout = rq->to->requests + rq->newid;
273             pthread_mutex_lock(rqout->lock);
274             if (rqout->rq == rq) /* still pointing to our request */
275                 freerqoutdata(rqout);
276             pthread_mutex_unlock(rqout->lock);
277         }
278         freerq(rq);
279     }
280     removeclientrqs_sendrq_freeserver_lock(0);
281 }
282
283 void removelockedclient(struct client *client) {
284     struct clsrvconf *conf;
285
286     conf = client->conf;
287     if (conf->clients) {
288         removeclientrqs(client);
289         removequeue(client->replyq);
290         list_removedata(conf->clients, client);
291         free(client->addr);
292         free(client);
293     }
294 }
295
296 void removeclient(struct client *client) {
297     struct clsrvconf *conf;
298
299     if (!client)
300         return;
301
302     conf = client->conf;
303     pthread_mutex_lock(conf->lock);
304     removelockedclient(client);
305     pthread_mutex_unlock(conf->lock);
306 }
307
308 void freeserver(struct server *server, uint8_t destroymutex) {
309     struct rqout *rqout, *end;
310
311     if (!server)
312         return;
313
314     removeclientrqs_sendrq_freeserver_lock(1);
315     if (server->requests) {
316         rqout = server->requests;
317         for (end = rqout + MAX_REQUESTS; rqout < end; rqout++) {
318             if (rqout->rq)
319                 rqout->rq->to = NULL;
320             freerqoutdata(rqout);
321             pthread_mutex_destroy(rqout->lock);
322             free(rqout->lock);
323         }
324         free(server->requests);
325     }
326     if (server->rbios)
327         freebios(server->rbios);
328     free(server->dynamiclookuparg);
329     if (server->ssl)
330         SSL_free(server->ssl);
331     if (destroymutex) {
332         pthread_mutex_destroy(&server->lock);
333         pthread_cond_destroy(&server->newrq_cond);
334         pthread_mutex_destroy(&server->newrq_mutex);
335     }
336     removeclientrqs_sendrq_freeserver_lock(0);
337     free(server);
338 }
339
340 int addserver(struct clsrvconf *conf) {
341     int i;
342
343     if (conf->servers) {
344         debug(DBG_ERR, "addserver: currently works with just one server per conf");
345         return 0;
346     }
347     conf->servers = malloc(sizeof(struct server));
348     if (!conf->servers) {
349         debug(DBG_ERR, "malloc failed");
350         return 0;
351     }
352     memset(conf->servers, 0, sizeof(struct server));
353     conf->servers->conf = conf;
354
355 #ifdef RADPROT_DTLS
356     if (conf->type == RAD_DTLS)
357         conf->servers->rbios = newqueue();
358 #endif
359     conf->pdef->setsrcres();
360
361     conf->servers->sock = -1;
362     if (conf->pdef->addserverextra)
363         conf->pdef->addserverextra(conf);
364
365     conf->servers->requests = calloc(MAX_REQUESTS, sizeof(struct rqout));
366     if (!conf->servers->requests) {
367         debug(DBG_ERR, "malloc failed");
368         goto errexit;
369     }
370     for (i = 0; i < MAX_REQUESTS; i++) {
371         conf->servers->requests[i].lock = malloc(sizeof(pthread_mutex_t));
372         if (!conf->servers->requests[i].lock) {
373             debug(DBG_ERR, "malloc failed");
374             goto errexit;
375         }
376         if (pthread_mutex_init(conf->servers->requests[i].lock, NULL)) {
377             debugerrno(errno, DBG_ERR, "mutex init failed");
378             free(conf->servers->requests[i].lock);
379             conf->servers->requests[i].lock = NULL;
380             goto errexit;
381         }
382     }
383     if (pthread_mutex_init(&conf->servers->lock, NULL)) {
384         debugerrno(errno, DBG_ERR, "mutex init failed");
385         goto errexit;
386     }
387     conf->servers->newrq = 0;
388     if (pthread_mutex_init(&conf->servers->newrq_mutex, NULL)) {
389         debugerrno(errno, DBG_ERR, "mutex init failed");
390         pthread_mutex_destroy(&conf->servers->lock);
391         goto errexit;
392     }
393     if (pthread_cond_init(&conf->servers->newrq_cond, NULL)) {
394         debugerrno(errno, DBG_ERR, "mutex init failed");
395         pthread_mutex_destroy(&conf->servers->newrq_mutex);
396         pthread_mutex_destroy(&conf->servers->lock);
397         goto errexit;
398     }
399
400     return 1;
401
402 errexit:
403     freeserver(conf->servers, 0);
404     conf->servers = NULL;
405     return 0;
406 }
407
408 unsigned char *attrget(unsigned char *attrs, int length, uint8_t type) {
409     while (length > 1) {
410         if (ATTRTYPE(attrs) == type)
411             return attrs;
412         length -= ATTRLEN(attrs);
413         attrs += ATTRLEN(attrs);
414     }
415     return NULL;
416 }
417
418 struct request *newrqref(struct request *rq) {
419     if (rq)
420         rq->refcount++;
421     return rq;
422 }
423
424 void freerq(struct request *rq) {
425     if (!rq)
426         return;
427     debug(DBG_DBG, "freerq: called with refcount %d", rq->refcount);
428     if (--rq->refcount)
429         return;
430     if (rq->origusername)
431         free(rq->origusername);
432     if (rq->buf)
433         free(rq->buf);
434     if (rq->replybuf)
435         free(rq->replybuf);
436     if (rq->msg)
437         radmsg_free(rq->msg);
438     free(rq);
439 }
440
441 void freerqoutdata(struct rqout *rqout) {
442     if (!rqout)
443         return;
444     if (rqout->rq) {
445         if (rqout->rq->buf) {
446             free(rqout->rq->buf);
447             rqout->rq->buf = NULL;
448         }
449         freerq(rqout->rq);
450         rqout->rq = NULL;
451     }
452     rqout->tries = 0;
453     memset(&rqout->expiry, 0, sizeof(struct timeval));
454 }
455
456 void sendrq(struct request *rq) {
457     int i, start;
458     struct server *to;
459
460     removeclientrqs_sendrq_freeserver_lock(1);
461     to = rq->to;
462     if (!to)
463         goto errexit;
464
465     start = to->conf->statusserver ? 1 : 0;
466     pthread_mutex_lock(&to->newrq_mutex);
467     if (start && rq->msg->code == RAD_Status_Server) {
468         pthread_mutex_lock(to->requests[0].lock);
469         if (to->requests[0].rq) {
470             pthread_mutex_unlock(to->requests[0].lock);
471             debug(DBG_INFO, "sendrq: status server already in queue, dropping request");
472             goto errexit;
473         }
474         i = 0;
475     } else {
476         if (!to->nextid)
477             to->nextid = start;
478         /* might simplify if only try nextid, might be ok */
479         for (i = to->nextid; i < MAX_REQUESTS; i++) {
480             if (!to->requests[i].rq) {
481                 pthread_mutex_lock(to->requests[i].lock);
482                 if (!to->requests[i].rq)
483                     break;
484                 pthread_mutex_unlock(to->requests[i].lock);
485             }
486         }
487         if (i == MAX_REQUESTS) {
488             for (i = start; i < to->nextid; i++) {
489                 if (!to->requests[i].rq) {
490                     pthread_mutex_lock(to->requests[i].lock);
491                     if (!to->requests[i].rq)
492                         break;
493                     pthread_mutex_unlock(to->requests[i].lock);
494                 }
495             }
496             if (i == to->nextid) {
497                 debug(DBG_INFO, "sendrq: no room in queue, dropping request");
498                 goto errexit;
499             }
500         }
501     }
502     rq->newid = (uint8_t)i;
503     rq->msg->id = (uint8_t)i;
504     rq->buf = radmsg2buf(rq->msg, (uint8_t *)to->conf->secret);
505     if (!rq->buf) {
506         pthread_mutex_unlock(to->requests[i].lock);
507         debug(DBG_ERR, "sendrq: radmsg2buf failed");
508         goto errexit;
509     }
510
511     debug(DBG_DBG, "sendrq: inserting packet with id %d in queue for %s", i, to->conf->name);
512     to->requests[i].rq = rq;
513     pthread_mutex_unlock(to->requests[i].lock);
514     if (i >= start) /* i is not reserved for statusserver */
515         to->nextid = i + 1;
516
517     if (!to->newrq) {
518         to->newrq = 1;
519         debug(DBG_DBG, "sendrq: signalling client writer");
520         pthread_cond_signal(&to->newrq_cond);
521     }
522
523     pthread_mutex_unlock(&to->newrq_mutex);
524     removeclientrqs_sendrq_freeserver_lock(0);
525     return;
526
527 errexit:
528     if (rq->from)
529         rmclientrq(rq, rq->msg->id);
530     freerq(rq);
531     pthread_mutex_unlock(&to->newrq_mutex);
532     removeclientrqs_sendrq_freeserver_lock(0);
533 }
534
535 void sendreply(struct request *rq) {
536     uint8_t first;
537     struct client *to = rq->from;
538
539     if (!rq->replybuf)
540         rq->replybuf = radmsg2buf(rq->msg, (uint8_t *)to->conf->secret);
541     radmsg_free(rq->msg);
542     rq->msg = NULL;
543     if (!rq->replybuf) {
544         freerq(rq);
545         debug(DBG_ERR, "sendreply: radmsg2buf failed");
546         return;
547     }
548
549     pthread_mutex_lock(&to->replyq->mutex);
550     first = list_first(to->replyq->entries) == NULL;
551
552     if (!list_push(to->replyq->entries, rq)) {
553         pthread_mutex_unlock(&to->replyq->mutex);
554         freerq(rq);
555         debug(DBG_ERR, "sendreply: malloc failed");
556         return;
557     }
558
559     if (first) {
560         debug(DBG_DBG, "signalling server writer");
561         pthread_cond_signal(&to->replyq->cond);
562     }
563     pthread_mutex_unlock(&to->replyq->mutex);
564 }
565
566 int pwdcrypt(char encrypt_flag, uint8_t *in, uint8_t len, char *shared, uint8_t sharedlen, uint8_t *auth) {
567     static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
568     static unsigned char first = 1;
569     static EVP_MD_CTX mdctx;
570     unsigned char hash[EVP_MAX_MD_SIZE], *input;
571     unsigned int md_len;
572     uint8_t i, offset = 0, out[128];
573
574     pthread_mutex_lock(&lock);
575     if (first) {
576         EVP_MD_CTX_init(&mdctx);
577         first = 0;
578     }
579
580     input = auth;
581     for (;;) {
582         if (!EVP_DigestInit_ex(&mdctx, EVP_md5(), NULL) ||
583             !EVP_DigestUpdate(&mdctx, (uint8_t *)shared, sharedlen) ||
584             !EVP_DigestUpdate(&mdctx, input, 16) ||
585             !EVP_DigestFinal_ex(&mdctx, hash, &md_len) ||
586             md_len != 16) {
587             pthread_mutex_unlock(&lock);
588             return 0;
589         }
590         for (i = 0; i < 16; i++)
591             out[offset + i] = hash[i] ^ in[offset + i];
592         if (encrypt_flag)
593             input = out + offset;
594         else
595             input = in + offset;
596         offset += 16;
597         if (offset == len)
598             break;
599     }
600     memcpy(in, out, len);
601     pthread_mutex_unlock(&lock);
602     return 1;
603 }
604
605 int msmppencrypt(uint8_t *text, uint8_t len, uint8_t *shared, uint8_t sharedlen, uint8_t *auth, uint8_t *salt) {
606     static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
607     static unsigned char first = 1;
608     static EVP_MD_CTX mdctx;
609     unsigned char hash[EVP_MAX_MD_SIZE];
610     unsigned int md_len;
611     uint8_t i, offset;
612
613     pthread_mutex_lock(&lock);
614     if (first) {
615         EVP_MD_CTX_init(&mdctx);
616         first = 0;
617     }
618
619 #if 0
620     printfchars(NULL, "msppencrypt auth in", "%02x ", auth, 16);
621     printfchars(NULL, "msppencrypt salt in", "%02x ", salt, 2);
622     printfchars(NULL, "msppencrypt in", "%02x ", text, len);
623 #endif
624
625     if (!EVP_DigestInit_ex(&mdctx, EVP_md5(), NULL) ||
626         !EVP_DigestUpdate(&mdctx, shared, sharedlen) ||
627         !EVP_DigestUpdate(&mdctx, auth, 16) ||
628         !EVP_DigestUpdate(&mdctx, salt, 2) ||
629         !EVP_DigestFinal_ex(&mdctx, hash, &md_len)) {
630         pthread_mutex_unlock(&lock);
631         return 0;
632     }
633
634 #if 0
635     printfchars(NULL, "msppencrypt hash", "%02x ", hash, 16);
636 #endif
637
638     for (i = 0; i < 16; i++)
639         text[i] ^= hash[i];
640
641     for (offset = 16; offset < len; offset += 16) {
642 #if 0
643         printf("text + offset - 16 c(%d): ", offset / 16);
644         printfchars(NULL, NULL, "%02x ", text + offset - 16, 16);
645 #endif
646         if (!EVP_DigestInit_ex(&mdctx, EVP_md5(), NULL) ||
647             !EVP_DigestUpdate(&mdctx, shared, sharedlen) ||
648             !EVP_DigestUpdate(&mdctx, text + offset - 16, 16) ||
649             !EVP_DigestFinal_ex(&mdctx, hash, &md_len) ||
650             md_len != 16) {
651             pthread_mutex_unlock(&lock);
652             return 0;
653         }
654 #if 0
655         printfchars(NULL, "msppencrypt hash", "%02x ", hash, 16);
656 #endif
657
658         for (i = 0; i < 16; i++)
659             text[offset + i] ^= hash[i];
660     }
661
662 #if 0
663     printfchars(NULL, "msppencrypt out", "%02x ", text, len);
664 #endif
665
666     pthread_mutex_unlock(&lock);
667     return 1;
668 }
669
670 int msmppdecrypt(uint8_t *text, uint8_t len, uint8_t *shared, uint8_t sharedlen, uint8_t *auth, uint8_t *salt) {
671     static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
672     static unsigned char first = 1;
673     static EVP_MD_CTX mdctx;
674     unsigned char hash[EVP_MAX_MD_SIZE];
675     unsigned int md_len;
676     uint8_t i, offset;
677     char plain[255];
678
679     pthread_mutex_lock(&lock);
680     if (first) {
681         EVP_MD_CTX_init(&mdctx);
682         first = 0;
683     }
684
685 #if 0
686     printfchars(NULL, "msppdecrypt auth in", "%02x ", auth, 16);
687     printfchars(NULL, "msppdecrypt salt in", "%02x ", salt, 2);
688     printfchars(NULL, "msppdecrypt in", "%02x ", text, len);
689 #endif
690
691     if (!EVP_DigestInit_ex(&mdctx, EVP_md5(), NULL) ||
692         !EVP_DigestUpdate(&mdctx, shared, sharedlen) ||
693         !EVP_DigestUpdate(&mdctx, auth, 16) ||
694         !EVP_DigestUpdate(&mdctx, salt, 2) ||
695         !EVP_DigestFinal_ex(&mdctx, hash, &md_len)) {
696         pthread_mutex_unlock(&lock);
697         return 0;
698     }
699
700 #if 0
701     printfchars(NULL, "msppdecrypt hash", "%02x ", hash, 16);
702 #endif
703
704     for (i = 0; i < 16; i++)
705         plain[i] = text[i] ^ hash[i];
706
707     for (offset = 16; offset < len; offset += 16) {
708 #if 0
709         printf("text + offset - 16 c(%d): ", offset / 16);
710         printfchars(NULL, NULL, "%02x ", text + offset - 16, 16);
711 #endif
712         if (!EVP_DigestInit_ex(&mdctx, EVP_md5(), NULL) ||
713             !EVP_DigestUpdate(&mdctx, shared, sharedlen) ||
714             !EVP_DigestUpdate(&mdctx, text + offset - 16, 16) ||
715             !EVP_DigestFinal_ex(&mdctx, hash, &md_len) ||
716             md_len != 16) {
717             pthread_mutex_unlock(&lock);
718             return 0;
719         }
720 #if 0
721         printfchars(NULL, "msppdecrypt hash", "%02x ", hash, 16);
722 #endif
723
724         for (i = 0; i < 16; i++)
725             plain[offset + i] = text[offset + i] ^ hash[i];
726     }
727
728     memcpy(text, plain, len);
729 #if 0
730     printfchars(NULL, "msppdecrypt out", "%02x ", text, len);
731 #endif
732
733     pthread_mutex_unlock(&lock);
734     return 1;
735 }
736
737 struct realm *newrealmref(struct realm *r) {
738     if (r)
739         r->refcount++;
740     return r;
741 }
742
743 /* returns with lock on realm */
744 struct realm *id2realm(struct list *realmlist, char *id) {
745     struct list_node *entry;
746     struct realm *realm, *subrealm;
747
748     /* need to do locking for subrealms and check subrealm timers */
749     for (entry = list_first(realmlist); entry; entry = list_next(entry)) {
750         realm = (struct realm *)entry->data;
751         if (!regexec(&realm->regex, id, 0, NULL, 0)) {
752             pthread_mutex_lock(&realm->mutex);
753             if (realm->subrealms) {
754                 subrealm = id2realm(realm->subrealms, id);
755                 if (subrealm) {
756                     pthread_mutex_unlock(&realm->mutex);
757                     return subrealm;
758                 }
759             }
760             return newrealmref(realm);
761         }
762     }
763     return NULL;
764 }
765
766 int hasdynamicserver(struct list *srvconfs) {
767     struct list_node *entry;
768
769     for (entry = list_first(srvconfs); entry; entry = list_next(entry))
770         if (((struct clsrvconf *)entry->data)->dynamiclookupcommand)
771             return 1;
772     return 0;
773 }
774
775 /* helper function, only used by removeserversubrealms() */
776 void _internal_removeserversubrealms(struct list *realmlist, struct clsrvconf *srv) {
777     struct list_node *entry, *entry2;
778     struct realm *realm;
779
780     for (entry = list_first(realmlist); entry;) {
781         realm = newrealmref((struct realm *)entry->data);
782         pthread_mutex_lock(&realm->mutex);
783         entry = list_next(entry);
784
785         if (realm->srvconfs) {
786             for (entry2 = list_first(realm->srvconfs); entry2; entry2 = list_next(entry2))
787                 if (entry2->data == srv)
788                     freerealm(realm);
789             list_removedata(realm->srvconfs, srv);
790         }
791         if (realm->accsrvconfs) {
792             for (entry2 = list_first(realm->accsrvconfs); entry2; entry2 = list_next(entry2))
793                 if (entry2->data == srv)
794                     freerealm(realm);
795             list_removedata(realm->accsrvconfs, srv);
796         }
797
798         /* remove subrealm if no dynamic servers left */
799         if (!hasdynamicserver(realm->srvconfs) && !hasdynamicserver(realm->accsrvconfs)) {
800             while (list_shift(realm->srvconfs))
801                 freerealm(realm);
802             list_destroy(realm->srvconfs);
803             realm->srvconfs = NULL;
804             while (list_shift(realm->accsrvconfs))
805                 freerealm(realm);
806             list_destroy(realm->accsrvconfs);
807             realm->accsrvconfs = NULL;
808             list_removedata(realmlist, realm);
809         }
810         pthread_mutex_unlock(&realm->mutex);
811         freerealm(realm);
812     }
813 }
814
815 void removeserversubrealms(struct list *realmlist, struct clsrvconf *srv) {
816     struct list_node *entry;
817     struct realm *realm;
818
819     for (entry = list_first(realmlist); entry; entry = list_next(entry)) {
820         realm = (struct realm *)entry->data;
821         pthread_mutex_lock(&realm->mutex);
822         if (realm->subrealms) {
823             _internal_removeserversubrealms(realm->subrealms, srv);
824             if (!list_first(realm->subrealms)) {
825                 list_destroy(realm->subrealms);
826                 realm->subrealms = NULL;
827             }
828         }
829         pthread_mutex_unlock(&realm->mutex);
830     }
831 }
832
833 int attrvalidate(unsigned char *attrs, int length) {
834     while (length > 1) {
835         if (ATTRLEN(attrs) < 2) {
836             debug(DBG_INFO, "attrvalidate: invalid attribute length %d", ATTRLEN(attrs));
837             return 0;
838         }
839         length -= ATTRLEN(attrs);
840         if (length < 0) {
841             debug(DBG_INFO, "attrvalidate: attribute length %d exceeds packet length", ATTRLEN(attrs));
842             return 0;
843         }
844         attrs += ATTRLEN(attrs);
845     }
846     if (length)
847         debug(DBG_INFO, "attrvalidate: malformed packet? remaining byte after last attribute");
848     return 1;
849 }
850
851 int pwdrecrypt(uint8_t *pwd, uint8_t len, char *oldsecret, char *newsecret, uint8_t *oldauth, uint8_t *newauth) {
852     if (len < 16 || len > 128 || len % 16) {
853         debug(DBG_WARN, "pwdrecrypt: invalid password length");
854         return 0;
855     }
856
857     if (!pwdcrypt(0, pwd, len, oldsecret, strlen(oldsecret), oldauth)) {
858         debug(DBG_WARN, "pwdrecrypt: cannot decrypt password");
859         return 0;
860     }
861 #ifdef DEBUG
862     printfchars(NULL, "pwdrecrypt: password", "%02x ", pwd, len);
863 #endif
864     if (!pwdcrypt(1, pwd, len, newsecret, strlen(newsecret), newauth)) {
865         debug(DBG_WARN, "pwdrecrypt: cannot encrypt password");
866         return 0;
867     }
868     return 1;
869 }
870
871 int msmpprecrypt(uint8_t *msmpp, uint8_t len, char *oldsecret, char *newsecret, uint8_t *oldauth, uint8_t *newauth) {
872     if (len < 18)
873         return 0;
874     if (!msmppdecrypt(msmpp + 2, len - 2, (uint8_t *)oldsecret, strlen(oldsecret), oldauth, msmpp)) {
875         debug(DBG_WARN, "msmpprecrypt: failed to decrypt msppe key");
876         return 0;
877     }
878     if (!msmppencrypt(msmpp + 2, len - 2, (uint8_t *)newsecret, strlen(newsecret), newauth, msmpp)) {
879         debug(DBG_WARN, "msmpprecrypt: failed to encrypt msppe key");
880         return 0;
881     }
882     return 1;
883 }
884
885 int msmppe(unsigned char *attrs, int length, uint8_t type, char *attrtxt, struct request *rq,
886            char *oldsecret, char *newsecret) {
887     unsigned char *attr;
888
889     for (attr = attrs; (attr = attrget(attr, length - (attr - attrs), type)); attr += ATTRLEN(attr)) {
890         debug(DBG_DBG, "msmppe: Got %s", attrtxt);
891         if (!msmpprecrypt(ATTRVAL(attr), ATTRVALLEN(attr), oldsecret, newsecret, rq->buf + 4, rq->rqauth))
892             return 0;
893     }
894     return 1;
895 }
896
897 int findvendorsubattr(uint32_t *attrs, uint32_t vendor, uint32_t subattr) {
898     if (!attrs)
899         return 0;
900
901     for (; attrs[0]; attrs += 2)
902         if (attrs[0] == vendor && attrs[1] == subattr)
903             return 1;
904     return 0;
905 }
906
907 /* returns 1 if entire element is to be removed, else 0 */
908 int dovendorrewriterm(struct tlv *attr, uint32_t *removevendorattrs) {
909     uint8_t alen, sublen;
910     uint32_t vendor;
911     uint8_t *subattrs;
912
913     if (!removevendorattrs)
914         return 0;
915
916     memcpy(&vendor, attr->v, 4);
917     vendor = ntohl(vendor);
918     while (*removevendorattrs && *removevendorattrs != vendor)
919         removevendorattrs += 2;
920     if (!*removevendorattrs)
921         return 0;
922
923     if (findvendorsubattr(removevendorattrs, vendor, 256))
924         return 1; /* remove entire vendor attribute */
925
926     sublen = attr->l - 4;
927     subattrs = attr->v + 4;
928
929     if (!attrvalidate(subattrs, sublen)) {
930         debug(DBG_INFO, "dovendorrewrite: vendor attribute validation failed, no rewrite");
931         return 0;
932     }
933
934     while (sublen > 1) {
935         alen = ATTRLEN(subattrs);
936         sublen -= alen;
937         if (findvendorsubattr(removevendorattrs, vendor, ATTRTYPE(subattrs))) {
938             memmove(subattrs, subattrs + alen, sublen);
939             attr->l -= alen;
940         } else
941             subattrs += alen;
942     }
943     return 0;
944 }
945
946 void dorewriterm(struct radmsg *msg, uint8_t *rmattrs, uint32_t *rmvattrs) {
947     struct list_node *n, *p;
948     struct tlv *attr;
949
950     p = NULL;
951     n = list_first(msg->attrs);
952     while (n) {
953         attr = (struct tlv *)n->data;
954         if ((rmattrs && strchr((char *)rmattrs, attr->t)) ||
955             (rmvattrs && attr->t == RAD_Attr_Vendor_Specific && dovendorrewriterm(attr, rmvattrs))) {
956             list_removedata(msg->attrs, attr);
957             freetlv(attr);
958             n = p ? list_next(p) : list_first(msg->attrs);
959         } else {
960             p = n;
961             n = list_next(n);
962         }
963     }
964 }
965
966 int dorewriteadd(struct radmsg *msg, struct list *addattrs) {
967     struct list_node *n;
968     struct tlv *a;
969
970     for (n = list_first(addattrs); n; n = list_next(n)) {
971         a = copytlv((struct tlv *)n->data);
972         if (!a)
973             return 0;
974         if (!radmsg_add(msg, a)) {
975             freetlv(a);
976             return 0;
977         }
978     }
979     return 1;
980 }
981
982 int resizeattr(struct tlv *attr, uint8_t newlen) {
983     uint8_t *newv;
984
985     if (newlen != attr->l) {
986         newv = realloc(attr->v, newlen);
987         if (!newv)
988             return 0;
989         attr->v = newv;
990         attr->l = newlen;
991     }
992     return 1;
993 }
994
995 int dorewritemodattr(struct tlv *attr, struct modattr *modattr) {
996     size_t nmatch = 10, reslen = 0, start = 0;
997     regmatch_t pmatch[10], *pfield;
998     int i;
999     char *in, *out;
1000
1001     in = stringcopy((char *)attr->v, attr->l);
1002     if (!in)
1003         return 0;
1004
1005     if (regexec(modattr->regex, in, nmatch, pmatch, 0)) {
1006         free(in);
1007         return 1;
1008     }
1009
1010     out = modattr->replacement;
1011
1012     for (i = start; out[i]; i++) {
1013         if (out[i] == '\\' && out[i + 1] >= '1' && out[i + 1] <= '9') {
1014             pfield = &pmatch[out[i + 1] - '0'];
1015             if (pfield->rm_so >= 0) {
1016                 reslen += i - start + pfield->rm_eo - pfield->rm_so;
1017                 start = i + 2;
1018             }
1019             i++;
1020         }
1021     }
1022     reslen += i - start;
1023     if (reslen > 253) {
1024         debug(DBG_INFO, "rewritten attribute length would be %d, max possible is 253, discarding message", reslen);
1025         free(in);
1026         return 0;
1027     }
1028
1029     if (!resizeattr(attr, reslen)) {
1030         free(in);
1031         return 0;
1032     }
1033
1034     start = 0;
1035     reslen = 0;
1036     for (i = start; out[i]; i++) {
1037         if (out[i] == '\\' && out[i + 1] >= '1' && out[i + 1] <= '9') {
1038             pfield = &pmatch[out[i + 1] - '0'];
1039             if (pfield->rm_so >= 0) {
1040                 memcpy(attr->v + reslen, out + start, i - start);
1041                 reslen += i - start;
1042                 memcpy(attr->v + reslen, in + pfield->rm_so, pfield->rm_eo - pfield->rm_so);
1043                 reslen += pfield->rm_eo - pfield->rm_so;
1044                 start = i + 2;
1045             }
1046             i++;
1047         }
1048     }
1049
1050     memcpy(attr->v + reslen, out + start, i - start);
1051     return 1;
1052 }
1053
1054 int dorewritemod(struct radmsg *msg, struct list *modattrs) {
1055     struct list_node *n, *m;
1056
1057     for (n = list_first(msg->attrs); n; n = list_next(n))
1058         for (m = list_first(modattrs); m; m = list_next(m))
1059             if (((struct tlv *)n->data)->t == ((struct modattr *)m->data)->t &&
1060                 !dorewritemodattr((struct tlv *)n->data, (struct modattr *)m->data))
1061                 return 0;
1062     return 1;
1063 }
1064
1065 int dorewrite(struct radmsg *msg, struct rewrite *rewrite) {
1066     int rv = 1;                 /* Success.  */
1067
1068     if (rewrite) {
1069         if (rewrite->removeattrs || rewrite->removevendorattrs)
1070             dorewriterm(msg, rewrite->removeattrs, rewrite->removevendorattrs);
1071         if (rewrite->modattrs)
1072             if (!dorewritemod(msg, rewrite->modattrs))
1073                 rv = 0;
1074         if (rewrite->addattrs)
1075             if (!dorewriteadd(msg, rewrite->addattrs))
1076                 rv = 0;
1077     }
1078     return rv;
1079 }
1080
1081 int rewriteusername(struct request *rq, struct tlv *attr) {
1082     char *orig = (char *)tlv2str(attr);
1083     if (!dorewritemodattr(attr, rq->from->conf->rewriteusername)) {
1084         free(orig);
1085         return 0;
1086     }
1087     if (strlen(orig) != attr->l || memcmp(orig, attr->v, attr->l))
1088         rq->origusername = (char *)orig;
1089     else
1090         free(orig);
1091     return 1;
1092 }
1093
1094 /** Create vendor specific tlv with ATTR.  ATTR is consumed (freed) if
1095  * all is well with the new tlv, i.e. if the function returns
1096  * !NULL.  */
1097 static struct tlv *
1098 makevendortlv(uint32_t vendor, struct tlv *attr)
1099 {
1100     struct tlv *newtlv = NULL;
1101     uint8_t l, *v;
1102
1103     if (!attr)
1104         return NULL;
1105     l = attr->l + 6;
1106     v = malloc(l);
1107     if (v) {
1108         vendor = htonl(vendor & 0x00ffffff); /* MSB=0 according to RFC 2865. */
1109         memcpy(v, &vendor, 4);
1110         tlv2buf(v + 4, attr);
1111         v[5] += 2; /* Vendor length increased for type and length fields. */
1112         newtlv = maketlv(RAD_Attr_Vendor_Specific, l, v);
1113         if (newtlv == NULL)
1114             free(v);
1115         else
1116             freetlv(attr);
1117     }
1118     return newtlv;
1119 }
1120
1121 /** Ad vendor attribute with VENDOR + ATTR and push it on MSG.  ATTR
1122  * is consumed.  */
1123 int addvendorattr(struct radmsg *msg, uint32_t vendor, struct tlv *attr) {
1124     struct tlv *vattr;
1125
1126     vattr = makevendortlv(vendor, attr);
1127     if (!vattr) {
1128         freetlv(attr);
1129         return 0;
1130     }
1131     if (!radmsg_add(msg, vattr)) {
1132         freetlv(vattr);
1133         return 0;
1134     }
1135     return 1;
1136 }
1137
1138 void addttlattr(struct radmsg *msg, uint32_t *attrtype, uint8_t addttl) {
1139     uint8_t ttl[4];
1140     struct tlv *attr;
1141
1142     memset(ttl, 0, 4);
1143     ttl[3] = addttl;
1144
1145     if (attrtype[1] == 256) { /* not vendor */
1146         attr = maketlv(attrtype[0], 4, ttl);
1147         if (attr && !radmsg_add(msg, attr))
1148             freetlv(attr);
1149     } else {
1150         attr = maketlv(attrtype[1], 4, ttl);
1151         if (attr)
1152             addvendorattr(msg, attrtype[0], attr);
1153     }
1154 }
1155
1156 int decttl(uint8_t l, uint8_t *v) {
1157     int i;
1158
1159     i = l - 1;
1160     if (v[i]) {
1161         if (--v[i--])
1162             return 1;
1163         while (i >= 0 && !v[i])
1164             i--;
1165         return i >= 0;
1166     }
1167     for (i--; i >= 0 && !v[i]; i--);
1168     if (i < 0)
1169         return 0;
1170     v[i]--;
1171     while (++i < l)
1172         v[i] = 255;
1173     return 1;
1174 }
1175
1176 /* returns -1 if no ttl, 0 if exceeded, 1 if ok */
1177 int checkttl(struct radmsg *msg, uint32_t *attrtype) {
1178     uint8_t alen, *subattrs;
1179     struct tlv *attr;
1180     struct list_node *node;
1181     uint32_t vendor;
1182     int sublen;
1183
1184     if (attrtype[1] == 256) { /* not vendor */
1185         attr = radmsg_gettype(msg, attrtype[0]);
1186         if (attr)
1187             return decttl(attr->l, attr->v);
1188     } else
1189         for (node = list_first(msg->attrs); node; node = list_next(node)) {
1190             attr = (struct tlv *)node->data;
1191             if (attr->t != RAD_Attr_Vendor_Specific || attr->l <= 4)
1192                 continue;
1193             memcpy(&vendor, attr->v, 4);
1194             if (ntohl(vendor) != attrtype[0])
1195                 continue;
1196             sublen = attr->l - 4;
1197             subattrs = attr->v + 4;
1198             if (!attrvalidate(subattrs, sublen))
1199                 continue;
1200             while (sublen > 1) {
1201                 if (ATTRTYPE(subattrs) == attrtype[1])
1202                     return decttl(ATTRVALLEN(subattrs), ATTRVAL(subattrs));
1203                 alen = ATTRLEN(subattrs);
1204                 sublen -= alen;
1205                 subattrs += alen;
1206             }
1207         }
1208     return -1;
1209 }
1210
1211 const char *radmsgtype2string(uint8_t code) {
1212     static const char *rad_msg_names[] = {
1213         "", "Access-Request", "Access-Accept", "Access-Reject",
1214         "Accounting-Request", "Accounting-Response", "", "",
1215         "", "", "", "Access-Challenge",
1216         "Status-Server", "Status-Client"
1217     };
1218     return code < 14 && *rad_msg_names[code] ? rad_msg_names[code] : "Unknown";
1219 }
1220
1221 void char2hex(char *h, unsigned char c) {
1222     static const char hexdigits[] = { '0', '1', '2', '3', '4', '5', '6', '7',
1223                                       '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
1224     h[0] = hexdigits[c / 16];
1225     h[1] = hexdigits[c % 16];
1226     return;
1227 }
1228
1229 uint8_t *radattr2ascii(struct tlv *attr) {
1230     int i, l;
1231     uint8_t *a, *d;
1232
1233     if (!attr)
1234         return NULL;
1235
1236     l = attr->l;
1237     for (i = 0; i < attr->l; i++)
1238         if (attr->v[i] < 32 || attr->v[i] > 126)
1239             l += 2;
1240     if (l == attr->l)
1241         return (uint8_t *)stringcopy((char *)attr->v, attr->l);
1242
1243     a = malloc(l + 1);
1244     if (!a)
1245         return NULL;
1246
1247     d = a;
1248     for (i = 0; i < attr->l; i++)
1249         if (attr->v[i] < 32 || attr->v[i] > 126) {
1250             *d++ = '%';
1251             char2hex((char *)d, attr->v[i]);
1252             d += 2;
1253         } else
1254             *d++ = attr->v[i];
1255     *d = '\0';
1256     return a;
1257 }
1258
1259 void acclog(struct radmsg *msg, struct client *from) {
1260     struct tlv *attr;
1261     uint8_t *username;
1262
1263     attr = radmsg_gettype(msg, RAD_Attr_User_Name);
1264     if (!attr) {
1265         debug(DBG_INFO, "acclog: accounting-request from client %s (%s) without username attribute", from->conf->name, addr2string(from->addr));
1266         return;
1267     }
1268     username = radattr2ascii(attr);
1269     if (username) {
1270         debug(DBG_INFO, "acclog: accounting-request from client %s (%s) with username: %s", from->conf->name, addr2string(from->addr), username);
1271
1272         free(username);
1273     }
1274 }
1275
1276 void respond(struct request *rq, uint8_t code, char *message) {
1277     struct radmsg *msg;
1278     struct tlv *attr;
1279
1280     msg = radmsg_init(code, rq->msg->id, rq->msg->auth);
1281     if (!msg) {
1282         debug(DBG_ERR, "respond: malloc failed");
1283         return;
1284     }
1285     if (message && *message) {
1286         attr = maketlv(RAD_Attr_Reply_Message, strlen(message), message);
1287         if (!attr || !radmsg_add(msg, attr)) {
1288             freetlv(attr);
1289             radmsg_free(msg);
1290             debug(DBG_ERR, "respond: malloc failed");
1291             return;
1292         }
1293     }
1294
1295     radmsg_free(rq->msg);
1296     rq->msg = msg;
1297     debug(DBG_DBG, "respond: sending %s to %s (%s)", radmsgtype2string(msg->code), rq->from->conf->name, addr2string(rq->from->addr));
1298     sendreply(newrqref(rq));
1299 }
1300
1301 struct clsrvconf *choosesrvconf(struct list *srvconfs) {
1302     struct list_node *entry;
1303     struct clsrvconf *server, *best = NULL, *first = NULL;
1304
1305     for (entry = list_first(srvconfs); entry; entry = list_next(entry)) {
1306         server = (struct clsrvconf *)entry->data;
1307         if (!server->servers)
1308             return server;
1309         if (!first)
1310             first = server;
1311         if (!server->servers->connectionok && !server->servers->dynstartup)
1312             continue;
1313         if (!server->servers->lostrqs)
1314             return server;
1315         if (!best) {
1316             best = server;
1317             continue;
1318         }
1319         if (server->servers->lostrqs < best->servers->lostrqs)
1320             best = server;
1321     }
1322     return best ? best : first;
1323 }
1324
1325 /* returns with lock on realm, protects from server changes while in use by radsrv/sendrq */
1326 struct server *findserver(struct realm **realm, struct tlv *username, uint8_t acc) {
1327     struct clsrvconf *srvconf;
1328     struct realm *subrealm;
1329     struct server *server = NULL;
1330     char *id = (char *)tlv2str(username);
1331
1332     if (!id)
1333         return NULL;
1334     /* returns with lock on realm */
1335     *realm = id2realm(realms, id);
1336     if (!*realm)
1337         goto exit;
1338     debug(DBG_DBG, "found matching realm: %s", (*realm)->name);
1339     srvconf = choosesrvconf(acc ? (*realm)->accsrvconfs : (*realm)->srvconfs);
1340     if (srvconf && !(*realm)->parent && !srvconf->servers && srvconf->dynamiclookupcommand) {
1341         subrealm = adddynamicrealmserver(*realm, id);
1342         if (subrealm) {
1343             pthread_mutex_lock(&subrealm->mutex);
1344             pthread_mutex_unlock(&(*realm)->mutex);
1345             freerealm(*realm);
1346             *realm = subrealm;
1347             srvconf = choosesrvconf(acc ? (*realm)->accsrvconfs : (*realm)->srvconfs);
1348         }
1349     }
1350     if (srvconf)
1351         server = srvconf->servers;
1352
1353 exit:
1354     free(id);
1355     return server;
1356 }
1357
1358
1359 struct request *newrequest() {
1360     struct request *rq;
1361
1362     rq = malloc(sizeof(struct request));
1363     if (!rq) {
1364         debug(DBG_ERR, "newrequest: malloc failed");
1365         return NULL;
1366     }
1367     memset(rq, 0, sizeof(struct request));
1368     rq->refcount = 1;
1369     gettimeofday(&rq->created, NULL);
1370     return rq;
1371 }
1372
1373 int addclientrq(struct request *rq) {
1374     struct request *r;
1375     struct timeval now;
1376
1377     r = rq->from->rqs[rq->rqid];
1378     if (r) {
1379         if (rq->udpport == r->udpport && !memcmp(rq->rqauth, r->rqauth, 16)) {
1380             gettimeofday(&now, NULL);
1381             if (now.tv_sec - r->created.tv_sec < r->from->conf->dupinterval) {
1382                 if (r->replybuf) {
1383                     debug(DBG_INFO, "addclientrq: already sent reply to request with id %d from %s, resending", rq->rqid, addr2string(r->from->addr));
1384                     sendreply(newrqref(r));
1385                 } else
1386                     debug(DBG_INFO, "addclientrq: already got request with id %d from %s, ignoring", rq->rqid, addr2string(r->from->addr));
1387                 return 0;
1388             }
1389         }
1390         freerq(r);
1391     }
1392     rq->from->rqs[rq->rqid] = newrqref(rq);
1393     return 1;
1394 }
1395
1396 void rmclientrq(struct request *rq, uint8_t id) {
1397     struct request *r;
1398
1399     r = rq->from->rqs[id];
1400     if (r) {
1401         freerq(r);
1402         rq->from->rqs[id] = NULL;
1403     }
1404 }
1405
1406 /* returns 0 if validation/authentication fails, else 1 */
1407 int radsrv(struct request *rq) {
1408     struct radmsg *msg = NULL;
1409     struct tlv *attr;
1410     uint8_t *userascii = NULL;
1411     struct realm *realm = NULL;
1412     struct server *to = NULL;
1413     struct client *from = rq->from;
1414     int ttlres;
1415
1416     msg = buf2radmsg(rq->buf, (uint8_t *)from->conf->secret, NULL);
1417     free(rq->buf);
1418     rq->buf = NULL;
1419
1420     if (!msg) {
1421         debug(DBG_INFO, "radsrv: message validation failed, ignoring packet");
1422         freerq(rq);
1423         return 0;
1424     }
1425
1426     rq->msg = msg;
1427     rq->rqid = msg->id;
1428     memcpy(rq->rqauth, msg->auth, 16);
1429
1430     debug(DBG_DBG, "radsrv: code %d, id %d", msg->code, msg->id);
1431     if (msg->code != RAD_Access_Request && msg->code != RAD_Status_Server && msg->code != RAD_Accounting_Request) {
1432         debug(DBG_INFO, "radsrv: server currently accepts only access-requests, accounting-requests and status-server, ignoring");
1433         goto exit;
1434     }
1435
1436     if (!addclientrq(rq))
1437         goto exit;
1438
1439     if (msg->code == RAD_Status_Server) {
1440         respond(rq, RAD_Access_Accept, NULL);
1441         goto exit;
1442     }
1443
1444     /* below: code == RAD_Access_Request || code == RAD_Accounting_Request */
1445
1446     if (from->conf->rewritein && !dorewrite(msg, from->conf->rewritein))
1447         goto rmclrqexit;
1448
1449     ttlres = checkttl(msg, options.ttlattrtype);
1450     if (!ttlres) {
1451         debug(DBG_INFO, "radsrv: ignoring request from client %s (%s), ttl exceeded", from->conf->name, addr2string(from->addr));
1452         goto exit;
1453     }
1454
1455     attr = radmsg_gettype(msg, RAD_Attr_User_Name);
1456     if (!attr) {
1457         if (msg->code == RAD_Accounting_Request) {
1458             acclog(msg, from);
1459             respond(rq, RAD_Accounting_Response, NULL);
1460         } else
1461             debug(DBG_INFO, "radsrv: ignoring access request, no username attribute");
1462         goto exit;
1463     }
1464
1465     if (from->conf->rewriteusername && !rewriteusername(rq, attr)) {
1466         debug(DBG_WARN, "radsrv: username malloc failed, ignoring request");
1467         goto rmclrqexit;
1468     }
1469
1470     userascii = radattr2ascii(attr);
1471     if (!userascii)
1472         goto rmclrqexit;
1473     debug(DBG_DBG, "%s with username: %s", radmsgtype2string(msg->code), userascii);
1474
1475     /* will return with lock on the realm */
1476     to = findserver(&realm, attr, msg->code == RAD_Accounting_Request);
1477     if (!realm) {
1478         debug(DBG_INFO, "radsrv: ignoring request, don't know where to send it");
1479         goto exit;
1480     }
1481
1482     if (!to) {
1483         if (realm->message && msg->code == RAD_Access_Request) {
1484             debug(DBG_INFO, "radsrv: sending reject to %s (%s) for %s", from->conf->name, addr2string(from->addr), userascii);
1485             respond(rq, RAD_Access_Reject, realm->message);
1486         } else if (realm->accresp && msg->code == RAD_Accounting_Request) {
1487             acclog(msg, from);
1488             respond(rq, RAD_Accounting_Response, NULL);
1489         }
1490         goto exit;
1491     }
1492
1493     if ((to->conf->loopprevention == 1
1494          || (to->conf->loopprevention == UCHAR_MAX && options.loopprevention == 1))
1495         && !strcmp(from->conf->name, to->conf->name)) {
1496         debug(DBG_INFO, "radsrv: Loop prevented, not forwarding request from client %s (%s) to server %s, discarding",
1497               from->conf->name, addr2string(from->addr), to->conf->name);
1498         goto exit;
1499     }
1500
1501     if (msg->code == RAD_Accounting_Request)
1502         memset(msg->auth, 0, 16);
1503     else if (!RAND_bytes(msg->auth, 16)) {
1504         debug(DBG_WARN, "radsrv: failed to generate random auth");
1505         goto rmclrqexit;
1506     }
1507
1508 #ifdef DEBUG
1509     printfchars(NULL, "auth", "%02x ", auth, 16);
1510 #endif
1511
1512     attr = radmsg_gettype(msg, RAD_Attr_User_Password);
1513     if (attr) {
1514         debug(DBG_DBG, "radsrv: found userpwdattr with value length %d", attr->l);
1515         if (!pwdrecrypt(attr->v, attr->l, from->conf->secret, to->conf->secret, rq->rqauth, msg->auth))
1516             goto rmclrqexit;
1517     }
1518
1519     attr = radmsg_gettype(msg, RAD_Attr_Tunnel_Password);
1520     if (attr) {
1521         debug(DBG_DBG, "radsrv: found tunnelpwdattr with value length %d", attr->l);
1522         if (!pwdrecrypt(attr->v, attr->l, from->conf->secret, to->conf->secret, rq->rqauth, msg->auth))
1523             goto rmclrqexit;
1524     }
1525
1526     if (to->conf->rewriteout && !dorewrite(msg, to->conf->rewriteout))
1527         goto rmclrqexit;
1528
1529     if (ttlres == -1 && (options.addttl || to->conf->addttl))
1530         addttlattr(msg, options.ttlattrtype, to->conf->addttl ? to->conf->addttl : options.addttl);
1531
1532     free(userascii);
1533     rq->to = to;
1534     sendrq(rq);
1535     pthread_mutex_unlock(&realm->mutex);
1536     freerealm(realm);
1537     return 1;
1538
1539 rmclrqexit:
1540     rmclientrq(rq, msg->id);
1541 exit:
1542     freerq(rq);
1543     free(userascii);
1544     if (realm) {
1545         pthread_mutex_unlock(&realm->mutex);
1546         freerealm(realm);
1547     }
1548     return 1;
1549 }
1550
1551 void replyh(struct server *server, unsigned char *buf) {
1552     struct client *from;
1553     struct rqout *rqout;
1554     int sublen, ttlres;
1555     unsigned char *subattrs;
1556     uint8_t *username, *stationid, *replymsg;
1557     struct radmsg *msg = NULL;
1558     struct tlv *attr;
1559     struct list_node *node;
1560
1561     server->connectionok = 1;
1562     server->lostrqs = 0;
1563
1564     rqout = server->requests + buf[1];
1565     pthread_mutex_lock(rqout->lock);
1566     if (!rqout->tries) {
1567         free(buf);
1568         buf = NULL;
1569         debug(DBG_INFO, "replyh: no outstanding request with this id, ignoring reply");
1570         goto errunlock;
1571     }
1572
1573     msg = buf2radmsg(buf, (uint8_t *)server->conf->secret, rqout->rq->msg->auth);
1574     free(buf);
1575     buf = NULL;
1576     if (!msg) {
1577         debug(DBG_INFO, "replyh: message validation failed, ignoring packet");
1578         goto errunlock;
1579     }
1580     if (msg->code != RAD_Access_Accept && msg->code != RAD_Access_Reject && msg->code != RAD_Access_Challenge
1581         && msg->code != RAD_Accounting_Response) {
1582         debug(DBG_INFO, "replyh: discarding message type %s, accepting only access accept, access reject, access challenge and accounting response messages", radmsgtype2string(msg->code));
1583         goto errunlock;
1584     }
1585     debug(DBG_DBG, "got %s message with id %d", radmsgtype2string(msg->code), msg->id);
1586
1587     gettimeofday(&server->lastrcv, NULL);
1588
1589     if (rqout->rq->msg->code == RAD_Status_Server) {
1590         freerqoutdata(rqout);
1591         debug(DBG_DBG, "replyh: got status server response from %s", server->conf->name);
1592         goto errunlock;
1593     }
1594
1595     gettimeofday(&server->lastreply, NULL);
1596     from = rqout->rq->from;
1597
1598     if (server->conf->rewritein && !dorewrite(msg, from->conf->rewritein)) {
1599         debug(DBG_INFO, "replyh: rewritein failed");
1600         goto errunlock;
1601     }
1602
1603     ttlres = checkttl(msg, options.ttlattrtype);
1604     if (!ttlres) {
1605         debug(DBG_INFO, "replyh: ignoring reply from server %s, ttl exceeded", server->conf->name);
1606         goto errunlock;
1607     }
1608
1609     /* MS MPPE */
1610     for (node = list_first(msg->attrs); node; node = list_next(node)) {
1611         attr = (struct tlv *)node->data;
1612         if (attr->t != RAD_Attr_Vendor_Specific)
1613             continue;
1614         if (attr->l <= 4)
1615             break;
1616         if (attr->v[0] != 0 || attr->v[1] != 0 || attr->v[2] != 1 || attr->v[3] != 55)  /* 311 == MS */
1617             continue;
1618
1619         sublen = attr->l - 4;
1620         subattrs = attr->v + 4;
1621         if (!attrvalidate(subattrs, sublen) ||
1622             !msmppe(subattrs, sublen, RAD_VS_ATTR_MS_MPPE_Send_Key, "MS MPPE Send Key",
1623                     rqout->rq, server->conf->secret, from->conf->secret) ||
1624             !msmppe(subattrs, sublen, RAD_VS_ATTR_MS_MPPE_Recv_Key, "MS MPPE Recv Key",
1625                     rqout->rq, server->conf->secret, from->conf->secret))
1626             break;
1627     }
1628     if (node) {
1629         debug(DBG_WARN, "replyh: MS attribute handling failed, ignoring reply");
1630         goto errunlock;
1631     }
1632
1633     if (msg->code == RAD_Access_Accept || msg->code == RAD_Access_Reject || msg->code == RAD_Accounting_Response) {
1634         username = radattr2ascii(radmsg_gettype(rqout->rq->msg, RAD_Attr_User_Name));
1635         if (username) {
1636             stationid = radattr2ascii(radmsg_gettype(rqout->rq->msg, RAD_Attr_Calling_Station_Id));
1637             replymsg = radattr2ascii(radmsg_gettype(msg, RAD_Attr_Reply_Message));
1638             if (stationid) {
1639                 if (replymsg) {
1640                     debug(DBG_NOTICE,
1641                           "%s for user %s stationid %s from %s (%s) to %s (%s)",
1642                           radmsgtype2string(msg->code), username, stationid,
1643                           server->conf->name, replymsg, from->conf->name,
1644                           addr2string(from->addr));
1645                     free(replymsg);
1646                 } else
1647                     debug(DBG_NOTICE,
1648                           "%s for user %s stationid %s from %s to %s (%s)",
1649                           radmsgtype2string(msg->code), username, stationid,
1650                           server->conf->name, from->conf->name,
1651                           addr2string(from->addr));
1652                 free(stationid);
1653             } else {
1654                 if (replymsg) {
1655                     debug(DBG_NOTICE, "%s for user %s from %s (%s) to %s (%s)",
1656                           radmsgtype2string(msg->code), username,
1657                           server->conf->name, replymsg, from->conf->name,
1658                           addr2string(from->addr));
1659                     free(replymsg);
1660                 } else
1661                     debug(DBG_NOTICE, "%s for user %s from %s to %s (%s)",
1662                           radmsgtype2string(msg->code), username,
1663                           server->conf->name, from->conf->name,
1664                           addr2string(from->addr));
1665             }
1666             free(username);
1667         }
1668     }
1669
1670 #if defined(WANT_FTICKS)
1671     if (msg->code == RAD_Access_Accept || msg->code == RAD_Access_Reject)
1672         if (options.fticks_reporting && from->conf->fticks_viscountry != NULL)
1673             fticks_log(&options, from, msg, rqout);
1674 #endif
1675
1676     msg->id = (char)rqout->rq->rqid;
1677     memcpy(msg->auth, rqout->rq->rqauth, 16);
1678
1679 #ifdef DEBUG
1680     printfchars(NULL, "origauth/buf+4", "%02x ", buf + 4, 16);
1681 #endif
1682
1683     if (rqout->rq->origusername && (attr = radmsg_gettype(msg, RAD_Attr_User_Name))) {
1684         if (!resizeattr(attr, strlen(rqout->rq->origusername))) {
1685             debug(DBG_WARN, "replyh: malloc failed, ignoring reply");
1686             goto errunlock;
1687         }
1688         memcpy(attr->v, rqout->rq->origusername, strlen(rqout->rq->origusername));
1689     }
1690
1691     if (from->conf->rewriteout && !dorewrite(msg, from->conf->rewriteout)) {
1692         debug(DBG_WARN, "replyh: rewriteout failed");
1693         goto errunlock;
1694     }
1695
1696     if (ttlres == -1 && (options.addttl || from->conf->addttl))
1697         addttlattr(msg, options.ttlattrtype, from->conf->addttl ? from->conf->addttl : options.addttl);
1698
1699     debug(msg->code == RAD_Access_Accept || msg->code == RAD_Access_Reject || msg->code == RAD_Accounting_Response ? DBG_WARN : DBG_INFO,
1700           "replyh: passing %s to client %s (%s)", radmsgtype2string(msg->code), from->conf->name, addr2string(from->addr));
1701
1702     radmsg_free(rqout->rq->msg);
1703     rqout->rq->msg = msg;
1704     sendreply(newrqref(rqout->rq));
1705     freerqoutdata(rqout);
1706     pthread_mutex_unlock(rqout->lock);
1707     return;
1708
1709 errunlock:
1710     radmsg_free(msg);
1711     pthread_mutex_unlock(rqout->lock);
1712     return;
1713 }
1714
1715 struct request *createstatsrvrq() {
1716     struct request *rq;
1717     struct tlv *attr;
1718
1719     rq = newrequest();
1720     if (!rq)
1721         return NULL;
1722     rq->msg = radmsg_init(RAD_Status_Server, 0, NULL);
1723     if (!rq->msg)
1724         goto exit;
1725     attr = maketlv(RAD_Attr_Message_Authenticator, 16, NULL);
1726     if (!attr)
1727         goto exit;
1728     if (!radmsg_add(rq->msg, attr)) {
1729         freetlv(attr);
1730         goto exit;
1731     }
1732     return rq;
1733
1734 exit:
1735     freerq(rq);
1736     return NULL;
1737 }
1738
1739 /* code for removing state not finished */
1740 void *clientwr(void *arg) {
1741     struct server *server = (struct server *)arg;
1742     struct rqout *rqout = NULL;
1743     pthread_t clientrdth;
1744     int i, dynconffail = 0;
1745     time_t secs;
1746     uint8_t rnd;
1747     struct timeval now, laststatsrv;
1748     struct timespec timeout;
1749     struct request *statsrvrq;
1750     struct clsrvconf *conf;
1751
1752     conf = server->conf;
1753
1754     if (server->dynamiclookuparg && !dynamicconfig(server)) {
1755         dynconffail = 1;
1756         server->dynstartup = 0;
1757         sleep(900);
1758         goto errexit;
1759     }
1760
1761     if (!resolvehostports(conf->hostports, conf->pdef->socktype)) {
1762         debug(DBG_WARN, "clientwr: resolve failed");
1763         server->dynstartup = 0;
1764         sleep(900);
1765         goto errexit;
1766     }
1767
1768     memset(&timeout, 0, sizeof(struct timespec));
1769
1770     if (conf->statusserver) {
1771         gettimeofday(&server->lastrcv, NULL);
1772         gettimeofday(&laststatsrv, NULL);
1773     }
1774
1775     if (conf->pdef->connecter) {
1776         if (!conf->pdef->connecter(server, NULL, server->dynamiclookuparg ? 5 : 0, "clientwr")) {
1777             if (server->dynamiclookuparg) {
1778                 server->dynstartup = 0;
1779                 sleep(900);
1780             }
1781             goto errexit;
1782         }
1783         server->connectionok = 1;
1784         if (pthread_create(&clientrdth, NULL, conf->pdef->clientconnreader, (void *)server)) {
1785             debugerrno(errno, DBG_ERR, "clientwr: pthread_create failed");
1786             goto errexit;
1787         }
1788     } else
1789         server->connectionok = 1;
1790     server->dynstartup = 0;
1791
1792     for (;;) {
1793         pthread_mutex_lock(&server->newrq_mutex);
1794         if (!server->newrq) {
1795             gettimeofday(&now, NULL);
1796             /* random 0-7 seconds */
1797             RAND_bytes(&rnd, 1);
1798             rnd /= 32;
1799             if (conf->statusserver) {
1800                 secs = server->lastrcv.tv_sec > laststatsrv.tv_sec ? server->lastrcv.tv_sec : laststatsrv.tv_sec;
1801                 if (now.tv_sec - secs > STATUS_SERVER_PERIOD)
1802                     secs = now.tv_sec;
1803                 if (!timeout.tv_sec || timeout.tv_sec > secs + STATUS_SERVER_PERIOD + rnd)
1804                     timeout.tv_sec = secs + STATUS_SERVER_PERIOD + rnd;
1805             } else {
1806                 if (!timeout.tv_sec || timeout.tv_sec > now.tv_sec + STATUS_SERVER_PERIOD + rnd)
1807                     timeout.tv_sec = now.tv_sec + STATUS_SERVER_PERIOD + rnd;
1808             }
1809 #if 0
1810             if (timeout.tv_sec > now.tv_sec)
1811                 debug(DBG_DBG, "clientwr: waiting up to %ld secs for new request", timeout.tv_sec - now.tv_sec);
1812 #endif
1813             pthread_cond_timedwait(&server->newrq_cond, &server->newrq_mutex, &timeout);
1814             timeout.tv_sec = 0;
1815         }
1816         if (server->newrq) {
1817             debug(DBG_DBG, "clientwr: got new request");
1818             server->newrq = 0;
1819         }
1820 #if 0
1821         else
1822             debug(DBG_DBG, "clientwr: request timer expired, processing request queue");
1823 #endif
1824         pthread_mutex_unlock(&server->newrq_mutex);
1825
1826         for (i = 0; i < MAX_REQUESTS; i++) {
1827             if (server->clientrdgone) {
1828                 pthread_join(clientrdth, NULL);
1829                 goto errexit;
1830             }
1831
1832             for (; i < MAX_REQUESTS; i++) {
1833                 rqout = server->requests + i;
1834                 if (rqout->rq) {
1835                     pthread_mutex_lock(rqout->lock);
1836                     if (rqout->rq)
1837                         break;
1838                     pthread_mutex_unlock(rqout->lock);
1839                 }
1840             }
1841
1842             if (i == MAX_REQUESTS)
1843                 break;
1844
1845             gettimeofday(&now, NULL);
1846             if (now.tv_sec < rqout->expiry.tv_sec) {
1847                 if (!timeout.tv_sec || rqout->expiry.tv_sec < timeout.tv_sec)
1848                     timeout.tv_sec = rqout->expiry.tv_sec;
1849                 pthread_mutex_unlock(rqout->lock);
1850                 continue;
1851             }
1852
1853             if (rqout->tries == (*rqout->rq->buf == RAD_Status_Server ? 1 : conf->retrycount + 1)) {
1854                 debug(DBG_DBG, "clientwr: removing expired packet from queue");
1855                 if (conf->statusserver) {
1856                     if (*rqout->rq->buf == RAD_Status_Server) {
1857                         debug(DBG_WARN, "clientwr: no status server response, %s dead?", conf->name);
1858                         if (server->lostrqs < 255)
1859                             server->lostrqs++;
1860                     }
1861                 } else {
1862                     debug(DBG_WARN, "clientwr: no server response, %s dead?", conf->name);
1863                     if (server->lostrqs < 255)
1864                         server->lostrqs++;
1865                 }
1866                 freerqoutdata(rqout);
1867                 pthread_mutex_unlock(rqout->lock);
1868                 continue;
1869             }
1870
1871             rqout->expiry.tv_sec = now.tv_sec + conf->retryinterval;
1872             if (!timeout.tv_sec || rqout->expiry.tv_sec < timeout.tv_sec)
1873                 timeout.tv_sec = rqout->expiry.tv_sec;
1874             rqout->tries++;
1875             conf->pdef->clientradput(server, rqout->rq->buf);
1876             pthread_mutex_unlock(rqout->lock);
1877         }
1878         if (conf->statusserver && server->connectionok) {
1879             secs = server->lastrcv.tv_sec > laststatsrv.tv_sec ? server->lastrcv.tv_sec : laststatsrv.tv_sec;
1880             gettimeofday(&now, NULL);
1881             if (now.tv_sec - secs > STATUS_SERVER_PERIOD) {
1882                 laststatsrv = now;
1883                 statsrvrq = createstatsrvrq();
1884                 if (statsrvrq) {
1885                     statsrvrq->to = server;
1886                     debug(DBG_DBG, "clientwr: sending status server to %s", conf->name);
1887                     sendrq(statsrvrq);
1888                 }
1889             }
1890         }
1891     }
1892 errexit:
1893     conf->servers = NULL;
1894     if (server->dynamiclookuparg) {
1895         removeserversubrealms(realms, conf);
1896         if (dynconffail)
1897             free(conf);
1898         else
1899             freeclsrvconf(conf);
1900     }
1901     freeserver(server, 1);
1902     ERR_remove_state(0);
1903     return NULL;
1904 }
1905
1906 void createlistener(uint8_t type, char *arg) {
1907     pthread_t th;
1908     struct addrinfo *res;
1909     int s = -1, on = 1, *sp = NULL;
1910     struct hostportres *hp = newhostport(arg, protodefs[type]->portdefault, 0);
1911
1912     if (!hp || !resolvehostport(hp, protodefs[type]->socktype, 1))
1913         debugx(1, DBG_ERR, "createlistener: failed to resolve %s", arg);
1914
1915     for (res = hp->addrinfo; res; res = res->ai_next) {
1916         s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
1917         if (s < 0) {
1918             debugerrno(errno, DBG_WARN, "createlistener: socket failed");
1919             continue;
1920         }
1921         setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
1922
1923         disable_DF_bit(s, res);
1924
1925 #ifdef IPV6_V6ONLY
1926         if (res->ai_family == AF_INET6)
1927             setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
1928 #endif
1929         if (bind(s, res->ai_addr, res->ai_addrlen)) {
1930             debugerrno(errno, DBG_WARN, "createlistener: bind failed");
1931             close(s);
1932             s = -1;
1933             continue;
1934         }
1935
1936         sp = malloc(sizeof(int));
1937         if (!sp)
1938             debugx(1, DBG_ERR, "malloc failed");
1939         *sp = s;
1940         if (pthread_create(&th, NULL, protodefs[type]->listener, (void *)sp))
1941             debugerrnox(errno, DBG_ERR, "pthread_create failed");
1942         pthread_detach(th);
1943     }
1944     if (!sp)
1945         debugx(1, DBG_ERR, "createlistener: socket/bind failed");
1946
1947     debug(DBG_WARN, "createlistener: listening for %s on %s:%s", protodefs[type]->name, hp->host ? hp->host : "*", hp->port);
1948     freehostport(hp);
1949 }
1950
1951 void createlisteners(uint8_t type) {
1952     int i;
1953     char **args;
1954
1955     args = protodefs[type]->getlistenerargs();
1956     if (args)
1957         for (i = 0; args[i]; i++)
1958             createlistener(type, args[i]);
1959     else
1960         createlistener(type, NULL);
1961 }
1962
1963 void sslinit() {
1964     int i;
1965     time_t t;
1966     pid_t pid;
1967
1968     ssl_locks = calloc(CRYPTO_num_locks(), sizeof(pthread_mutex_t));
1969     ssl_lock_count = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long));
1970     for (i = 0; i < CRYPTO_num_locks(); i++) {
1971         ssl_lock_count[i] = 0;
1972         pthread_mutex_init(&ssl_locks[i], NULL);
1973     }
1974     CRYPTO_set_id_callback(ssl_thread_id);
1975     CRYPTO_set_locking_callback(ssl_locking_callback);
1976
1977     SSL_load_error_strings();
1978     SSL_library_init();
1979
1980     while (!RAND_status()) {
1981         t = time(NULL);
1982         pid = getpid();
1983         RAND_seed((unsigned char *)&t, sizeof(time_t));
1984         RAND_seed((unsigned char *)&pid, sizeof(pid));
1985     }
1986 }
1987
1988 struct list *addsrvconfs(char *value, char **names) {
1989     struct list *conflist;
1990     int n;
1991     struct list_node *entry;
1992     struct clsrvconf *conf = NULL;
1993
1994     if (!names || !*names)
1995         return NULL;
1996
1997     conflist = list_create();
1998     if (!conflist) {
1999         debug(DBG_ERR, "malloc failed");
2000         return NULL;
2001     }
2002
2003     for (n = 0; names[n]; n++) {
2004         for (entry = list_first(srvconfs); entry; entry = list_next(entry)) {
2005             conf = (struct clsrvconf *)entry->data;
2006             if (!strcasecmp(names[n], conf->name))
2007                 break;
2008         }
2009         if (!entry) {
2010             debug(DBG_ERR, "addsrvconfs failed for realm %s, no server named %s", value, names[n]);
2011             list_destroy(conflist);
2012             return NULL;
2013         }
2014         if (!list_push(conflist, conf)) {
2015             debug(DBG_ERR, "malloc failed");
2016             list_destroy(conflist);
2017             return NULL;
2018         }
2019         debug(DBG_DBG, "addsrvconfs: added server %s for realm %s", conf->name, value);
2020     }
2021     return conflist;
2022 }
2023
2024 void freerealm(struct realm *realm) {
2025     if (!realm)
2026         return;
2027     debug(DBG_DBG, "freerealm: called with refcount %d", realm->refcount);
2028     if (--realm->refcount)
2029         return;
2030
2031     free(realm->name);
2032     free(realm->message);
2033     regfree(&realm->regex);
2034     pthread_mutex_destroy(&realm->mutex);
2035     /* if refcount == 0, all subrealms gone */
2036     list_destroy(realm->subrealms);
2037     /* if refcount == 0, all srvconfs gone */
2038     list_destroy(realm->srvconfs);
2039     /* if refcount == 0, all accsrvconfs gone */
2040     list_destroy(realm->accsrvconfs);
2041     freerealm(realm->parent);
2042     free(realm);
2043 }
2044
2045 struct realm *addrealm(struct list *realmlist, char *value, char **servers, char **accservers, char *message, uint8_t accresp) {
2046     int n;
2047     struct realm *realm;
2048     char *s, *regex = NULL;
2049
2050     if (*value == '/') {
2051         /* regexp, remove optional trailing / if present */
2052         if (value[strlen(value) - 1] == '/')
2053             value[strlen(value) - 1] = '\0';
2054     } else {
2055         /* not a regexp, let us make it one */
2056         if (*value == '*' && !value[1])
2057             regex = stringcopy(".*", 0);
2058         else {
2059             for (n = 0, s = value; *s;)
2060                 if (*s++ == '.')
2061                     n++;
2062             regex = malloc(strlen(value) + n + 3);
2063             if (regex) {
2064                 regex[0] = '@';
2065                 for (n = 1, s = value; *s; s++) {
2066                     if (*s == '.')
2067                         regex[n++] = '\\';
2068                     regex[n++] = *s;
2069                 }
2070                 regex[n++] = '$';
2071                 regex[n] = '\0';
2072             }
2073         }
2074         if (!regex) {
2075             debug(DBG_ERR, "malloc failed");
2076             realm = NULL;
2077             goto exit;
2078         }
2079         debug(DBG_DBG, "addrealm: constructed regexp %s from %s", regex, value);
2080     }
2081
2082     realm = malloc(sizeof(struct realm));
2083     if (!realm) {
2084         debug(DBG_ERR, "malloc failed");
2085         goto exit;
2086     }
2087     memset(realm, 0, sizeof(struct realm));
2088
2089     if (pthread_mutex_init(&realm->mutex, NULL)) {
2090         debugerrno(errno, DBG_ERR, "mutex init failed");
2091         free(realm);
2092         realm = NULL;
2093         goto exit;
2094     }
2095
2096     realm->name = stringcopy(value, 0);
2097     if (!realm->name) {
2098         debug(DBG_ERR, "malloc failed");
2099         goto errexit;
2100     }
2101     if (message && strlen(message) > 253) {
2102         debug(DBG_ERR, "ReplyMessage can be at most 253 bytes");
2103         goto errexit;
2104     }
2105     realm->message = message;
2106     realm->accresp = accresp;
2107
2108     if (regcomp(&realm->regex, regex ? regex : value + 1, REG_EXTENDED | REG_ICASE | REG_NOSUB)) {
2109         debug(DBG_ERR, "addrealm: failed to compile regular expression %s", regex ? regex : value + 1);
2110         goto errexit;
2111     }
2112
2113     if (servers && *servers) {
2114         realm->srvconfs = addsrvconfs(value, servers);
2115         if (!realm->srvconfs)
2116             goto errexit;
2117     }
2118
2119     if (accservers && *accservers) {
2120         realm->accsrvconfs = addsrvconfs(value, accservers);
2121         if (!realm->accsrvconfs)
2122             goto errexit;
2123     }
2124
2125     if (!list_push(realmlist, realm)) {
2126         debug(DBG_ERR, "malloc failed");
2127         pthread_mutex_destroy(&realm->mutex);
2128         goto errexit;
2129     }
2130
2131     debug(DBG_DBG, "addrealm: added realm %s", value);
2132     goto exit;
2133
2134 errexit:
2135     while (list_shift(realm->srvconfs));
2136     while (list_shift(realm->accsrvconfs));
2137     freerealm(realm);
2138     realm = NULL;
2139 exit:
2140     free(regex);
2141     if (servers) {
2142         if (realm)
2143             for (n = 0; servers[n]; n++)
2144                 newrealmref(realm);
2145         freegconfmstr(servers);
2146     }
2147     if (accservers) {
2148         if (realm)
2149             for (n = 0; accservers[n]; n++)
2150                 newrealmref(realm);
2151         freegconfmstr(accservers);
2152     }
2153     return newrealmref(realm);
2154 }
2155
2156 struct list *createsubrealmservers(struct realm *realm, struct list *srvconfs) {
2157     struct list_node *entry;
2158     struct clsrvconf *conf, *srvconf;
2159     struct list *subrealmservers = NULL;
2160     pthread_t clientth;
2161
2162     if (list_first(srvconfs)) {
2163         subrealmservers = list_create();
2164         if (!subrealmservers)
2165             return NULL;
2166     }
2167
2168     for (entry = list_first(srvconfs); entry; entry = list_next(entry)) {
2169         conf = (struct clsrvconf *)entry->data;
2170         if (!conf->servers && conf->dynamiclookupcommand) {
2171             srvconf = malloc(sizeof(struct clsrvconf));
2172             if (!srvconf) {
2173                 debug(DBG_ERR, "malloc failed");
2174                 continue;
2175             }
2176             *srvconf = *conf;
2177             if (addserver(srvconf)) {
2178                 srvconf->servers->dynamiclookuparg = stringcopy(realm->name, 0);
2179                 srvconf->servers->dynstartup = 1;
2180                 if (pthread_create(&clientth, NULL, clientwr, (void *)(srvconf->servers))) {
2181                     debugerrno(errno, DBG_ERR, "pthread_create failed");
2182                     freeserver(srvconf->servers, 1);
2183                     srvconf->servers = NULL;
2184                 } else
2185                     pthread_detach(clientth);
2186             }
2187             conf = srvconf;
2188         }
2189         if (conf->servers) {
2190             if (list_push(subrealmservers, conf))
2191                 newrealmref(realm);
2192             else
2193                 debug(DBG_ERR, "malloc failed");
2194         }
2195     }
2196     return subrealmservers;
2197 }
2198
2199 struct realm *adddynamicrealmserver(struct realm *realm, char *id) {
2200     struct realm *newrealm = NULL;
2201     char *realmname, *s;
2202
2203     /* create dynamic for the realm (string after last @, exit if nothing after @ */
2204     realmname = strrchr(id, '@');
2205     if (!realmname)
2206         return NULL;
2207     realmname++;
2208     if (!*realmname)
2209         return NULL;
2210     for (s = realmname; *s; s++)
2211         if (*s != '.' && *s != '-' && !isalnum((int)*s))
2212             return NULL;
2213
2214     if (!realm->subrealms)
2215         realm->subrealms = list_create();
2216     if (!realm->subrealms)
2217         return NULL;
2218
2219     newrealm = addrealm(realm->subrealms, realmname, NULL, NULL, stringcopy(realm->message, 0), realm->accresp);
2220     if (!newrealm) {
2221         list_destroy(realm->subrealms);
2222         realm->subrealms = NULL;
2223         return NULL;
2224     }
2225
2226     newrealm->parent = newrealmref(realm);
2227     /* add server and accserver to newrealm */
2228     newrealm->srvconfs = createsubrealmservers(newrealm, realm->srvconfs);
2229     newrealm->accsrvconfs = createsubrealmservers(newrealm, realm->accsrvconfs);
2230     return newrealm;
2231 }
2232
2233 int dynamicconfig(struct server *server) {
2234     int ok, fd[2], status;
2235     pid_t pid;
2236     struct clsrvconf *conf = server->conf;
2237     struct gconffile *cf = NULL;
2238
2239     /* for now we only learn hostname/address */
2240     debug(DBG_DBG, "dynamicconfig: need dynamic server config for %s", server->dynamiclookuparg);
2241
2242     if (pipe(fd) > 0) {
2243         debugerrno(errno, DBG_ERR, "dynamicconfig: pipe error");
2244         goto errexit;
2245     }
2246     pid = fork();
2247     if (pid < 0) {
2248         debugerrno(errno, DBG_ERR, "dynamicconfig: fork error");
2249         close(fd[0]);
2250         close(fd[1]);
2251         goto errexit;
2252     } else if (pid == 0) {
2253         /* child */
2254         close(fd[0]);
2255         if (fd[1] != STDOUT_FILENO) {
2256             if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO)
2257                 debugx(1, DBG_ERR, "dynamicconfig: dup2 error for command %s", conf->dynamiclookupcommand);
2258             close(fd[1]);
2259         }
2260         if (execlp(conf->dynamiclookupcommand, conf->dynamiclookupcommand, server->dynamiclookuparg, NULL) < 0)
2261             debugx(1, DBG_ERR, "dynamicconfig: exec error for command %s", conf->dynamiclookupcommand);
2262     }
2263
2264     close(fd[1]);
2265     pushgconffile(&cf, fdopen(fd[0], "r"), conf->dynamiclookupcommand);
2266     ok = getgenericconfig(&cf, NULL, "Server", CONF_CBK, confserver_cb,
2267                           (void *) conf, NULL);
2268     freegconf(&cf);
2269
2270     if (waitpid(pid, &status, 0) < 0) {
2271         debugerrno(errno, DBG_ERR, "dynamicconfig: wait error");
2272         goto errexit;
2273     }
2274
2275     if (status) {
2276         if (WEXITSTATUS(status) == 10) {
2277             debug(DBG_INFO, "dynamicconfig: command signals empty config");
2278         }
2279         else {
2280             debug(DBG_INFO, "dynamicconfig: command exited with status %d",
2281                   WEXITSTATUS(status));
2282             goto errexit;
2283         }
2284     }
2285
2286     if (ok)
2287         return 1;
2288
2289 errexit:
2290     debug(DBG_WARN, "dynamicconfig: failed to obtain dynamic server config");
2291     return 0;
2292 }
2293
2294 /* should accept both names and numeric values, only numeric right now */
2295 uint8_t attrname2val(char *attrname) {
2296     int val = 0;
2297
2298     val = atoi(attrname);
2299     return val > 0 && val < 256 ? val : 0;
2300 }
2301
2302 /* ATTRNAME is on the form vendor[:type].
2303    If only vendor is found, TYPE is set to 256 and 1 is returned.
2304    If type is >= 256, 1 is returned.
2305    Otherwise, 0 is returned.
2306 */
2307 /* should accept both names and numeric values, only numeric right now */
2308 int vattrname2val(char *attrname, uint32_t *vendor, uint32_t *type) {
2309     char *s;
2310
2311     *vendor = atoi(attrname);
2312     s = strchr(attrname, ':');
2313     if (!s) {                   /* Only vendor was found.  */
2314         *type = 256;
2315         return 1;
2316     }
2317     *type = atoi(s + 1);
2318     return *type < 256;
2319 }
2320
2321 /** Extract attributes from string NAMEVAL, create a struct tlv and
2322  * return the tlv.  If VENDOR_FLAG, NAMEVAL is on the form
2323  * "<vendor>:<name>:<val>" and otherwise it's "<name>:<val>".  Return
2324  * NULL if fields are missing or if conversion fails.
2325  *
2326  * FIXME: Should accept both names and numeric values, only numeric
2327  * right now */
2328 struct tlv *extractattr(char *nameval, char vendor_flag) {
2329     int len, name = 0;
2330     int vendor = 0;         /* Vendor 0 is reserved, see RFC 1700.  */
2331     char *s, *s2;
2332     struct tlv *a;
2333
2334     s = strchr(nameval, ':');
2335     if (!s)
2336         return NULL;
2337     name = atoi(nameval);
2338
2339     if (vendor_flag) {
2340         s2 = strchr(s + 1, ':');
2341         if (!s2)
2342             return NULL;
2343         vendor = name;
2344         name = atoi(s + 1);
2345         s = s2;
2346     }
2347     len = strlen(s + 1);
2348     if (len > 253)
2349         return NULL;
2350
2351     if (name < 1 || name > 255)
2352         return NULL;
2353     a = malloc(sizeof(struct tlv));
2354     if (!a)
2355         return NULL;
2356
2357     a->v = (uint8_t *)stringcopy(s + 1, 0);
2358     if (!a->v) {
2359         free(a);
2360         return NULL;
2361     }
2362     a->t = name;
2363     a->l = len;
2364
2365     if (vendor_flag)
2366         a = makevendortlv(vendor, a);
2367
2368     return a;
2369 }
2370
2371 /* should accept both names and numeric values, only numeric right now */
2372 struct modattr *extractmodattr(char *nameval) {
2373     int name = 0;
2374     char *s, *t;
2375     struct modattr *m;
2376
2377     if (!strncasecmp(nameval, "User-Name:/", 11)) {
2378         s = nameval + 11;
2379         name = 1;
2380     } else {
2381         s = strchr(nameval, ':');
2382         name = atoi(nameval);
2383         if (!s || name < 1 || name > 255 || s[1] != '/')
2384             return NULL;
2385         s += 2;
2386     }
2387     /* regexp, remove optional trailing / if present */
2388     if (s[strlen(s) - 1] == '/')
2389         s[strlen(s) - 1] = '\0';
2390
2391     t = strchr(s, '/');
2392     if (!t)
2393         return NULL;
2394     *t = '\0';
2395     t++;
2396
2397     m = malloc(sizeof(struct modattr));
2398     if (!m) {
2399         debug(DBG_ERR, "malloc failed");
2400         return NULL;
2401     }
2402     m->t = name;
2403
2404     m->replacement = stringcopy(t, 0);
2405     if (!m->replacement) {
2406         free(m);
2407         debug(DBG_ERR, "malloc failed");
2408         return NULL;
2409     }
2410
2411     m->regex = malloc(sizeof(regex_t));
2412     if (!m->regex) {
2413         free(m->replacement);
2414         free(m);
2415         debug(DBG_ERR, "malloc failed");
2416         return NULL;
2417     }
2418
2419     if (regcomp(m->regex, s, REG_ICASE | REG_EXTENDED)) {
2420         free(m->regex);
2421         free(m->replacement);
2422         free(m);
2423         debug(DBG_ERR, "failed to compile regular expression %s", s);
2424         return NULL;
2425     }
2426
2427     return m;
2428 }
2429
2430 struct rewrite *getrewrite(char *alt1, char *alt2) {
2431     struct rewrite *r;
2432
2433     if (alt1)
2434         if ((r = hash_read(rewriteconfs,  alt1, strlen(alt1))))
2435             return r;
2436     if (alt2)
2437         if ((r = hash_read(rewriteconfs,  alt2, strlen(alt2))))
2438             return r;
2439     return NULL;
2440 }
2441
2442 void addrewrite(char *value, char **rmattrs, char **rmvattrs, char **addattrs, char **addvattrs, char **modattrs)
2443 {
2444     struct rewrite *rewrite = NULL;
2445     int i, n;
2446     uint8_t *rma = NULL;
2447     uint32_t *p, *rmva = NULL;
2448     struct list *adda = NULL, *moda = NULL;
2449     struct tlv *a;
2450     struct modattr *m;
2451
2452     if (rmattrs) {
2453         for (n = 0; rmattrs[n]; n++);
2454         rma = calloc(n + 1, sizeof(uint8_t));
2455         if (!rma)
2456             debugx(1, DBG_ERR, "malloc failed");
2457
2458         for (i = 0; i < n; i++)
2459             if (!(rma[i] = attrname2val(rmattrs[i])))
2460                 debugx(1, DBG_ERR, "addrewrite: removing invalid attribute %s", rmattrs[i]);
2461         freegconfmstr(rmattrs);
2462         rma[i] = 0;
2463     }
2464
2465     if (rmvattrs) {
2466         for (n = 0; rmvattrs[n]; n++);
2467         rmva = calloc(2 * n + 1, sizeof(uint32_t));
2468         if (!rmva)
2469             debugx(1, DBG_ERR, "malloc failed");
2470
2471         for (p = rmva, i = 0; i < n; i++, p += 2)
2472             if (!vattrname2val(rmvattrs[i], p, p + 1))
2473                 debugx(1, DBG_ERR, "addrewrite: removing invalid vendor attribute %s", rmvattrs[i]);
2474         freegconfmstr(rmvattrs);
2475         *p = 0;
2476     }
2477
2478     if (addattrs) {
2479         adda = list_create();
2480         if (!adda)
2481             debugx(1, DBG_ERR, "malloc failed");
2482         for (i = 0; addattrs[i]; i++) {
2483             a = extractattr(addattrs[i], 0);
2484             if (!a)
2485                 debugx(1, DBG_ERR, "addrewrite: adding invalid attribute %s", addattrs[i]);
2486             if (!list_push(adda, a))
2487                 debugx(1, DBG_ERR, "malloc failed");
2488         }
2489         freegconfmstr(addattrs);
2490     }
2491
2492     if (addvattrs) {
2493         if (!adda)
2494             adda = list_create();
2495         if (!adda)
2496             debugx(1, DBG_ERR, "malloc failed");
2497         for (i = 0; addvattrs[i]; i++) {
2498             a = extractattr(addvattrs[i], 1);
2499             if (!a)
2500                 debugx(1, DBG_ERR, "addrewrite: adding invalid vendor attribute %s", addvattrs[i]);
2501             if (!list_push(adda, a))
2502                 debugx(1, DBG_ERR, "malloc failed");
2503         }
2504         freegconfmstr(addvattrs);
2505     }
2506
2507     if (modattrs) {
2508         moda = list_create();
2509         if (!moda)
2510             debugx(1, DBG_ERR, "malloc failed");
2511         for (i = 0; modattrs[i]; i++) {
2512             m = extractmodattr(modattrs[i]);
2513             if (!m)
2514                 debugx(1, DBG_ERR, "addrewrite: modifying invalid attribute %s", modattrs[i]);
2515             if (!list_push(moda, m))
2516                 debugx(1, DBG_ERR, "malloc failed");
2517         }
2518         freegconfmstr(modattrs);
2519     }
2520
2521     if (rma || rmva || adda || moda) {
2522         rewrite = malloc(sizeof(struct rewrite));
2523         if (!rewrite)
2524             debugx(1, DBG_ERR, "malloc failed");
2525         rewrite->removeattrs = rma;
2526         rewrite->removevendorattrs = rmva;
2527         rewrite->addattrs = adda;
2528         rewrite->modattrs = moda;
2529     }
2530
2531     if (!hash_insert(rewriteconfs, value, strlen(value), rewrite))
2532         debugx(1, DBG_ERR, "malloc failed");
2533     debug(DBG_DBG, "addrewrite: added rewrite block %s", value);
2534 }
2535
2536 int setttlattr(struct options *opts, char *defaultattr) {
2537     char *ttlattr = opts->ttlattr ? opts->ttlattr : defaultattr;
2538
2539     if (vattrname2val(ttlattr, opts->ttlattrtype, opts->ttlattrtype + 1) &&
2540         (opts->ttlattrtype[1] != 256 || opts->ttlattrtype[0] < 256))
2541         return 1;
2542     debug(DBG_ERR, "setttlattr: invalid TTLAttribute value %s", ttlattr);
2543     return 0;
2544 }
2545
2546 void freeclsrvconf(struct clsrvconf *conf) {
2547     free(conf->name);
2548     if (conf->hostsrc)
2549         freegconfmstr(conf->hostsrc);
2550     free(conf->portsrc);
2551     free(conf->secret);
2552     free(conf->tls);
2553     free(conf->matchcertattr);
2554     if (conf->certcnregex)
2555         regfree(conf->certcnregex);
2556     if (conf->certuriregex)
2557         regfree(conf->certuriregex);
2558     free(conf->confrewritein);
2559     free(conf->confrewriteout);
2560     if (conf->rewriteusername) {
2561         if (conf->rewriteusername->regex)
2562             regfree(conf->rewriteusername->regex);
2563         free(conf->rewriteusername->replacement);
2564         free(conf->rewriteusername);
2565     }
2566     free(conf->dynamiclookupcommand);
2567     free(conf->rewritein);
2568     free(conf->rewriteout);
2569     if (conf->hostports)
2570         freehostports(conf->hostports);
2571     if (conf->lock) {
2572         pthread_mutex_destroy(conf->lock);
2573         free(conf->lock);
2574     }
2575     /* not touching ssl_ctx, clients and servers */
2576     free(conf);
2577 }
2578
2579 int mergeconfstring(char **dst, char **src) {
2580     char *t;
2581
2582     if (*src) {
2583         *dst = *src;
2584         *src = NULL;
2585         return 1;
2586     }
2587     if (*dst) {
2588         t = stringcopy(*dst, 0);
2589         if (!t) {
2590             debug(DBG_ERR, "malloc failed");
2591             return 0;
2592         }
2593         *dst = t;
2594     }
2595     return 1;
2596 }
2597
2598 char **mstringcopy(char **in) {
2599     char **out;
2600     int n;
2601
2602     if (!in)
2603         return NULL;
2604
2605     for (n = 0; in[n]; n++);
2606     out = malloc((n + 1) * sizeof(char *));
2607     if (!out)
2608         return NULL;
2609     for (n = 0; in[n]; n++) {
2610         out[n] = stringcopy(in[n], 0);
2611         if (!out[n]) {
2612             freegconfmstr(out);
2613             return NULL;
2614         }
2615     }
2616     out[n] = NULL;
2617     return out;
2618 }
2619
2620 int mergeconfmstring(char ***dst, char ***src) {
2621     char **t;
2622
2623     if (*src) {
2624         *dst = *src;
2625         *src = NULL;
2626         return 1;
2627     }
2628     if (*dst) {
2629         t = mstringcopy(*dst);
2630         if (!t) {
2631             debug(DBG_ERR, "malloc failed");
2632             return 0;
2633         }
2634         *dst = t;
2635     }
2636     return 1;
2637 }
2638
2639 /* assumes dst is a shallow copy */
2640 int mergesrvconf(struct clsrvconf *dst, struct clsrvconf *src) {
2641     if (!mergeconfstring(&dst->name, &src->name) ||
2642         !mergeconfmstring(&dst->hostsrc, &src->hostsrc) ||
2643         !mergeconfstring(&dst->portsrc, &src->portsrc) ||
2644         !mergeconfstring(&dst->secret, &src->secret) ||
2645         !mergeconfstring(&dst->tls, &src->tls) ||
2646         !mergeconfstring(&dst->matchcertattr, &src->matchcertattr) ||
2647         !mergeconfstring(&dst->confrewritein, &src->confrewritein) ||
2648         !mergeconfstring(&dst->confrewriteout, &src->confrewriteout) ||
2649         !mergeconfstring(&dst->dynamiclookupcommand, &src->dynamiclookupcommand))
2650         return 0;
2651     if (src->pdef)
2652         dst->pdef = src->pdef;
2653     dst->statusserver = src->statusserver;
2654     dst->certnamecheck = src->certnamecheck;
2655     if (src->retryinterval != 255)
2656         dst->retryinterval = src->retryinterval;
2657     if (src->retrycount != 255)
2658         dst->retrycount = src->retrycount;
2659     return 1;
2660 }
2661
2662 int confclient_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val) {
2663     struct clsrvconf *conf;
2664     char *conftype = NULL, *rewriteinalias = NULL;
2665     long int dupinterval = LONG_MIN, addttl = LONG_MIN;
2666
2667     debug(DBG_DBG, "confclient_cb called for %s", block);
2668
2669     conf = malloc(sizeof(struct clsrvconf));
2670     if (!conf)
2671         debugx(1, DBG_ERR, "malloc failed");
2672     memset(conf, 0, sizeof(struct clsrvconf));
2673     conf->certnamecheck = 1;
2674
2675     if (!getgenericconfig(
2676             cf, block,
2677             "type", CONF_STR, &conftype,
2678             "host", CONF_MSTR, &conf->hostsrc,
2679             "secret", CONF_STR, &conf->secret,
2680 #if defined(RADPROT_TLS) || defined(RADPROT_DTLS)
2681             "tls", CONF_STR, &conf->tls,
2682             "matchcertificateattribute", CONF_STR, &conf->matchcertattr,
2683             "CertificateNameCheck", CONF_BLN, &conf->certnamecheck,
2684 #endif
2685             "DuplicateInterval", CONF_LINT, &dupinterval,
2686             "addTTL", CONF_LINT, &addttl,
2687             "rewrite", CONF_STR, &rewriteinalias,
2688             "rewriteIn", CONF_STR, &conf->confrewritein,
2689             "rewriteOut", CONF_STR, &conf->confrewriteout,
2690             "rewriteattribute", CONF_STR, &conf->confrewriteusername,
2691 #if defined(WANT_FTICKS)
2692             "fticksVISCOUNTRY", CONF_STR, &conf->fticks_viscountry,
2693 #endif
2694             NULL
2695             ))
2696         debugx(1, DBG_ERR, "configuration error");
2697
2698     conf->name = stringcopy(val, 0);
2699     if (conf->name && !conf->hostsrc) {
2700         conf->hostsrc = malloc(2 * sizeof(char *));
2701         if (conf->hostsrc) {
2702             conf->hostsrc[0] = stringcopy(val, 0);
2703             conf->hostsrc[1] = NULL;
2704         }
2705     }
2706     if (!conf->name || !conf->hostsrc || !conf->hostsrc[0])
2707         debugx(1, DBG_ERR, "malloc failed");
2708
2709     if (!conftype)
2710         debugx(1, DBG_ERR, "error in block %s, option type missing", block);
2711     conf->type = protoname2int(conftype);
2712     if (conf->type == 255)
2713         debugx(1, DBG_ERR, "error in block %s, unknown transport %s", block, conftype);
2714     free(conftype);
2715     conf->pdef = protodefs[conf->type];
2716
2717 #if defined(RADPROT_TLS) || defined(RADPROT_DTLS)
2718     if (conf->type == RAD_TLS || conf->type == RAD_DTLS) {
2719         conf->tlsconf = conf->tls ? tlsgettls(conf->tls, NULL) : tlsgettls("defaultclient", "default");
2720         if (!conf->tlsconf)
2721             debugx(1, DBG_ERR, "error in block %s, no tls context defined", block);
2722         if (conf->matchcertattr && !addmatchcertattr(conf))
2723             debugx(1, DBG_ERR, "error in block %s, invalid MatchCertificateAttributeValue", block);
2724     }
2725 #endif
2726
2727     if (dupinterval != LONG_MIN) {
2728         if (dupinterval < 0 || dupinterval > 255)
2729             debugx(1, DBG_ERR, "error in block %s, value of option DuplicateInterval is %d, must be 0-255", block, dupinterval);
2730         conf->dupinterval = (uint8_t)dupinterval;
2731     } else
2732         conf->dupinterval = conf->pdef->duplicateintervaldefault;
2733
2734     if (addttl != LONG_MIN) {
2735         if (addttl < 1 || addttl > 255)
2736             debugx(1, DBG_ERR, "error in block %s, value of option addTTL is %d, must be 1-255", block, addttl);
2737         conf->addttl = (uint8_t)addttl;
2738     }
2739
2740     if (!conf->confrewritein)
2741         conf->confrewritein = rewriteinalias;
2742     else
2743         free(rewriteinalias);
2744     conf->rewritein = conf->confrewritein ? getrewrite(conf->confrewritein, NULL) : getrewrite("defaultclient", "default");
2745     if (conf->confrewriteout)
2746         conf->rewriteout = getrewrite(conf->confrewriteout, NULL);
2747
2748     if (conf->confrewriteusername) {
2749         conf->rewriteusername = extractmodattr(conf->confrewriteusername);
2750         if (!conf->rewriteusername)
2751             debugx(1, DBG_ERR, "error in block %s, invalid RewriteAttributeValue", block);
2752     }
2753
2754     if (!addhostport(&conf->hostports, conf->hostsrc, conf->pdef->portdefault, 1) ||
2755         !resolvehostports(conf->hostports, conf->pdef->socktype))
2756         debugx(1, DBG_ERR, "resolve failed, exiting");
2757
2758     if (!conf->secret) {
2759         if (!conf->pdef->secretdefault)
2760             debugx(1, DBG_ERR, "error in block %s, secret must be specified for transport type %s", block, conf->pdef->name);
2761         conf->secret = stringcopy(conf->pdef->secretdefault, 0);
2762         if (!conf->secret)
2763             debugx(1, DBG_ERR, "malloc failed");
2764     }
2765
2766     conf->lock = malloc(sizeof(pthread_mutex_t));
2767     if (!conf->lock)
2768         debugx(1, DBG_ERR, "malloc failed");
2769
2770     pthread_mutex_init(conf->lock, NULL);
2771     if (!list_push(clconfs, conf))
2772         debugx(1, DBG_ERR, "malloc failed");
2773     return 1;
2774 }
2775
2776 int compileserverconfig(struct clsrvconf *conf, const char *block) {
2777 #if defined(RADPROT_TLS) || defined(RADPROT_DTLS)
2778     if (conf->type == RAD_TLS || conf->type == RAD_DTLS) {
2779         conf->tlsconf = conf->tls ? tlsgettls(conf->tls, NULL) : tlsgettls("defaultserver", "default");
2780         if (!conf->tlsconf) {
2781             debug(DBG_ERR, "error in block %s, no tls context defined", block);
2782             return 0;
2783         }
2784         if (conf->matchcertattr && !addmatchcertattr(conf)) {
2785             debug(DBG_ERR, "error in block %s, invalid MatchCertificateAttributeValue", block);
2786             return 0;
2787         }
2788     }
2789 #endif
2790
2791     if (!conf->portsrc) {
2792         conf->portsrc = stringcopy(conf->pdef->portdefault, 0);
2793         if (!conf->portsrc) {
2794             debug(DBG_ERR, "malloc failed");
2795             return 0;
2796         }
2797     }
2798
2799     if (conf->retryinterval == 255)
2800         conf->retryinterval = conf->pdef->retryintervaldefault;
2801     if (conf->retrycount == 255)
2802         conf->retrycount = conf->pdef->retrycountdefault;
2803
2804     conf->rewritein = conf->confrewritein ? getrewrite(conf->confrewritein, NULL) : getrewrite("defaultserver", "default");
2805     if (conf->confrewriteout)
2806         conf->rewriteout = getrewrite(conf->confrewriteout, NULL);
2807
2808     if (!addhostport(&conf->hostports, conf->hostsrc, conf->portsrc, 0)) {
2809         debug(DBG_ERR, "error in block %s, failed to parse %s", block, *conf->hostsrc);
2810         return 0;
2811     }
2812
2813     if (!conf->dynamiclookupcommand && !resolvehostports(conf->hostports, conf->pdef->socktype)) {
2814         debug(DBG_ERR, "resolve failed, exiting");
2815         return 0;
2816     }
2817     return 1;
2818 }
2819
2820 int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val) {
2821     struct clsrvconf *conf, *resconf;
2822     char *conftype = NULL, *rewriteinalias = NULL;
2823     long int retryinterval = LONG_MIN, retrycount = LONG_MIN, addttl = LONG_MIN;
2824
2825     debug(DBG_DBG, "confserver_cb called for %s", block);
2826
2827     conf = malloc(sizeof(struct clsrvconf));
2828     if (!conf) {
2829         debug(DBG_ERR, "malloc failed");
2830         return 0;
2831     }
2832     memset(conf, 0, sizeof(struct clsrvconf));
2833     conf->loopprevention = UCHAR_MAX; /* Uninitialized.  */
2834     resconf = (struct clsrvconf *)arg;
2835     if (resconf) {
2836         conf->statusserver = resconf->statusserver;
2837         conf->certnamecheck = resconf->certnamecheck;
2838     } else
2839         conf->certnamecheck = 1;
2840
2841     if (!getgenericconfig(cf, block,
2842                           "type", CONF_STR, &conftype,
2843                           "host", CONF_MSTR, &conf->hostsrc,
2844                           "port", CONF_STR, &conf->portsrc,
2845                           "secret", CONF_STR, &conf->secret,
2846 #if defined(RADPROT_TLS) || defined(RADPROT_DTLS)
2847                           "tls", CONF_STR, &conf->tls,
2848                           "MatchCertificateAttribute", CONF_STR, &conf->matchcertattr,
2849                           "CertificateNameCheck", CONF_BLN, &conf->certnamecheck,
2850 #endif
2851                           "addTTL", CONF_LINT, &addttl,
2852                           "rewrite", CONF_STR, &rewriteinalias,
2853                           "rewriteIn", CONF_STR, &conf->confrewritein,
2854                           "rewriteOut", CONF_STR, &conf->confrewriteout,
2855                           "StatusServer", CONF_BLN, &conf->statusserver,
2856                           "RetryInterval", CONF_LINT, &retryinterval,
2857                           "RetryCount", CONF_LINT, &retrycount,
2858                           "DynamicLookupCommand", CONF_STR, &conf->dynamiclookupcommand,
2859                           "LoopPrevention", CONF_BLN, &conf->loopprevention,
2860                           NULL
2861             )) {
2862         debug(DBG_ERR, "configuration error");
2863         goto errexit;
2864     }
2865
2866     conf->name = stringcopy(val, 0);
2867     if (conf->name && !conf->hostsrc) {
2868         conf->hostsrc = malloc(2 * sizeof(char *));
2869         if (conf->hostsrc) {
2870             conf->hostsrc[0] = stringcopy(val, 0);
2871             conf->hostsrc[1] = NULL;
2872         }
2873     }
2874     if (!conf->name || !conf->hostsrc || !conf->hostsrc[0]) {
2875         debug(DBG_ERR, "malloc failed");
2876         goto errexit;
2877     }
2878
2879     if (!conftype) {
2880         debug(DBG_ERR, "error in block %s, option type missing", block);
2881         goto errexit;
2882     }
2883     conf->type = protoname2int(conftype);
2884     if (conf->type == 255) {
2885         debug(DBG_ERR, "error in block %s, unknown transport %s", block, conftype);
2886         goto errexit;
2887     }
2888     free(conftype);
2889     conftype = NULL;
2890
2891     conf->pdef = protodefs[conf->type];
2892
2893     if (!conf->confrewritein)
2894         conf->confrewritein = rewriteinalias;
2895     else
2896         free(rewriteinalias);
2897     rewriteinalias = NULL;
2898
2899     if (retryinterval != LONG_MIN) {
2900         if (retryinterval < 1 || retryinterval > conf->pdef->retryintervalmax) {
2901             debug(DBG_ERR, "error in block %s, value of option RetryInterval is %d, must be 1-%d", block, retryinterval, conf->pdef->retryintervalmax);
2902             goto errexit;
2903         }
2904         conf->retryinterval = (uint8_t)retryinterval;
2905     } else
2906         conf->retryinterval = 255;
2907
2908     if (retrycount != LONG_MIN) {
2909         if (retrycount < 0 || retrycount > conf->pdef->retrycountmax) {
2910             debug(DBG_ERR, "error in block %s, value of option RetryCount is %d, must be 0-%d", block, retrycount, conf->pdef->retrycountmax);
2911             goto errexit;
2912         }
2913         conf->retrycount = (uint8_t)retrycount;
2914     } else
2915         conf->retrycount = 255;
2916
2917     if (addttl != LONG_MIN) {
2918         if (addttl < 1 || addttl > 255) {
2919             debug(DBG_ERR, "error in block %s, value of option addTTL is %d, must be 1-255", block, addttl);
2920             goto errexit;
2921         }
2922         conf->addttl = (uint8_t)addttl;
2923     }
2924
2925     if (resconf) {
2926         if (!mergesrvconf(resconf, conf))
2927             goto errexit;
2928         free(conf);
2929         conf = resconf;
2930         if (conf->dynamiclookupcommand) {
2931             free(conf->dynamiclookupcommand);
2932             conf->dynamiclookupcommand = NULL;
2933         }
2934     }
2935
2936     if (resconf || !conf->dynamiclookupcommand) {
2937         if (!compileserverconfig(conf, block))
2938             goto errexit;
2939     }
2940
2941     if (!conf->secret) {
2942         if (!conf->pdef->secretdefault) {
2943             debug(DBG_ERR, "error in block %s, secret must be specified for transport type %s", block, conf->pdef->name);
2944             return 0;
2945         }
2946         conf->secret = stringcopy(conf->pdef->secretdefault, 0);
2947         if (!conf->secret) {
2948             debug(DBG_ERR, "malloc failed");
2949             return 0;
2950         }
2951     }
2952
2953     if (resconf)
2954         return 1;
2955
2956     if (!list_push(srvconfs, conf)) {
2957         debug(DBG_ERR, "malloc failed");
2958         goto errexit;
2959     }
2960     return 1;
2961
2962 errexit:
2963     free(conftype);
2964     free(rewriteinalias);
2965     freeclsrvconf(conf);
2966     return 0;
2967 }
2968
2969 int confrealm_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val) {
2970     char **servers = NULL, **accservers = NULL, *msg = NULL;
2971     uint8_t accresp = 0;
2972
2973     debug(DBG_DBG, "confrealm_cb called for %s", block);
2974
2975     if (!getgenericconfig(cf, block,
2976                           "server", CONF_MSTR, &servers,
2977                           "accountingServer", CONF_MSTR, &accservers,
2978                           "ReplyMessage", CONF_STR, &msg,
2979                           "AccountingResponse", CONF_BLN, &accresp,
2980                           NULL
2981             ))
2982         debugx(1, DBG_ERR, "configuration error");
2983
2984     addrealm(realms, val, servers, accservers, msg, accresp);
2985     return 1;
2986 }
2987
2988 int confrewrite_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val) {
2989     char **rmattrs = NULL, **rmvattrs = NULL;
2990     char **addattrs = NULL, **addvattrs = NULL;
2991     char **modattrs = NULL;
2992
2993     debug(DBG_DBG, "confrewrite_cb called for %s", block);
2994
2995     if (!getgenericconfig(cf, block,
2996                           "removeAttribute", CONF_MSTR, &rmattrs,
2997                           "removeVendorAttribute", CONF_MSTR, &rmvattrs,
2998                           "addAttribute", CONF_MSTR, &addattrs,
2999                           "addVendorAttribute", CONF_MSTR, &addvattrs,
3000                           "modifyAttribute", CONF_MSTR, &modattrs,
3001                           NULL
3002             ))
3003         debugx(1, DBG_ERR, "configuration error");
3004     addrewrite(val, rmattrs, rmvattrs, addattrs, addvattrs, modattrs);
3005     return 1;
3006 }
3007
3008 int setprotoopts(uint8_t type, char **listenargs, char *sourcearg) {
3009     struct commonprotoopts *protoopts;
3010
3011     protoopts = malloc(sizeof(struct commonprotoopts));
3012     if (!protoopts)
3013         return 0;
3014     memset(protoopts, 0, sizeof(struct commonprotoopts));
3015     protoopts->listenargs = listenargs;
3016     protoopts->sourcearg = sourcearg;
3017     protodefs[type]->setprotoopts(protoopts);
3018     return 1;
3019 }
3020
3021 void getmainconfig(const char *configfile) {
3022     long int addttl = LONG_MIN, loglevel = LONG_MIN;
3023     struct gconffile *cfs;
3024     char **listenargs[RAD_PROTOCOUNT];
3025     char *sourcearg[RAD_PROTOCOUNT];
3026 #if defined(WANT_FTICKS)
3027     uint8_t *fticks_reporting_str = NULL;
3028     uint8_t *fticks_mac_str = NULL;
3029     uint8_t *fticks_key_str = NULL;
3030 #endif
3031     int i;
3032
3033     cfs = openconfigfile(configfile);
3034     memset(&options, 0, sizeof(options));
3035     memset(&listenargs, 0, sizeof(listenargs));
3036     memset(&sourcearg, 0, sizeof(sourcearg));
3037
3038     clconfs = list_create();
3039     if (!clconfs)
3040         debugx(1, DBG_ERR, "malloc failed");
3041
3042     srvconfs = list_create();
3043     if (!srvconfs)
3044         debugx(1, DBG_ERR, "malloc failed");
3045
3046     realms = list_create();
3047     if (!realms)
3048         debugx(1, DBG_ERR, "malloc failed");
3049
3050     rewriteconfs = hash_create();
3051     if (!rewriteconfs)
3052         debugx(1, DBG_ERR, "malloc failed");
3053
3054     if (!getgenericconfig(
3055             &cfs, NULL,
3056 #ifdef RADPROT_UDP
3057             "ListenUDP", CONF_MSTR, &listenargs[RAD_UDP],
3058             "SourceUDP", CONF_STR, &sourcearg[RAD_UDP],
3059 #endif
3060 #ifdef RADPROT_TCP
3061             "ListenTCP", CONF_MSTR, &listenargs[RAD_TCP],
3062             "SourceTCP", CONF_STR, &sourcearg[RAD_TCP],
3063 #endif
3064 #ifdef RADPROT_TLS
3065             "ListenTLS", CONF_MSTR, &listenargs[RAD_TLS],
3066             "SourceTLS", CONF_STR, &sourcearg[RAD_TLS],
3067 #endif
3068 #ifdef RADPROT_DTLS
3069             "ListenDTLS", CONF_MSTR, &listenargs[RAD_DTLS],
3070             "SourceDTLS", CONF_STR, &sourcearg[RAD_DTLS],
3071 #endif
3072             "TTLAttribute", CONF_STR, &options.ttlattr,
3073             "addTTL", CONF_LINT, &addttl,
3074             "LogLevel", CONF_LINT, &loglevel,
3075             "LogDestination", CONF_STR, &options.logdestination,
3076             "LoopPrevention", CONF_BLN, &options.loopprevention,
3077             "Client", CONF_CBK, confclient_cb, NULL,
3078             "Server", CONF_CBK, confserver_cb, NULL,
3079             "Realm", CONF_CBK, confrealm_cb, NULL,
3080 #if defined(RADPROT_TLS) || defined(RADPROT_DTLS)
3081             "TLS", CONF_CBK, conftls_cb, NULL,
3082 #endif
3083             "Rewrite", CONF_CBK, confrewrite_cb, NULL,
3084 #if defined(WANT_FTICKS)
3085             "FTicksReporting", CONF_STR, &fticks_reporting_str,
3086             "FTicksMAC", CONF_STR, &fticks_mac_str,
3087             "FTicksKey", CONF_STR, &fticks_key_str,
3088 #endif
3089             NULL
3090             ))
3091         debugx(1, DBG_ERR, "configuration error");
3092
3093     if (loglevel != LONG_MIN) {
3094         if (loglevel < 1 || loglevel > 5)
3095             debugx(1, DBG_ERR, "error in %s, value of option LogLevel is %d, must be 1, 2, 3, 4 or 5", configfile, loglevel);
3096         options.loglevel = (uint8_t)loglevel;
3097     }
3098     if (addttl != LONG_MIN) {
3099         if (addttl < 1 || addttl > 255)
3100             debugx(1, DBG_ERR, "error in %s, value of option addTTL is %d, must be 1-255", configfile, addttl);
3101         options.addttl = (uint8_t)addttl;
3102     }
3103     if (!setttlattr(&options, DEFAULT_TTL_ATTR))
3104         debugx(1, DBG_ERR, "Failed to set TTLAttribute, exiting");
3105
3106 #if defined(WANT_FTICKS)
3107     fticks_configure(&options, &fticks_reporting_str, &fticks_mac_str,
3108                      &fticks_key_str);
3109 #endif
3110
3111     for (i = 0; i < RAD_PROTOCOUNT; i++)
3112         if (listenargs[i] || sourcearg[i])
3113             setprotoopts(i, listenargs[i], sourcearg[i]);
3114 }
3115
3116 void getargs(int argc, char **argv, uint8_t *foreground, uint8_t *pretend, uint8_t *loglevel, char **configfile, char **pidfile) {
3117     int c;
3118
3119     while ((c = getopt(argc, argv, "c:d:i:fpv")) != -1) {
3120         switch (c) {
3121         case 'c':
3122             *configfile = optarg;
3123             break;
3124         case 'd':
3125             if (strlen(optarg) != 1 || *optarg < '1' || *optarg > '5')
3126                 debugx(1, DBG_ERR, "Debug level must be 1, 2, 3, 4 or 5, not %s", optarg);
3127             *loglevel = *optarg - '0';
3128             break;
3129         case 'f':
3130             *foreground = 1;
3131             break;
3132         case 'i':
3133             *pidfile = optarg;
3134             break;
3135         case 'p':
3136             *pretend = 1;
3137             break;
3138         case 'v':
3139             debug(DBG_ERR, "radsecproxy revision %s", PACKAGE_VERSION);
3140             debug(DBG_ERR, "This binary was built with support for the following transports:");
3141 #ifdef RADPROT_UDP
3142             debug(DBG_ERR, "  UDP");
3143 #endif
3144 #ifdef RADPROT_TCP
3145             debug(DBG_ERR, "  TCP");
3146 #endif
3147 #ifdef RADPROT_TLS
3148             debug(DBG_ERR, "  TLS");
3149 #endif
3150 #ifdef RADPROT_DTLS
3151             debug(DBG_ERR, "  DTLS");
3152 #endif
3153             exit(0);
3154         default:
3155             goto usage;
3156         }
3157     }
3158     if (!(argc - optind))
3159         return;
3160
3161 usage:
3162     debugx(1, DBG_ERR, "Usage:\n%s [ -c configfile ] [ -d debuglevel ] [ -f ] [ -i pidfile ] [ -p ] [ -v ]", argv[0]);
3163 }
3164
3165 #ifdef SYS_SOLARIS9
3166 int daemon(int a, int b) {
3167     int i;
3168
3169     if (fork())
3170         exit(0);
3171
3172     setsid();
3173
3174     for (i = 0; i < 3; i++) {
3175         close(i);
3176         open("/dev/null", O_RDWR);
3177     }
3178     return 1;
3179 }
3180 #endif
3181
3182 void *sighandler(void *arg) {
3183     sigset_t sigset;
3184     int sig;
3185
3186     for(;;) {
3187         sigemptyset(&sigset);
3188         sigaddset(&sigset, SIGHUP);
3189         sigaddset(&sigset, SIGPIPE);
3190         sigwait(&sigset, &sig);
3191         switch (sig) {
3192         case 0:
3193             /* completely ignoring this */
3194             break;
3195         case SIGHUP:
3196             debug(DBG_INFO, "sighandler: got SIGHUP");
3197             debug_reopen_log();
3198             break;
3199         case SIGPIPE:
3200             debug(DBG_WARN, "sighandler: got SIGPIPE, TLS write error?");
3201             break;
3202         default:
3203             debug(DBG_WARN, "sighandler: ignoring signal %d", sig);
3204         }
3205     }
3206 }
3207
3208 int createpidfile(const char *pidfile) {
3209     int r = 0;
3210     FILE *f = fopen(pidfile, "w");
3211     if (f)
3212         r = fprintf(f, "%ld\n", (long) getpid());
3213     return f && !fclose(f) && r >= 0;
3214 }
3215
3216 int radsecproxy_main(int argc, char **argv) {
3217     pthread_t sigth;
3218     sigset_t sigset;
3219     struct list_node *entry;
3220     uint8_t foreground = 0, pretend = 0, loglevel = 0;
3221     char *configfile = NULL, *pidfile = NULL;
3222     struct clsrvconf *srvconf;
3223     int i;
3224
3225     debug_init("radsecproxy");
3226     debug_set_level(DEBUG_LEVEL);
3227
3228     for (i = 0; i < RAD_PROTOCOUNT; i++)
3229         protodefs[i] = protoinits[i](i);
3230
3231     /* needed even if no TLS/DTLS transport */
3232     sslinit();
3233
3234     getargs(argc, argv, &foreground, &pretend, &loglevel, &configfile, &pidfile);
3235     if (loglevel)
3236         debug_set_level(loglevel);
3237     getmainconfig(configfile ? configfile : CONFIG_MAIN);
3238     if (loglevel)
3239         options.loglevel = loglevel;
3240     else if (options.loglevel)
3241         debug_set_level(options.loglevel);
3242     if (!foreground)
3243         debug_set_destination(options.logdestination ? options.logdestination : "x-syslog:///");
3244     free(options.logdestination);
3245
3246     if (!list_first(clconfs))
3247         debugx(1, DBG_ERR, "No clients configured, nothing to do, exiting");
3248     if (!list_first(realms))
3249         debugx(1, DBG_ERR, "No realms configured, nothing to do, exiting");
3250
3251     if (pretend)
3252         debugx(0, DBG_ERR, "All OK so far; exiting since only pretending");
3253
3254     if (!foreground && (daemon(0, 0) < 0))
3255         debugx(1, DBG_ERR, "daemon() failed: %s", strerror(errno));
3256
3257     debug_timestamp_on();
3258     debug(DBG_INFO, "radsecproxy revision %s starting", PACKAGE_VERSION);
3259     if (pidfile && !createpidfile(pidfile))
3260         debugx(1, DBG_ERR, "failed to create pidfile %s: %s", pidfile, strerror(errno));
3261
3262     sigemptyset(&sigset);
3263     /* exit on all but SIGHUP|SIGPIPE, ignore more? */
3264     sigaddset(&sigset, SIGHUP);
3265     sigaddset(&sigset, SIGPIPE);
3266     pthread_sigmask(SIG_BLOCK, &sigset, NULL);
3267     pthread_create(&sigth, NULL, sighandler, NULL);
3268
3269     for (entry = list_first(srvconfs); entry; entry = list_next(entry)) {
3270         srvconf = (struct clsrvconf *)entry->data;
3271         if (srvconf->dynamiclookupcommand)
3272             continue;
3273         if (!addserver(srvconf))
3274             debugx(1, DBG_ERR, "failed to add server");
3275         if (pthread_create(&srvconf->servers->clientth, NULL, clientwr,
3276                            (void *)(srvconf->servers)))
3277             debugx(1, DBG_ERR, "pthread_create failed");
3278     }
3279
3280     for (i = 0; i < RAD_PROTOCOUNT; i++) {
3281         if (!protodefs[i])
3282             continue;
3283         if (protodefs[i]->initextra)
3284             protodefs[i]->initextra();
3285         if (find_clconf_type(i, NULL))
3286             createlisteners(i);
3287     }
3288
3289     /* just hang around doing nothing, anything to do here? */
3290     for (;;)
3291         sleep(1000);
3292 }
3293
3294 /* Local Variables: */
3295 /* c-file-style: "stroustrup" */
3296 /* End: */