radlib.c revision 130490
1/*-
2 * Copyright 1998 Juniper Networks, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/lib/libradius/radlib.c 130490 2004-06-14 20:55:30Z stefanf $");
29
30#include <sys/types.h>
31#include <sys/socket.h>
32#include <sys/time.h>
33#include <netinet/in.h>
34#include <arpa/inet.h>
35#ifdef WITH_SSL
36#include <openssl/hmac.h>
37#include <openssl/md5.h>
38#define MD5Init MD5_Init
39#define MD5Update MD5_Update
40#define MD5Final MD5_Final
41#else
42#define MD5_DIGEST_LENGTH 16
43#include <md5.h>
44#endif
45
46/* We need the MPPE_KEY_LEN define */
47#include <netgraph/ng_mppc.h>
48
49#include <errno.h>
50#include <netdb.h>
51#include <stdarg.h>
52#include <stddef.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56#include <unistd.h>
57
58#include "radlib_private.h"
59
60static void	 clear_password(struct rad_handle *);
61static void	 generr(struct rad_handle *, const char *, ...)
62		    __printflike(2, 3);
63static void	 insert_scrambled_password(struct rad_handle *, int);
64static void	 insert_request_authenticator(struct rad_handle *, int);
65static void	 insert_message_authenticator(struct rad_handle *, int);
66static int	 is_valid_response(struct rad_handle *, int,
67		    const struct sockaddr_in *);
68static int	 put_password_attr(struct rad_handle *, int,
69		    const void *, size_t);
70static int	 put_raw_attr(struct rad_handle *, int,
71		    const void *, size_t);
72static int	 split(char *, char *[], int, char *, size_t);
73
74static void
75clear_password(struct rad_handle *h)
76{
77	if (h->pass_len != 0) {
78		memset(h->pass, 0, h->pass_len);
79		h->pass_len = 0;
80	}
81	h->pass_pos = 0;
82}
83
84static void
85generr(struct rad_handle *h, const char *format, ...)
86{
87	va_list		 ap;
88
89	va_start(ap, format);
90	vsnprintf(h->errmsg, ERRSIZE, format, ap);
91	va_end(ap);
92}
93
94static void
95insert_scrambled_password(struct rad_handle *h, int srv)
96{
97	MD5_CTX ctx;
98	unsigned char md5[MD5_DIGEST_LENGTH];
99	const struct rad_server *srvp;
100	int padded_len;
101	int pos;
102
103	srvp = &h->servers[srv];
104	padded_len = h->pass_len == 0 ? 16 : (h->pass_len+15) & ~0xf;
105
106	memcpy(md5, &h->request[POS_AUTH], LEN_AUTH);
107	for (pos = 0;  pos < padded_len;  pos += 16) {
108		int i;
109
110		/* Calculate the new scrambler */
111		MD5Init(&ctx);
112		MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
113		MD5Update(&ctx, md5, 16);
114		MD5Final(md5, &ctx);
115
116		/*
117		 * Mix in the current chunk of the password, and copy
118		 * the result into the right place in the request.  Also
119		 * modify the scrambler in place, since we will use this
120		 * in calculating the scrambler for next time.
121		 */
122		for (i = 0;  i < 16;  i++)
123			h->request[h->pass_pos + pos + i] =
124			    md5[i] ^= h->pass[pos + i];
125	}
126}
127
128static void
129insert_request_authenticator(struct rad_handle *h, int srv)
130{
131	MD5_CTX ctx;
132	const struct rad_server *srvp;
133
134	srvp = &h->servers[srv];
135
136	/* Create the request authenticator */
137	MD5Init(&ctx);
138	MD5Update(&ctx, &h->request[POS_CODE], POS_AUTH - POS_CODE);
139	MD5Update(&ctx, memset(&h->request[POS_AUTH], 0, LEN_AUTH), LEN_AUTH);
140	MD5Update(&ctx, &h->request[POS_ATTRS], h->req_len - POS_ATTRS);
141	MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
142	MD5Final(&h->request[POS_AUTH], &ctx);
143}
144
145static void
146insert_message_authenticator(struct rad_handle *h, int srv)
147{
148#ifdef WITH_SSL
149	u_char md[EVP_MAX_MD_SIZE];
150	u_int md_len;
151	const struct rad_server *srvp;
152	HMAC_CTX ctx;
153	srvp = &h->servers[srv];
154
155	if (h->authentic_pos != 0) {
156		HMAC_CTX_init(&ctx);
157		HMAC_Init(&ctx, srvp->secret, strlen(srvp->secret), EVP_md5());
158		HMAC_Update(&ctx, &h->request[POS_CODE], POS_AUTH - POS_CODE);
159		HMAC_Update(&ctx, &h->request[POS_AUTH], LEN_AUTH);
160		HMAC_Update(&ctx, &h->request[POS_ATTRS],
161		    h->req_len - POS_ATTRS);
162		HMAC_Final(&ctx, md, &md_len);
163		HMAC_CTX_cleanup(&ctx);
164		HMAC_cleanup(&ctx);
165		memcpy(&h->request[h->authentic_pos + 2], md, md_len);
166	}
167#endif
168}
169
170/*
171 * Return true if the current response is valid for a request to the
172 * specified server.
173 */
174static int
175is_valid_response(struct rad_handle *h, int srv,
176    const struct sockaddr_in *from)
177{
178	MD5_CTX ctx;
179	unsigned char md5[MD5_DIGEST_LENGTH];
180	const struct rad_server *srvp;
181	int len;
182#ifdef WITH_SSL
183	HMAC_CTX hctx;
184	u_char resp[MSGSIZE], md[EVP_MAX_MD_SIZE];
185	int pos, md_len;
186#endif
187
188	srvp = &h->servers[srv];
189
190	/* Check the source address */
191	if (from->sin_family != srvp->addr.sin_family ||
192	    from->sin_addr.s_addr != srvp->addr.sin_addr.s_addr ||
193	    from->sin_port != srvp->addr.sin_port)
194		return 0;
195
196	/* Check the message length */
197	if (h->resp_len < POS_ATTRS)
198		return 0;
199	len = h->response[POS_LENGTH] << 8 | h->response[POS_LENGTH+1];
200	if (len > h->resp_len)
201		return 0;
202
203	/* Check the response authenticator */
204	MD5Init(&ctx);
205	MD5Update(&ctx, &h->response[POS_CODE], POS_AUTH - POS_CODE);
206	MD5Update(&ctx, &h->request[POS_AUTH], LEN_AUTH);
207	MD5Update(&ctx, &h->response[POS_ATTRS], len - POS_ATTRS);
208	MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
209	MD5Final(md5, &ctx);
210	if (memcmp(&h->response[POS_AUTH], md5, sizeof md5) != 0)
211		return 0;
212
213#ifdef WITH_SSL
214	/*
215	 * For non accounting responses check the message authenticator,
216	 * if any.
217	 */
218	if (h->response[POS_CODE] != RAD_ACCOUNTING_RESPONSE) {
219
220		memcpy(resp, h->response, MSGSIZE);
221		pos = POS_ATTRS;
222
223		/* Search and verify the Message-Authenticator */
224		while (pos < len - 2) {
225
226			if (h->response[pos] == RAD_MESSAGE_AUTHENTIC) {
227				/* zero fill the Message-Authenticator */
228				memset(&resp[pos + 2], 0, MD5_DIGEST_LENGTH);
229
230				HMAC_CTX_init(&hctx);
231				HMAC_Init(&hctx, srvp->secret,
232				    strlen(srvp->secret), EVP_md5());
233				HMAC_Update(&hctx, &h->response[POS_CODE],
234				    POS_AUTH - POS_CODE);
235				HMAC_Update(&hctx, &h->request[POS_AUTH],
236				    LEN_AUTH);
237				HMAC_Update(&hctx, &resp[POS_ATTRS],
238				    h->resp_len - POS_ATTRS);
239				HMAC_Final(&hctx, md, &md_len);
240				HMAC_CTX_cleanup(&hctx);
241				HMAC_cleanup(&hctx);
242				if (memcmp(md, &h->response[pos + 2],
243				    MD5_DIGEST_LENGTH) != 0)
244					return 0;
245				break;
246			}
247			pos += h->response[pos + 1];
248		}
249	}
250#endif
251	return 1;
252}
253
254static int
255put_password_attr(struct rad_handle *h, int type, const void *value, size_t len)
256{
257	int padded_len;
258	int pad_len;
259
260	if (h->pass_pos != 0) {
261		generr(h, "Multiple User-Password attributes specified");
262		return -1;
263	}
264	if (len > PASSSIZE)
265		len = PASSSIZE;
266	padded_len = len == 0 ? 16 : (len+15) & ~0xf;
267	pad_len = padded_len - len;
268
269	/*
270	 * Put in a place-holder attribute containing all zeros, and
271	 * remember where it is so we can fill it in later.
272	 */
273	clear_password(h);
274	put_raw_attr(h, type, h->pass, padded_len);
275	h->pass_pos = h->req_len - padded_len;
276
277	/* Save the cleartext password, padded as necessary */
278	memcpy(h->pass, value, len);
279	h->pass_len = len;
280	memset(h->pass + len, 0, pad_len);
281	return 0;
282}
283
284static int
285put_raw_attr(struct rad_handle *h, int type, const void *value, size_t len)
286{
287	if (len > 253) {
288		generr(h, "Attribute too long");
289		return -1;
290	}
291	if (h->req_len + 2 + len > MSGSIZE) {
292		generr(h, "Maximum message length exceeded");
293		return -1;
294	}
295	h->request[h->req_len++] = type;
296	h->request[h->req_len++] = len + 2;
297	memcpy(&h->request[h->req_len], value, len);
298	h->req_len += len;
299	return 0;
300}
301
302int
303rad_add_server(struct rad_handle *h, const char *host, int port,
304    const char *secret, int timeout, int tries)
305{
306	struct rad_server *srvp;
307
308	if (h->num_servers >= MAXSERVERS) {
309		generr(h, "Too many RADIUS servers specified");
310		return -1;
311	}
312	srvp = &h->servers[h->num_servers];
313
314	memset(&srvp->addr, 0, sizeof srvp->addr);
315	srvp->addr.sin_len = sizeof srvp->addr;
316	srvp->addr.sin_family = AF_INET;
317	if (!inet_aton(host, &srvp->addr.sin_addr)) {
318		struct hostent *hent;
319
320		if ((hent = gethostbyname(host)) == NULL) {
321			generr(h, "%s: host not found", host);
322			return -1;
323		}
324		memcpy(&srvp->addr.sin_addr, hent->h_addr,
325		    sizeof srvp->addr.sin_addr);
326	}
327	if (port != 0)
328		srvp->addr.sin_port = htons((u_short)port);
329	else {
330		struct servent *sent;
331
332		if (h->type == RADIUS_AUTH)
333			srvp->addr.sin_port =
334			    (sent = getservbyname("radius", "udp")) != NULL ?
335				sent->s_port : htons(RADIUS_PORT);
336		else
337			srvp->addr.sin_port =
338			    (sent = getservbyname("radacct", "udp")) != NULL ?
339				sent->s_port : htons(RADACCT_PORT);
340	}
341	if ((srvp->secret = strdup(secret)) == NULL) {
342		generr(h, "Out of memory");
343		return -1;
344	}
345	srvp->timeout = timeout;
346	srvp->max_tries = tries;
347	srvp->num_tries = 0;
348	h->num_servers++;
349	return 0;
350}
351
352void
353rad_close(struct rad_handle *h)
354{
355	int srv;
356
357	if (h->fd != -1)
358		close(h->fd);
359	for (srv = 0;  srv < h->num_servers;  srv++) {
360		memset(h->servers[srv].secret, 0,
361		    strlen(h->servers[srv].secret));
362		free(h->servers[srv].secret);
363	}
364	clear_password(h);
365	free(h);
366}
367
368int
369rad_config(struct rad_handle *h, const char *path)
370{
371	FILE *fp;
372	char buf[MAXCONFLINE];
373	int linenum;
374	int retval;
375
376	if (path == NULL)
377		path = PATH_RADIUS_CONF;
378	if ((fp = fopen(path, "r")) == NULL) {
379		generr(h, "Cannot open \"%s\": %s", path, strerror(errno));
380		return -1;
381	}
382	retval = 0;
383	linenum = 0;
384	while (fgets(buf, sizeof buf, fp) != NULL) {
385		int len;
386		char *fields[5];
387		int nfields;
388		char msg[ERRSIZE];
389		char *type;
390		char *host, *res;
391		char *port_str;
392		char *secret;
393		char *timeout_str;
394		char *maxtries_str;
395		char *end;
396		char *wanttype;
397		unsigned long timeout;
398		unsigned long maxtries;
399		int port;
400		int i;
401
402		linenum++;
403		len = strlen(buf);
404		/* We know len > 0, else fgets would have returned NULL. */
405		if (buf[len - 1] != '\n') {
406			if (len == sizeof buf - 1)
407				generr(h, "%s:%d: line too long", path,
408				    linenum);
409			else
410				generr(h, "%s:%d: missing newline", path,
411				    linenum);
412			retval = -1;
413			break;
414		}
415		buf[len - 1] = '\0';
416
417		/* Extract the fields from the line. */
418		nfields = split(buf, fields, 5, msg, sizeof msg);
419		if (nfields == -1) {
420			generr(h, "%s:%d: %s", path, linenum, msg);
421			retval = -1;
422			break;
423		}
424		if (nfields == 0)
425			continue;
426		/*
427		 * The first field should contain "auth" or "acct" for
428		 * authentication or accounting, respectively.  But older
429		 * versions of the file didn't have that field.  Default
430		 * it to "auth" for backward compatibility.
431		 */
432		if (strcmp(fields[0], "auth") != 0 &&
433		    strcmp(fields[0], "acct") != 0) {
434			if (nfields >= 5) {
435				generr(h, "%s:%d: invalid service type", path,
436				    linenum);
437				retval = -1;
438				break;
439			}
440			nfields++;
441			for (i = nfields;  --i > 0;  )
442				fields[i] = fields[i - 1];
443			fields[0] = "auth";
444		}
445		if (nfields < 3) {
446			generr(h, "%s:%d: missing shared secret", path,
447			    linenum);
448			retval = -1;
449			break;
450		}
451		type = fields[0];
452		host = fields[1];
453		secret = fields[2];
454		timeout_str = fields[3];
455		maxtries_str = fields[4];
456
457		/* Ignore the line if it is for the wrong service type. */
458		wanttype = h->type == RADIUS_AUTH ? "auth" : "acct";
459		if (strcmp(type, wanttype) != 0)
460			continue;
461
462		/* Parse and validate the fields. */
463		res = host;
464		host = strsep(&res, ":");
465		port_str = strsep(&res, ":");
466		if (port_str != NULL) {
467			port = strtoul(port_str, &end, 10);
468			if (*end != '\0') {
469				generr(h, "%s:%d: invalid port", path,
470				    linenum);
471				retval = -1;
472				break;
473			}
474		} else
475			port = 0;
476		if (timeout_str != NULL) {
477			timeout = strtoul(timeout_str, &end, 10);
478			if (*end != '\0') {
479				generr(h, "%s:%d: invalid timeout", path,
480				    linenum);
481				retval = -1;
482				break;
483			}
484		} else
485			timeout = TIMEOUT;
486		if (maxtries_str != NULL) {
487			maxtries = strtoul(maxtries_str, &end, 10);
488			if (*end != '\0') {
489				generr(h, "%s:%d: invalid maxtries", path,
490				    linenum);
491				retval = -1;
492				break;
493			}
494		} else
495			maxtries = MAXTRIES;
496
497		if (rad_add_server(h, host, port, secret, timeout, maxtries) ==
498		    -1) {
499			strcpy(msg, h->errmsg);
500			generr(h, "%s:%d: %s", path, linenum, msg);
501			retval = -1;
502			break;
503		}
504	}
505	/* Clear out the buffer to wipe a possible copy of a shared secret */
506	memset(buf, 0, sizeof buf);
507	fclose(fp);
508	return retval;
509}
510
511/*
512 * rad_init_send_request() must have previously been called.
513 * Returns:
514 *   0     The application should select on *fd with a timeout of tv before
515 *         calling rad_continue_send_request again.
516 *   < 0   Failure
517 *   > 0   Success
518 */
519int
520rad_continue_send_request(struct rad_handle *h, int selected, int *fd,
521                          struct timeval *tv)
522{
523	int n;
524
525	if (selected) {
526		struct sockaddr_in from;
527		int fromlen;
528
529		fromlen = sizeof from;
530		h->resp_len = recvfrom(h->fd, h->response,
531		    MSGSIZE, MSG_WAITALL, (struct sockaddr *)&from, &fromlen);
532		if (h->resp_len == -1) {
533			generr(h, "recvfrom: %s", strerror(errno));
534			return -1;
535		}
536		if (is_valid_response(h, h->srv, &from)) {
537			h->resp_len = h->response[POS_LENGTH] << 8 |
538			    h->response[POS_LENGTH+1];
539			h->resp_pos = POS_ATTRS;
540			return h->response[POS_CODE];
541		}
542	}
543
544	if (h->try == h->total_tries) {
545		generr(h, "No valid RADIUS responses received");
546		return -1;
547	}
548
549	/*
550         * Scan round-robin to the next server that has some
551         * tries left.  There is guaranteed to be one, or we
552         * would have exited this loop by now.
553	 */
554	while (h->servers[h->srv].num_tries >= h->servers[h->srv].max_tries)
555		if (++h->srv >= h->num_servers)
556			h->srv = 0;
557
558	if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST)
559		/* Insert the request authenticator into the request */
560		insert_request_authenticator(h, h->srv);
561	else
562		/* Insert the scrambled password into the request */
563		if (h->pass_pos != 0)
564			insert_scrambled_password(h, h->srv);
565
566	insert_message_authenticator(h, h->srv);
567
568	/* Send the request */
569	n = sendto(h->fd, h->request, h->req_len, 0,
570	    (const struct sockaddr *)&h->servers[h->srv].addr,
571	    sizeof h->servers[h->srv].addr);
572	if (n != h->req_len) {
573		if (n == -1)
574			generr(h, "sendto: %s", strerror(errno));
575		else
576			generr(h, "sendto: short write");
577		return -1;
578	}
579
580	h->try++;
581	h->servers[h->srv].num_tries++;
582	tv->tv_sec = h->servers[h->srv].timeout;
583	tv->tv_usec = 0;
584	*fd = h->fd;
585
586	return 0;
587}
588
589int
590rad_create_request(struct rad_handle *h, int code)
591{
592	int i;
593
594	h->request[POS_CODE] = code;
595	h->request[POS_IDENT] = ++h->ident;
596	/* Create a random authenticator */
597	for (i = 0;  i < LEN_AUTH;  i += 2) {
598		long r;
599		r = random();
600		h->request[POS_AUTH+i] = (u_char)r;
601		h->request[POS_AUTH+i+1] = (u_char)(r >> 8);
602	}
603	h->req_len = POS_ATTRS;
604	clear_password(h);
605	h->request_created = 1;
606	return 0;
607}
608
609struct in_addr
610rad_cvt_addr(const void *data)
611{
612	struct in_addr value;
613
614	memcpy(&value.s_addr, data, sizeof value.s_addr);
615	return value;
616}
617
618u_int32_t
619rad_cvt_int(const void *data)
620{
621	u_int32_t value;
622
623	memcpy(&value, data, sizeof value);
624	return ntohl(value);
625}
626
627char *
628rad_cvt_string(const void *data, size_t len)
629{
630	char *s;
631
632	s = malloc(len + 1);
633	if (s != NULL) {
634		memcpy(s, data, len);
635		s[len] = '\0';
636	}
637	return s;
638}
639
640/*
641 * Returns the attribute type.  If none are left, returns 0.  On failure,
642 * returns -1.
643 */
644int
645rad_get_attr(struct rad_handle *h, const void **value, size_t *len)
646{
647	int type;
648
649	if (h->resp_pos >= h->resp_len)
650		return 0;
651	if (h->resp_pos + 2 > h->resp_len) {
652		generr(h, "Malformed attribute in response");
653		return -1;
654	}
655	type = h->response[h->resp_pos++];
656	*len = h->response[h->resp_pos++] - 2;
657	if (h->resp_pos + (int)*len > h->resp_len) {
658		generr(h, "Malformed attribute in response");
659		return -1;
660	}
661	*value = &h->response[h->resp_pos];
662	h->resp_pos += *len;
663	return type;
664}
665
666/*
667 * Returns -1 on error, 0 to indicate no event and >0 for success
668 */
669int
670rad_init_send_request(struct rad_handle *h, int *fd, struct timeval *tv)
671{
672	int srv;
673
674	/* Make sure we have a socket to use */
675	if (h->fd == -1) {
676		struct sockaddr_in sin;
677
678		if ((h->fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
679			generr(h, "Cannot create socket: %s", strerror(errno));
680			return -1;
681		}
682		memset(&sin, 0, sizeof sin);
683		sin.sin_len = sizeof sin;
684		sin.sin_family = AF_INET;
685		sin.sin_addr.s_addr = INADDR_ANY;
686		sin.sin_port = htons(0);
687		if (bind(h->fd, (const struct sockaddr *)&sin,
688		    sizeof sin) == -1) {
689			generr(h, "bind: %s", strerror(errno));
690			close(h->fd);
691			h->fd = -1;
692			return -1;
693		}
694	}
695
696	if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) {
697		/* Make sure no password given */
698		if (h->pass_pos || h->chap_pass) {
699			generr(h, "User or Chap Password"
700			    " in accounting request");
701			return -1;
702		}
703	} else {
704		if (h->eap_msg == 0) {
705			/* Make sure the user gave us a password */
706			if (h->pass_pos == 0 && !h->chap_pass) {
707				generr(h, "No User or Chap Password"
708				    " attributes given");
709				return -1;
710			}
711			if (h->pass_pos != 0 && h->chap_pass) {
712				generr(h, "Both User and Chap Password"
713				    " attributes given");
714				return -1;
715			}
716		}
717	}
718
719	/* Fill in the length field in the message */
720	h->request[POS_LENGTH] = h->req_len >> 8;
721	h->request[POS_LENGTH+1] = h->req_len;
722
723	/*
724	 * Count the total number of tries we will make, and zero the
725	 * counter for each server.
726	 */
727	h->total_tries = 0;
728	for (srv = 0;  srv < h->num_servers;  srv++) {
729		h->total_tries += h->servers[srv].max_tries;
730		h->servers[srv].num_tries = 0;
731	}
732	if (h->total_tries == 0) {
733		generr(h, "No RADIUS servers specified");
734		return -1;
735	}
736
737	h->try = h->srv = 0;
738
739	return rad_continue_send_request(h, 0, fd, tv);
740}
741
742/*
743 * Create and initialize a rad_handle structure, and return it to the
744 * caller.  Can fail only if the necessary memory cannot be allocated.
745 * In that case, it returns NULL.
746 */
747struct rad_handle *
748rad_auth_open(void)
749{
750	struct rad_handle *h;
751
752	h = (struct rad_handle *)malloc(sizeof(struct rad_handle));
753	if (h != NULL) {
754		srandomdev();
755		h->fd = -1;
756		h->num_servers = 0;
757		h->ident = random();
758		h->errmsg[0] = '\0';
759		memset(h->pass, 0, sizeof h->pass);
760		h->pass_len = 0;
761		h->pass_pos = 0;
762		h->chap_pass = 0;
763		h->authentic_pos = 0;
764		h->type = RADIUS_AUTH;
765		h->request_created = 0;
766		h->eap_msg = 0;
767	}
768	return h;
769}
770
771struct rad_handle *
772rad_acct_open(void)
773{
774	struct rad_handle *h;
775
776	h = rad_open();
777	if (h != NULL)
778	        h->type = RADIUS_ACCT;
779	return h;
780}
781
782struct rad_handle *
783rad_open(void)
784{
785    return rad_auth_open();
786}
787
788int
789rad_put_addr(struct rad_handle *h, int type, struct in_addr addr)
790{
791	return rad_put_attr(h, type, &addr.s_addr, sizeof addr.s_addr);
792}
793
794int
795rad_put_attr(struct rad_handle *h, int type, const void *value, size_t len)
796{
797	int result;
798
799	if (!h->request_created) {
800		generr(h, "Please call rad_create_request()"
801		    " before putting attributes");
802		return -1;
803	}
804
805	if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) {
806		if (type == RAD_EAP_MESSAGE) {
807			generr(h, "EAP-Message attribute is not valid"
808			    " in accounting requests");
809			return -1;
810		}
811	}
812
813	/*
814	 * When proxying EAP Messages, the Message Authenticator
815	 * MUST be present; see RFC 3579.
816	 */
817	if (type == RAD_EAP_MESSAGE) {
818		if (rad_put_message_authentic(h) == -1)
819			return -1;
820	}
821
822	if (type == RAD_USER_PASSWORD) {
823		result = put_password_attr(h, type, value, len);
824	} else if (type == RAD_MESSAGE_AUTHENTIC) {
825		result = rad_put_message_authentic(h);
826	} else {
827		result = put_raw_attr(h, type, value, len);
828		if (result == 0) {
829			if (type == RAD_CHAP_PASSWORD)
830				h->chap_pass = 1;
831			else if (type == RAD_EAP_MESSAGE)
832				h->eap_msg = 1;
833		}
834	}
835
836	return result;
837}
838
839int
840rad_put_int(struct rad_handle *h, int type, u_int32_t value)
841{
842	u_int32_t nvalue;
843
844	nvalue = htonl(value);
845	return rad_put_attr(h, type, &nvalue, sizeof nvalue);
846}
847
848int
849rad_put_string(struct rad_handle *h, int type, const char *str)
850{
851	return rad_put_attr(h, type, str, strlen(str));
852}
853
854int
855rad_put_message_authentic(struct rad_handle *h)
856{
857#ifdef WITH_SSL
858	u_char md_zero[MD5_DIGEST_LENGTH];
859
860	if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) {
861		generr(h, "Message-Authenticator is not valid"
862		    " in accounting requests");
863		return -1;
864	}
865
866	if (h->authentic_pos == 0) {
867		h->authentic_pos = h->req_len;
868		memset(md_zero, 0, sizeof(md_zero));
869		return (put_raw_attr(h, RAD_MESSAGE_AUTHENTIC, md_zero,
870		    sizeof(md_zero)));
871	}
872	return 0;
873#else
874	generr(h, "Message Authenticator not supported,"
875	    " please recompile libradius with SSL support");
876	return -1;
877#endif
878}
879
880/*
881 * Returns the response type code on success, or -1 on failure.
882 */
883int
884rad_send_request(struct rad_handle *h)
885{
886	struct timeval timelimit;
887	struct timeval tv;
888	int fd;
889	int n;
890
891	n = rad_init_send_request(h, &fd, &tv);
892
893	if (n != 0)
894		return n;
895
896	gettimeofday(&timelimit, NULL);
897	timeradd(&tv, &timelimit, &timelimit);
898
899	for ( ; ; ) {
900		fd_set readfds;
901
902		FD_ZERO(&readfds);
903		FD_SET(fd, &readfds);
904
905		n = select(fd + 1, &readfds, NULL, NULL, &tv);
906
907		if (n == -1) {
908			generr(h, "select: %s", strerror(errno));
909			return -1;
910		}
911
912		if (!FD_ISSET(fd, &readfds)) {
913			/* Compute a new timeout */
914			gettimeofday(&tv, NULL);
915			timersub(&timelimit, &tv, &tv);
916			if (tv.tv_sec > 0 || (tv.tv_sec == 0 && tv.tv_usec > 0))
917				/* Continue the select */
918				continue;
919		}
920
921		n = rad_continue_send_request(h, n, &fd, &tv);
922
923		if (n != 0)
924			return n;
925
926		gettimeofday(&timelimit, NULL);
927		timeradd(&tv, &timelimit, &timelimit);
928	}
929}
930
931const char *
932rad_strerror(struct rad_handle *h)
933{
934	return h->errmsg;
935}
936
937/*
938 * Destructively split a string into fields separated by white space.
939 * `#' at the beginning of a field begins a comment that extends to the
940 * end of the string.  Fields may be quoted with `"'.  Inside quoted
941 * strings, the backslash escapes `\"' and `\\' are honored.
942 *
943 * Pointers to up to the first maxfields fields are stored in the fields
944 * array.  Missing fields get NULL pointers.
945 *
946 * The return value is the actual number of fields parsed, and is always
947 * <= maxfields.
948 *
949 * On a syntax error, places a message in the msg string, and returns -1.
950 */
951static int
952split(char *str, char *fields[], int maxfields, char *msg, size_t msglen)
953{
954	char *p;
955	int i;
956	static const char ws[] = " \t";
957
958	for (i = 0;  i < maxfields;  i++)
959		fields[i] = NULL;
960	p = str;
961	i = 0;
962	while (*p != '\0') {
963		p += strspn(p, ws);
964		if (*p == '#' || *p == '\0')
965			break;
966		if (i >= maxfields) {
967			snprintf(msg, msglen, "line has too many fields");
968			return -1;
969		}
970		if (*p == '"') {
971			char *dst;
972
973			dst = ++p;
974			fields[i] = dst;
975			while (*p != '"') {
976				if (*p == '\\') {
977					p++;
978					if (*p != '"' && *p != '\\' &&
979					    *p != '\0') {
980						snprintf(msg, msglen,
981						    "invalid `\\' escape");
982						return -1;
983					}
984				}
985				if (*p == '\0') {
986					snprintf(msg, msglen,
987					    "unterminated quoted string");
988					return -1;
989				}
990				*dst++ = *p++;
991			}
992			*dst = '\0';
993			p++;
994			if (*fields[i] == '\0') {
995				snprintf(msg, msglen,
996				    "empty quoted string not permitted");
997				return -1;
998			}
999			if (*p != '\0' && strspn(p, ws) == 0) {
1000				snprintf(msg, msglen, "quoted string not"
1001				    " followed by white space");
1002				return -1;
1003			}
1004		} else {
1005			fields[i] = p;
1006			p += strcspn(p, ws);
1007			if (*p != '\0')
1008				*p++ = '\0';
1009		}
1010		i++;
1011	}
1012	return i;
1013}
1014
1015int
1016rad_get_vendor_attr(u_int32_t *vendor, const void **data, size_t *len)
1017{
1018	struct vendor_attribute *attr;
1019
1020	attr = (struct vendor_attribute *)*data;
1021	*vendor = ntohl(attr->vendor_value);
1022	*data = attr->attrib_data;
1023	*len = attr->attrib_len - 2;
1024
1025	return (attr->attrib_type);
1026}
1027
1028int
1029rad_put_vendor_addr(struct rad_handle *h, int vendor, int type,
1030    struct in_addr addr)
1031{
1032	return (rad_put_vendor_attr(h, vendor, type, &addr.s_addr,
1033	    sizeof addr.s_addr));
1034}
1035
1036int
1037rad_put_vendor_attr(struct rad_handle *h, int vendor, int type,
1038    const void *value, size_t len)
1039{
1040	struct vendor_attribute *attr;
1041	int res;
1042
1043	if (!h->request_created) {
1044		generr(h, "Please call rad_create_request()"
1045		    " before putting attributes");
1046		return -1;
1047	}
1048
1049	if ((attr = malloc(len + 6)) == NULL) {
1050		generr(h, "malloc failure (%zu bytes)", len + 6);
1051		return -1;
1052	}
1053
1054	attr->vendor_value = htonl(vendor);
1055	attr->attrib_type = type;
1056	attr->attrib_len = len + 2;
1057	memcpy(attr->attrib_data, value, len);
1058
1059	res = put_raw_attr(h, RAD_VENDOR_SPECIFIC, attr, len + 6);
1060	free(attr);
1061	if (res == 0 && vendor == RAD_VENDOR_MICROSOFT
1062	    && (type == RAD_MICROSOFT_MS_CHAP_RESPONSE
1063	    || type == RAD_MICROSOFT_MS_CHAP2_RESPONSE)) {
1064		h->chap_pass = 1;
1065	}
1066	return (res);
1067}
1068
1069int
1070rad_put_vendor_int(struct rad_handle *h, int vendor, int type, u_int32_t i)
1071{
1072	u_int32_t value;
1073
1074	value = htonl(i);
1075	return (rad_put_vendor_attr(h, vendor, type, &value, sizeof value));
1076}
1077
1078int
1079rad_put_vendor_string(struct rad_handle *h, int vendor, int type,
1080    const char *str)
1081{
1082	return (rad_put_vendor_attr(h, vendor, type, str, strlen(str)));
1083}
1084
1085ssize_t
1086rad_request_authenticator(struct rad_handle *h, char *buf, size_t len)
1087{
1088	if (len < LEN_AUTH)
1089		return (-1);
1090	memcpy(buf, h->request + POS_AUTH, LEN_AUTH);
1091	if (len > LEN_AUTH)
1092		buf[LEN_AUTH] = '\0';
1093	return (LEN_AUTH);
1094}
1095
1096u_char *
1097rad_demangle(struct rad_handle *h, const void *mangled, size_t mlen)
1098{
1099	char R[LEN_AUTH];
1100	const char *S;
1101	int i, Ppos;
1102	MD5_CTX Context;
1103	u_char b[MD5_DIGEST_LENGTH], *C, *demangled;
1104
1105	if ((mlen % 16 != 0) || mlen > 128) {
1106		generr(h, "Cannot interpret mangled data of length %lu",
1107		    (u_long)mlen);
1108		return NULL;
1109	}
1110
1111	C = (u_char *)mangled;
1112
1113	/* We need the shared secret as Salt */
1114	S = rad_server_secret(h);
1115
1116	/* We need the request authenticator */
1117	if (rad_request_authenticator(h, R, sizeof R) != LEN_AUTH) {
1118		generr(h, "Cannot obtain the RADIUS request authenticator");
1119		return NULL;
1120	}
1121
1122	demangled = malloc(mlen);
1123	if (!demangled)
1124		return NULL;
1125
1126	MD5Init(&Context);
1127	MD5Update(&Context, S, strlen(S));
1128	MD5Update(&Context, R, LEN_AUTH);
1129	MD5Final(b, &Context);
1130	Ppos = 0;
1131	while (mlen) {
1132
1133		mlen -= 16;
1134		for (i = 0; i < 16; i++)
1135			demangled[Ppos++] = C[i] ^ b[i];
1136
1137		if (mlen) {
1138			MD5Init(&Context);
1139			MD5Update(&Context, S, strlen(S));
1140			MD5Update(&Context, C, 16);
1141			MD5Final(b, &Context);
1142		}
1143
1144		C += 16;
1145	}
1146
1147	return demangled;
1148}
1149
1150u_char *
1151rad_demangle_mppe_key(struct rad_handle *h, const void *mangled,
1152    size_t mlen, size_t *len)
1153{
1154	char R[LEN_AUTH];    /* variable names as per rfc2548 */
1155	const char *S;
1156	u_char b[MD5_DIGEST_LENGTH], *demangled;
1157	const u_char *A, *C;
1158	MD5_CTX Context;
1159	int Slen, i, Clen, Ppos;
1160	u_char *P;
1161
1162	if (mlen % 16 != SALT_LEN) {
1163		generr(h, "Cannot interpret mangled data of length %lu",
1164		    (u_long)mlen);
1165		return NULL;
1166	}
1167
1168	/* We need the RADIUS Request-Authenticator */
1169	if (rad_request_authenticator(h, R, sizeof R) != LEN_AUTH) {
1170		generr(h, "Cannot obtain the RADIUS request authenticator");
1171		return NULL;
1172	}
1173
1174	A = (const u_char *)mangled;      /* Salt comes first */
1175	C = (const u_char *)mangled + SALT_LEN;  /* Then the ciphertext */
1176	Clen = mlen - SALT_LEN;
1177	S = rad_server_secret(h);    /* We need the RADIUS secret */
1178	Slen = strlen(S);
1179	P = alloca(Clen);        /* We derive our plaintext */
1180
1181	MD5Init(&Context);
1182	MD5Update(&Context, S, Slen);
1183	MD5Update(&Context, R, LEN_AUTH);
1184	MD5Update(&Context, A, SALT_LEN);
1185	MD5Final(b, &Context);
1186	Ppos = 0;
1187
1188	while (Clen) {
1189		Clen -= 16;
1190
1191		for (i = 0; i < 16; i++)
1192		    P[Ppos++] = C[i] ^ b[i];
1193
1194		if (Clen) {
1195			MD5Init(&Context);
1196			MD5Update(&Context, S, Slen);
1197			MD5Update(&Context, C, 16);
1198			MD5Final(b, &Context);
1199		}
1200
1201		C += 16;
1202	}
1203
1204	/*
1205	* The resulting plain text consists of a one-byte length, the text and
1206	* maybe some padding.
1207	*/
1208	*len = *P;
1209	if (*len > mlen - 1) {
1210		generr(h, "Mangled data seems to be garbage %zu %zu",
1211		    *len, mlen-1);
1212		return NULL;
1213	}
1214
1215	if (*len > MPPE_KEY_LEN * 2) {
1216		generr(h, "Key to long (%zu) for me max. %d",
1217		    *len, MPPE_KEY_LEN * 2);
1218		return NULL;
1219	}
1220	demangled = malloc(*len);
1221	if (!demangled)
1222		return NULL;
1223
1224	memcpy(demangled, P + 1, *len);
1225	return demangled;
1226}
1227
1228const char *
1229rad_server_secret(struct rad_handle *h)
1230{
1231	return (h->servers[h->srv].secret);
1232}
1233