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.4 2005/04/20 20:45:57 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 *, const 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
) {
305 const char *fields
[5];
308 const char *ohost
, *secret
, *timeout_str
, *maxtries_str
;
309 const char *type
, *wanttype
;
314 unsigned long timeout
;
315 unsigned long maxtries
;
321 /* We know len > 0, else fgets would have returned NULL. */
322 if (buf
[len
- 1] != '\n') {
323 if (len
== sizeof buf
- 1)
324 generr(h
, "%s:%d: line too long", path
,
327 generr(h
, "%s:%d: missing newline", path
,
334 /* Extract the fields from the line. */
335 nfields
= split(buf
, fields
, 5, msg
, sizeof msg
);
337 generr(h
, "%s:%d: %s", path
, linenum
, msg
);
344 * The first field should contain "auth" or "acct" for
345 * authentication or accounting, respectively. But older
346 * versions of the file didn't have that field. Default
347 * it to "auth" for backward compatibility.
349 if (strcmp(fields
[0], "auth") != 0 &&
350 strcmp(fields
[0], "acct") != 0) {
352 generr(h
, "%s:%d: invalid service type", path
,
358 for (i
= nfields
; --i
> 0; )
359 fields
[i
] = fields
[i
- 1];
363 generr(h
, "%s:%d: missing shared secret", path
,
371 timeout_str
= fields
[3];
372 maxtries_str
= fields
[4];
374 /* Ignore the line if it is for the wrong service type. */
375 wanttype
= h
->type
== RADIUS_AUTH
? "auth" : "acct";
376 if (strcmp(type
, wanttype
) != 0)
379 /* Parse and validate the fields. */
380 if ((res
= strdup(ohost
)) == NULL
) {
381 generr(h
, "%s:%d: malloc failed", path
, linenum
);
385 host
= strsep(&res
, ":");
386 port_str
= strsep(&res
, ":");
387 if (port_str
!= NULL
) {
388 port
= strtoul(port_str
, &end
, 10);
391 generr(h
, "%s:%d: invalid port", path
,
398 if (timeout_str
!= NULL
) {
399 timeout
= strtoul(timeout_str
, &end
, 10);
402 generr(h
, "%s:%d: invalid timeout", path
,
409 if (maxtries_str
!= NULL
) {
410 maxtries
= strtoul(maxtries_str
, &end
, 10);
413 generr(h
, "%s:%d: invalid maxtries", path
,
421 if (rad_add_server(h
, host
, port
, secret
, timeout
, maxtries
) ==
424 strcpy(msg
, h
->errmsg
);
425 generr(h
, "%s:%d: %s", path
, linenum
, msg
);
431 /* Clear out the buffer to wipe a possible copy of a shared secret */
432 memset(buf
, 0, sizeof buf
);
438 * rad_init_send_request() must have previously been called.
440 * 0 The application should select on *fd with a timeout of tv before
441 * calling rad_continue_send_request again.
446 rad_continue_send_request(struct rad_handle
*h
, int selected
, int *fd
,
452 struct sockaddr_in from
;
455 fromlen
= sizeof from
;
456 h
->resp_len
= recvfrom(h
->fd
, h
->response
,
457 MSGSIZE
, MSG_WAITALL
, (struct sockaddr
*)&from
, &fromlen
);
458 if (h
->resp_len
== -1) {
459 generr(h
, "recvfrom: %s", strerror(errno
));
462 if (is_valid_response(h
, h
->srv
, &from
)) {
463 h
->resp_len
= h
->response
[POS_LENGTH
] << 8 |
464 h
->response
[POS_LENGTH
+1];
465 h
->resp_pos
= POS_ATTRS
;
466 return h
->response
[POS_CODE
];
470 if (h
->try == h
->total_tries
) {
471 generr(h
, "No valid RADIUS responses received");
476 * Scan round-robin to the next server that has some
477 * tries left. There is guaranteed to be one, or we
478 * would have exited this loop by now.
480 while (h
->servers
[h
->srv
].num_tries
>= h
->servers
[h
->srv
].max_tries
)
481 if (++h
->srv
>= h
->num_servers
)
484 if (h
->request
[POS_CODE
] == RAD_ACCOUNTING_REQUEST
)
485 /* Insert the request authenticator into the request */
486 insert_request_authenticator(h
, h
->srv
);
488 /* Insert the scrambled password into the request */
489 if (h
->pass_pos
!= 0)
490 insert_scrambled_password(h
, h
->srv
);
492 /* Send the request */
493 n
= sendto(h
->fd
, h
->request
, h
->req_len
, 0,
494 (const struct sockaddr
*)&h
->servers
[h
->srv
].addr
,
495 sizeof h
->servers
[h
->srv
].addr
);
496 if (n
!= h
->req_len
) {
498 generr(h
, "sendto: %s", strerror(errno
));
500 generr(h
, "sendto: short write");
505 h
->servers
[h
->srv
].num_tries
++;
506 tv
->tv_sec
= h
->servers
[h
->srv
].timeout
;
514 rad_create_request(struct rad_handle
*h
, int code
)
518 h
->request
[POS_CODE
] = code
;
519 h
->request
[POS_IDENT
] = ++h
->ident
;
520 /* Create a random authenticator */
521 for (i
= 0; i
< LEN_AUTH
; i
+= 2) {
524 h
->request
[POS_AUTH
+i
] = r
;
525 h
->request
[POS_AUTH
+i
+1] = r
>> 8;
527 h
->req_len
= POS_ATTRS
;
533 rad_cvt_addr(const void *data
)
535 struct in_addr value
;
537 memcpy(&value
.s_addr
, data
, sizeof value
.s_addr
);
542 rad_cvt_int(const void *data
)
546 memcpy(&value
, data
, sizeof value
);
551 rad_cvt_string(const void *data
, size_t len
)
557 memcpy(s
, data
, len
);
564 * Returns the attribute type. If none are left, returns 0. On failure,
568 rad_get_attr(struct rad_handle
*h
, const void **value
, size_t *len
)
572 if (h
->resp_pos
>= h
->resp_len
)
574 if (h
->resp_pos
+ 2 > h
->resp_len
) {
575 generr(h
, "Malformed attribute in response");
578 type
= h
->response
[h
->resp_pos
++];
579 *len
= h
->response
[h
->resp_pos
++] - 2;
580 if (h
->resp_pos
+ (int)*len
> h
->resp_len
) {
581 generr(h
, "Malformed attribute in response");
584 *value
= &h
->response
[h
->resp_pos
];
590 * Returns -1 on error, 0 to indicate no event and >0 for success
593 rad_init_send_request(struct rad_handle
*h
, int *fd
, struct timeval
*tv
)
597 /* Make sure we have a socket to use */
599 struct sockaddr_in sin
;
601 if ((h
->fd
= socket(PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
)) == -1) {
602 generr(h
, "Cannot create socket: %s", strerror(errno
));
605 memset(&sin
, 0, sizeof sin
);
606 sin
.sin_len
= sizeof sin
;
607 sin
.sin_family
= AF_INET
;
608 sin
.sin_addr
.s_addr
= INADDR_ANY
;
609 sin
.sin_port
= htons(0);
610 if (bind(h
->fd
, (const struct sockaddr
*)&sin
,
612 generr(h
, "bind: %s", strerror(errno
));
619 if (h
->request
[POS_CODE
] == RAD_ACCOUNTING_REQUEST
) {
620 /* Make sure no password given */
621 if (h
->pass_pos
|| h
->chap_pass
) {
622 generr(h
, "User or Chap Password in accounting request");
626 /* Make sure the user gave us a password */
627 if (h
->pass_pos
== 0 && !h
->chap_pass
) {
628 generr(h
, "No User or Chap Password attributes given");
631 if (h
->pass_pos
!= 0 && h
->chap_pass
) {
632 generr(h
, "Both User and Chap Password attributes given");
637 /* Fill in the length field in the message */
638 h
->request
[POS_LENGTH
] = h
->req_len
>> 8;
639 h
->request
[POS_LENGTH
+1] = h
->req_len
;
642 * Count the total number of tries we will make, and zero the
643 * counter for each server.
646 for (srv
= 0; srv
< h
->num_servers
; srv
++) {
647 h
->total_tries
+= h
->servers
[srv
].max_tries
;
648 h
->servers
[srv
].num_tries
= 0;
650 if (h
->total_tries
== 0) {
651 generr(h
, "No RADIUS servers specified");
657 return rad_continue_send_request(h
, 0, fd
, tv
);
661 * Create and initialize a rad_handle structure, and return it to the
662 * caller. Can fail only if the necessary memory cannot be allocated.
663 * In that case, it returns NULL.
668 struct rad_handle
*h
;
670 h
= (struct rad_handle
*)malloc(sizeof(struct rad_handle
));
677 memset(h
->pass
, 0, sizeof h
->pass
);
681 h
->type
= RADIUS_AUTH
;
689 struct rad_handle
*h
;
693 h
->type
= RADIUS_ACCT
;
700 return rad_auth_open();
704 rad_put_addr(struct rad_handle
*h
, int type
, struct in_addr addr
)
706 return rad_put_attr(h
, type
, &addr
.s_addr
, sizeof addr
.s_addr
);
710 rad_put_attr(struct rad_handle
*h
, int type
, const void *value
, size_t len
)
714 if (type
== RAD_USER_PASSWORD
)
715 result
= put_password_attr(h
, type
, value
, len
);
717 result
= put_raw_attr(h
, type
, value
, len
);
718 if (result
== 0 && type
== RAD_CHAP_PASSWORD
)
726 rad_put_int(struct rad_handle
*h
, int type
, u_int32_t value
)
730 nvalue
= htonl(value
);
731 return rad_put_attr(h
, type
, &nvalue
, sizeof nvalue
);
735 rad_put_string(struct rad_handle
*h
, int type
, const char *str
)
737 return rad_put_attr(h
, type
, str
, strlen(str
));
741 * Returns the response type code on success, or -1 on failure.
744 rad_send_request(struct rad_handle
*h
)
746 struct timeval timelimit
;
751 n
= rad_init_send_request(h
, &fd
, &tv
);
756 gettimeofday(&timelimit
, NULL
);
757 timeradd(&tv
, &timelimit
, &timelimit
);
763 FD_SET(fd
, &readfds
);
765 n
= select(fd
+ 1, &readfds
, NULL
, NULL
, &tv
);
768 generr(h
, "select: %s", strerror(errno
));
772 if (!FD_ISSET(fd
, &readfds
)) {
773 /* Compute a new timeout */
774 gettimeofday(&tv
, NULL
);
775 timersub(&timelimit
, &tv
, &tv
);
776 if (tv
.tv_sec
> 0 || (tv
.tv_sec
== 0 && tv
.tv_usec
> 0))
777 /* Continue the select */
781 n
= rad_continue_send_request(h
, n
, &fd
, &tv
);
786 gettimeofday(&timelimit
, NULL
);
787 timeradd(&tv
, &timelimit
, &timelimit
);
792 rad_strerror(struct rad_handle
*h
)
798 * Destructively split a string into fields separated by white space.
799 * `#' at the beginning of a field begins a comment that extends to the
800 * end of the string. Fields may be quoted with `"'. Inside quoted
801 * strings, the backslash escapes `\"' and `\\' are honored.
803 * Pointers to up to the first maxfields fields are stored in the fields
804 * array. Missing fields get NULL pointers.
806 * The return value is the actual number of fields parsed, and is always
809 * On a syntax error, places a message in the msg string, and returns -1.
812 split(char *str
, const char *fields
[], int maxfields
, char *msg
, size_t msglen
)
816 static const char ws
[] = " \t";
818 for (i
= 0; i
< maxfields
; i
++)
824 if (*p
== '#' || *p
== '\0')
826 if (i
>= maxfields
) {
827 snprintf(msg
, msglen
, "line has too many fields");
838 if (*p
!= '"' && *p
!= '\\' &&
840 snprintf(msg
, msglen
,
841 "invalid `\\' escape");
846 snprintf(msg
, msglen
,
847 "unterminated quoted string");
854 if (*fields
[i
] == '\0') {
855 snprintf(msg
, msglen
,
856 "empty quoted string not permitted");
859 if (*p
!= '\0' && strspn(p
, ws
) == 0) {
860 snprintf(msg
, msglen
, "quoted string not"
861 " followed by white space");
876 rad_get_vendor_attr(u_int32_t
*vendor
, const void **data
, size_t *len
)
878 const struct vendor_attribute
*attr
;
880 attr
= (const struct vendor_attribute
*)*data
;
881 *vendor
= ntohl(attr
->vendor_value
);
882 *data
= attr
->attrib_data
;
883 *len
= attr
->attrib_len
- 2;
885 return (attr
->attrib_type
);
889 rad_put_vendor_addr(struct rad_handle
*h
, int vendor
, int type
,
892 return (rad_put_vendor_attr(h
, vendor
, type
, &addr
.s_addr
,
893 sizeof addr
.s_addr
));
897 rad_put_vendor_attr(struct rad_handle
*h
, int vendor
, int type
,
898 const void *value
, size_t len
)
900 struct vendor_attribute
*attr
;
903 if ((attr
= malloc(len
+ 6)) == NULL
) {
904 generr(h
, "malloc failure (%d bytes)", len
+ 6);
908 attr
->vendor_value
= htonl(vendor
);
909 attr
->attrib_type
= type
;
910 attr
->attrib_len
= len
+ 2;
911 memcpy(attr
->attrib_data
, value
, len
);
913 res
= put_raw_attr(h
, RAD_VENDOR_SPECIFIC
, attr
, len
+ 6);
915 if (res
== 0 && vendor
== RAD_VENDOR_MICROSOFT
916 && (type
== RAD_MICROSOFT_MS_CHAP_RESPONSE
917 || type
== RAD_MICROSOFT_MS_CHAP2_RESPONSE
)) {
924 rad_put_vendor_int(struct rad_handle
*h
, int vendor
, int type
, u_int32_t i
)
929 return (rad_put_vendor_attr(h
, vendor
, type
, &value
, sizeof value
));
933 rad_put_vendor_string(struct rad_handle
*h
, int vendor
, int type
,
936 return (rad_put_vendor_attr(h
, vendor
, type
, str
, strlen(str
)));
940 rad_request_authenticator(struct rad_handle
*h
, char *buf
, size_t len
)
944 memcpy(buf
, h
->request
+ POS_AUTH
, LEN_AUTH
);
946 buf
[LEN_AUTH
] = '\0';
951 rad_server_secret(struct rad_handle
*h
)
953 return (h
->servers
[h
->srv
].secret
);