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