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