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