xref: /dragonfly/usr.sbin/ppp/libradius/radlib.c (revision ec21d9fb)
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  * $FreeBSD: head/lib/libradius/radlib.c 339270 2018-10-09 21:28:26Z gjb $
27  */
28 
29 #include <sys/cdefs.h>
30 
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <sys/time.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #ifdef WITH_SSL
37 #include <openssl/hmac.h>
38 #include <openssl/md5.h>
39 #define MD5Init MD5_Init
40 #define MD5Update MD5_Update
41 #define MD5Final MD5_Final
42 #else
43 #define MD5_DIGEST_LENGTH 16
44 #include <md5.h>
45 #endif
46 
47 #define	MAX_FIELDS	7
48 
49 /* We need the MPPE_KEY_LEN define */
50 #ifdef WANT_NETGRAPH7
51 #include <netgraph7/mppc/ng_mppc.h>
52 #else
53 #include <netgraph/mppc/ng_mppc.h>
54 #endif
55 
56 #include <errno.h>
57 #include <netdb.h>
58 #include <stdarg.h>
59 #include <stddef.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <unistd.h>
64 
65 #include "radlib_private.h"
66 
67 static void	 clear_password(struct rad_handle *);
68 static void	 generr(struct rad_handle *, const char *, ...)
69 		    __printflike(2, 3);
70 static void	 insert_scrambled_password(struct rad_handle *, int);
71 static void	 insert_request_authenticator(struct rad_handle *, int);
72 static void	 insert_message_authenticator(struct rad_handle *, int);
73 static int	 is_valid_response(struct rad_handle *, int,
74 		    const struct sockaddr_in *);
75 static int	 put_password_attr(struct rad_handle *, int,
76 		    const void *, size_t);
77 static int	 put_raw_attr(struct rad_handle *, int,
78 		    const void *, size_t);
79 static int	 split(char *, const char *[], int, char *, size_t);
80 
81 static void
82 clear_password(struct rad_handle *h)
83 {
84 	if (h->pass_len != 0) {
85 		memset(h->pass, 0, h->pass_len);
86 		h->pass_len = 0;
87 	}
88 	h->pass_pos = 0;
89 }
90 
91 static void
92 generr(struct rad_handle *h, const char *format, ...)
93 {
94 	va_list		 ap;
95 
96 	va_start(ap, format);
97 	vsnprintf(h->errmsg, ERRSIZE, format, ap);
98 	va_end(ap);
99 }
100 
101 static void
102 insert_scrambled_password(struct rad_handle *h, int srv)
103 {
104 	MD5_CTX ctx;
105 	unsigned char md5[MD5_DIGEST_LENGTH];
106 	const struct rad_server *srvp;
107 	int padded_len;
108 	int pos;
109 
110 	srvp = &h->servers[srv];
111 	padded_len = h->pass_len == 0 ? 16 : (h->pass_len+15) & ~0xf;
112 
113 	memcpy(md5, &h->out[POS_AUTH], LEN_AUTH);
114 	for (pos = 0;  pos < padded_len;  pos += 16) {
115 		int i;
116 
117 		/* Calculate the new scrambler */
118 		MD5Init(&ctx);
119 		MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
120 		MD5Update(&ctx, md5, 16);
121 		MD5Final(md5, &ctx);
122 
123 		/*
124 		 * Mix in the current chunk of the password, and copy
125 		 * the result into the right place in the request.  Also
126 		 * modify the scrambler in place, since we will use this
127 		 * in calculating the scrambler for next time.
128 		 */
129 		for (i = 0;  i < 16;  i++)
130 			h->out[h->pass_pos + pos + i] =
131 			    md5[i] ^= h->pass[pos + i];
132 	}
133 }
134 
135 static void
136 insert_request_authenticator(struct rad_handle *h, int resp)
137 {
138 	MD5_CTX ctx;
139 	const struct rad_server *srvp;
140 
141 	srvp = &h->servers[h->srv];
142 
143 	/* Create the request authenticator */
144 	MD5Init(&ctx);
145 	MD5Update(&ctx, &h->out[POS_CODE], POS_AUTH - POS_CODE);
146 	if (resp)
147 	    MD5Update(&ctx, &h->in[POS_AUTH], LEN_AUTH);
148 	else
149 	    MD5Update(&ctx, &h->out[POS_AUTH], LEN_AUTH);
150 	MD5Update(&ctx, &h->out[POS_ATTRS], h->out_len - POS_ATTRS);
151 	MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
152 	MD5Final(&h->out[POS_AUTH], &ctx);
153 }
154 
155 static void
156 insert_message_authenticator(struct rad_handle *h, int resp)
157 {
158 #ifdef WITH_SSL
159 	u_char md[EVP_MAX_MD_SIZE];
160 	u_int md_len;
161 	const struct rad_server *srvp;
162 	HMAC_CTX *ctx;
163 	srvp = &h->servers[h->srv];
164 
165 	if (h->authentic_pos != 0) {
166 		ctx = HMAC_CTX_new();
167 		HMAC_Init_ex(ctx, srvp->secret, strlen(srvp->secret), EVP_md5(), NULL);
168 		HMAC_Update(ctx, &h->out[POS_CODE], POS_AUTH - POS_CODE);
169 		if (resp)
170 		    HMAC_Update(ctx, &h->in[POS_AUTH], LEN_AUTH);
171 		else
172 		    HMAC_Update(ctx, &h->out[POS_AUTH], LEN_AUTH);
173 		HMAC_Update(ctx, &h->out[POS_ATTRS],
174 		    h->out_len - POS_ATTRS);
175 		HMAC_Final(ctx, md, &md_len);
176 		HMAC_CTX_free(ctx);
177 		memcpy(&h->out[h->authentic_pos + 2], md, md_len);
178 	}
179 #endif
180 }
181 
182 /*
183  * Return true if the current response is valid for a request to the
184  * specified server.
185  */
186 static int
187 is_valid_response(struct rad_handle *h, int srv,
188     const struct sockaddr_in *from)
189 {
190 	MD5_CTX ctx;
191 	unsigned char md5[MD5_DIGEST_LENGTH];
192 	const struct rad_server *srvp;
193 	int len;
194 #ifdef WITH_SSL
195 	HMAC_CTX *hctx;
196 	u_char resp[MSGSIZE], md[EVP_MAX_MD_SIZE];
197 	u_int md_len;
198 	int pos;
199 #endif
200 
201 	srvp = &h->servers[srv];
202 
203 	/* Check the source address */
204 	if (from->sin_family != srvp->addr.sin_family ||
205 	    from->sin_addr.s_addr != srvp->addr.sin_addr.s_addr ||
206 	    from->sin_port != srvp->addr.sin_port)
207 		return 0;
208 
209 	/* Check the message length */
210 	if (h->in_len < POS_ATTRS)
211 		return 0;
212 	len = h->in[POS_LENGTH] << 8 | h->in[POS_LENGTH+1];
213 	if (len > h->in_len)
214 		return 0;
215 
216 	/* Check the response authenticator */
217 	MD5Init(&ctx);
218 	MD5Update(&ctx, &h->in[POS_CODE], POS_AUTH - POS_CODE);
219 	MD5Update(&ctx, &h->out[POS_AUTH], LEN_AUTH);
220 	MD5Update(&ctx, &h->in[POS_ATTRS], len - POS_ATTRS);
221 	MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
222 	MD5Final(md5, &ctx);
223 	if (memcmp(&h->in[POS_AUTH], md5, sizeof md5) != 0)
224 		return 0;
225 
226 #ifdef WITH_SSL
227 	/*
228 	 * For non accounting responses check the message authenticator,
229 	 * if any.
230 	 */
231 	if (h->in[POS_CODE] != RAD_ACCOUNTING_RESPONSE) {
232 
233 		memcpy(resp, h->in, MSGSIZE);
234 		pos = POS_ATTRS;
235 
236 		/* Search and verify the Message-Authenticator */
237 		hctx = HMAC_CTX_new();
238 		while (pos < len - 2) {
239 
240 			if (h->in[pos] == RAD_MESSAGE_AUTHENTIC) {
241 				/* zero fill the Message-Authenticator */
242 				memset(&resp[pos + 2], 0, MD5_DIGEST_LENGTH);
243 
244 				HMAC_Init_ex(hctx, srvp->secret,
245 				    strlen(srvp->secret), EVP_md5(), NULL);
246 				HMAC_Update(hctx, &h->in[POS_CODE],
247 				    POS_AUTH - POS_CODE);
248 				HMAC_Update(hctx, &h->out[POS_AUTH],
249 				    LEN_AUTH);
250 				HMAC_Update(hctx, &resp[POS_ATTRS],
251 				    h->in_len - POS_ATTRS);
252 				HMAC_Final(hctx, md, &md_len);
253 				HMAC_CTX_reset(hctx);
254 				if (memcmp(md, &h->in[pos + 2],
255 				    MD5_DIGEST_LENGTH) != 0) {
256 					HMAC_CTX_free(hctx);
257 					return 0;
258 				}
259 				break;
260 			}
261 			pos += h->in[pos + 1];
262 		}
263 		HMAC_CTX_free(hctx);
264 	}
265 #endif
266 	return 1;
267 }
268 
269 /*
270  * Return true if the current request is valid for the specified server.
271  */
272 static int
273 is_valid_request(struct rad_handle *h)
274 {
275 	MD5_CTX ctx;
276 	unsigned char md5[MD5_DIGEST_LENGTH];
277 	const struct rad_server *srvp;
278 	int len;
279 #ifdef WITH_SSL
280 	HMAC_CTX *hctx;
281 	u_char resp[MSGSIZE], md[EVP_MAX_MD_SIZE];
282 	u_int md_len;
283 	int pos;
284 #endif
285 
286 	srvp = &h->servers[h->srv];
287 
288 	/* Check the message length */
289 	if (h->in_len < POS_ATTRS)
290 		return (0);
291 	len = h->in[POS_LENGTH] << 8 | h->in[POS_LENGTH+1];
292 	if (len > h->in_len)
293 		return (0);
294 
295 	if (h->in[POS_CODE] != RAD_ACCESS_REQUEST) {
296 		uint32_t zeroes[4] = { 0, 0, 0, 0 };
297 		/* Check the request authenticator */
298 		MD5Init(&ctx);
299 		MD5Update(&ctx, &h->in[POS_CODE], POS_AUTH - POS_CODE);
300 		MD5Update(&ctx, zeroes, LEN_AUTH);
301 		MD5Update(&ctx, &h->in[POS_ATTRS], len - POS_ATTRS);
302 		MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
303 		MD5Final(md5, &ctx);
304 		if (memcmp(&h->in[POS_AUTH], md5, sizeof md5) != 0)
305 			return (0);
306 	}
307 
308 #ifdef WITH_SSL
309 	/* Search and verify the Message-Authenticator */
310 	pos = POS_ATTRS;
311 	hctx = HMAC_CTX_new();
312 	while (pos < len - 2) {
313 		if (h->in[pos] == RAD_MESSAGE_AUTHENTIC) {
314 			memcpy(resp, h->in, MSGSIZE);
315 			/* zero fill the Request-Authenticator */
316 			if (h->in[POS_CODE] != RAD_ACCESS_REQUEST)
317 				memset(&resp[POS_AUTH], 0, LEN_AUTH);
318 			/* zero fill the Message-Authenticator */
319 			memset(&resp[pos + 2], 0, MD5_DIGEST_LENGTH);
320 
321 			HMAC_Init_ex(hctx, srvp->secret,
322 			    strlen(srvp->secret), EVP_md5(), NULL);
323 			HMAC_Update(hctx, resp, h->in_len);
324 			HMAC_Final(hctx, md, &md_len);
325 			HMAC_CTX_reset(hctx);
326 			if (memcmp(md, &h->in[pos + 2],
327 			    MD5_DIGEST_LENGTH) != 0) {
328 				HMAC_CTX_free(hctx);
329 				return (0);
330 			}
331 			break;
332 		}
333 		pos += h->in[pos + 1];
334 	}
335 	HMAC_CTX_free(hctx);
336 #endif
337 	return (1);
338 }
339 
340 static int
341 put_password_attr(struct rad_handle *h, int type, const void *value, size_t len)
342 {
343 	int padded_len;
344 	int pad_len;
345 
346 	if (h->pass_pos != 0) {
347 		generr(h, "Multiple User-Password attributes specified");
348 		return -1;
349 	}
350 	if (len > PASSSIZE)
351 		len = PASSSIZE;
352 	padded_len = len == 0 ? 16 : (len+15) & ~0xf;
353 	pad_len = padded_len - len;
354 
355 	/*
356 	 * Put in a place-holder attribute containing all zeros, and
357 	 * remember where it is so we can fill it in later.
358 	 */
359 	clear_password(h);
360 	put_raw_attr(h, type, h->pass, padded_len);
361 	h->pass_pos = h->out_len - padded_len;
362 
363 	/* Save the cleartext password, padded as necessary */
364 	memcpy(h->pass, value, len);
365 	h->pass_len = len;
366 	memset(h->pass + len, 0, pad_len);
367 	return 0;
368 }
369 
370 static int
371 put_raw_attr(struct rad_handle *h, int type, const void *value, size_t len)
372 {
373 	if (len > 253) {
374 		generr(h, "Attribute too long");
375 		return -1;
376 	}
377 	if (h->out_len + 2 + len > MSGSIZE) {
378 		generr(h, "Maximum message length exceeded");
379 		return -1;
380 	}
381 	h->out[h->out_len++] = type;
382 	h->out[h->out_len++] = len + 2;
383 	memcpy(&h->out[h->out_len], value, len);
384 	h->out_len += len;
385 	return 0;
386 }
387 
388 int
389 rad_add_server(struct rad_handle *h, const char *host, int port,
390     const char *secret, int timeout, int tries)
391 {
392 	struct in_addr bindto;
393 	bindto.s_addr = INADDR_ANY;
394 
395 	return rad_add_server_ex(h, host, port, secret, timeout, tries,
396 		DEAD_TIME, &bindto);
397 }
398 
399 int
400 rad_add_server_ex(struct rad_handle *h, const char *host, int port,
401     const char *secret, int timeout, int tries, int dead_time,
402     struct in_addr *bindto)
403 {
404 	struct rad_server *srvp;
405 
406 	if (h->num_servers >= MAXSERVERS) {
407 		generr(h, "Too many RADIUS servers specified");
408 		return -1;
409 	}
410 	srvp = &h->servers[h->num_servers];
411 
412 	memset(&srvp->addr, 0, sizeof srvp->addr);
413 	srvp->addr.sin_len = sizeof srvp->addr;
414 	srvp->addr.sin_family = AF_INET;
415 	if (!inet_aton(host, &srvp->addr.sin_addr)) {
416 		struct hostent *hent;
417 
418 		if ((hent = gethostbyname(host)) == NULL) {
419 			generr(h, "%s: host not found", host);
420 			return -1;
421 		}
422 		memcpy(&srvp->addr.sin_addr, hent->h_addr,
423 		    sizeof srvp->addr.sin_addr);
424 	}
425 	if (port != 0)
426 		srvp->addr.sin_port = htons((u_short)port);
427 	else {
428 		struct servent *sent;
429 
430 		if (h->type == RADIUS_AUTH)
431 			srvp->addr.sin_port =
432 			    (sent = getservbyname("radius", "udp")) != NULL ?
433 				sent->s_port : htons(RADIUS_PORT);
434 		else
435 			srvp->addr.sin_port =
436 			    (sent = getservbyname("radacct", "udp")) != NULL ?
437 				sent->s_port : htons(RADACCT_PORT);
438 	}
439 	if ((srvp->secret = strdup(secret)) == NULL) {
440 		generr(h, "Out of memory");
441 		return -1;
442 	}
443 	srvp->timeout = timeout;
444 	srvp->max_tries = tries;
445 	srvp->num_tries = 0;
446 	srvp->is_dead = 0;
447 	srvp->dead_time = dead_time;
448 	srvp->next_probe = 0;
449 	srvp->bindto = bindto->s_addr;
450 	h->num_servers++;
451 	return 0;
452 }
453 
454 void
455 rad_close(struct rad_handle *h)
456 {
457 	int srv;
458 
459 	if (h->fd != -1)
460 		close(h->fd);
461 	for (srv = 0;  srv < h->num_servers;  srv++) {
462 		memset(h->servers[srv].secret, 0,
463 		    strlen(h->servers[srv].secret));
464 		free(h->servers[srv].secret);
465 	}
466 	clear_password(h);
467 	free(h);
468 }
469 
470 void
471 rad_bind_to(struct rad_handle *h, in_addr_t addr)
472 {
473 
474 	h->bindto = addr;
475 }
476 
477 int
478 rad_config(struct rad_handle *h, const char *path)
479 {
480 	FILE *fp;
481 	char buf[MAXCONFLINE];
482 	int linenum;
483 	int retval;
484 
485 	if (path == NULL)
486 		path = PATH_RADIUS_CONF;
487 	if ((fp = fopen(path, "r")) == NULL) {
488 		generr(h, "Cannot open \"%s\": %s", path, strerror(errno));
489 		return -1;
490 	}
491 	retval = 0;
492 	linenum = 0;
493 	while (fgets(buf, sizeof buf, fp) != NULL) {
494 		int len;
495 		const char *fields[MAX_FIELDS];
496 		int nfields;
497 		char msg[ERRSIZE];
498 		const char *type;
499 		const char *host;
500 		const char *port_str;
501 		const char *secret;
502 		const char *timeout_str;
503 		const char *maxtries_str;
504 		const char *dead_time_str;
505 		const char *bindto_str;
506 		char *res, *host_dup;
507 		char *end;
508 		const char *wanttype;
509 		unsigned long timeout;
510 		unsigned long maxtries;
511 		unsigned long dead_time;
512 		int port;
513 		struct in_addr bindto;
514 		int i;
515 
516 		linenum++;
517 		len = strlen(buf);
518 		/* We know len > 0, else fgets would have returned NULL. */
519 		if (buf[len - 1] != '\n') {
520 			if (len == sizeof buf - 1)
521 				generr(h, "%s:%d: line too long", path,
522 				    linenum);
523 			else
524 				generr(h, "%s:%d: missing newline", path,
525 				    linenum);
526 			retval = -1;
527 			break;
528 		}
529 		buf[len - 1] = '\0';
530 
531 		/* Extract the fields from the line. */
532 		nfields = split(buf, fields, MAX_FIELDS, msg, sizeof msg);
533 		if (nfields == -1) {
534 			generr(h, "%s:%d: %s", path, linenum, msg);
535 			retval = -1;
536 			break;
537 		}
538 		if (nfields == 0)
539 			continue;
540 		/*
541 		 * The first field should contain "auth" or "acct" for
542 		 * authentication or accounting, respectively.  But older
543 		 * versions of the file didn't have that field.  Default
544 		 * it to "auth" for backward compatibility.
545 		 */
546 		if (strcmp(fields[0], "auth") != 0 &&
547 		    strcmp(fields[0], "acct") != 0) {
548 			if (nfields >= MAX_FIELDS) {
549 				generr(h, "%s:%d: invalid service type", path,
550 				    linenum);
551 				retval = -1;
552 				break;
553 			}
554 			nfields++;
555 			for (i = nfields;  --i > 0;  )
556 				fields[i] = fields[i - 1];
557 			fields[0] = "auth";
558 		}
559 		if (nfields < 3) {
560 			generr(h, "%s:%d: missing shared secret", path,
561 			    linenum);
562 			retval = -1;
563 			break;
564 		}
565 		type = fields[0];
566 		host = fields[1];
567 		secret = fields[2];
568 		timeout_str = fields[3];
569 		maxtries_str = fields[4];
570 		dead_time_str = fields[5];
571 		bindto_str = fields[6];
572 
573 		/* Ignore the line if it is for the wrong service type. */
574 		wanttype = h->type == RADIUS_AUTH ? "auth" : "acct";
575 		if (strcmp(type, wanttype) != 0)
576 			continue;
577 
578 		/* Parse and validate the fields. */
579 		if ((host_dup = strdup(host)) == NULL) {
580 			generr(h, "%s:%d: malloc failed", path, linenum);
581 			retval = -1;
582 			break;
583 		}
584 		res = host_dup;
585 		host = strsep(&res, ":");
586 		port_str = strsep(&res, ":");
587 		if (port_str != NULL) {
588 			port = strtoul(port_str, &end, 10);
589 			if (*end != '\0') {
590 				free(host_dup);
591 				generr(h, "%s:%d: invalid port", path,
592 				    linenum);
593 				retval = -1;
594 				break;
595 			}
596 		} else
597 			port = 0;
598 		if (timeout_str != NULL) {
599 			timeout = strtoul(timeout_str, &end, 10);
600 			if (*end != '\0') {
601 				free(host_dup);
602 				generr(h, "%s:%d: invalid timeout", path,
603 				    linenum);
604 				retval = -1;
605 				break;
606 			}
607 		} else
608 			timeout = TIMEOUT;
609 		if (maxtries_str != NULL) {
610 			maxtries = strtoul(maxtries_str, &end, 10);
611 			if (*end != '\0') {
612 				free(host_dup);
613 				generr(h, "%s:%d: invalid maxtries", path,
614 				    linenum);
615 				retval = -1;
616 				break;
617 			}
618 		} else
619 			maxtries = MAXTRIES;
620 
621 		if (dead_time_str != NULL) {
622 			dead_time = strtoul(dead_time_str, &end, 10);
623 			if (*end != '\0') {
624 				free(host_dup);
625 				generr(h, "%s:%d: invalid dead_time", path,
626 				    linenum);
627 				retval = -1;
628 				break;
629 			}
630 		} else
631 			dead_time = DEAD_TIME;
632 
633 		if (bindto_str != NULL) {
634 			bindto.s_addr = inet_addr(bindto_str);
635 			if (bindto.s_addr == INADDR_NONE) {
636 				free(host_dup);
637 				generr(h, "%s:%d: invalid bindto", path,
638 				    linenum);
639 				retval = -1;
640 				break;
641 			}
642 		} else
643 			bindto.s_addr = INADDR_ANY;
644 
645 		if (rad_add_server_ex(h, host, port, secret, timeout, maxtries,
646 			    dead_time, &bindto) == -1) {
647 			free(host_dup);
648 			strcpy(msg, h->errmsg);
649 			generr(h, "%s:%d: %s", path, linenum, msg);
650 			retval = -1;
651 			break;
652 		}
653 		free(host_dup);
654 	}
655 	/* Clear out the buffer to wipe a possible copy of a shared secret */
656 	memset(buf, 0, sizeof buf);
657 	fclose(fp);
658 	return retval;
659 }
660 
661 /*
662  * rad_init_send_request() must have previously been called.
663  * Returns:
664  *   0     The application should select on *fd with a timeout of tv before
665  *         calling rad_continue_send_request again.
666  *   < 0   Failure
667  *   > 0   Success
668  */
669 int
670 rad_continue_send_request(struct rad_handle *h, int selected, int *fd,
671                           struct timeval *tv)
672 {
673 	int n, cur_srv;
674 	time_t now;
675 	struct sockaddr_in sin;
676 
677 	if (h->type == RADIUS_SERVER) {
678 		generr(h, "denied function call");
679 		return (-1);
680 	}
681 	if (selected) {
682 		struct sockaddr_in from;
683 		socklen_t fromlen;
684 
685 		fromlen = sizeof from;
686 		h->in_len = recvfrom(h->fd, h->in,
687 		    MSGSIZE, MSG_WAITALL, (struct sockaddr *)&from, &fromlen);
688 		if (h->in_len == -1) {
689 			generr(h, "recvfrom: %s", strerror(errno));
690 			return -1;
691 		}
692 		if (is_valid_response(h, h->srv, &from)) {
693 			h->in_len = h->in[POS_LENGTH] << 8 |
694 			    h->in[POS_LENGTH+1];
695 			h->in_pos = POS_ATTRS;
696 			return h->in[POS_CODE];
697 		}
698 	}
699 
700 	/*
701          * Scan round-robin to the next server that has some
702          * tries left.  There is guaranteed to be one, or we
703          * would have exited this loop by now.
704 	 */
705 	cur_srv = h->srv;
706 	now = time(NULL);
707 	if (h->servers[h->srv].num_tries >= h->servers[h->srv].max_tries) {
708 		/* Set next probe time for this server */
709 		if (h->servers[h->srv].dead_time) {
710 			h->servers[h->srv].is_dead = 1;
711 			h->servers[h->srv].next_probe = now +
712 			h->servers[h->srv].dead_time;
713 		}
714 		do {
715 			h->srv++;
716 			if (h->srv >= h->num_servers)
717 				h->srv = 0;
718 			if (h->servers[h->srv].is_dead == 0)
719 				break;
720 			if (h->servers[h->srv].dead_time &&
721 				h->servers[h->srv].next_probe <= now) {
722 				h->servers[h->srv].is_dead = 0;
723 				h->servers[h->srv].num_tries = 0;
724 				break;
725 			}
726 		} while (h->srv != cur_srv);
727 
728 		if (h->srv == cur_srv) {
729 			generr(h, "No valid RADIUS responses received");
730 			return (-1);
731 		}
732 	}
733 
734 	/* Rebind */
735 	if (h->bindto != h->servers[h->srv].bindto) {
736 		h->bindto = h->servers[h->srv].bindto;
737 		close(h->fd);
738 		if ((h->fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
739 			generr(h, "Cannot create socket: %s", strerror(errno));
740 			return -1;
741 		}
742 		memset(&sin, 0, sizeof sin);
743 		sin.sin_len = sizeof sin;
744 		sin.sin_family = AF_INET;
745 		sin.sin_addr.s_addr = h->bindto;
746 		sin.sin_port = 0;
747 		if (bind(h->fd, (const struct sockaddr *)&sin,
748 		    sizeof sin) == -1) {
749 			generr(h, "bind: %s", strerror(errno));
750 			close(h->fd);
751 			h->fd = -1;
752 			return (-1);
753 		}
754 	}
755 
756 	if (h->out[POS_CODE] == RAD_ACCESS_REQUEST) {
757 		/* Insert the scrambled password into the request */
758 		if (h->pass_pos != 0)
759 			insert_scrambled_password(h, h->srv);
760 	}
761 	insert_message_authenticator(h, 0);
762 
763 	if (h->out[POS_CODE] != RAD_ACCESS_REQUEST) {
764 		/* Insert the request authenticator into the request */
765 		memset(&h->out[POS_AUTH], 0, LEN_AUTH);
766 		insert_request_authenticator(h, 0);
767 	}
768 
769 	/* Send the request */
770 	n = sendto(h->fd, h->out, h->out_len, 0,
771 	    (const struct sockaddr *)&h->servers[h->srv].addr,
772 	    sizeof h->servers[h->srv].addr);
773 	if (n != h->out_len)
774 		tv->tv_sec = 1; /* Do not wait full timeout if send failed. */
775 	else
776 		tv->tv_sec = h->servers[h->srv].timeout;
777 	h->servers[h->srv].num_tries++;
778 	tv->tv_usec = 0;
779 	*fd = h->fd;
780 
781 	return 0;
782 }
783 
784 int
785 rad_receive_request(struct rad_handle *h)
786 {
787 	struct sockaddr_in from;
788 	socklen_t fromlen;
789 	int n;
790 
791 	if (h->type != RADIUS_SERVER) {
792 		generr(h, "denied function call");
793 		return (-1);
794 	}
795 	h->srv = -1;
796 	fromlen = sizeof(from);
797 	h->in_len = recvfrom(h->fd, h->in,
798 	    MSGSIZE, MSG_WAITALL, (struct sockaddr *)&from, &fromlen);
799 	if (h->in_len == -1) {
800 		generr(h, "recvfrom: %s", strerror(errno));
801 		return (-1);
802 	}
803 	for (n = 0; n < h->num_servers; n++) {
804 		if (h->servers[n].addr.sin_addr.s_addr == from.sin_addr.s_addr) {
805 			h->servers[n].addr.sin_port = from.sin_port;
806 			h->srv = n;
807 			break;
808 		}
809 	}
810 	if (h->srv == -1)
811 		return (-2);
812 	if (is_valid_request(h)) {
813 		h->in_len = h->in[POS_LENGTH] << 8 |
814 		    h->in[POS_LENGTH+1];
815 		h->in_pos = POS_ATTRS;
816 		return (h->in[POS_CODE]);
817 	}
818 	return (-3);
819 }
820 
821 int
822 rad_send_response(struct rad_handle *h)
823 {
824 	int n;
825 
826 	if (h->type != RADIUS_SERVER) {
827 		generr(h, "denied function call");
828 		return (-1);
829 	}
830 	/* Fill in the length field in the message */
831 	h->out[POS_LENGTH] = h->out_len >> 8;
832 	h->out[POS_LENGTH+1] = h->out_len;
833 
834 	insert_message_authenticator(h,
835 	    (h->in[POS_CODE] == RAD_ACCESS_REQUEST) ? 1 : 0);
836 	insert_request_authenticator(h, 1);
837 
838 	/* Send the request */
839 	n = sendto(h->fd, h->out, h->out_len, 0,
840 	    (const struct sockaddr *)&h->servers[h->srv].addr,
841 	    sizeof h->servers[h->srv].addr);
842 	if (n != h->out_len) {
843 		if (n == -1)
844 			generr(h, "sendto: %s", strerror(errno));
845 		else
846 			generr(h, "sendto: short write");
847 		return -1;
848 	}
849 
850 	return 0;
851 }
852 
853 int
854 rad_create_request(struct rad_handle *h, int code)
855 {
856 	int i;
857 
858 	if (h->type == RADIUS_SERVER) {
859 		generr(h, "denied function call");
860 		return (-1);
861 	}
862 	if (h->num_servers == 0) {
863 		generr(h, "No RADIUS servers specified");
864 		return (-1);
865 	}
866 	h->out[POS_CODE] = code;
867 	h->out[POS_IDENT] = ++h->ident;
868 	if (code == RAD_ACCESS_REQUEST) {
869 		/* Create a random authenticator */
870 		for (i = 0;  i < LEN_AUTH;  i += 2) {
871 			long r;
872 			r = random();
873 			h->out[POS_AUTH+i] = (u_char)r;
874 			h->out[POS_AUTH+i+1] = (u_char)(r >> 8);
875 		}
876 	} else
877 		memset(&h->out[POS_AUTH], 0, LEN_AUTH);
878 	h->out_len = POS_ATTRS;
879 	clear_password(h);
880 	h->authentic_pos = 0;
881 	h->out_created = 1;
882 	return 0;
883 }
884 
885 int
886 rad_create_response(struct rad_handle *h, int code)
887 {
888 
889 	if (h->type != RADIUS_SERVER) {
890 		generr(h, "denied function call");
891 		return (-1);
892 	}
893 	h->out[POS_CODE] = code;
894 	h->out[POS_IDENT] = h->in[POS_IDENT];
895 	memset(&h->out[POS_AUTH], 0, LEN_AUTH);
896 	h->out_len = POS_ATTRS;
897 	clear_password(h);
898 	h->authentic_pos = 0;
899 	h->out_created = 1;
900 	return 0;
901 }
902 
903 struct in_addr
904 rad_cvt_addr(const void *data)
905 {
906 	struct in_addr value;
907 
908 	memcpy(&value.s_addr, data, sizeof value.s_addr);
909 	return value;
910 }
911 
912 struct in6_addr
913 rad_cvt_addr6(const void *data)
914 {
915 	struct in6_addr value;
916 
917 	memcpy(&value.s6_addr, data, sizeof value.s6_addr);
918 	return value;
919 }
920 
921 u_int32_t
922 rad_cvt_int(const void *data)
923 {
924 	u_int32_t value;
925 
926 	memcpy(&value, data, sizeof value);
927 	return ntohl(value);
928 }
929 
930 char *
931 rad_cvt_string(const void *data, size_t len)
932 {
933 	char *s;
934 
935 	s = malloc(len + 1);
936 	if (s != NULL) {
937 		memcpy(s, data, len);
938 		s[len] = '\0';
939 	}
940 	return s;
941 }
942 
943 /*
944  * Returns the attribute type.  If none are left, returns 0.  On failure,
945  * returns -1.
946  */
947 int
948 rad_get_attr(struct rad_handle *h, const void **value, size_t *len)
949 {
950 	int type;
951 
952 	if (h->in_pos >= h->in_len)
953 		return 0;
954 	if (h->in_pos + 2 > h->in_len) {
955 		generr(h, "Malformed attribute in response");
956 		return -1;
957 	}
958 	type = h->in[h->in_pos++];
959 	*len = h->in[h->in_pos++] - 2;
960 	if (h->in_pos + (int)*len > h->in_len) {
961 		generr(h, "Malformed attribute in response");
962 		return -1;
963 	}
964 	*value = &h->in[h->in_pos];
965 	h->in_pos += *len;
966 	return type;
967 }
968 
969 /*
970  * Returns -1 on error, 0 to indicate no event and >0 for success
971  */
972 int
973 rad_init_send_request(struct rad_handle *h, int *fd, struct timeval *tv)
974 {
975 	int srv;
976 	time_t now;
977 	struct sockaddr_in sin;
978 
979 	if (h->type == RADIUS_SERVER) {
980 		generr(h, "denied function call");
981 		return (-1);
982 	}
983 	/* Make sure we have a socket to use */
984 	if (h->fd == -1) {
985 		if ((h->fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
986 			generr(h, "Cannot create socket: %s", strerror(errno));
987 			return -1;
988 		}
989 		memset(&sin, 0, sizeof sin);
990 		sin.sin_len = sizeof sin;
991 		sin.sin_family = AF_INET;
992 		sin.sin_addr.s_addr = h->bindto;
993 		sin.sin_port = htons(0);
994 		if (bind(h->fd, (const struct sockaddr *)&sin,
995 		    sizeof sin) == -1) {
996 			generr(h, "bind: %s", strerror(errno));
997 			close(h->fd);
998 			h->fd = -1;
999 			return -1;
1000 		}
1001 	}
1002 
1003 	if (h->out[POS_CODE] != RAD_ACCESS_REQUEST) {
1004 		/* Make sure no password given */
1005 		if (h->pass_pos || h->chap_pass) {
1006 			generr(h, "User or Chap Password"
1007 			    " in accounting request");
1008 			return -1;
1009 		}
1010 	} else {
1011 		if (h->eap_msg == 0) {
1012 			/* Make sure the user gave us a password */
1013 			if (h->pass_pos == 0 && !h->chap_pass) {
1014 				generr(h, "No User or Chap Password"
1015 				    " attributes given");
1016 				return -1;
1017 			}
1018 			if (h->pass_pos != 0 && h->chap_pass) {
1019 				generr(h, "Both User and Chap Password"
1020 				    " attributes given");
1021 				return -1;
1022 			}
1023 		}
1024 	}
1025 
1026 	/* Fill in the length field in the message */
1027 	h->out[POS_LENGTH] = h->out_len >> 8;
1028 	h->out[POS_LENGTH+1] = h->out_len;
1029 
1030 	h->srv = 0;
1031 	now = time(NULL);
1032 	for (srv = 0;  srv < h->num_servers;  srv++)
1033 		h->servers[srv].num_tries = 0;
1034 	/* Find a first good server. */
1035 	for (srv = 0;  srv < h->num_servers;  srv++) {
1036 		if (h->servers[srv].is_dead == 0)
1037 			break;
1038 		if (h->servers[srv].dead_time &&
1039 			h->servers[srv].next_probe <= now) {
1040 			h->servers[srv].is_dead = 0;
1041 			break;
1042 		}
1043 		h->srv++;
1044 	}
1045 
1046 	/* If all servers was dead on the last probe, try from beginning */
1047 	if (h->srv == h->num_servers) {
1048 		for (srv = 0;  srv < h->num_servers;  srv++) {
1049 			h->servers[srv].is_dead = 0;
1050 			h->servers[srv].next_probe = 0;
1051 		}
1052 		h->srv = 0;
1053 	}
1054 
1055 	return rad_continue_send_request(h, 0, fd, tv);
1056 }
1057 
1058 /*
1059  * Create and initialize a rad_handle structure, and return it to the
1060  * caller.  Can fail only if the necessary memory cannot be allocated.
1061  * In that case, it returns NULL.
1062  */
1063 struct rad_handle *
1064 rad_auth_open(void)
1065 {
1066 	struct rad_handle *h;
1067 
1068 	h = (struct rad_handle *)malloc(sizeof(struct rad_handle));
1069 	if (h != NULL) {
1070 		srandomdev();
1071 		h->fd = -1;
1072 		h->num_servers = 0;
1073 		h->ident = random();
1074 		h->errmsg[0] = '\0';
1075 		memset(h->pass, 0, sizeof h->pass);
1076 		h->pass_len = 0;
1077 		h->pass_pos = 0;
1078 		h->chap_pass = 0;
1079 		h->authentic_pos = 0;
1080 		h->type = RADIUS_AUTH;
1081 		h->out_created = 0;
1082 		h->eap_msg = 0;
1083 		h->bindto = INADDR_ANY;
1084 	}
1085 	return h;
1086 }
1087 
1088 struct rad_handle *
1089 rad_acct_open(void)
1090 {
1091 	struct rad_handle *h;
1092 
1093 	h = rad_open();
1094 	if (h != NULL)
1095 	        h->type = RADIUS_ACCT;
1096 	return h;
1097 }
1098 
1099 struct rad_handle *
1100 rad_server_open(int fd)
1101 {
1102 	struct rad_handle *h;
1103 
1104 	h = rad_open();
1105 	if (h != NULL) {
1106 	        h->type = RADIUS_SERVER;
1107 	        h->fd = fd;
1108 	}
1109 	return h;
1110 }
1111 
1112 struct rad_handle *
1113 rad_open(void)
1114 {
1115     return rad_auth_open();
1116 }
1117 
1118 int
1119 rad_put_addr(struct rad_handle *h, int type, struct in_addr addr)
1120 {
1121 	return rad_put_attr(h, type, &addr.s_addr, sizeof addr.s_addr);
1122 }
1123 
1124 int
1125 rad_put_addr6(struct rad_handle *h, int type, struct in6_addr addr)
1126 {
1127 
1128 	return rad_put_attr(h, type, &addr.s6_addr, sizeof addr.s6_addr);
1129 }
1130 
1131 int
1132 rad_put_attr(struct rad_handle *h, int type, const void *value, size_t len)
1133 {
1134 	int result;
1135 
1136 	if (!h->out_created) {
1137 		generr(h, "Please call rad_create_request()"
1138 		    " before putting attributes");
1139 		return -1;
1140 	}
1141 
1142 	if (h->out[POS_CODE] == RAD_ACCOUNTING_REQUEST) {
1143 		if (type == RAD_EAP_MESSAGE) {
1144 			generr(h, "EAP-Message attribute is not valid"
1145 			    " in accounting requests");
1146 			return -1;
1147 		}
1148 	}
1149 
1150 	/*
1151 	 * When proxying EAP Messages, the Message Authenticator
1152 	 * MUST be present; see RFC 3579.
1153 	 */
1154 	if (type == RAD_EAP_MESSAGE) {
1155 		if (rad_put_message_authentic(h) == -1)
1156 			return -1;
1157 	}
1158 
1159 	if (type == RAD_USER_PASSWORD) {
1160 		result = put_password_attr(h, type, value, len);
1161 	} else if (type == RAD_MESSAGE_AUTHENTIC) {
1162 		result = rad_put_message_authentic(h);
1163 	} else {
1164 		result = put_raw_attr(h, type, value, len);
1165 		if (result == 0) {
1166 			if (type == RAD_CHAP_PASSWORD)
1167 				h->chap_pass = 1;
1168 			else if (type == RAD_EAP_MESSAGE)
1169 				h->eap_msg = 1;
1170 		}
1171 	}
1172 
1173 	return result;
1174 }
1175 
1176 int
1177 rad_put_int(struct rad_handle *h, int type, u_int32_t value)
1178 {
1179 	u_int32_t nvalue;
1180 
1181 	nvalue = htonl(value);
1182 	return rad_put_attr(h, type, &nvalue, sizeof nvalue);
1183 }
1184 
1185 int
1186 rad_put_string(struct rad_handle *h, int type, const char *str)
1187 {
1188 	return rad_put_attr(h, type, str, strlen(str));
1189 }
1190 
1191 int
1192 rad_put_message_authentic(struct rad_handle *h)
1193 {
1194 #ifdef WITH_SSL
1195 	u_char md_zero[MD5_DIGEST_LENGTH];
1196 
1197 	if (h->out[POS_CODE] == RAD_ACCOUNTING_REQUEST) {
1198 		generr(h, "Message-Authenticator is not valid"
1199 		    " in accounting requests");
1200 		return -1;
1201 	}
1202 
1203 	if (h->authentic_pos == 0) {
1204 		h->authentic_pos = h->out_len;
1205 		memset(md_zero, 0, sizeof(md_zero));
1206 		return (put_raw_attr(h, RAD_MESSAGE_AUTHENTIC, md_zero,
1207 		    sizeof(md_zero)));
1208 	}
1209 	return 0;
1210 #else
1211 	generr(h, "Message Authenticator not supported,"
1212 	    " please recompile libradius with SSL support");
1213 	return -1;
1214 #endif
1215 }
1216 
1217 /*
1218  * Returns the response type code on success, or -1 on failure.
1219  */
1220 int
1221 rad_send_request(struct rad_handle *h)
1222 {
1223 	struct timeval timelimit;
1224 	struct timeval tv;
1225 	int fd;
1226 	int n;
1227 
1228 	n = rad_init_send_request(h, &fd, &tv);
1229 
1230 	if (n != 0)
1231 		return n;
1232 
1233 	gettimeofday(&timelimit, NULL);
1234 	timeradd(&tv, &timelimit, &timelimit);
1235 
1236 	for ( ; ; ) {
1237 		fd_set readfds;
1238 
1239 		FD_ZERO(&readfds);
1240 		FD_SET(fd, &readfds);
1241 
1242 		n = select(fd + 1, &readfds, NULL, NULL, &tv);
1243 
1244 		if (n == -1) {
1245 			generr(h, "select: %s", strerror(errno));
1246 			return -1;
1247 		}
1248 
1249 		if (!FD_ISSET(fd, &readfds)) {
1250 			/* Compute a new timeout */
1251 			gettimeofday(&tv, NULL);
1252 			timersub(&timelimit, &tv, &tv);
1253 			if (tv.tv_sec > 0 || (tv.tv_sec == 0 && tv.tv_usec > 0))
1254 				/* Continue the select */
1255 				continue;
1256 		}
1257 
1258 		n = rad_continue_send_request(h, n, &fd, &tv);
1259 
1260 		if (n != 0)
1261 			return n;
1262 
1263 		gettimeofday(&timelimit, NULL);
1264 		timeradd(&tv, &timelimit, &timelimit);
1265 	}
1266 }
1267 
1268 const char *
1269 rad_strerror(struct rad_handle *h)
1270 {
1271 	return h->errmsg;
1272 }
1273 
1274 /*
1275  * Destructively split a string into fields separated by white space.
1276  * `#' at the beginning of a field begins a comment that extends to the
1277  * end of the string.  Fields may be quoted with `"'.  Inside quoted
1278  * strings, the backslash escapes `\"' and `\\' are honored.
1279  *
1280  * Pointers to up to the first maxfields fields are stored in the fields
1281  * array.  Missing fields get NULL pointers.
1282  *
1283  * The return value is the actual number of fields parsed, and is always
1284  * <= maxfields.
1285  *
1286  * On a syntax error, places a message in the msg string, and returns -1.
1287  */
1288 static int
1289 split(char *str, const char *fields[], int maxfields, char *msg, size_t msglen)
1290 {
1291 	char *p;
1292 	int i;
1293 	static const char ws[] = " \t";
1294 
1295 	for (i = 0;  i < maxfields;  i++)
1296 		fields[i] = NULL;
1297 	p = str;
1298 	i = 0;
1299 	while (*p != '\0') {
1300 		p += strspn(p, ws);
1301 		if (*p == '#' || *p == '\0')
1302 			break;
1303 		if (i >= maxfields) {
1304 			snprintf(msg, msglen, "line has too many fields");
1305 			return -1;
1306 		}
1307 		if (*p == '"') {
1308 			char *dst;
1309 
1310 			dst = ++p;
1311 			fields[i] = dst;
1312 			while (*p != '"') {
1313 				if (*p == '\\') {
1314 					p++;
1315 					if (*p != '"' && *p != '\\' &&
1316 					    *p != '\0') {
1317 						snprintf(msg, msglen,
1318 						    "invalid `\\' escape");
1319 						return -1;
1320 					}
1321 				}
1322 				if (*p == '\0') {
1323 					snprintf(msg, msglen,
1324 					    "unterminated quoted string");
1325 					return -1;
1326 				}
1327 				*dst++ = *p++;
1328 			}
1329 			*dst = '\0';
1330 			p++;
1331 			if (*fields[i] == '\0') {
1332 				snprintf(msg, msglen,
1333 				    "empty quoted string not permitted");
1334 				return -1;
1335 			}
1336 			if (*p != '\0' && strspn(p, ws) == 0) {
1337 				snprintf(msg, msglen, "quoted string not"
1338 				    " followed by white space");
1339 				return -1;
1340 			}
1341 		} else {
1342 			fields[i] = p;
1343 			p += strcspn(p, ws);
1344 			if (*p != '\0')
1345 				*p++ = '\0';
1346 		}
1347 		i++;
1348 	}
1349 	return i;
1350 }
1351 
1352 int
1353 rad_get_vendor_attr(u_int32_t *vendor, const void **data, size_t *len)
1354 {
1355 	const struct vendor_attribute *attr;
1356 
1357 	attr = (const struct vendor_attribute *)*data;
1358 	*vendor = ntohl(attr->vendor_value);
1359 	*data = attr->attrib_data;
1360 	*len = attr->attrib_len - 2;
1361 
1362 	return (attr->attrib_type);
1363 }
1364 
1365 int
1366 rad_put_vendor_addr(struct rad_handle *h, int vendor, int type,
1367     struct in_addr addr)
1368 {
1369 	return (rad_put_vendor_attr(h, vendor, type, &addr.s_addr,
1370 	    sizeof addr.s_addr));
1371 }
1372 
1373 int
1374 rad_put_vendor_addr6(struct rad_handle *h, int vendor, int type,
1375     struct in6_addr addr)
1376 {
1377 
1378 	return (rad_put_vendor_attr(h, vendor, type, &addr.s6_addr,
1379 	    sizeof addr.s6_addr));
1380 }
1381 
1382 int
1383 rad_put_vendor_attr(struct rad_handle *h, int vendor, int type,
1384     const void *value, size_t len)
1385 {
1386 	struct vendor_attribute *attr;
1387 	int res;
1388 
1389 	if (!h->out_created) {
1390 		generr(h, "Please call rad_create_request()"
1391 		    " before putting attributes");
1392 		return -1;
1393 	}
1394 
1395 	if ((attr = malloc(len + 6)) == NULL) {
1396 		generr(h, "malloc failure (%zu bytes)", len + 6);
1397 		return -1;
1398 	}
1399 
1400 	attr->vendor_value = htonl(vendor);
1401 	attr->attrib_type = type;
1402 	attr->attrib_len = len + 2;
1403 	memcpy(attr->attrib_data, value, len);
1404 
1405 	res = put_raw_attr(h, RAD_VENDOR_SPECIFIC, attr, len + 6);
1406 	free(attr);
1407 	if (res == 0 && vendor == RAD_VENDOR_MICROSOFT
1408 	    && (type == RAD_MICROSOFT_MS_CHAP_RESPONSE
1409 	    || type == RAD_MICROSOFT_MS_CHAP2_RESPONSE)) {
1410 		h->chap_pass = 1;
1411 	}
1412 	return (res);
1413 }
1414 
1415 int
1416 rad_put_vendor_int(struct rad_handle *h, int vendor, int type, u_int32_t i)
1417 {
1418 	u_int32_t value;
1419 
1420 	value = htonl(i);
1421 	return (rad_put_vendor_attr(h, vendor, type, &value, sizeof value));
1422 }
1423 
1424 int
1425 rad_put_vendor_string(struct rad_handle *h, int vendor, int type,
1426     const char *str)
1427 {
1428 	return (rad_put_vendor_attr(h, vendor, type, str, strlen(str)));
1429 }
1430 
1431 ssize_t
1432 rad_request_authenticator(struct rad_handle *h, char *buf, size_t len)
1433 {
1434 	if (len < LEN_AUTH)
1435 		return (-1);
1436 	memcpy(buf, h->out + POS_AUTH, LEN_AUTH);
1437 	if (len > LEN_AUTH)
1438 		buf[LEN_AUTH] = '\0';
1439 	return (LEN_AUTH);
1440 }
1441 
1442 u_char *
1443 rad_demangle(struct rad_handle *h, const void *mangled, size_t mlen)
1444 {
1445 	char R[LEN_AUTH];
1446 	const char *S;
1447 	int i, Ppos;
1448 	MD5_CTX Context;
1449 	u_char b[MD5_DIGEST_LENGTH], *demangled;
1450 	const u_char *C;
1451 
1452 	if ((mlen % 16 != 0) || mlen > 128) {
1453 		generr(h, "Cannot interpret mangled data of length %lu",
1454 		    (u_long)mlen);
1455 		return NULL;
1456 	}
1457 
1458 	C = mangled;
1459 
1460 	/* We need the shared secret as Salt */
1461 	S = rad_server_secret(h);
1462 
1463 	/* We need the request authenticator */
1464 	if (rad_request_authenticator(h, R, sizeof R) != LEN_AUTH) {
1465 		generr(h, "Cannot obtain the RADIUS request authenticator");
1466 		return NULL;
1467 	}
1468 
1469 	demangled = malloc(mlen);
1470 	if (!demangled)
1471 		return NULL;
1472 
1473 	MD5Init(&Context);
1474 	MD5Update(&Context, S, strlen(S));
1475 	MD5Update(&Context, R, LEN_AUTH);
1476 	MD5Final(b, &Context);
1477 	Ppos = 0;
1478 	while (mlen) {
1479 
1480 		mlen -= 16;
1481 		for (i = 0; i < 16; i++)
1482 			demangled[Ppos++] = C[i] ^ b[i];
1483 
1484 		if (mlen) {
1485 			MD5Init(&Context);
1486 			MD5Update(&Context, S, strlen(S));
1487 			MD5Update(&Context, C, 16);
1488 			MD5Final(b, &Context);
1489 		}
1490 
1491 		C += 16;
1492 	}
1493 
1494 	return demangled;
1495 }
1496 
1497 u_char *
1498 rad_demangle_mppe_key(struct rad_handle *h, const void *mangled,
1499     size_t mlen, size_t *len)
1500 {
1501 	char R[LEN_AUTH];    /* variable names as per rfc2548 */
1502 	const char *S;
1503 	u_char b[MD5_DIGEST_LENGTH], *demangled;
1504 	const u_char *A, *C;
1505 	MD5_CTX Context;
1506 	int Slen, i, Clen, Ppos;
1507 	u_char *P;
1508 
1509 	if (mlen % 16 != SALT_LEN) {
1510 		generr(h, "Cannot interpret mangled data of length %lu",
1511 		    (u_long)mlen);
1512 		return NULL;
1513 	}
1514 
1515 	/* We need the RADIUS Request-Authenticator */
1516 	if (rad_request_authenticator(h, R, sizeof R) != LEN_AUTH) {
1517 		generr(h, "Cannot obtain the RADIUS request authenticator");
1518 		return NULL;
1519 	}
1520 
1521 	A = (const u_char *)mangled;      /* Salt comes first */
1522 	C = (const u_char *)mangled + SALT_LEN;  /* Then the ciphertext */
1523 	Clen = mlen - SALT_LEN;
1524 	S = rad_server_secret(h);    /* We need the RADIUS secret */
1525 	Slen = strlen(S);
1526 	P = alloca(Clen);        /* We derive our plaintext */
1527 
1528 	MD5Init(&Context);
1529 	MD5Update(&Context, S, Slen);
1530 	MD5Update(&Context, R, LEN_AUTH);
1531 	MD5Update(&Context, A, SALT_LEN);
1532 	MD5Final(b, &Context);
1533 	Ppos = 0;
1534 
1535 	while (Clen) {
1536 		Clen -= 16;
1537 
1538 		for (i = 0; i < 16; i++)
1539 		    P[Ppos++] = C[i] ^ b[i];
1540 
1541 		if (Clen) {
1542 			MD5Init(&Context);
1543 			MD5Update(&Context, S, Slen);
1544 			MD5Update(&Context, C, 16);
1545 			MD5Final(b, &Context);
1546 		}
1547 
1548 		C += 16;
1549 	}
1550 
1551 	/*
1552 	* The resulting plain text consists of a one-byte length, the text and
1553 	* maybe some padding.
1554 	*/
1555 	*len = *P;
1556 	if (*len > mlen - 1) {
1557 		generr(h, "Mangled data seems to be garbage %zu %zu",
1558 		    *len, mlen-1);
1559 		return NULL;
1560 	}
1561 
1562 	if (*len > MPPE_KEY_LEN * 2) {
1563 		generr(h, "Key to long (%zu) for me max. %d",
1564 		    *len, MPPE_KEY_LEN * 2);
1565 		return NULL;
1566 	}
1567 	demangled = malloc(*len);
1568 	if (!demangled)
1569 		return NULL;
1570 
1571 	memcpy(demangled, P + 1, *len);
1572 	return demangled;
1573 }
1574 
1575 const char *
1576 rad_server_secret(struct rad_handle *h)
1577 {
1578 	return (h->servers[h->srv].secret);
1579 }
1580