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