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