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