5dfe24159ce273f6f2b391fa18c78c6898e4da12
[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     struct radmsg *msg;
1279     struct tlv *attr;
1280
1281     msg = radmsg_init(code, rq->msg->id, rq->msg->auth);
1282     if (!msg) {
1283         debug(DBG_ERR, "respond: malloc failed");
1284         return;
1285     }
1286     if (message && *message) {
1287         attr = maketlv(RAD_Attr_Reply_Message, strlen(message), message);
1288         if (!attr || !radmsg_add(msg, attr)) {
1289             freetlv(attr);
1290             radmsg_free(msg);
1291             debug(DBG_ERR, "respond: malloc failed");
1292             return;
1293         }
1294     }
1295
1296     radmsg_free(rq->msg);
1297     rq->msg = msg;
1298     debug(DBG_DBG, "respond: sending %s to %s (%s)", radmsgtype2string(msg->code), rq->from->conf->name, addr2string(rq->from->addr));
1299     sendreply(newrqref(rq));
1300 }
1301
1302 struct clsrvconf *choosesrvconf(struct list *srvconfs) {
1303     struct list_node *entry;
1304     struct clsrvconf *server, *best = NULL, *first = NULL;
1305
1306     for (entry = list_first(srvconfs); entry; entry = list_next(entry)) {
1307         server = (struct clsrvconf *)entry->data;
1308         if (!server->servers)
1309             return server;
1310         if (server->servers->dynfailing)
1311             continue;
1312         if (!first)
1313             first = server;
1314         if (!server->servers->connectionok && !server->servers->dynstartup)
1315             continue;
1316         if (!server->servers->lostrqs)
1317             return server;
1318         if (!best) {
1319             best = server;
1320             continue;
1321         }
1322         if (server->servers->lostrqs < best->servers->lostrqs)
1323             best = server;
1324     }
1325     return best ? best : first;
1326 }
1327
1328 /* returns with lock on realm, protects from server changes while in use by radsrv/sendrq */
1329 struct server *findserver(struct realm **realm, struct tlv *username, uint8_t acc) {
1330     struct clsrvconf *srvconf;
1331     struct realm *subrealm;
1332     struct server *server = NULL;
1333     char *id = (char *)tlv2str(username);
1334
1335     if (!id)
1336         return NULL;
1337     /* returns with lock on realm */
1338     *realm = id2realm(realms, id);
1339     if (!*realm)
1340         goto exit;
1341     debug(DBG_DBG, "found matching realm: %s", (*realm)->name);
1342     srvconf = choosesrvconf(acc ? (*realm)->accsrvconfs : (*realm)->srvconfs);
1343     if (srvconf && !(*realm)->parent && !srvconf->servers && srvconf->dynamiclookupcommand) {
1344         subrealm = adddynamicrealmserver(*realm, id);
1345         if (subrealm) {
1346             pthread_mutex_lock(&subrealm->mutex);
1347             pthread_mutex_unlock(&(*realm)->mutex);
1348             freerealm(*realm);
1349             *realm = subrealm;
1350             debug(DBG_DBG, "added realm: %s", (*realm)->name);
1351             srvconf = choosesrvconf(acc ? (*realm)->accsrvconfs : (*realm)->srvconfs);
1352             debug(DBG_DBG, "found conf for new realm: %s", srvconf->name);
1353         }
1354     }
1355     if (srvconf) {
1356         debug(DBG_DBG, "found matching conf: %s", srvconf->name);
1357         server = srvconf->servers;
1358     }
1359
1360 exit:
1361     free(id);
1362     return server;
1363 }
1364
1365
1366 struct request *newrequest() {
1367     struct request *rq;
1368
1369     rq = malloc(sizeof(struct request));
1370     if (!rq) {
1371         debug(DBG_ERR, "newrequest: malloc failed");
1372         return NULL;
1373     }
1374     memset(rq, 0, sizeof(struct request));
1375     rq->refcount = 1;
1376     gettimeofday(&rq->created, NULL);
1377     return rq;
1378 }
1379
1380 static void
1381 purgedupcache(struct client *client) {
1382     struct request *r;
1383     struct timeval now;
1384     int i;
1385
1386     gettimeofday(&now, NULL);
1387     for (i = 0; i < MAX_REQUESTS; i++) {
1388         r = client->rqs[i];
1389         if (r && now.tv_sec - r->created.tv_sec > r->from->conf->dupinterval) {
1390             freerq(r);
1391             client->rqs[i] = NULL;
1392         }
1393     }
1394 }
1395
1396 int addclientrq(struct request *rq) {
1397     struct request *r;
1398     struct timeval now;
1399
1400     r = rq->from->rqs[rq->rqid];
1401     if (r) {
1402         if (rq->udpport == r->udpport && !memcmp(rq->rqauth, r->rqauth, 16)) {
1403             gettimeofday(&now, NULL);
1404             if (now.tv_sec - r->created.tv_sec < r->from->conf->dupinterval) {
1405                 if (r->replybuf) {
1406                     debug(DBG_INFO, "addclientrq: already sent reply to request with id %d from %s, resending", rq->rqid, addr2string(r->from->addr));
1407                     sendreply(newrqref(r));
1408                 } else
1409                     debug(DBG_INFO, "addclientrq: already got request with id %d from %s, ignoring", rq->rqid, addr2string(r->from->addr));
1410                 return 0;
1411             }
1412         }
1413         freerq(r);
1414     }
1415     rq->from->rqs[rq->rqid] = newrqref(rq);
1416     return 1;
1417 }
1418
1419 void rmclientrq(struct request *rq, uint8_t id) {
1420     struct request *r;
1421
1422     r = rq->from->rqs[id];
1423     if (r) {
1424         freerq(r);
1425         rq->from->rqs[id] = NULL;
1426     }
1427 }
1428
1429 /* returns 0 if validation/authentication fails, else 1 */
1430 int radsrv(struct request *rq) {
1431     struct radmsg *msg = NULL;
1432     struct tlv *attr;
1433     uint8_t *userascii = NULL;
1434     struct realm *realm = NULL;
1435     struct server *to = NULL;
1436     struct client *from = rq->from;
1437     int ttlres;
1438
1439     msg = buf2radmsg(rq->buf, (uint8_t *)from->conf->secret, NULL);
1440     free(rq->buf);
1441     rq->buf = NULL;
1442
1443     if (!msg) {
1444         debug(DBG_INFO, "radsrv: message validation failed, ignoring packet");
1445         freerq(rq);
1446         return 0;
1447     }
1448
1449     rq->msg = msg;
1450     rq->rqid = msg->id;
1451     memcpy(rq->rqauth, msg->auth, 16);
1452
1453     debug(DBG_DBG, "radsrv: code %d, id %d", msg->code, msg->id);
1454     if (msg->code != RAD_Access_Request && msg->code != RAD_Status_Server && msg->code != RAD_Accounting_Request) {
1455         debug(DBG_INFO, "radsrv: server currently accepts only access-requests, accounting-requests and status-server, ignoring");
1456         goto exit;
1457     }
1458
1459     purgedupcache(from);
1460     if (!addclientrq(rq))
1461         goto exit;
1462
1463     if (msg->code == RAD_Status_Server) {
1464         respond(rq, RAD_Access_Accept, NULL);
1465         goto exit;
1466     }
1467
1468     /* below: code == RAD_Access_Request || code == RAD_Accounting_Request */
1469
1470     if (from->conf->rewritein && !dorewrite(msg, from->conf->rewritein))
1471         goto rmclrqexit;
1472
1473     ttlres = checkttl(msg, options.ttlattrtype);
1474     if (!ttlres) {
1475         debug(DBG_INFO, "radsrv: ignoring request from client %s (%s), ttl exceeded", from->conf->name, addr2string(from->addr));
1476         goto exit;
1477     }
1478
1479     attr = radmsg_gettype(msg, RAD_Attr_User_Name);
1480     if (!attr) {
1481         if (msg->code == RAD_Accounting_Request) {
1482             acclog(msg, from);
1483             respond(rq, RAD_Accounting_Response, NULL);
1484         } else
1485             debug(DBG_INFO, "radsrv: ignoring access request, no username attribute");
1486         goto exit;
1487     }
1488
1489     if (from->conf->rewriteusername && !rewriteusername(rq, attr)) {
1490         debug(DBG_WARN, "radsrv: username malloc failed, ignoring request");
1491         goto rmclrqexit;
1492     }
1493
1494     userascii = radattr2ascii(attr);
1495     if (!userascii)
1496         goto rmclrqexit;
1497     debug(DBG_DBG, "%s with username: %s", radmsgtype2string(msg->code), userascii);
1498
1499     /* will return with lock on the realm */
1500     to = findserver(&realm, attr, msg->code == RAD_Accounting_Request);
1501     if (!realm) {
1502         debug(DBG_INFO, "radsrv: ignoring request, don't know where to send it");
1503         goto exit;
1504     }
1505
1506     if (!to) {
1507         if (realm->message && msg->code == RAD_Access_Request) {
1508             debug(DBG_INFO, "radsrv: sending reject to %s (%s) for %s", from->conf->name, addr2string(from->addr), userascii);
1509             respond(rq, RAD_Access_Reject, realm->message);
1510         } else if (realm->accresp && msg->code == RAD_Accounting_Request) {
1511             acclog(msg, from);
1512             respond(rq, RAD_Accounting_Response, NULL);
1513         }
1514         goto exit;
1515     }
1516
1517     if ((to->conf->loopprevention == 1
1518          || (to->conf->loopprevention == UCHAR_MAX && options.loopprevention == 1))
1519         && !strcmp(from->conf->name, to->conf->name)) {
1520         debug(DBG_INFO, "radsrv: Loop prevented, not forwarding request from client %s (%s) to server %s, discarding",
1521               from->conf->name, addr2string(from->addr), to->conf->name);
1522         goto exit;
1523     }
1524
1525     if (msg->code == RAD_Accounting_Request)
1526         memset(msg->auth, 0, 16);
1527     else if (!RAND_bytes(msg->auth, 16)) {
1528         debug(DBG_WARN, "radsrv: failed to generate random auth");
1529         goto rmclrqexit;
1530     }
1531
1532 #ifdef DEBUG
1533     printfchars(NULL, "auth", "%02x ", auth, 16);
1534 #endif
1535
1536     attr = radmsg_gettype(msg, RAD_Attr_User_Password);
1537     if (attr) {
1538         debug(DBG_DBG, "radsrv: found userpwdattr with value length %d", attr->l);
1539         if (!pwdrecrypt(attr->v, attr->l, from->conf->secret, to->conf->secret, rq->rqauth, msg->auth))
1540             goto rmclrqexit;
1541     }
1542
1543     attr = radmsg_gettype(msg, RAD_Attr_Tunnel_Password);
1544     if (attr) {
1545         debug(DBG_DBG, "radsrv: found tunnelpwdattr with value length %d", attr->l);
1546         if (!pwdrecrypt(attr->v, attr->l, from->conf->secret, to->conf->secret, rq->rqauth, msg->auth))
1547             goto rmclrqexit;
1548     }
1549
1550     if (to->conf->rewriteout && !dorewrite(msg, to->conf->rewriteout))
1551         goto rmclrqexit;
1552
1553     if (ttlres == -1 && (options.addttl || to->conf->addttl))
1554         addttlattr(msg, options.ttlattrtype, to->conf->addttl ? to->conf->addttl : options.addttl);
1555
1556     free(userascii);
1557     rq->to = to;
1558     sendrq(rq);
1559     pthread_mutex_unlock(&realm->mutex);
1560     freerealm(realm);
1561     return 1;
1562
1563 rmclrqexit:
1564     rmclientrq(rq, msg->id);
1565 exit:
1566     freerq(rq);
1567     free(userascii);
1568     if (realm) {
1569         pthread_mutex_unlock(&realm->mutex);
1570         freerealm(realm);
1571     }
1572     return 1;
1573 }
1574
1575 void replyh(struct server *server, unsigned char *buf) {
1576     struct client *from;
1577     struct rqout *rqout;
1578     int sublen, ttlres;
1579     unsigned char *subattrs;
1580     uint8_t *username, *stationid, *replymsg;
1581     struct radmsg *msg = NULL;
1582     struct tlv *attr;
1583     struct list_node *node;
1584
1585     server->connectionok = 1;
1586     server->lostrqs = 0;
1587
1588     rqout = server->requests + buf[1];
1589     pthread_mutex_lock(rqout->lock);
1590     if (!rqout->tries) {
1591         free(buf);
1592         buf = NULL;
1593         debug(DBG_INFO, "replyh: no outstanding request with this id, ignoring reply");
1594         goto errunlock;
1595     }
1596
1597     msg = buf2radmsg(buf, (uint8_t *)server->conf->secret, rqout->rq->msg->auth);
1598     free(buf);
1599     buf = NULL;
1600     if (!msg) {
1601         debug(DBG_INFO, "replyh: message validation failed, ignoring packet");
1602         goto errunlock;
1603     }
1604     if (msg->code != RAD_Access_Accept && msg->code != RAD_Access_Reject && msg->code != RAD_Access_Challenge
1605         && msg->code != RAD_Accounting_Response) {
1606         debug(DBG_INFO, "replyh: discarding message type %s, accepting only access accept, access reject, access challenge and accounting response messages", radmsgtype2string(msg->code));
1607         goto errunlock;
1608     }
1609     debug(DBG_DBG, "got %s message with id %d", radmsgtype2string(msg->code), msg->id);
1610
1611     gettimeofday(&server->lastrcv, NULL);
1612
1613     if (rqout->rq->msg->code == RAD_Status_Server) {
1614         freerqoutdata(rqout);
1615         debug(DBG_DBG, "replyh: got status server response from %s", server->conf->name);
1616         goto errunlock;
1617     }
1618
1619     gettimeofday(&server->lastreply, NULL);
1620     from = rqout->rq->from;
1621
1622     if (server->conf->rewritein && !dorewrite(msg, from->conf->rewritein)) {
1623         debug(DBG_INFO, "replyh: rewritein failed");
1624         goto errunlock;
1625     }
1626
1627     ttlres = checkttl(msg, options.ttlattrtype);
1628     if (!ttlres) {
1629         debug(DBG_INFO, "replyh: ignoring reply from server %s, ttl exceeded", server->conf->name);
1630         goto errunlock;
1631     }
1632
1633     /* MS MPPE */
1634     for (node = list_first(msg->attrs); node; node = list_next(node)) {
1635         attr = (struct tlv *)node->data;
1636         if (attr->t != RAD_Attr_Vendor_Specific)
1637             continue;
1638         if (attr->l <= 4)
1639             break;
1640         if (attr->v[0] != 0 || attr->v[1] != 0 || attr->v[2] != 1 || attr->v[3] != 55)  /* 311 == MS */
1641             continue;
1642
1643         sublen = attr->l - 4;
1644         subattrs = attr->v + 4;
1645         if (!attrvalidate(subattrs, sublen) ||
1646             !msmppe(subattrs, sublen, RAD_VS_ATTR_MS_MPPE_Send_Key, "MS MPPE Send Key",
1647                     rqout->rq, server->conf->secret, from->conf->secret) ||
1648             !msmppe(subattrs, sublen, RAD_VS_ATTR_MS_MPPE_Recv_Key, "MS MPPE Recv Key",
1649                     rqout->rq, server->conf->secret, from->conf->secret))
1650             break;
1651     }
1652     if (node) {
1653         debug(DBG_WARN, "replyh: MS attribute handling failed, ignoring reply");
1654         goto errunlock;
1655     }
1656
1657     if (msg->code == RAD_Access_Accept || msg->code == RAD_Access_Reject || msg->code == RAD_Accounting_Response) {
1658         username = radattr2ascii(radmsg_gettype(rqout->rq->msg, RAD_Attr_User_Name));
1659         if (username) {
1660             stationid = radattr2ascii(radmsg_gettype(rqout->rq->msg, RAD_Attr_Calling_Station_Id));
1661             replymsg = radattr2ascii(radmsg_gettype(msg, RAD_Attr_Reply_Message));
1662             if (stationid) {
1663                 if (replymsg) {
1664                     debug(DBG_NOTICE,
1665                           "%s for user %s stationid %s from %s (%s) to %s (%s)",
1666                           radmsgtype2string(msg->code), username, stationid,
1667                           server->conf->name, replymsg, from->conf->name,
1668                           addr2string(from->addr));
1669                     free(replymsg);
1670                 } else
1671                     debug(DBG_NOTICE,
1672                           "%s for user %s stationid %s from %s to %s (%s)",
1673                           radmsgtype2string(msg->code), username, stationid,
1674                           server->conf->name, from->conf->name,
1675                           addr2string(from->addr));
1676                 free(stationid);
1677             } else {
1678                 if (replymsg) {
1679                     debug(DBG_NOTICE, "%s for user %s from %s (%s) to %s (%s)",
1680                           radmsgtype2string(msg->code), username,
1681                           server->conf->name, replymsg, from->conf->name,
1682                           addr2string(from->addr));
1683                     free(replymsg);
1684                 } else
1685                     debug(DBG_NOTICE, "%s for user %s from %s to %s (%s)",
1686                           radmsgtype2string(msg->code), username,
1687                           server->conf->name, from->conf->name,
1688                           addr2string(from->addr));
1689             }
1690             free(username);
1691         }
1692     }
1693
1694 #if defined(WANT_FTICKS)
1695     if (msg->code == RAD_Access_Accept || msg->code == RAD_Access_Reject)
1696         if (options.fticks_reporting && from->conf->fticks_viscountry != NULL)
1697             fticks_log(&options, from, msg, rqout);
1698 #endif
1699
1700     msg->id = (char)rqout->rq->rqid;
1701     memcpy(msg->auth, rqout->rq->rqauth, 16);
1702
1703 #ifdef DEBUG
1704     printfchars(NULL, "origauth/buf+4", "%02x ", buf + 4, 16);
1705 #endif
1706
1707     if (rqout->rq->origusername && (attr = radmsg_gettype(msg, RAD_Attr_User_Name))) {
1708         if (!resizeattr(attr, strlen(rqout->rq->origusername))) {
1709             debug(DBG_WARN, "replyh: malloc failed, ignoring reply");
1710             goto errunlock;
1711         }
1712         memcpy(attr->v, rqout->rq->origusername, strlen(rqout->rq->origusername));
1713     }
1714
1715     if (from->conf->rewriteout && !dorewrite(msg, from->conf->rewriteout)) {
1716         debug(DBG_WARN, "replyh: rewriteout failed");
1717         goto errunlock;
1718     }
1719
1720     if (ttlres == -1 && (options.addttl || from->conf->addttl))
1721         addttlattr(msg, options.ttlattrtype, from->conf->addttl ? from->conf->addttl : options.addttl);
1722
1723     debug(msg->code == RAD_Access_Accept || msg->code == RAD_Access_Reject || msg->code == RAD_Accounting_Response ? DBG_WARN : DBG_INFO,
1724           "replyh: passing %s to client %s (%s)", radmsgtype2string(msg->code), from->conf->name, addr2string(from->addr));
1725
1726     radmsg_free(rqout->rq->msg);
1727     rqout->rq->msg = msg;
1728     sendreply(newrqref(rqout->rq));
1729     freerqoutdata(rqout);
1730     pthread_mutex_unlock(rqout->lock);
1731     return;
1732
1733 errunlock:
1734     radmsg_free(msg);
1735     pthread_mutex_unlock(rqout->lock);
1736     return;
1737 }
1738
1739 struct request *createstatsrvrq() {
1740     struct request *rq;
1741     struct tlv *attr;
1742
1743     rq = newrequest();
1744     if (!rq)
1745         return NULL;
1746     rq->msg = radmsg_init(RAD_Status_Server, 0, NULL);
1747     if (!rq->msg)
1748         goto exit;
1749     attr = maketlv(RAD_Attr_Message_Authenticator, 16, NULL);
1750     if (!attr)
1751         goto exit;
1752     if (!radmsg_add(rq->msg, attr)) {
1753         freetlv(attr);
1754         goto exit;
1755     }
1756     return rq;
1757
1758 exit:
1759     freerq(rq);
1760     return NULL;
1761 }
1762
1763 /* code for removing state not finished */
1764 void *clientwr(void *arg) {
1765     struct server *server = (struct server *)arg;
1766     struct rqout *rqout = NULL;
1767     pthread_t clientrdth;
1768     int i, dynconffail = 0;
1769     time_t secs;
1770     uint8_t rnd;
1771     struct timeval now, laststatsrv;
1772     struct timespec timeout;
1773     struct request *statsrvrq;
1774     struct clsrvconf *conf;
1775
1776     conf = server->conf;
1777
1778 #define ZZZ 900
1779
1780     if (server->dynamiclookuparg && !dynamicconfig(server)) {
1781         dynconffail = 1;
1782         server->dynstartup = 0;
1783         server->dynfailing = 1;
1784 #if defined ENABLE_EXPERIMENTAL_DYNDISC
1785         pthread_mutex_unlock(&server->lock);
1786 #endif
1787         debug(DBG_WARN, "%s: dynamicconfig(%s: %s) failed, sleeping %ds",
1788               __func__, server->conf->name, server->dynamiclookuparg, ZZZ);
1789         sleep(ZZZ);
1790         goto errexit;
1791     }
1792 #if defined ENABLE_EXPERIMENTAL_DYNDISC
1793     pthread_mutex_unlock(&server->lock);
1794 #endif
1795     /* FIXME: Is resolving not always done by compileserverconfig(),
1796      * either as part of static configuration setup or by
1797      * dynamicconfig() above?  */
1798     if (!resolvehostports(conf->hostports, conf->hostaf, conf->pdef->socktype)) {
1799         debug(DBG_WARN, "%s: resolve failed, sleeping %ds", __func__, ZZZ);
1800         sleep(ZZZ);
1801         goto errexit;
1802     }
1803
1804     memset(&timeout, 0, sizeof(struct timespec));
1805
1806     if (conf->statusserver) {
1807         gettimeofday(&server->lastrcv, NULL);
1808         gettimeofday(&laststatsrv, NULL);
1809     }
1810
1811     if (conf->pdef->connecter) {
1812         if (!conf->pdef->connecter(server, NULL, server->dynamiclookuparg ? 5 : 0, "clientwr")) {
1813             if (server->dynamiclookuparg) {
1814                 server->dynstartup = 0;
1815                 server->dynfailing = 1;
1816                 debug(DBG_WARN, "%s: connect failed, sleeping %ds",
1817                       __func__, ZZZ);
1818                 sleep(ZZZ);
1819             }
1820             goto errexit;
1821         }
1822         server->connectionok = 1;
1823 #if defined ENABLE_EXPERIMENTAL_DYNDISC
1824         server->in_use = 1;
1825 #endif
1826         if (pthread_create(&clientrdth, &pthread_attr, conf->pdef->clientconnreader, (void *)server)) {
1827             debugerrno(errno, DBG_ERR, "clientwr: pthread_create failed");
1828             goto errexit;
1829         }
1830     } else
1831         server->connectionok = 1;
1832     server->dynstartup = 0;
1833
1834     for (;;) {
1835         pthread_mutex_lock(&server->newrq_mutex);
1836         if (!server->newrq) {
1837             gettimeofday(&now, NULL);
1838             /* random 0-7 seconds */
1839             RAND_bytes(&rnd, 1);
1840             rnd /= 32;
1841             if (conf->statusserver) {
1842                 secs = server->lastrcv.tv_sec > laststatsrv.tv_sec ? server->lastrcv.tv_sec : laststatsrv.tv_sec;
1843                 if (now.tv_sec - secs > STATUS_SERVER_PERIOD)
1844                     secs = now.tv_sec;
1845                 if (!timeout.tv_sec || timeout.tv_sec > secs + STATUS_SERVER_PERIOD + rnd)
1846                     timeout.tv_sec = secs + STATUS_SERVER_PERIOD + rnd;
1847             } else {
1848                 if (!timeout.tv_sec || timeout.tv_sec > now.tv_sec + STATUS_SERVER_PERIOD + rnd)
1849                     timeout.tv_sec = now.tv_sec + STATUS_SERVER_PERIOD + rnd;
1850             }
1851 #if 0
1852             if (timeout.tv_sec > now.tv_sec)
1853                 debug(DBG_DBG, "clientwr: waiting up to %ld secs for new request", timeout.tv_sec - now.tv_sec);
1854 #endif
1855             pthread_cond_timedwait(&server->newrq_cond, &server->newrq_mutex, &timeout);
1856             timeout.tv_sec = 0;
1857         }
1858         if (server->newrq) {
1859             debug(DBG_DBG, "clientwr: got new request");
1860             server->newrq = 0;
1861         }
1862 #if 0
1863         else
1864             debug(DBG_DBG, "clientwr: request timer expired, processing request queue");
1865 #endif
1866         pthread_mutex_unlock(&server->newrq_mutex);
1867
1868         for (i = 0; i < MAX_REQUESTS; i++) {
1869             if (server->clientrdgone) {
1870                 pthread_join(clientrdth, NULL);
1871                 goto errexit;
1872             }
1873
1874             for (; i < MAX_REQUESTS; i++) {
1875                 rqout = server->requests + i;
1876                 if (rqout->rq) {
1877                     pthread_mutex_lock(rqout->lock);
1878                     if (rqout->rq)
1879                         break;
1880                     pthread_mutex_unlock(rqout->lock);
1881                 }
1882             }
1883
1884             if (i == MAX_REQUESTS)
1885                 break;
1886
1887             gettimeofday(&now, NULL);
1888             if (now.tv_sec < rqout->expiry.tv_sec) {
1889                 if (!timeout.tv_sec || rqout->expiry.tv_sec < timeout.tv_sec)
1890                     timeout.tv_sec = rqout->expiry.tv_sec;
1891                 pthread_mutex_unlock(rqout->lock);
1892                 continue;
1893             }
1894
1895             if (rqout->tries == (*rqout->rq->buf == RAD_Status_Server ? 1 : conf->retrycount + 1)) {
1896                 debug(DBG_DBG, "clientwr: removing expired packet from queue");
1897                 if (conf->statusserver) {
1898                     if (*rqout->rq->buf == RAD_Status_Server) {
1899                         debug(DBG_WARN, "clientwr: no status server response, %s dead?", conf->name);
1900                         if (server->lostrqs < 255)
1901                             server->lostrqs++;
1902                     }
1903                 } else {
1904                     debug(DBG_WARN, "clientwr: no server response, %s dead?", conf->name);
1905                     if (server->lostrqs < 255)
1906                         server->lostrqs++;
1907                 }
1908                 freerqoutdata(rqout);
1909                 pthread_mutex_unlock(rqout->lock);
1910                 continue;
1911             }
1912
1913             rqout->expiry.tv_sec = now.tv_sec + conf->retryinterval;
1914             if (!timeout.tv_sec || rqout->expiry.tv_sec < timeout.tv_sec)
1915                 timeout.tv_sec = rqout->expiry.tv_sec;
1916             rqout->tries++;
1917             conf->pdef->clientradput(server, rqout->rq->buf);
1918             pthread_mutex_unlock(rqout->lock);
1919         }
1920         if (conf->statusserver && server->connectionok) {
1921             secs = server->lastrcv.tv_sec > laststatsrv.tv_sec ? server->lastrcv.tv_sec : laststatsrv.tv_sec;
1922             gettimeofday(&now, NULL);
1923             if (now.tv_sec - secs > STATUS_SERVER_PERIOD) {
1924                 laststatsrv = now;
1925                 statsrvrq = createstatsrvrq();
1926                 if (statsrvrq) {
1927                     statsrvrq->to = server;
1928                     debug(DBG_DBG, "clientwr: sending status server to %s", conf->name);
1929                     sendrq(statsrvrq);
1930                 }
1931             }
1932         }
1933     }
1934 errexit:
1935 #if defined ENABLE_EXPERIMENTAL_DYNDISC
1936     server->in_use = 0;
1937 #endif
1938     conf->servers = NULL;
1939     if (server->dynamiclookuparg) {
1940         removeserversubrealms(realms, conf);
1941         if (dynconffail)
1942             free(conf);
1943         else
1944             freeclsrvconf(conf);
1945     }
1946     freeserver(server, 1);
1947     ERR_remove_state(0);
1948     return NULL;
1949 }
1950
1951 void createlistener(uint8_t type, char *arg) {
1952     pthread_t th;
1953     struct addrinfo *res;
1954     int s = -1, on = 1, *sp = NULL;
1955     struct hostportres *hp = newhostport(arg, protodefs[type]->portdefault, 0);
1956
1957     if (!hp || !resolvehostport(hp, AF_UNSPEC, protodefs[type]->socktype, 1))
1958         debugx(1, DBG_ERR, "createlistener: failed to resolve %s", arg);
1959
1960     for (res = hp->addrinfo; res; res = res->ai_next) {
1961         s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
1962         if (s < 0) {
1963             debugerrno(errno, DBG_WARN, "createlistener: socket failed");
1964             continue;
1965         }
1966         setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
1967
1968         disable_DF_bit(s, res);
1969
1970 #ifdef IPV6_V6ONLY
1971         if (res->ai_family == AF_INET6)
1972             setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
1973 #endif
1974         if (bind(s, res->ai_addr, res->ai_addrlen)) {
1975             debugerrno(errno, DBG_WARN, "createlistener: bind failed");
1976             close(s);
1977             s = -1;
1978             continue;
1979         }
1980
1981         sp = malloc(sizeof(int));
1982         if (!sp)
1983             debugx(1, DBG_ERR, "malloc failed");
1984         *sp = s;
1985         if (pthread_create(&th, &pthread_attr, protodefs[type]->listener, (void *)sp))
1986             debugerrnox(errno, DBG_ERR, "pthread_create failed");
1987         pthread_detach(th);
1988     }
1989     if (!sp)
1990         debugx(1, DBG_ERR, "createlistener: socket/bind failed");
1991
1992     debug(DBG_WARN, "createlistener: listening for %s on %s:%s", protodefs[type]->name, hp->host ? hp->host : "*", hp->port);
1993     freehostport(hp);
1994 }
1995
1996 void createlisteners(uint8_t type) {
1997     int i;
1998     char **args;
1999
2000     args = protodefs[type]->getlistenerargs();
2001     if (args)
2002         for (i = 0; args[i]; i++)
2003             createlistener(type, args[i]);
2004     else
2005         createlistener(type, NULL);
2006 }
2007
2008 void sslinit() {
2009     int i;
2010     time_t t;
2011     pid_t pid;
2012
2013     ssl_locks = calloc(CRYPTO_num_locks(), sizeof(pthread_mutex_t));
2014     ssl_lock_count = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long));
2015     for (i = 0; i < CRYPTO_num_locks(); i++) {
2016         ssl_lock_count[i] = 0;
2017         pthread_mutex_init(&ssl_locks[i], NULL);
2018     }
2019     CRYPTO_set_id_callback(ssl_thread_id);
2020     CRYPTO_set_locking_callback(ssl_locking_callback);
2021
2022     SSL_load_error_strings();
2023     SSL_library_init();
2024
2025     while (!RAND_status()) {
2026         t = time(NULL);
2027         pid = getpid();
2028         RAND_seed((unsigned char *)&t, sizeof(time_t));
2029         RAND_seed((unsigned char *)&pid, sizeof(pid));
2030     }
2031 }
2032
2033 struct list *addsrvconfs(char *value, char **names) {
2034     struct list *conflist;
2035     int n;
2036     struct list_node *entry;
2037     struct clsrvconf *conf = NULL;
2038
2039     if (!names || !*names)
2040         return NULL;
2041
2042     conflist = list_create();
2043     if (!conflist) {
2044         debug(DBG_ERR, "malloc failed");
2045         return NULL;
2046     }
2047
2048     for (n = 0; names[n]; n++) {
2049         for (entry = list_first(srvconfs); entry; entry = list_next(entry)) {
2050             conf = (struct clsrvconf *)entry->data;
2051             if (!strcasecmp(names[n], conf->name))
2052                 break;
2053         }
2054         if (!entry) {
2055             debug(DBG_ERR, "addsrvconfs failed for realm %s, no server named %s", value, names[n]);
2056             list_destroy(conflist);
2057             return NULL;
2058         }
2059         if (!list_push(conflist, conf)) {
2060             debug(DBG_ERR, "malloc failed");
2061             list_destroy(conflist);
2062             return NULL;
2063         }
2064         debug(DBG_DBG, "addsrvconfs: added server %s for realm %s", conf->name, value);
2065     }
2066     return conflist;
2067 }
2068
2069 void freerealm(struct realm *realm) {
2070     if (!realm)
2071         return;
2072     debug(DBG_DBG, "freerealm: called with refcount %d", realm->refcount);
2073     if (--realm->refcount)
2074         return;
2075
2076     free(realm->name);
2077     free(realm->message);
2078     regfree(&realm->regex);
2079     pthread_mutex_destroy(&realm->mutex);
2080     /* if refcount == 0, all subrealms gone */
2081     list_destroy(realm->subrealms);
2082     /* if refcount == 0, all srvconfs gone */
2083     list_destroy(realm->srvconfs);
2084     /* if refcount == 0, all accsrvconfs gone */
2085     list_destroy(realm->accsrvconfs);
2086     freerealm(realm->parent);
2087     free(realm);
2088 }
2089
2090 struct realm *addrealm(struct list *realmlist, char *value, char **servers, char **accservers, char *message, uint8_t accresp) {
2091     int n;
2092     struct realm *realm;
2093     char *s, *regex = NULL;
2094
2095     if (*value == '/') {
2096         /* regexp, remove optional trailing / if present */
2097         if (value[strlen(value) - 1] == '/')
2098             value[strlen(value) - 1] = '\0';
2099     } else {
2100         /* not a regexp, let us make it one */
2101         if (*value == '*' && !value[1])
2102             regex = stringcopy(".*", 0);
2103         else {
2104             for (n = 0, s = value; *s;)
2105                 if (*s++ == '.')
2106                     n++;
2107             regex = malloc(strlen(value) + n + 3);
2108             if (regex) {
2109                 regex[0] = '@';
2110                 for (n = 1, s = value; *s; s++) {
2111                     if (*s == '.')
2112                         regex[n++] = '\\';
2113                     regex[n++] = *s;
2114                 }
2115                 regex[n++] = '$';
2116                 regex[n] = '\0';
2117             }
2118         }
2119         if (!regex) {
2120             debug(DBG_ERR, "malloc failed");
2121             realm = NULL;
2122             goto exit;
2123         }
2124         debug(DBG_DBG, "addrealm: constructed regexp %s from %s", regex, value);
2125     }
2126
2127     realm = malloc(sizeof(struct realm));
2128     if (!realm) {
2129         debug(DBG_ERR, "malloc failed");
2130         goto exit;
2131     }
2132     memset(realm, 0, sizeof(struct realm));
2133
2134     if (pthread_mutex_init(&realm->mutex, NULL)) {
2135         debugerrno(errno, DBG_ERR, "mutex init failed");
2136         free(realm);
2137         realm = NULL;
2138         goto exit;
2139     }
2140
2141     realm->name = stringcopy(value, 0);
2142     if (!realm->name) {
2143         debug(DBG_ERR, "malloc failed");
2144         goto errexit;
2145     }
2146     if (message && strlen(message) > 253) {
2147         debug(DBG_ERR, "ReplyMessage can be at most 253 bytes");
2148         goto errexit;
2149     }
2150     realm->message = message;
2151     realm->accresp = accresp;
2152
2153     if (regcomp(&realm->regex, regex ? regex : value + 1, REG_EXTENDED | REG_ICASE | REG_NOSUB)) {
2154         debug(DBG_ERR, "addrealm: failed to compile regular expression %s", regex ? regex : value + 1);
2155         goto errexit;
2156     }
2157
2158     if (servers && *servers) {
2159         realm->srvconfs = addsrvconfs(value, servers);
2160         if (!realm->srvconfs)
2161             goto errexit;
2162     }
2163
2164     if (accservers && *accservers) {
2165         realm->accsrvconfs = addsrvconfs(value, accservers);
2166         if (!realm->accsrvconfs)
2167             goto errexit;
2168     }
2169
2170     if (!list_push(realmlist, realm)) {
2171         debug(DBG_ERR, "malloc failed");
2172         pthread_mutex_destroy(&realm->mutex);
2173         goto errexit;
2174     }
2175
2176     debug(DBG_DBG, "addrealm: added realm %s", value);
2177     goto exit;
2178
2179 errexit:
2180     while (list_shift(realm->srvconfs));
2181     while (list_shift(realm->accsrvconfs));
2182     freerealm(realm);
2183     realm = NULL;
2184 exit:
2185     free(regex);
2186     if (servers) {
2187         if (realm)
2188             for (n = 0; servers[n]; n++)
2189                 newrealmref(realm);
2190         freegconfmstr(servers);
2191     }
2192     if (accservers) {
2193         if (realm)
2194             for (n = 0; accservers[n]; n++)
2195                 newrealmref(realm);
2196         freegconfmstr(accservers);
2197     }
2198     return newrealmref(realm);
2199 }
2200
2201 struct list *createsubrealmservers(struct realm *realm, struct list *srvconfs) {
2202     struct list_node *entry;
2203     struct clsrvconf *conf, *srvconf;
2204     struct list *subrealmservers = NULL;
2205     pthread_t clientth;
2206
2207     if (list_first(srvconfs)) {
2208         subrealmservers = list_create();
2209         if (!subrealmservers)
2210             return NULL;
2211     }
2212
2213     for (entry = list_first(srvconfs); entry; entry = list_next(entry)) {
2214         conf = (struct clsrvconf *)entry->data;
2215         if (!conf->servers && conf->dynamiclookupcommand) {
2216             srvconf = malloc(sizeof(struct clsrvconf));
2217             if (!srvconf) {
2218                 debug(DBG_ERR, "malloc failed");
2219                 continue;
2220             }
2221             debug(DBG_DBG, "%s: copying config %s", __func__, conf->name);
2222             *srvconf = *conf;
2223             /* Shallow copy -- sharing all the pointers.  addserver()
2224              * will take care of servers (which btw has to be NUL) but
2225              * the rest of them are shared with the config found in
2226              * the srvconfs list.  */
2227             if (addserver(srvconf)) {
2228                 srvconf->servers->dynamiclookuparg = stringcopy(realm->name, 0);
2229                 srvconf->servers->dynstartup = 1;
2230                 debug(DBG_DBG, "%s: new client writer for %s",
2231                       __func__, srvconf->servers->conf->name);
2232 #if defined ENABLE_EXPERIMENTAL_DYNDISC
2233                 pthread_mutex_lock(&srvconf->servers->lock);
2234 #endif
2235                 if (pthread_create(&clientth, &pthread_attr, clientwr, (void *)(srvconf->servers))) {
2236 #if defined ENABLE_EXPERIMENTAL_DYNDISC
2237                     pthread_mutex_unlock(&srvconf->servers->lock);
2238 #endif
2239                     debugerrno(errno, DBG_ERR, "pthread_create failed");
2240                     freeserver(srvconf->servers, 1);
2241                     srvconf->servers = NULL;
2242 #if defined ENABLE_EXPERIMENTAL_DYNDISC
2243                     conf = srvconf;
2244                     continue;
2245 #endif
2246                 } else
2247                     pthread_detach(clientth);
2248
2249 #if defined ENABLE_EXPERIMENTAL_DYNDISC
2250                 /* If clientwr() could not find a NAPTR we have to
2251                  * wait for dynfailing=1 what is set in clientwr().  */
2252                 pthread_mutex_lock(&srvconf->servers->lock);
2253                 pthread_mutex_unlock(&srvconf->servers->lock);
2254 #endif
2255             }
2256             conf = srvconf;
2257         }
2258         if (conf->servers) {
2259             if (list_push(subrealmservers, conf))
2260                 newrealmref(realm);
2261             else
2262                 debug(DBG_ERR, "malloc failed");
2263         }
2264     }
2265     return subrealmservers;
2266 }
2267
2268 struct realm *adddynamicrealmserver(struct realm *realm, char *id) {
2269     struct realm *newrealm = NULL;
2270     char *realmname, *s;
2271
2272     /* create dynamic for the realm (string after last @, exit if nothing after @ */
2273     realmname = strrchr(id, '@');
2274     if (!realmname)
2275         return NULL;
2276     realmname++;
2277     if (!*realmname)
2278         return NULL;
2279     for (s = realmname; *s; s++)
2280         if (*s != '.' && *s != '-' && !isalnum((int)*s))
2281             return NULL;
2282
2283     if (!realm->subrealms)
2284         realm->subrealms = list_create();
2285     if (!realm->subrealms)
2286         return NULL;
2287
2288     newrealm = addrealm(realm->subrealms, realmname, NULL, NULL, stringcopy(realm->message, 0), realm->accresp);
2289     if (!newrealm) {
2290         list_destroy(realm->subrealms);
2291         realm->subrealms = NULL;
2292         return NULL;
2293     }
2294
2295     newrealm->parent = newrealmref(realm);
2296     /* add server and accserver to newrealm */
2297     newrealm->srvconfs = createsubrealmservers(newrealm, realm->srvconfs);
2298     newrealm->accsrvconfs = createsubrealmservers(newrealm, realm->accsrvconfs);
2299     return newrealm;
2300 }
2301
2302 int dynamicconfig(struct server *server) {
2303     int ok, fd[2], status;
2304     pid_t pid;
2305     struct clsrvconf *conf = server->conf;
2306     struct gconffile *cf = NULL;
2307
2308     /* for now we only learn hostname/address */
2309     debug(DBG_DBG, "dynamicconfig: need dynamic server config for %s", server->dynamiclookuparg);
2310
2311     if (pipe(fd) > 0) {
2312         debugerrno(errno, DBG_ERR, "dynamicconfig: pipe error");
2313         goto errexit;
2314     }
2315     pid = fork();
2316     if (pid < 0) {
2317         debugerrno(errno, DBG_ERR, "dynamicconfig: fork error");
2318         close(fd[0]);
2319         close(fd[1]);
2320         goto errexit;
2321     } else if (pid == 0) {
2322         /* child */
2323         close(fd[0]);
2324         if (fd[1] != STDOUT_FILENO) {
2325             if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO)
2326                 debugx(1, DBG_ERR, "dynamicconfig: dup2 error for command %s", conf->dynamiclookupcommand);
2327             close(fd[1]);
2328         }
2329         if (execlp(conf->dynamiclookupcommand, conf->dynamiclookupcommand, server->dynamiclookuparg, NULL) < 0)
2330             debugx(1, DBG_ERR, "dynamicconfig: exec error for command %s", conf->dynamiclookupcommand);
2331     }
2332
2333     close(fd[1]);
2334     pushgconffile(&cf, fdopen(fd[0], "r"), conf->dynamiclookupcommand);
2335     ok = getgenericconfig(&cf, NULL, "Server", CONF_CBK, confserver_cb,
2336                           (void *) conf, NULL);
2337     freegconf(&cf);
2338
2339     if (waitpid(pid, &status, 0) < 0) {
2340         debugerrno(errno, DBG_ERR, "dynamicconfig: wait error");
2341         goto errexit;
2342     }
2343
2344     if (status) {
2345         debug(DBG_INFO, "dynamicconfig: command exited with status %d",
2346               WEXITSTATUS(status));
2347         goto errexit;
2348     }
2349
2350     if (ok)
2351         return 1;
2352
2353 errexit:
2354     debug(DBG_WARN, "dynamicconfig: failed to obtain dynamic server config");
2355     return 0;
2356 }
2357
2358 /* should accept both names and numeric values, only numeric right now */
2359 uint8_t attrname2val(char *attrname) {
2360     int val = 0;
2361
2362     val = atoi(attrname);
2363     return val > 0 && val < 256 ? val : 0;
2364 }
2365
2366 /* ATTRNAME is on the form vendor[:type].
2367    If only vendor is found, TYPE is set to 256 and 1 is returned.
2368    If type is >= 256, 1 is returned.
2369    Otherwise, 0 is returned.
2370 */
2371 /* should accept both names and numeric values, only numeric right now */
2372 int vattrname2val(char *attrname, uint32_t *vendor, uint32_t *type) {
2373     char *s;
2374
2375     *vendor = atoi(attrname);
2376     s = strchr(attrname, ':');
2377     if (!s) {                   /* Only vendor was found.  */
2378         *type = 256;
2379         return 1;
2380     }
2381     *type = atoi(s + 1);
2382     return *type < 256;
2383 }
2384
2385 /** Extract attributes from string NAMEVAL, create a struct tlv and
2386  * return the tlv.  If VENDOR_FLAG, NAMEVAL is on the form
2387  * "<vendor>:<name>:<val>" and otherwise it's "<name>:<val>".  Return
2388  * NULL if fields are missing or if conversion fails.
2389  *
2390  * FIXME: Should accept both names and numeric values, only numeric
2391  * right now */
2392 struct tlv *extractattr(char *nameval, char vendor_flag) {
2393     int len, name = 0;
2394     int vendor = 0;         /* Vendor 0 is reserved, see RFC 1700.  */
2395     char *s, *s2;
2396     struct tlv *a;
2397
2398     s = strchr(nameval, ':');
2399     if (!s)
2400         return NULL;
2401     name = atoi(nameval);
2402
2403     if (vendor_flag) {
2404         s2 = strchr(s + 1, ':');
2405         if (!s2)
2406             return NULL;
2407         vendor = name;
2408         name = atoi(s + 1);
2409         s = s2;
2410     }
2411     len = strlen(s + 1);
2412     if (len > 253)
2413         return NULL;
2414
2415     if (name < 1 || name > 255)
2416         return NULL;
2417     a = malloc(sizeof(struct tlv));
2418     if (!a)
2419         return NULL;
2420
2421     a->v = (uint8_t *)stringcopy(s + 1, 0);
2422     if (!a->v) {
2423         free(a);
2424         return NULL;
2425     }
2426     a->t = name;
2427     a->l = len;
2428
2429     if (vendor_flag)
2430         a = makevendortlv(vendor, a);
2431
2432     return a;
2433 }
2434
2435 /* should accept both names and numeric values, only numeric right now */
2436 struct modattr *extractmodattr(char *nameval) {
2437     int name = 0;
2438     char *s, *t;
2439     struct modattr *m;
2440
2441     if (!strncasecmp(nameval, "User-Name:/", 11)) {
2442         s = nameval + 11;
2443         name = 1;
2444     } else {
2445         s = strchr(nameval, ':');
2446         name = atoi(nameval);
2447         if (!s || name < 1 || name > 255 || s[1] != '/')
2448             return NULL;
2449         s += 2;
2450     }
2451     /* regexp, remove optional trailing / if present */
2452     if (s[strlen(s) - 1] == '/')
2453         s[strlen(s) - 1] = '\0';
2454
2455     for (t = strchr(s, '/'); t; t = strchr(t+1, '/'))
2456         if (t == s || t[-1] != '\\')
2457             break;
2458     if (!t)
2459         return NULL;
2460     *t = '\0';
2461     t++;
2462
2463     m = malloc(sizeof(struct modattr));
2464     if (!m) {
2465         debug(DBG_ERR, "malloc failed");
2466         return NULL;
2467     }
2468     m->t = name;
2469
2470     m->replacement = stringcopy(t, 0);
2471     if (!m->replacement) {
2472         free(m);
2473         debug(DBG_ERR, "malloc failed");
2474         return NULL;
2475     }
2476
2477     m->regex = malloc(sizeof(regex_t));
2478     if (!m->regex) {
2479         free(m->replacement);
2480         free(m);
2481         debug(DBG_ERR, "malloc failed");
2482         return NULL;
2483     }
2484
2485     if (regcomp(m->regex, s, REG_ICASE | REG_EXTENDED)) {
2486         free(m->regex);
2487         free(m->replacement);
2488         free(m);
2489         debug(DBG_ERR, "failed to compile regular expression %s", s);
2490         return NULL;
2491     }
2492
2493     return m;
2494 }
2495
2496 struct rewrite *getrewrite(char *alt1, char *alt2) {
2497     struct rewrite *r;
2498
2499     if (alt1)
2500         if ((r = hash_read(rewriteconfs,  alt1, strlen(alt1))))
2501             return r;
2502     if (alt2)
2503         if ((r = hash_read(rewriteconfs,  alt2, strlen(alt2))))
2504             return r;
2505     return NULL;
2506 }
2507
2508 void addrewrite(char *value, char **rmattrs, char **rmvattrs, char **addattrs, char **addvattrs, char **modattrs)
2509 {
2510     struct rewrite *rewrite = NULL;
2511     int i, n;
2512     uint8_t *rma = NULL;
2513     uint32_t *p, *rmva = NULL;
2514     struct list *adda = NULL, *moda = NULL;
2515     struct tlv *a;
2516     struct modattr *m;
2517
2518     if (rmattrs) {
2519         for (n = 0; rmattrs[n]; n++);
2520         rma = calloc(n + 1, sizeof(uint8_t));
2521         if (!rma)
2522             debugx(1, DBG_ERR, "malloc failed");
2523
2524         for (i = 0; i < n; i++)
2525             if (!(rma[i] = attrname2val(rmattrs[i])))
2526                 debugx(1, DBG_ERR, "addrewrite: removing invalid attribute %s", rmattrs[i]);
2527         freegconfmstr(rmattrs);
2528         rma[i] = 0;
2529     }
2530
2531     if (rmvattrs) {
2532         for (n = 0; rmvattrs[n]; n++);
2533         rmva = calloc(2 * n + 1, sizeof(uint32_t));
2534         if (!rmva)
2535             debugx(1, DBG_ERR, "malloc failed");
2536
2537         for (p = rmva, i = 0; i < n; i++, p += 2)
2538             if (!vattrname2val(rmvattrs[i], p, p + 1))
2539                 debugx(1, DBG_ERR, "addrewrite: removing invalid vendor attribute %s", rmvattrs[i]);
2540         freegconfmstr(rmvattrs);
2541         *p = 0;
2542     }
2543
2544     if (addattrs) {
2545         adda = list_create();
2546         if (!adda)
2547             debugx(1, DBG_ERR, "malloc failed");
2548         for (i = 0; addattrs[i]; i++) {
2549             a = extractattr(addattrs[i], 0);
2550             if (!a)
2551                 debugx(1, DBG_ERR, "addrewrite: adding invalid attribute %s", addattrs[i]);
2552             if (!list_push(adda, a))
2553                 debugx(1, DBG_ERR, "malloc failed");
2554         }
2555         freegconfmstr(addattrs);
2556     }
2557
2558     if (addvattrs) {
2559         if (!adda)
2560             adda = list_create();
2561         if (!adda)
2562             debugx(1, DBG_ERR, "malloc failed");
2563         for (i = 0; addvattrs[i]; i++) {
2564             a = extractattr(addvattrs[i], 1);
2565             if (!a)
2566                 debugx(1, DBG_ERR, "addrewrite: adding invalid vendor attribute %s", addvattrs[i]);
2567             if (!list_push(adda, a))
2568                 debugx(1, DBG_ERR, "malloc failed");
2569         }
2570         freegconfmstr(addvattrs);
2571     }
2572
2573     if (modattrs) {
2574         moda = list_create();
2575         if (!moda)
2576             debugx(1, DBG_ERR, "malloc failed");
2577         for (i = 0; modattrs[i]; i++) {
2578             m = extractmodattr(modattrs[i]);
2579             if (!m)
2580                 debugx(1, DBG_ERR, "addrewrite: modifying invalid attribute %s", modattrs[i]);
2581             if (!list_push(moda, m))
2582                 debugx(1, DBG_ERR, "malloc failed");
2583         }
2584         freegconfmstr(modattrs);
2585     }
2586
2587     if (rma || rmva || adda || moda) {
2588         rewrite = malloc(sizeof(struct rewrite));
2589         if (!rewrite)
2590             debugx(1, DBG_ERR, "malloc failed");
2591         rewrite->removeattrs = rma;
2592         rewrite->removevendorattrs = rmva;
2593         rewrite->addattrs = adda;
2594         rewrite->modattrs = moda;
2595     }
2596
2597     if (!hash_insert(rewriteconfs, value, strlen(value), rewrite))
2598         debugx(1, DBG_ERR, "malloc failed");
2599     debug(DBG_DBG, "addrewrite: added rewrite block %s", value);
2600 }
2601
2602 int setttlattr(struct options *opts, char *defaultattr) {
2603     char *ttlattr = opts->ttlattr ? opts->ttlattr : defaultattr;
2604
2605     if (vattrname2val(ttlattr, opts->ttlattrtype, opts->ttlattrtype + 1) &&
2606         (opts->ttlattrtype[1] != 256 || opts->ttlattrtype[0] < 256))
2607         return 1;
2608     debug(DBG_ERR, "setttlattr: invalid TTLAttribute value %s", ttlattr);
2609     return 0;
2610 }
2611
2612 void freeclsrvconf(struct clsrvconf *conf) {
2613     assert(conf);
2614     assert(conf->name);
2615     debug(DBG_DBG, "%s: freeing %p (%s)", __func__, conf, conf->name);
2616     free(conf->name);
2617     if (conf->hostsrc)
2618         freegconfmstr(conf->hostsrc);
2619     free(conf->portsrc);
2620     free(conf->secret);
2621     free(conf->tls);
2622     free(conf->matchcertattr);
2623     if (conf->certcnregex)
2624         regfree(conf->certcnregex);
2625     if (conf->certuriregex)
2626         regfree(conf->certuriregex);
2627     free(conf->confrewritein);
2628     free(conf->confrewriteout);
2629     if (conf->rewriteusername) {
2630         if (conf->rewriteusername->regex)
2631             regfree(conf->rewriteusername->regex);
2632         free(conf->rewriteusername->replacement);
2633         free(conf->rewriteusername);
2634     }
2635     free(conf->dynamiclookupcommand);
2636     conf->rewritein=NULL;
2637     conf->rewriteout=NULL;
2638     if (conf->hostports)
2639         freehostports(conf->hostports);
2640     if (conf->lock) {
2641         pthread_mutex_destroy(conf->lock);
2642         free(conf->lock);
2643     }
2644     /* not touching ssl_ctx, clients and servers */
2645     free(conf);
2646 }
2647
2648 int mergeconfstring(char **dst, char **src) {
2649     char *t;
2650
2651     if (*src) {
2652         *dst = *src;
2653         *src = NULL;
2654         return 1;
2655     }
2656     if (*dst) {
2657         t = stringcopy(*dst, 0);
2658         if (!t) {
2659             debug(DBG_ERR, "malloc failed");
2660             return 0;
2661         }
2662         *dst = t;
2663     }
2664     return 1;
2665 }
2666
2667 char **mstringcopy(char **in) {
2668     char **out;
2669     int n;
2670
2671     if (!in)
2672         return NULL;
2673
2674     for (n = 0; in[n]; n++);
2675     out = malloc((n + 1) * sizeof(char *));
2676     if (!out)
2677         return NULL;
2678     for (n = 0; in[n]; n++) {
2679         out[n] = stringcopy(in[n], 0);
2680         if (!out[n]) {
2681             freegconfmstr(out);
2682             return NULL;
2683         }
2684     }
2685     out[n] = NULL;
2686     return out;
2687 }
2688
2689 int mergeconfmstring(char ***dst, char ***src) {
2690     char **t;
2691
2692     if (*src) {
2693         *dst = *src;
2694         *src = NULL;
2695         return 1;
2696     }
2697     if (*dst) {
2698         t = mstringcopy(*dst);
2699         if (!t) {
2700             debug(DBG_ERR, "malloc failed");
2701             return 0;
2702         }
2703         *dst = t;
2704     }
2705     return 1;
2706 }
2707
2708 /* assumes dst is a shallow copy */
2709 int mergesrvconf(struct clsrvconf *dst, struct clsrvconf *src) {
2710     if (!mergeconfstring(&dst->name, &src->name) ||
2711         !mergeconfmstring(&dst->hostsrc, &src->hostsrc) ||
2712         !mergeconfstring(&dst->portsrc, &src->portsrc) ||
2713         !mergeconfstring(&dst->secret, &src->secret) ||
2714         !mergeconfstring(&dst->tls, &src->tls) ||
2715         !mergeconfstring(&dst->matchcertattr, &src->matchcertattr) ||
2716         !mergeconfstring(&dst->confrewritein, &src->confrewritein) ||
2717         !mergeconfstring(&dst->confrewriteout, &src->confrewriteout) ||
2718         !mergeconfstring(&dst->confrewriteusername, &src->confrewriteusername) ||
2719         !mergeconfstring(&dst->dynamiclookupcommand, &src->dynamiclookupcommand) ||
2720         !mergeconfstring(&dst->fticks_viscountry, &src->fticks_viscountry) ||
2721         !mergeconfstring(&dst->fticks_visinst, &src->fticks_visinst))
2722         return 0;
2723     if (src->pdef)
2724         dst->pdef = src->pdef;
2725     dst->statusserver = src->statusserver;
2726     dst->certnamecheck = src->certnamecheck;
2727     if (src->retryinterval != 255)
2728         dst->retryinterval = src->retryinterval;
2729     if (src->retrycount != 255)
2730         dst->retrycount = src->retrycount;
2731     return 1;
2732 }
2733
2734 /** Set *AF according to IPV4ONLY and IPV6ONLY:
2735     - If both are set, the function fails.
2736     - If exactly one is set, *AF is set accordingly.
2737     - If none is set, *AF is not affected.
2738     Return 0 on success and !0 on failure.
2739     In the case of an error, *AF is not affected.  */
2740 int config_hostaf(const char *desc, int ipv4only, int ipv6only, int *af) {
2741     assert(af != NULL);
2742     if (ipv4only && ipv6only) {
2743         debug(DBG_ERR, "error in block %s, at most one of IPv4Only and "
2744               "IPv6Only can be enabled", desc);
2745         return -1;
2746     }
2747     if (ipv4only)
2748         *af = AF_INET;
2749     if (ipv6only)
2750         *af = AF_INET6;
2751     return 0;
2752 }
2753
2754 int confclient_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val) {
2755     struct clsrvconf *conf;
2756     char *conftype = NULL, *rewriteinalias = NULL;
2757     long int dupinterval = LONG_MIN, addttl = LONG_MIN;
2758     uint8_t ipv4only = 0, ipv6only = 0;
2759
2760     debug(DBG_DBG, "confclient_cb called for %s", block);
2761
2762     conf = malloc(sizeof(struct clsrvconf));
2763     if (!conf)
2764         debugx(1, DBG_ERR, "malloc failed");
2765     memset(conf, 0, sizeof(struct clsrvconf));
2766     conf->certnamecheck = 1;
2767
2768     if (!getgenericconfig(
2769             cf, block,
2770             "type", CONF_STR, &conftype,
2771             "host", CONF_MSTR, &conf->hostsrc,
2772             "IPv4Only", CONF_BLN, &ipv4only,
2773             "IPv6Only", CONF_BLN, &ipv6only,
2774             "secret", CONF_STR, &conf->secret,
2775 #if defined(RADPROT_TLS) || defined(RADPROT_DTLS)
2776             "tls", CONF_STR, &conf->tls,
2777             "matchcertificateattribute", CONF_STR, &conf->matchcertattr,
2778             "CertificateNameCheck", CONF_BLN, &conf->certnamecheck,
2779 #endif
2780             "DuplicateInterval", CONF_LINT, &dupinterval,
2781             "addTTL", CONF_LINT, &addttl,
2782             "rewrite", CONF_STR, &rewriteinalias,
2783             "rewriteIn", CONF_STR, &conf->confrewritein,
2784             "rewriteOut", CONF_STR, &conf->confrewriteout,
2785             "rewriteattribute", CONF_STR, &conf->confrewriteusername,
2786 #if defined(WANT_FTICKS)
2787             "fticksVISCOUNTRY", CONF_STR, &conf->fticks_viscountry,
2788             "fticksVISINST", CONF_STR, &conf->fticks_visinst,
2789 #endif
2790             NULL
2791             ))
2792         debugx(1, DBG_ERR, "configuration error");
2793
2794     conf->name = stringcopy(val, 0);
2795     if (conf->name && !conf->hostsrc) {
2796         conf->hostsrc = malloc(2 * sizeof(char *));
2797         if (conf->hostsrc) {
2798             conf->hostsrc[0] = stringcopy(val, 0);
2799             conf->hostsrc[1] = NULL;
2800         }
2801     }
2802     if (!conf->name || !conf->hostsrc || !conf->hostsrc[0])
2803         debugx(1, DBG_ERR, "malloc failed");
2804
2805     if (!conftype)
2806         debugx(1, DBG_ERR, "error in block %s, option type missing", block);
2807     conf->type = protoname2int(conftype);
2808     if (conf->type == 255)
2809         debugx(1, DBG_ERR, "error in block %s, unknown transport %s", block, conftype);
2810     free(conftype);
2811     conf->pdef = protodefs[conf->type];
2812
2813 #if defined(RADPROT_TLS) || defined(RADPROT_DTLS)
2814     if (conf->type == RAD_TLS || conf->type == RAD_DTLS) {
2815         conf->tlsconf = conf->tls
2816             ? tlsgettls(conf->tls, NULL)
2817             : tlsgettls("defaultClient", "default");
2818         if (!conf->tlsconf)
2819             debugx(1, DBG_ERR, "error in block %s, no tls context defined", block);
2820         if (conf->matchcertattr && !addmatchcertattr(conf))
2821             debugx(1, DBG_ERR, "error in block %s, invalid MatchCertificateAttributeValue", block);
2822     }
2823 #endif
2824
2825     conf->hostaf = AF_UNSPEC;
2826     if (config_hostaf("top level", options.ipv4only, options.ipv6only, &conf->hostaf))
2827         debugx(1, DBG_ERR, "config error: ^");
2828     if (config_hostaf(block, ipv4only, ipv6only, &conf->hostaf))
2829         debugx(1, DBG_ERR, "error in block %s: ^", block);
2830
2831     if (dupinterval != LONG_MIN) {
2832         if (dupinterval < 0 || dupinterval > 255)
2833             debugx(1, DBG_ERR, "error in block %s, value of option DuplicateInterval is %d, must be 0-255", block, dupinterval);
2834         conf->dupinterval = (uint8_t)dupinterval;
2835     } else
2836         conf->dupinterval = conf->pdef->duplicateintervaldefault;
2837
2838     if (addttl != LONG_MIN) {
2839         if (addttl < 1 || addttl > 255)
2840             debugx(1, DBG_ERR, "error in block %s, value of option addTTL is %d, must be 1-255", block, addttl);
2841         conf->addttl = (uint8_t)addttl;
2842     }
2843
2844     if (!conf->confrewritein)
2845         conf->confrewritein = rewriteinalias;
2846     else
2847         free(rewriteinalias);
2848     conf->rewritein = conf->confrewritein
2849         ? getrewrite(conf->confrewritein, NULL)
2850         : getrewrite("defaultClient", "default");
2851     if (conf->confrewriteout)
2852         conf->rewriteout = getrewrite(conf->confrewriteout, NULL);
2853
2854     if (conf->confrewriteusername) {
2855         conf->rewriteusername = extractmodattr(conf->confrewriteusername);
2856         if (!conf->rewriteusername)
2857             debugx(1, DBG_ERR, "error in block %s, invalid RewriteAttributeValue", block);
2858     }
2859
2860     if (!addhostport(&conf->hostports, conf->hostsrc, conf->pdef->portdefault, 1) ||
2861         !resolvehostports(conf->hostports, conf->hostaf, conf->pdef->socktype))
2862         debugx(1, DBG_ERR, "%s: resolve failed, exiting", __func__);
2863
2864     if (!conf->secret) {
2865         if (!conf->pdef->secretdefault)
2866             debugx(1, DBG_ERR, "error in block %s, secret must be specified for transport type %s", block, conf->pdef->name);
2867         conf->secret = stringcopy(conf->pdef->secretdefault, 0);
2868         if (!conf->secret)
2869             debugx(1, DBG_ERR, "malloc failed");
2870     }
2871
2872     conf->lock = malloc(sizeof(pthread_mutex_t));
2873     if (!conf->lock)
2874         debugx(1, DBG_ERR, "malloc failed");
2875
2876     pthread_mutex_init(conf->lock, NULL);
2877     if (!list_push(clconfs, conf))
2878         debugx(1, DBG_ERR, "malloc failed");
2879     return 1;
2880 }
2881
2882 int compileserverconfig(struct clsrvconf *conf, const char *block) {
2883 #if defined(RADPROT_TLS) || defined(RADPROT_DTLS)
2884     if (conf->type == RAD_TLS || conf->type == RAD_DTLS) {
2885         conf->tlsconf = conf->tls
2886             ? tlsgettls(conf->tls, NULL)
2887             : tlsgettls("defaultServer", "default");
2888         if (!conf->tlsconf) {
2889             debug(DBG_ERR, "error in block %s, no tls context defined", block);
2890             return 0;
2891         }
2892         if (conf->matchcertattr && !addmatchcertattr(conf)) {
2893             debug(DBG_ERR, "error in block %s, invalid MatchCertificateAttributeValue", block);
2894             return 0;
2895         }
2896     }
2897 #endif
2898
2899     if (!conf->portsrc) {
2900         conf->portsrc = stringcopy(conf->pdef->portdefault, 0);
2901         if (!conf->portsrc) {
2902             debug(DBG_ERR, "malloc failed");
2903             return 0;
2904         }
2905     }
2906
2907     if (conf->retryinterval == 255)
2908         conf->retryinterval = conf->pdef->retryintervaldefault;
2909     if (conf->retrycount == 255)
2910         conf->retrycount = conf->pdef->retrycountdefault;
2911
2912     conf->rewritein = conf->confrewritein
2913         ? getrewrite(conf->confrewritein, NULL)
2914         : getrewrite("defaultServer", "default");
2915     if (conf->confrewriteout)
2916         conf->rewriteout = getrewrite(conf->confrewriteout, NULL);
2917
2918     if (!addhostport(&conf->hostports, conf->hostsrc, conf->portsrc, 0)) {
2919         debug(DBG_ERR, "error in block %s, failed to parse %s", block, *conf->hostsrc);
2920         return 0;
2921     }
2922
2923     if (!conf->dynamiclookupcommand &&
2924         !resolvehostports(conf->hostports, conf->hostaf,
2925                           conf->pdef->socktype)) {
2926         debug(DBG_ERR, "%s: resolve failed", __func__);
2927         return 0;
2928     }
2929     return 1;
2930 }
2931
2932 int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val) {
2933     struct clsrvconf *conf, *resconf;
2934     char *conftype = NULL, *rewriteinalias = NULL;
2935     long int retryinterval = LONG_MIN, retrycount = LONG_MIN, addttl = LONG_MIN;
2936     uint8_t ipv4only = 0, ipv6only = 0;
2937
2938     debug(DBG_DBG, "confserver_cb called for %s", block);
2939
2940     conf = malloc(sizeof(struct clsrvconf));
2941     if (!conf) {
2942         debug(DBG_ERR, "malloc failed");
2943         return 0;
2944     }
2945     memset(conf, 0, sizeof(struct clsrvconf));
2946     conf->loopprevention = UCHAR_MAX; /* Uninitialized.  */
2947     resconf = (struct clsrvconf *)arg;
2948     if (resconf) {
2949         conf->statusserver = resconf->statusserver;
2950         conf->certnamecheck = resconf->certnamecheck;
2951     } else
2952         conf->certnamecheck = 1;
2953
2954     if (!getgenericconfig(cf, block,
2955                           "type", CONF_STR, &conftype,
2956                           "host", CONF_MSTR, &conf->hostsrc,
2957                           "IPv4Only", CONF_BLN, &ipv4only,
2958                           "IPv6Only", CONF_BLN, &ipv6only,
2959                           "port", CONF_STR, &conf->portsrc,
2960                           "secret", CONF_STR, &conf->secret,
2961 #if defined(RADPROT_TLS) || defined(RADPROT_DTLS)
2962                           "tls", CONF_STR, &conf->tls,
2963                           "MatchCertificateAttribute", CONF_STR, &conf->matchcertattr,
2964                           "CertificateNameCheck", CONF_BLN, &conf->certnamecheck,
2965 #endif
2966                           "addTTL", CONF_LINT, &addttl,
2967                           "rewrite", CONF_STR, &rewriteinalias,
2968                           "rewriteIn", CONF_STR, &conf->confrewritein,
2969                           "rewriteOut", CONF_STR, &conf->confrewriteout,
2970                           "StatusServer", CONF_BLN, &conf->statusserver,
2971                           "RetryInterval", CONF_LINT, &retryinterval,
2972                           "RetryCount", CONF_LINT, &retrycount,
2973                           "DynamicLookupCommand", CONF_STR, &conf->dynamiclookupcommand,
2974                           "LoopPrevention", CONF_BLN, &conf->loopprevention,
2975                           NULL
2976             )) {
2977         debug(DBG_ERR, "configuration error");
2978         goto errexit;
2979     }
2980
2981     conf->name = stringcopy(val, 0);
2982     if (conf->name && !conf->hostsrc) {
2983         conf->hostsrc = malloc(2 * sizeof(char *));
2984         if (conf->hostsrc) {
2985             conf->hostsrc[0] = stringcopy(val, 0);
2986             conf->hostsrc[1] = NULL;
2987         }
2988     }
2989     if (!conf->name || !conf->hostsrc || !conf->hostsrc[0]) {
2990         debug(DBG_ERR, "malloc failed");
2991         goto errexit;
2992     }
2993
2994     if (!conftype) {
2995         debug(DBG_ERR, "error in block %s, option type missing", block);
2996         goto errexit;
2997     }
2998     conf->type = protoname2int(conftype);
2999     if (conf->type == 255) {
3000         debug(DBG_ERR, "error in block %s, unknown transport %s", block, conftype);
3001         goto errexit;
3002     }
3003     free(conftype);
3004     conftype = NULL;
3005
3006     conf->hostaf = AF_UNSPEC;
3007     if (config_hostaf("top level", options.ipv4only, options.ipv6only, &conf->hostaf))
3008         debugx(1, DBG_ERR, "config error: ^");
3009     if (config_hostaf(block, ipv4only, ipv6only, &conf->hostaf))
3010         goto errexit;
3011
3012     conf->pdef = protodefs[conf->type];
3013
3014     if (!conf->confrewritein)
3015         conf->confrewritein = rewriteinalias;
3016     else
3017         free(rewriteinalias);
3018     rewriteinalias = NULL;
3019
3020     if (retryinterval != LONG_MIN) {
3021         if (retryinterval < 1 || retryinterval > conf->pdef->retryintervalmax) {
3022             debug(DBG_ERR, "error in block %s, value of option RetryInterval is %d, must be 1-%d", block, retryinterval, conf->pdef->retryintervalmax);
3023             goto errexit;
3024         }
3025         conf->retryinterval = (uint8_t)retryinterval;
3026     } else
3027         conf->retryinterval = 255;
3028
3029     if (retrycount != LONG_MIN) {
3030         if (retrycount < 0 || retrycount > conf->pdef->retrycountmax) {
3031             debug(DBG_ERR, "error in block %s, value of option RetryCount is %d, must be 0-%d", block, retrycount, conf->pdef->retrycountmax);
3032             goto errexit;
3033         }
3034         conf->retrycount = (uint8_t)retrycount;
3035     } else
3036         conf->retrycount = 255;
3037
3038     if (addttl != LONG_MIN) {
3039         if (addttl < 1 || addttl > 255) {
3040             debug(DBG_ERR, "error in block %s, value of option addTTL is %d, must be 1-255", block, addttl);
3041             goto errexit;
3042         }
3043         conf->addttl = (uint8_t)addttl;
3044     }
3045
3046     if (resconf) {
3047         if (!mergesrvconf(resconf, conf))
3048             goto errexit;
3049         free(conf);
3050         conf = resconf;
3051         if (conf->dynamiclookupcommand) {
3052             free(conf->dynamiclookupcommand);
3053             conf->dynamiclookupcommand = NULL;
3054         }
3055     }
3056
3057     if (resconf || !conf->dynamiclookupcommand) {
3058         if (!compileserverconfig(conf, block))
3059             return 0; /* Don't goto errexit and free resconf -- it's
3060                        * not ours to free.  */
3061     }
3062
3063     if (!conf->secret) {
3064         if (!conf->pdef->secretdefault) {
3065             debug(DBG_ERR, "error in block %s, secret must be specified for transport type %s", block, conf->pdef->name);
3066             return 0;
3067         }
3068         conf->secret = stringcopy(conf->pdef->secretdefault, 0);
3069         if (!conf->secret) {
3070             debug(DBG_ERR, "malloc failed");
3071             return 0;
3072         }
3073     }
3074
3075     if (resconf)
3076         return 1;
3077
3078     if (!list_push(srvconfs, conf)) {
3079         debug(DBG_ERR, "malloc failed");
3080         goto errexit;
3081     }
3082     return 1;
3083
3084 errexit:
3085     free(conftype);
3086     free(rewriteinalias);
3087     freeclsrvconf(conf);
3088     return 0;
3089 }
3090
3091 int confrealm_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val) {
3092     char **servers = NULL, **accservers = NULL, *msg = NULL;
3093     uint8_t accresp = 0;
3094
3095     debug(DBG_DBG, "confrealm_cb called for %s", block);
3096
3097     if (!getgenericconfig(cf, block,
3098                           "server", CONF_MSTR, &servers,
3099                           "accountingServer", CONF_MSTR, &accservers,
3100                           "ReplyMessage", CONF_STR, &msg,
3101                           "AccountingResponse", CONF_BLN, &accresp,
3102                           NULL
3103             ))
3104         debugx(1, DBG_ERR, "configuration error");
3105
3106     addrealm(realms, val, servers, accservers, msg, accresp);
3107     return 1;
3108 }
3109
3110 int confrewrite_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val) {
3111     char **rmattrs = NULL, **rmvattrs = NULL;
3112     char **addattrs = NULL, **addvattrs = NULL;
3113     char **modattrs = NULL;
3114
3115     debug(DBG_DBG, "confrewrite_cb called for %s", block);
3116
3117     if (!getgenericconfig(cf, block,
3118                           "removeAttribute", CONF_MSTR, &rmattrs,
3119                           "removeVendorAttribute", CONF_MSTR, &rmvattrs,
3120                           "addAttribute", CONF_MSTR, &addattrs,
3121                           "addVendorAttribute", CONF_MSTR, &addvattrs,
3122                           "modifyAttribute", CONF_MSTR, &modattrs,
3123                           NULL
3124             ))
3125         debugx(1, DBG_ERR, "configuration error");
3126     addrewrite(val, rmattrs, rmvattrs, addattrs, addvattrs, modattrs);
3127     return 1;
3128 }
3129
3130 int setprotoopts(uint8_t type, char **listenargs, char *sourcearg) {
3131     struct commonprotoopts *protoopts;
3132
3133     protoopts = malloc(sizeof(struct commonprotoopts));
3134     if (!protoopts)
3135         return 0;
3136     memset(protoopts, 0, sizeof(struct commonprotoopts));
3137     protoopts->listenargs = listenargs;
3138     protoopts->sourcearg = sourcearg;
3139     protodefs[type]->setprotoopts(protoopts);
3140     return 1;
3141 }
3142
3143 void getmainconfig(const char *configfile) {
3144     long int addttl = LONG_MIN, loglevel = LONG_MIN;
3145     struct gconffile *cfs;
3146     char **listenargs[RAD_PROTOCOUNT];
3147     char *sourcearg[RAD_PROTOCOUNT];
3148 #if defined(WANT_FTICKS)
3149     uint8_t *fticks_reporting_str = NULL;
3150     uint8_t *fticks_mac_str = NULL;
3151     uint8_t *fticks_key_str = NULL;
3152 #endif
3153     int i;
3154
3155     cfs = openconfigfile(configfile);
3156     memset(&options, 0, sizeof(options));
3157     memset(&listenargs, 0, sizeof(listenargs));
3158     memset(&sourcearg, 0, sizeof(sourcearg));
3159
3160     clconfs = list_create();
3161     if (!clconfs)
3162         debugx(1, DBG_ERR, "malloc failed");
3163
3164     srvconfs = list_create();
3165     if (!srvconfs)
3166         debugx(1, DBG_ERR, "malloc failed");
3167
3168     realms = list_create();
3169     if (!realms)
3170         debugx(1, DBG_ERR, "malloc failed");
3171
3172     rewriteconfs = hash_create();
3173     if (!rewriteconfs)
3174         debugx(1, DBG_ERR, "malloc failed");
3175
3176     if (!getgenericconfig(
3177             &cfs, NULL,
3178 #ifdef RADPROT_UDP
3179             "ListenUDP", CONF_MSTR, &listenargs[RAD_UDP],
3180             "SourceUDP", CONF_STR, &sourcearg[RAD_UDP],
3181 #endif
3182 #ifdef RADPROT_TCP
3183             "ListenTCP", CONF_MSTR, &listenargs[RAD_TCP],
3184             "SourceTCP", CONF_STR, &sourcearg[RAD_TCP],
3185 #endif
3186 #ifdef RADPROT_TLS
3187             "ListenTLS", CONF_MSTR, &listenargs[RAD_TLS],
3188             "SourceTLS", CONF_STR, &sourcearg[RAD_TLS],
3189 #endif
3190 #ifdef RADPROT_DTLS
3191             "ListenDTLS", CONF_MSTR, &listenargs[RAD_DTLS],
3192             "SourceDTLS", CONF_STR, &sourcearg[RAD_DTLS],
3193 #endif
3194             "PidFile", CONF_STR, &options.pidfile,
3195             "TTLAttribute", CONF_STR, &options.ttlattr,
3196             "addTTL", CONF_LINT, &addttl,
3197             "LogLevel", CONF_LINT, &loglevel,
3198             "LogDestination", CONF_STR, &options.logdestination,
3199             "LoopPrevention", CONF_BLN, &options.loopprevention,
3200             "Client", CONF_CBK, confclient_cb, NULL,
3201             "Server", CONF_CBK, confserver_cb, NULL,
3202             "Realm", CONF_CBK, confrealm_cb, NULL,
3203 #if defined(RADPROT_TLS) || defined(RADPROT_DTLS)
3204             "TLS", CONF_CBK, conftls_cb, NULL,
3205 #endif
3206             "Rewrite", CONF_CBK, confrewrite_cb, NULL,
3207 #if defined(WANT_FTICKS)
3208             "FTicksReporting", CONF_STR, &fticks_reporting_str,
3209             "FTicksMAC", CONF_STR, &fticks_mac_str,
3210             "FTicksKey", CONF_STR, &fticks_key_str,
3211             "FTicksSyslogFacility", CONF_STR, &options.ftickssyslogfacility,
3212 #endif
3213             "IPv4Only", CONF_BLN, &options.ipv4only,
3214             "IPv6Only", CONF_BLN, &options.ipv6only,
3215             NULL
3216             ))
3217         debugx(1, DBG_ERR, "configuration error");
3218
3219     if (loglevel != LONG_MIN) {
3220         if (loglevel < 1 || loglevel > 5)
3221             debugx(1, DBG_ERR, "error in %s, value of option LogLevel is %d, must be 1, 2, 3, 4 or 5", configfile, loglevel);
3222         options.loglevel = (uint8_t)loglevel;
3223     }
3224     if (addttl != LONG_MIN) {
3225         if (addttl < 1 || addttl > 255)
3226             debugx(1, DBG_ERR, "error in %s, value of option addTTL is %d, must be 1-255", configfile, addttl);
3227         options.addttl = (uint8_t)addttl;
3228     }
3229     if (!setttlattr(&options, DEFAULT_TTL_ATTR))
3230         debugx(1, DBG_ERR, "Failed to set TTLAttribute, exiting");
3231
3232 #if defined(WANT_FTICKS)
3233     fticks_configure(&options, &fticks_reporting_str, &fticks_mac_str,
3234                      &fticks_key_str);
3235 #endif
3236
3237     for (i = 0; i < RAD_PROTOCOUNT; i++)
3238         if (listenargs[i] || sourcearg[i])
3239             setprotoopts(i, listenargs[i], sourcearg[i]);
3240 }
3241
3242 void getargs(int argc, char **argv, uint8_t *foreground, uint8_t *pretend, uint8_t *loglevel, char **configfile, char **pidfile) {
3243     int c;
3244
3245     while ((c = getopt(argc, argv, "c:d:i:fpv")) != -1) {
3246         switch (c) {
3247         case 'c':
3248             *configfile = optarg;
3249             break;
3250         case 'd':
3251             if (strlen(optarg) != 1 || *optarg < '1' || *optarg > '5')
3252                 debugx(1, DBG_ERR, "Debug level must be 1, 2, 3, 4 or 5, not %s", optarg);
3253             *loglevel = *optarg - '0';
3254             break;
3255         case 'f':
3256             *foreground = 1;
3257             break;
3258         case 'i':
3259             *pidfile = optarg;
3260             break;
3261         case 'p':
3262             *pretend = 1;
3263             break;
3264         case 'v':
3265             debug(DBG_ERR, "radsecproxy revision %s", PACKAGE_VERSION);
3266             debug(DBG_ERR, "This binary was built with support for the following transports:");
3267 #ifdef RADPROT_UDP
3268             debug(DBG_ERR, "  UDP");
3269 #endif
3270 #ifdef RADPROT_TCP
3271             debug(DBG_ERR, "  TCP");
3272 #endif
3273 #ifdef RADPROT_TLS
3274             debug(DBG_ERR, "  TLS");
3275 #endif
3276 #ifdef RADPROT_DTLS
3277             debug(DBG_ERR, "  DTLS");
3278 #endif
3279             exit(0);
3280         default:
3281             goto usage;
3282         }
3283     }
3284     if (!(argc - optind))
3285         return;
3286
3287 usage:
3288     debugx(1, DBG_ERR, "Usage:\n%s [ -c configfile ] [ -d debuglevel ] [ -f ] [ -i pidfile ] [ -p ] [ -v ]", argv[0]);
3289 }
3290
3291 #ifdef SYS_SOLARIS9
3292 int daemon(int a, int b) {
3293     int i;
3294
3295     if (fork())
3296         exit(0);
3297
3298     setsid();
3299
3300     for (i = 0; i < 3; i++) {
3301         close(i);
3302         open("/dev/null", O_RDWR);
3303     }
3304     return 1;
3305 }
3306 #endif
3307
3308 void *sighandler(void *arg) {
3309     sigset_t sigset;
3310     int sig;
3311
3312     for(;;) {
3313         sigemptyset(&sigset);
3314         sigaddset(&sigset, SIGHUP);
3315         sigaddset(&sigset, SIGPIPE);
3316         sigwait(&sigset, &sig);
3317         switch (sig) {
3318         case 0:
3319             /* completely ignoring this */
3320             break;
3321         case SIGHUP:
3322             debug(DBG_INFO, "sighandler: got SIGHUP");
3323             debug_reopen_log();
3324             break;
3325         case SIGPIPE:
3326             debug(DBG_WARN, "sighandler: got SIGPIPE, TLS write error?");
3327             break;
3328         default:
3329             debug(DBG_WARN, "sighandler: ignoring signal %d", sig);
3330         }
3331     }
3332 }
3333
3334 int createpidfile(const char *pidfile) {
3335     int r = 0;
3336     FILE *f = fopen(pidfile, "w");
3337     if (f)
3338         r = fprintf(f, "%ld\n", (long) getpid());
3339     return f && !fclose(f) && r >= 0;
3340 }
3341
3342 int radsecproxy_main(int argc, char **argv) {
3343     pthread_t sigth;
3344     sigset_t sigset;
3345     struct list_node *entry;
3346     uint8_t foreground = 0, pretend = 0, loglevel = 0;
3347     char *configfile = NULL, *pidfile = NULL;
3348     struct clsrvconf *srvconf;
3349     int i;
3350
3351     debug_init("radsecproxy");
3352     debug_set_level(DEBUG_LEVEL);
3353
3354     if (pthread_attr_init(&pthread_attr))
3355         debugx(1, DBG_ERR, "pthread_attr_init failed");
3356     if (pthread_attr_setstacksize(&pthread_attr, PTHREAD_STACK_SIZE))
3357         debugx(1, DBG_ERR, "pthread_attr_setstacksize failed");
3358 #if defined(HAVE_MALLOPT)
3359     if (mallopt(M_TRIM_THRESHOLD, 4 * 1024) != 1)
3360         debugx(1, DBG_ERR, "mallopt failed");
3361 #endif
3362
3363     for (i = 0; i < RAD_PROTOCOUNT; i++)
3364         protodefs[i] = protoinits[i](i);
3365
3366     /* needed even if no TLS/DTLS transport */
3367     sslinit();
3368
3369     getargs(argc, argv, &foreground, &pretend, &loglevel, &configfile, &pidfile);
3370     if (loglevel)
3371         debug_set_level(loglevel);
3372     getmainconfig(configfile ? configfile : CONFIG_MAIN);
3373     if (loglevel)
3374         options.loglevel = loglevel;
3375     else if (options.loglevel)
3376         debug_set_level(options.loglevel);
3377     if (!foreground) {
3378         debug_set_destination(options.logdestination
3379                               ? options.logdestination
3380                               : "x-syslog:///", LOG_TYPE_DEBUG);
3381 #if defined(WANT_FTICKS)
3382         if (options.ftickssyslogfacility) {
3383             debug_set_destination(options.ftickssyslogfacility,
3384                                   LOG_TYPE_FTICKS);
3385             free(options.ftickssyslogfacility);
3386         }
3387 #endif
3388     }
3389     free(options.logdestination);
3390
3391     if (!list_first(clconfs))
3392         debugx(1, DBG_ERR, "No clients configured, nothing to do, exiting");
3393     if (!list_first(realms))
3394         debugx(1, DBG_ERR, "No realms configured, nothing to do, exiting");
3395
3396     if (pretend)
3397         debugx(0, DBG_ERR, "All OK so far; exiting since only pretending");
3398
3399     if (!foreground && (daemon(0, 0) < 0))
3400         debugx(1, DBG_ERR, "daemon() failed: %s", strerror(errno));
3401
3402     debug_timestamp_on();
3403     debug(DBG_INFO, "radsecproxy revision %s starting", PACKAGE_VERSION);
3404     if (!pidfile)
3405         pidfile = options.pidfile;
3406     if (pidfile && !createpidfile(pidfile))
3407         debugx(1, DBG_ERR, "failed to create pidfile %s: %s", pidfile, strerror(errno));
3408
3409     sigemptyset(&sigset);
3410     /* exit on all but SIGHUP|SIGPIPE, ignore more? */
3411     sigaddset(&sigset, SIGHUP);
3412     sigaddset(&sigset, SIGPIPE);
3413     pthread_sigmask(SIG_BLOCK, &sigset, NULL);
3414     pthread_create(&sigth, &pthread_attr, sighandler, NULL);
3415
3416     for (entry = list_first(srvconfs); entry; entry = list_next(entry)) {
3417         srvconf = (struct clsrvconf *)entry->data;
3418         if (srvconf->dynamiclookupcommand)
3419             continue;
3420         if (!addserver(srvconf))
3421             debugx(1, DBG_ERR, "failed to add server");
3422         if (pthread_create(&srvconf->servers->clientth, &pthread_attr, clientwr,
3423                            (void *)(srvconf->servers)))
3424             debugx(1, DBG_ERR, "pthread_create failed");
3425     }
3426
3427     for (i = 0; i < RAD_PROTOCOUNT; i++) {
3428         if (!protodefs[i])
3429             continue;
3430         if (protodefs[i]->initextra)
3431             protodefs[i]->initextra();
3432         if (find_clconf_type(i, NULL))
3433             createlisteners(i);
3434     }
3435
3436     /* just hang around doing nothing, anything to do here? */
3437     for (;;)
3438         sleep(1000);
3439 }
3440
3441 /* Local Variables: */
3442 /* c-file-style: "stroustrup" */
3443 /* End: */