2 * Copyright 1998 Juniper Networks, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
26 * $FreeBSD: src/lib/libradius/radlib.c,v 1.4.2.3 2002/06/17 02:24:57 brian Exp $
27 * $DragonFly: src/lib/libradius/radlib.c,v 1.3 2004/08/19 21:25:58 joerg Exp $
30 #include <sys/param.h>
31 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
46 #include "radlib_private.h"
48 static void clear_password(struct rad_handle *);
49 static void generr(struct rad_handle *, const char *, ...)
51 static void insert_scrambled_password(struct rad_handle *, int);
52 static void insert_request_authenticator(struct rad_handle *, int);
53 static int is_valid_response(struct rad_handle *, int,
54 const struct sockaddr_in *);
55 static int put_password_attr(struct rad_handle *, int,
56 const void *, size_t);
57 static int put_raw_attr(struct rad_handle *, int,
58 const void *, size_t);
59 static int split(char *, char *[], int, char *, size_t);
62 clear_password(struct rad_handle *h)
64 if (h->pass_len != 0) {
65 memset(h->pass, 0, h->pass_len);
72 generr(struct rad_handle *h, const char *format, ...)
77 vsnprintf(h->errmsg, ERRSIZE, format, ap);
82 insert_scrambled_password(struct rad_handle *h, int srv)
85 unsigned char md5[16];
86 const struct rad_server *srvp;
90 srvp = &h->servers[srv];
91 padded_len = h->pass_len == 0 ? 16 : (h->pass_len+15) & ~0xf;
93 memcpy(md5, &h->request[POS_AUTH], LEN_AUTH);
94 for (pos = 0; pos < padded_len; pos += 16) {
97 /* Calculate the new scrambler */
99 MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
100 MD5Update(&ctx, md5, 16);
104 * Mix in the current chunk of the password, and copy
105 * the result into the right place in the request. Also
106 * modify the scrambler in place, since we will use this
107 * in calculating the scrambler for next time.
109 for (i = 0; i < 16; i++)
110 h->request[h->pass_pos + pos + i] =
111 md5[i] ^= h->pass[pos + i];
116 insert_request_authenticator(struct rad_handle *h, int srv)
119 const struct rad_server *srvp;
121 srvp = &h->servers[srv];
123 /* Create the request authenticator */
125 MD5Update(&ctx, &h->request[POS_CODE], POS_AUTH - POS_CODE);
126 MD5Update(&ctx, memset(&h->request[POS_AUTH], 0, LEN_AUTH), LEN_AUTH);
127 MD5Update(&ctx, &h->request[POS_ATTRS], h->req_len - POS_ATTRS);
128 MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
129 MD5Final(&h->request[POS_AUTH], &ctx);
133 * Return true if the current response is valid for a request to the
137 is_valid_response(struct rad_handle *h, int srv,
138 const struct sockaddr_in *from)
141 unsigned char md5[16];
142 const struct rad_server *srvp;
145 srvp = &h->servers[srv];
147 /* Check the source address */
148 if (from->sin_family != srvp->addr.sin_family ||
149 from->sin_addr.s_addr != srvp->addr.sin_addr.s_addr ||
150 from->sin_port != srvp->addr.sin_port)
153 /* Check the message length */
154 if (h->resp_len < POS_ATTRS)
156 len = h->response[POS_LENGTH] << 8 | h->response[POS_LENGTH+1];
157 if (len > h->resp_len)
160 /* Check the response authenticator */
162 MD5Update(&ctx, &h->response[POS_CODE], POS_AUTH - POS_CODE);
163 MD5Update(&ctx, &h->request[POS_AUTH], LEN_AUTH);
164 MD5Update(&ctx, &h->response[POS_ATTRS], len - POS_ATTRS);
165 MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
167 if (memcmp(&h->response[POS_AUTH], md5, sizeof md5) != 0)
174 put_password_attr(struct rad_handle *h, int type, const void *value, size_t len)
179 if (h->pass_pos != 0) {
180 generr(h, "Multiple User-Password attributes specified");
185 padded_len = len == 0 ? 16 : (len+15) & ~0xf;
186 pad_len = padded_len - len;
189 * Put in a place-holder attribute containing all zeros, and
190 * remember where it is so we can fill it in later.
193 put_raw_attr(h, type, h->pass, padded_len);
194 h->pass_pos = h->req_len - padded_len;
196 /* Save the cleartext password, padded as necessary */
197 memcpy(h->pass, value, len);
199 memset(h->pass + len, 0, pad_len);
204 put_raw_attr(struct rad_handle *h, int type, const void *value, size_t len)
207 generr(h, "Attribute too long");
210 if (h->req_len + 2 + len > MSGSIZE) {
211 generr(h, "Maximum message length exceeded");
214 h->request[h->req_len++] = type;
215 h->request[h->req_len++] = len + 2;
216 memcpy(&h->request[h->req_len], value, len);
222 rad_add_server(struct rad_handle *h, const char *host, int port,
223 const char *secret, int timeout, int tries)
225 struct rad_server *srvp;
227 if (h->num_servers >= MAXSERVERS) {
228 generr(h, "Too many RADIUS servers specified");
231 srvp = &h->servers[h->num_servers];
233 memset(&srvp->addr, 0, sizeof srvp->addr);
234 srvp->addr.sin_len = sizeof srvp->addr;
235 srvp->addr.sin_family = AF_INET;
236 if (!inet_aton(host, &srvp->addr.sin_addr)) {
237 struct hostent *hent;
239 if ((hent = gethostbyname(host)) == NULL) {
240 generr(h, "%s: host not found", host);
243 memcpy(&srvp->addr.sin_addr, hent->h_addr,
244 sizeof srvp->addr.sin_addr);
247 srvp->addr.sin_port = htons(port);
249 struct servent *sent;
251 if (h->type == RADIUS_AUTH)
252 srvp->addr.sin_port =
253 (sent = getservbyname("radius", "udp")) != NULL ?
254 sent->s_port : htons(RADIUS_PORT);
256 srvp->addr.sin_port =
257 (sent = getservbyname("radacct", "udp")) != NULL ?
258 sent->s_port : htons(RADACCT_PORT);
260 if ((srvp->secret = strdup(secret)) == NULL) {
261 generr(h, "Out of memory");
264 srvp->timeout = timeout;
265 srvp->max_tries = tries;
272 rad_close(struct rad_handle *h)
278 for (srv = 0; srv < h->num_servers; srv++) {
279 memset(h->servers[srv].secret, 0,
280 strlen(h->servers[srv].secret));
281 free(h->servers[srv].secret);
288 rad_config(struct rad_handle *h, const char *path)
291 char buf[MAXCONFLINE];
296 path = PATH_RADIUS_CONF;
297 if ((fp = fopen(path, "r")) == NULL) {
298 generr(h, "Cannot open \"%s\": %s", path, strerror(errno));
303 while (fgets(buf, sizeof buf, fp) != NULL) {
316 unsigned long timeout;
317 unsigned long maxtries;
323 /* We know len > 0, else fgets would have returned NULL. */
324 if (buf[len - 1] != '\n') {
325 if (len == sizeof buf - 1)
326 generr(h, "%s:%d: line too long", path,
329 generr(h, "%s:%d: missing newline", path,
336 /* Extract the fields from the line. */
337 nfields = split(buf, fields, 5, msg, sizeof msg);
339 generr(h, "%s:%d: %s", path, linenum, msg);
346 * The first field should contain "auth" or "acct" for
347 * authentication or accounting, respectively. But older
348 * versions of the file didn't have that field. Default
349 * it to "auth" for backward compatibility.
351 if (strcmp(fields[0], "auth") != 0 &&
352 strcmp(fields[0], "acct") != 0) {
354 generr(h, "%s:%d: invalid service type", path,
360 for (i = nfields; --i > 0; )
361 fields[i] = fields[i - 1];
365 generr(h, "%s:%d: missing shared secret", path,
373 timeout_str = fields[3];
374 maxtries_str = fields[4];
376 /* Ignore the line if it is for the wrong service type. */
377 wanttype = h->type == RADIUS_AUTH ? "auth" : "acct";
378 if (strcmp(type, wanttype) != 0)
381 /* Parse and validate the fields. */
383 host = strsep(&res, ":");
384 port_str = strsep(&res, ":");
385 if (port_str != NULL) {
386 port = strtoul(port_str, &end, 10);
388 generr(h, "%s:%d: invalid port", path,
395 if (timeout_str != NULL) {
396 timeout = strtoul(timeout_str, &end, 10);
398 generr(h, "%s:%d: invalid timeout", path,
405 if (maxtries_str != NULL) {
406 maxtries = strtoul(maxtries_str, &end, 10);
408 generr(h, "%s:%d: invalid maxtries", path,
416 if (rad_add_server(h, host, port, secret, timeout, maxtries) ==
418 strcpy(msg, h->errmsg);
419 generr(h, "%s:%d: %s", path, linenum, msg);
424 /* Clear out the buffer to wipe a possible copy of a shared secret */
425 memset(buf, 0, sizeof buf);
431 * rad_init_send_request() must have previously been called.
433 * 0 The application should select on *fd with a timeout of tv before
434 * calling rad_continue_send_request again.
439 rad_continue_send_request(struct rad_handle *h, int selected, int *fd,
445 struct sockaddr_in from;
448 fromlen = sizeof from;
449 h->resp_len = recvfrom(h->fd, h->response,
450 MSGSIZE, MSG_WAITALL, (struct sockaddr *)&from, &fromlen);
451 if (h->resp_len == -1) {
452 generr(h, "recvfrom: %s", strerror(errno));
455 if (is_valid_response(h, h->srv, &from)) {
456 h->resp_len = h->response[POS_LENGTH] << 8 |
457 h->response[POS_LENGTH+1];
458 h->resp_pos = POS_ATTRS;
459 return h->response[POS_CODE];
463 if (h->try == h->total_tries) {
464 generr(h, "No valid RADIUS responses received");
469 * Scan round-robin to the next server that has some
470 * tries left. There is guaranteed to be one, or we
471 * would have exited this loop by now.
473 while (h->servers[h->srv].num_tries >= h->servers[h->srv].max_tries)
474 if (++h->srv >= h->num_servers)
477 if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST)
478 /* Insert the request authenticator into the request */
479 insert_request_authenticator(h, h->srv);
481 /* Insert the scrambled password into the request */
482 if (h->pass_pos != 0)
483 insert_scrambled_password(h, h->srv);
485 /* Send the request */
486 n = sendto(h->fd, h->request, h->req_len, 0,
487 (const struct sockaddr *)&h->servers[h->srv].addr,
488 sizeof h->servers[h->srv].addr);
489 if (n != h->req_len) {
491 generr(h, "sendto: %s", strerror(errno));
493 generr(h, "sendto: short write");
498 h->servers[h->srv].num_tries++;
499 tv->tv_sec = h->servers[h->srv].timeout;
507 rad_create_request(struct rad_handle *h, int code)
511 h->request[POS_CODE] = code;
512 h->request[POS_IDENT] = ++h->ident;
513 /* Create a random authenticator */
514 for (i = 0; i < LEN_AUTH; i += 2) {
517 h->request[POS_AUTH+i] = r;
518 h->request[POS_AUTH+i+1] = r >> 8;
520 h->req_len = POS_ATTRS;
526 rad_cvt_addr(const void *data)
528 struct in_addr value;
530 memcpy(&value.s_addr, data, sizeof value.s_addr);
535 rad_cvt_int(const void *data)
539 memcpy(&value, data, sizeof value);
544 rad_cvt_string(const void *data, size_t len)
550 memcpy(s, data, len);
557 * Returns the attribute type. If none are left, returns 0. On failure,
561 rad_get_attr(struct rad_handle *h, const void **value, size_t *len)
565 if (h->resp_pos >= h->resp_len)
567 if (h->resp_pos + 2 > h->resp_len) {
568 generr(h, "Malformed attribute in response");
571 type = h->response[h->resp_pos++];
572 *len = h->response[h->resp_pos++] - 2;
573 if (h->resp_pos + *len > h->resp_len) {
574 generr(h, "Malformed attribute in response");
577 *value = &h->response[h->resp_pos];
583 * Returns -1 on error, 0 to indicate no event and >0 for success
586 rad_init_send_request(struct rad_handle *h, int *fd, struct timeval *tv)
590 /* Make sure we have a socket to use */
592 struct sockaddr_in sin;
594 if ((h->fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
595 generr(h, "Cannot create socket: %s", strerror(errno));
598 memset(&sin, 0, sizeof sin);
599 sin.sin_len = sizeof sin;
600 sin.sin_family = AF_INET;
601 sin.sin_addr.s_addr = INADDR_ANY;
602 sin.sin_port = htons(0);
603 if (bind(h->fd, (const struct sockaddr *)&sin,
605 generr(h, "bind: %s", strerror(errno));
612 if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) {
613 /* Make sure no password given */
614 if (h->pass_pos || h->chap_pass) {
615 generr(h, "User or Chap Password in accounting request");
619 /* Make sure the user gave us a password */
620 if (h->pass_pos == 0 && !h->chap_pass) {
621 generr(h, "No User or Chap Password attributes given");
624 if (h->pass_pos != 0 && h->chap_pass) {
625 generr(h, "Both User and Chap Password attributes given");
630 /* Fill in the length field in the message */
631 h->request[POS_LENGTH] = h->req_len >> 8;
632 h->request[POS_LENGTH+1] = h->req_len;
635 * Count the total number of tries we will make, and zero the
636 * counter for each server.
639 for (srv = 0; srv < h->num_servers; srv++) {
640 h->total_tries += h->servers[srv].max_tries;
641 h->servers[srv].num_tries = 0;
643 if (h->total_tries == 0) {
644 generr(h, "No RADIUS servers specified");
650 return rad_continue_send_request(h, 0, fd, tv);
654 * Create and initialize a rad_handle structure, and return it to the
655 * caller. Can fail only if the necessary memory cannot be allocated.
656 * In that case, it returns NULL.
661 struct rad_handle *h;
663 h = (struct rad_handle *)malloc(sizeof(struct rad_handle));
670 memset(h->pass, 0, sizeof h->pass);
674 h->type = RADIUS_AUTH;
682 struct rad_handle *h;
686 h->type = RADIUS_ACCT;
693 return rad_auth_open();
697 rad_put_addr(struct rad_handle *h, int type, struct in_addr addr)
699 return rad_put_attr(h, type, &addr.s_addr, sizeof addr.s_addr);
703 rad_put_attr(struct rad_handle *h, int type, const void *value, size_t len)
707 if (type == RAD_USER_PASSWORD)
708 result = put_password_attr(h, type, value, len);
710 result = put_raw_attr(h, type, value, len);
711 if (result == 0 && type == RAD_CHAP_PASSWORD)
719 rad_put_int(struct rad_handle *h, int type, u_int32_t value)
723 nvalue = htonl(value);
724 return rad_put_attr(h, type, &nvalue, sizeof nvalue);
728 rad_put_string(struct rad_handle *h, int type, const char *str)
730 return rad_put_attr(h, type, str, strlen(str));
734 * Returns the response type code on success, or -1 on failure.
737 rad_send_request(struct rad_handle *h)
739 struct timeval timelimit;
744 n = rad_init_send_request(h, &fd, &tv);
749 gettimeofday(&timelimit, NULL);
750 timeradd(&tv, &timelimit, &timelimit);
756 FD_SET(fd, &readfds);
758 n = select(fd + 1, &readfds, NULL, NULL, &tv);
761 generr(h, "select: %s", strerror(errno));
765 if (!FD_ISSET(fd, &readfds)) {
766 /* Compute a new timeout */
767 gettimeofday(&tv, NULL);
768 timersub(&timelimit, &tv, &tv);
769 if (tv.tv_sec > 0 || (tv.tv_sec == 0 && tv.tv_usec > 0))
770 /* Continue the select */
774 n = rad_continue_send_request(h, n, &fd, &tv);
779 gettimeofday(&timelimit, NULL);
780 timeradd(&tv, &timelimit, &timelimit);
785 rad_strerror(struct rad_handle *h)
791 * Destructively split a string into fields separated by white space.
792 * `#' at the beginning of a field begins a comment that extends to the
793 * end of the string. Fields may be quoted with `"'. Inside quoted
794 * strings, the backslash escapes `\"' and `\\' are honored.
796 * Pointers to up to the first maxfields fields are stored in the fields
797 * array. Missing fields get NULL pointers.
799 * The return value is the actual number of fields parsed, and is always
802 * On a syntax error, places a message in the msg string, and returns -1.
805 split(char *str, char *fields[], int maxfields, char *msg, size_t msglen)
809 static const char ws[] = " \t";
811 for (i = 0; i < maxfields; i++)
817 if (*p == '#' || *p == '\0')
819 if (i >= maxfields) {
820 snprintf(msg, msglen, "line has too many fields");
831 if (*p != '"' && *p != '\\' &&
833 snprintf(msg, msglen,
834 "invalid `\\' escape");
839 snprintf(msg, msglen,
840 "unterminated quoted string");
847 if (*fields[i] == '\0') {
848 snprintf(msg, msglen,
849 "empty quoted string not permitted");
852 if (*p != '\0' && strspn(p, ws) == 0) {
853 snprintf(msg, msglen, "quoted string not"
854 " followed by white space");
869 rad_get_vendor_attr(u_int32_t *vendor, const void **data, size_t *len)
871 struct vendor_attribute *attr;
873 attr = (struct vendor_attribute *)*data;
874 *vendor = ntohl(attr->vendor_value);
875 *data = attr->attrib_data;
876 *len = attr->attrib_len - 2;
878 return (attr->attrib_type);
882 rad_put_vendor_addr(struct rad_handle *h, int vendor, int type,
885 return (rad_put_vendor_attr(h, vendor, type, &addr.s_addr,
886 sizeof addr.s_addr));
890 rad_put_vendor_attr(struct rad_handle *h, int vendor, int type,
891 const void *value, size_t len)
893 struct vendor_attribute *attr;
896 if ((attr = malloc(len + 6)) == NULL) {
897 generr(h, "malloc failure (%d bytes)", len + 6);
901 attr->vendor_value = htonl(vendor);
902 attr->attrib_type = type;
903 attr->attrib_len = len + 2;
904 memcpy(attr->attrib_data, value, len);
906 res = put_raw_attr(h, RAD_VENDOR_SPECIFIC, attr, len + 6);
908 if (res == 0 && vendor == RAD_VENDOR_MICROSOFT
909 && (type == RAD_MICROSOFT_MS_CHAP_RESPONSE
910 || type == RAD_MICROSOFT_MS_CHAP2_RESPONSE)) {
917 rad_put_vendor_int(struct rad_handle *h, int vendor, int type, u_int32_t i)
922 return (rad_put_vendor_attr(h, vendor, type, &value, sizeof value));
926 rad_put_vendor_string(struct rad_handle *h, int vendor, int type,
929 return (rad_put_vendor_attr(h, vendor, type, str, strlen(str)));
933 rad_request_authenticator(struct rad_handle *h, char *buf, size_t len)
937 memcpy(buf, h->request + POS_AUTH, LEN_AUTH);
939 buf[LEN_AUTH] = '\0';
944 rad_server_secret(struct rad_handle *h)
946 return (h->servers[h->srv].secret);