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