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