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