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 $
29 #include <sys/types.h>
30 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
45 #include "radlib_private.h"
47 static void clear_password(struct rad_handle *);
48 static void generr(struct rad_handle *, const char *, ...)
50 static void insert_scrambled_password(struct rad_handle *, int);
51 static void insert_request_authenticator(struct rad_handle *, int);
52 static int is_valid_response(struct rad_handle *, int,
53 const struct sockaddr_in *);
54 static int put_password_attr(struct rad_handle *, int,
55 const void *, size_t);
56 static int put_raw_attr(struct rad_handle *, int,
57 const void *, size_t);
58 static int split(char *, char *[], int, char *, size_t);
61 clear_password(struct rad_handle *h)
63 if (h->pass_len != 0) {
64 memset(h->pass, 0, h->pass_len);
71 generr(struct rad_handle *h, const char *format, ...)
76 vsnprintf(h->errmsg, ERRSIZE, format, ap);
81 insert_scrambled_password(struct rad_handle *h, int srv)
84 unsigned char md5[16];
85 const struct rad_server *srvp;
89 srvp = &h->servers[srv];
90 padded_len = h->pass_len == 0 ? 16 : (h->pass_len+15) & ~0xf;
92 memcpy(md5, &h->request[POS_AUTH], LEN_AUTH);
93 for (pos = 0; pos < padded_len; pos += 16) {
96 /* Calculate the new scrambler */
98 MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
99 MD5Update(&ctx, md5, 16);
103 * Mix in the current chunk of the password, and copy
104 * the result into the right place in the request. Also
105 * modify the scrambler in place, since we will use this
106 * in calculating the scrambler for next time.
108 for (i = 0; i < 16; i++)
109 h->request[h->pass_pos + pos + i] =
110 md5[i] ^= h->pass[pos + i];
115 insert_request_authenticator(struct rad_handle *h, int srv)
118 const struct rad_server *srvp;
120 srvp = &h->servers[srv];
122 /* Create the request authenticator */
124 MD5Update(&ctx, &h->request[POS_CODE], POS_AUTH - POS_CODE);
125 MD5Update(&ctx, memset(&h->request[POS_AUTH], 0, LEN_AUTH), LEN_AUTH);
126 MD5Update(&ctx, &h->request[POS_ATTRS], h->req_len - POS_ATTRS);
127 MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
128 MD5Final(&h->request[POS_AUTH], &ctx);
132 * Return true if the current response is valid for a request to the
136 is_valid_response(struct rad_handle *h, int srv,
137 const struct sockaddr_in *from)
140 unsigned char md5[16];
141 const struct rad_server *srvp;
144 srvp = &h->servers[srv];
146 /* Check the source address */
147 if (from->sin_family != srvp->addr.sin_family ||
148 from->sin_addr.s_addr != srvp->addr.sin_addr.s_addr ||
149 from->sin_port != srvp->addr.sin_port)
152 /* Check the message length */
153 if (h->resp_len < POS_ATTRS)
155 len = h->response[POS_LENGTH] << 8 | h->response[POS_LENGTH+1];
156 if (len > h->resp_len)
159 /* Check the response authenticator */
161 MD5Update(&ctx, &h->response[POS_CODE], POS_AUTH - POS_CODE);
162 MD5Update(&ctx, &h->request[POS_AUTH], LEN_AUTH);
163 MD5Update(&ctx, &h->response[POS_ATTRS], len - POS_ATTRS);
164 MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
166 if (memcmp(&h->response[POS_AUTH], md5, sizeof md5) != 0)
173 put_password_attr(struct rad_handle *h, int type, const void *value, size_t len)
178 if (h->pass_pos != 0) {
179 generr(h, "Multiple User-Password attributes specified");
184 padded_len = len == 0 ? 16 : (len+15) & ~0xf;
185 pad_len = padded_len - len;
188 * Put in a place-holder attribute containing all zeros, and
189 * remember where it is so we can fill it in later.
192 put_raw_attr(h, type, h->pass, padded_len);
193 h->pass_pos = h->req_len - padded_len;
195 /* Save the cleartext password, padded as necessary */
196 memcpy(h->pass, value, len);
198 memset(h->pass + len, 0, pad_len);
203 put_raw_attr(struct rad_handle *h, int type, const void *value, size_t len)
206 generr(h, "Attribute too long");
209 if (h->req_len + 2 + len > MSGSIZE) {
210 generr(h, "Maximum message length exceeded");
213 h->request[h->req_len++] = type;
214 h->request[h->req_len++] = len + 2;
215 memcpy(&h->request[h->req_len], value, len);
221 rad_add_server(struct rad_handle *h, const char *host, int port,
222 const char *secret, int timeout, int tries)
224 struct rad_server *srvp;
226 if (h->num_servers >= MAXSERVERS) {
227 generr(h, "Too many RADIUS servers specified");
230 srvp = &h->servers[h->num_servers];
232 memset(&srvp->addr, 0, sizeof srvp->addr);
233 srvp->addr.sin_len = sizeof srvp->addr;
234 srvp->addr.sin_family = AF_INET;
235 if (!inet_aton(host, &srvp->addr.sin_addr)) {
236 struct hostent *hent;
238 if ((hent = gethostbyname(host)) == NULL) {
239 generr(h, "%s: host not found", host);
242 memcpy(&srvp->addr.sin_addr, hent->h_addr,
243 sizeof srvp->addr.sin_addr);
246 srvp->addr.sin_port = htons(port);
248 struct servent *sent;
250 if (h->type == RADIUS_AUTH)
251 srvp->addr.sin_port =
252 (sent = getservbyname("radius", "udp")) != NULL ?
253 sent->s_port : htons(RADIUS_PORT);
255 srvp->addr.sin_port =
256 (sent = getservbyname("radacct", "udp")) != NULL ?
257 sent->s_port : htons(RADACCT_PORT);
259 if ((srvp->secret = strdup(secret)) == NULL) {
260 generr(h, "Out of memory");
263 srvp->timeout = timeout;
264 srvp->max_tries = tries;
271 rad_close(struct rad_handle *h)
277 for (srv = 0; srv < h->num_servers; srv++) {
278 memset(h->servers[srv].secret, 0,
279 strlen(h->servers[srv].secret));
280 free(h->servers[srv].secret);
287 rad_config(struct rad_handle *h, const char *path)
290 char buf[MAXCONFLINE];
295 path = PATH_RADIUS_CONF;
296 if ((fp = fopen(path, "r")) == NULL) {
297 generr(h, "Cannot open \"%s\": %s", path, strerror(errno));
302 while (fgets(buf, sizeof buf, fp) != NULL) {
315 unsigned long timeout;
316 unsigned long maxtries;
322 /* We know len > 0, else fgets would have returned NULL. */
323 if (buf[len - 1] != '\n') {
324 if (len == sizeof buf - 1)
325 generr(h, "%s:%d: line too long", path,
328 generr(h, "%s:%d: missing newline", path,
335 /* Extract the fields from the line. */
336 nfields = split(buf, fields, 5, msg, sizeof msg);
338 generr(h, "%s:%d: %s", path, linenum, msg);
345 * The first field should contain "auth" or "acct" for
346 * authentication or accounting, respectively. But older
347 * versions of the file didn't have that field. Default
348 * it to "auth" for backward compatibility.
350 if (strcmp(fields[0], "auth") != 0 &&
351 strcmp(fields[0], "acct") != 0) {
353 generr(h, "%s:%d: invalid service type", path,
359 for (i = nfields; --i > 0; )
360 fields[i] = fields[i - 1];
364 generr(h, "%s:%d: missing shared secret", path,
372 timeout_str = fields[3];
373 maxtries_str = fields[4];
375 /* Ignore the line if it is for the wrong service type. */
376 wanttype = h->type == RADIUS_AUTH ? "auth" : "acct";
377 if (strcmp(type, wanttype) != 0)
380 /* Parse and validate the fields. */
382 host = strsep(&res, ":");
383 port_str = strsep(&res, ":");
384 if (port_str != NULL) {
385 port = strtoul(port_str, &end, 10);
387 generr(h, "%s:%d: invalid port", path,
394 if (timeout_str != NULL) {
395 timeout = strtoul(timeout_str, &end, 10);
397 generr(h, "%s:%d: invalid timeout", path,
404 if (maxtries_str != NULL) {
405 maxtries = strtoul(maxtries_str, &end, 10);
407 generr(h, "%s:%d: invalid maxtries", path,
415 if (rad_add_server(h, host, port, secret, timeout, maxtries) ==
417 strcpy(msg, h->errmsg);
418 generr(h, "%s:%d: %s", path, linenum, msg);
423 /* Clear out the buffer to wipe a possible copy of a shared secret */
424 memset(buf, 0, sizeof buf);
430 * rad_init_send_request() must have previously been called.
432 * 0 The application should select on *fd with a timeout of tv before
433 * calling rad_continue_send_request again.
438 rad_continue_send_request(struct rad_handle *h, int selected, int *fd,
444 struct sockaddr_in from;
447 fromlen = sizeof from;
448 h->resp_len = recvfrom(h->fd, h->response,
449 MSGSIZE, MSG_WAITALL, (struct sockaddr *)&from, &fromlen);
450 if (h->resp_len == -1) {
451 generr(h, "recvfrom: %s", strerror(errno));
454 if (is_valid_response(h, h->srv, &from)) {
455 h->resp_len = h->response[POS_LENGTH] << 8 |
456 h->response[POS_LENGTH+1];
457 h->resp_pos = POS_ATTRS;
458 return h->response[POS_CODE];
462 if (h->try == h->total_tries) {
463 generr(h, "No valid RADIUS responses received");
468 * Scan round-robin to the next server that has some
469 * tries left. There is guaranteed to be one, or we
470 * would have exited this loop by now.
472 while (h->servers[h->srv].num_tries >= h->servers[h->srv].max_tries)
473 if (++h->srv >= h->num_servers)
476 if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST)
477 /* Insert the request authenticator into the request */
478 insert_request_authenticator(h, h->srv);
480 /* Insert the scrambled password into the request */
481 if (h->pass_pos != 0)
482 insert_scrambled_password(h, h->srv);
484 /* Send the request */
485 n = sendto(h->fd, h->request, h->req_len, 0,
486 (const struct sockaddr *)&h->servers[h->srv].addr,
487 sizeof h->servers[h->srv].addr);
488 if (n != h->req_len) {
490 generr(h, "sendto: %s", strerror(errno));
492 generr(h, "sendto: short write");
497 h->servers[h->srv].num_tries++;
498 tv->tv_sec = h->servers[h->srv].timeout;
506 rad_create_request(struct rad_handle *h, int code)
510 h->request[POS_CODE] = code;
511 h->request[POS_IDENT] = ++h->ident;
512 /* Create a random authenticator */
513 for (i = 0; i < LEN_AUTH; i += 2) {
516 h->request[POS_AUTH+i] = r;
517 h->request[POS_AUTH+i+1] = r >> 8;
519 h->req_len = POS_ATTRS;
525 rad_cvt_addr(const void *data)
527 struct in_addr value;
529 memcpy(&value.s_addr, data, sizeof value.s_addr);
534 rad_cvt_int(const void *data)
538 memcpy(&value, data, sizeof value);
543 rad_cvt_string(const void *data, size_t len)
549 memcpy(s, data, len);
556 * Returns the attribute type. If none are left, returns 0. On failure,
560 rad_get_attr(struct rad_handle *h, const void **value, size_t *len)
564 if (h->resp_pos >= h->resp_len)
566 if (h->resp_pos + 2 > h->resp_len) {
567 generr(h, "Malformed attribute in response");
570 type = h->response[h->resp_pos++];
571 *len = h->response[h->resp_pos++] - 2;
572 if (h->resp_pos + *len > h->resp_len) {
573 generr(h, "Malformed attribute in response");
576 *value = &h->response[h->resp_pos];
582 * Returns -1 on error, 0 to indicate no event and >0 for success
585 rad_init_send_request(struct rad_handle *h, int *fd, struct timeval *tv)
589 /* Make sure we have a socket to use */
591 struct sockaddr_in sin;
593 if ((h->fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
594 generr(h, "Cannot create socket: %s", strerror(errno));
597 memset(&sin, 0, sizeof sin);
598 sin.sin_len = sizeof sin;
599 sin.sin_family = AF_INET;
600 sin.sin_addr.s_addr = INADDR_ANY;
601 sin.sin_port = htons(0);
602 if (bind(h->fd, (const struct sockaddr *)&sin,
604 generr(h, "bind: %s", strerror(errno));
611 if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) {
612 /* Make sure no password given */
613 if (h->pass_pos || h->chap_pass) {
614 generr(h, "User or Chap Password in accounting request");
618 /* Make sure the user gave us a password */
619 if (h->pass_pos == 0 && !h->chap_pass) {
620 generr(h, "No User or Chap Password attributes given");
623 if (h->pass_pos != 0 && h->chap_pass) {
624 generr(h, "Both User and Chap Password attributes given");
629 /* Fill in the length field in the message */
630 h->request[POS_LENGTH] = h->req_len >> 8;
631 h->request[POS_LENGTH+1] = h->req_len;
634 * Count the total number of tries we will make, and zero the
635 * counter for each server.
638 for (srv = 0; srv < h->num_servers; srv++) {
639 h->total_tries += h->servers[srv].max_tries;
640 h->servers[srv].num_tries = 0;
642 if (h->total_tries == 0) {
643 generr(h, "No RADIUS servers specified");
649 return rad_continue_send_request(h, 0, fd, tv);
653 * Create and initialize a rad_handle structure, and return it to the
654 * caller. Can fail only if the necessary memory cannot be allocated.
655 * In that case, it returns NULL.
660 struct rad_handle *h;
662 h = (struct rad_handle *)malloc(sizeof(struct rad_handle));
669 memset(h->pass, 0, sizeof h->pass);
673 h->type = RADIUS_AUTH;
681 struct rad_handle *h;
685 h->type = RADIUS_ACCT;
692 return rad_auth_open();
696 rad_put_addr(struct rad_handle *h, int type, struct in_addr addr)
698 return rad_put_attr(h, type, &addr.s_addr, sizeof addr.s_addr);
702 rad_put_attr(struct rad_handle *h, int type, const void *value, size_t len)
706 if (type == RAD_USER_PASSWORD)
707 result = put_password_attr(h, type, value, len);
709 result = put_raw_attr(h, type, value, len);
710 if (result == 0 && type == RAD_CHAP_PASSWORD)
718 rad_put_int(struct rad_handle *h, int type, u_int32_t value)
722 nvalue = htonl(value);
723 return rad_put_attr(h, type, &nvalue, sizeof nvalue);
727 rad_put_string(struct rad_handle *h, int type, const char *str)
729 return rad_put_attr(h, type, str, strlen(str));
733 * Returns the response type code on success, or -1 on failure.
736 rad_send_request(struct rad_handle *h)
738 struct timeval timelimit;
743 n = rad_init_send_request(h, &fd, &tv);
748 gettimeofday(&timelimit, NULL);
749 timeradd(&tv, &timelimit, &timelimit);
755 FD_SET(fd, &readfds);
757 n = select(fd + 1, &readfds, NULL, NULL, &tv);
760 generr(h, "select: %s", strerror(errno));
764 if (!FD_ISSET(fd, &readfds)) {
765 /* Compute a new timeout */
766 gettimeofday(&tv, NULL);
767 timersub(&timelimit, &tv, &tv);
768 if (tv.tv_sec > 0 || (tv.tv_sec == 0 && tv.tv_usec > 0))
769 /* Continue the select */
773 n = rad_continue_send_request(h, n, &fd, &tv);
778 gettimeofday(&timelimit, NULL);
779 timeradd(&tv, &timelimit, &timelimit);
784 rad_strerror(struct rad_handle *h)
790 * Destructively split a string into fields separated by white space.
791 * `#' at the beginning of a field begins a comment that extends to the
792 * end of the string. Fields may be quoted with `"'. Inside quoted
793 * strings, the backslash escapes `\"' and `\\' are honored.
795 * Pointers to up to the first maxfields fields are stored in the fields
796 * array. Missing fields get NULL pointers.
798 * The return value is the actual number of fields parsed, and is always
801 * On a syntax error, places a message in the msg string, and returns -1.
804 split(char *str, char *fields[], int maxfields, char *msg, size_t msglen)
808 static const char ws[] = " \t";
810 for (i = 0; i < maxfields; i++)
816 if (*p == '#' || *p == '\0')
818 if (i >= maxfields) {
819 snprintf(msg, msglen, "line has too many fields");
830 if (*p != '"' && *p != '\\' &&
832 snprintf(msg, msglen,
833 "invalid `\\' escape");
838 snprintf(msg, msglen,
839 "unterminated quoted string");
846 if (*fields[i] == '\0') {
847 snprintf(msg, msglen,
848 "empty quoted string not permitted");
851 if (*p != '\0' && strspn(p, ws) == 0) {
852 snprintf(msg, msglen, "quoted string not"
853 " followed by white space");
868 rad_get_vendor_attr(u_int32_t *vendor, const void **data, size_t *len)
870 struct vendor_attribute *attr;
872 attr = (struct vendor_attribute *)*data;
873 *vendor = ntohl(attr->vendor_value);
874 *data = attr->attrib_data;
875 *len = attr->attrib_len - 2;
877 return (attr->attrib_type);
881 rad_put_vendor_addr(struct rad_handle *h, int vendor, int type,
884 return (rad_put_vendor_attr(h, vendor, type, &addr.s_addr,
885 sizeof addr.s_addr));
889 rad_put_vendor_attr(struct rad_handle *h, int vendor, int type,
890 const void *value, size_t len)
892 struct vendor_attribute *attr;
895 if ((attr = malloc(len + 6)) == NULL) {
896 generr(h, "malloc failure (%d bytes)", len + 6);
900 attr->vendor_value = htonl(vendor);
901 attr->attrib_type = type;
902 attr->attrib_len = len + 2;
903 memcpy(attr->attrib_data, value, len);
905 res = put_raw_attr(h, RAD_VENDOR_SPECIFIC, attr, len + 6);
907 if (res == 0 && vendor == RAD_VENDOR_MICROSOFT
908 && (type == RAD_MICROSOFT_MS_CHAP_RESPONSE
909 || type == RAD_MICROSOFT_MS_CHAP2_RESPONSE)) {
916 rad_put_vendor_int(struct rad_handle *h, int vendor, int type, u_int32_t i)
921 return (rad_put_vendor_attr(h, vendor, type, &value, sizeof value));
925 rad_put_vendor_string(struct rad_handle *h, int vendor, int type,
928 return (rad_put_vendor_attr(h, vendor, type, str, strlen(str)));
932 rad_request_authenticator(struct rad_handle *h, char *buf, size_t len)
936 memcpy(buf, h->request + POS_AUTH, LEN_AUTH);
938 buf[LEN_AUTH] = '\0';
943 rad_server_secret(struct rad_handle *h)
945 return (h->servers[h->srv].secret);