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