1 /* $NetBSD: radlib.c,v 1.10 2009/01/19 07:21:59 lukem Exp $ */
4 * Copyright 1998 Juniper Networks, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD: /repoman/r/ncvs/src/lib/libradius/radlib.c,v 1.12 2004/06/14 20:55:30 stefanf Exp $");
33 __RCSID("$NetBSD: radlib.c,v 1.10 2009/01/19 07:21:59 lukem Exp $");
36 #include <sys/types.h>
37 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
42 #include <openssl/hmac.h>
43 #include <openssl/md5.h>
44 #define MD5Init MD5_Init
45 #define MD5Update MD5_Update
46 #define MD5Final MD5_Final
48 #define MD5Buf const void *
50 #define MD5_DIGEST_LENGTH 16
51 #define MD5Len unsigned int
52 #define MD5Buf const unsigned char *
56 /* We need the MPPE_KEY_LEN define */
58 #include <netgraph/ng_mppc.h>
60 #define MPPE_KEY_LEN 16
72 #include "radlib_private.h"
73 #if !defined(__printflike)
74 #define __printflike(fmtarg, firstvararg) \
75 __attribute__((__format__ (__printf__, fmtarg, firstvararg)))
80 #define random arc4random
83 static void clear_password(struct rad_handle
*);
84 static void generr(struct rad_handle
*, const char *, ...)
86 static void insert_scrambled_password(struct rad_handle
*, size_t);
87 static void insert_request_authenticator(struct rad_handle
*, size_t);
88 static void insert_message_authenticator(struct rad_handle
*, size_t);
89 static int is_valid_response(struct rad_handle
*, size_t,
90 const struct sockaddr_in
*);
91 static int put_password_attr(struct rad_handle
*, int,
92 const void *, size_t);
93 static int put_raw_attr(struct rad_handle
*, int,
94 const void *, size_t);
95 static size_t split(char *, const char *[], size_t, char *, size_t);
98 clear_password(struct rad_handle
*h
)
100 if (h
->pass_len
!= 0) {
101 (void)memset(h
->pass
, 0, h
->pass_len
);
108 generr(struct rad_handle
*h
, const char *format
, ...)
112 va_start(ap
, format
);
113 vsnprintf(h
->errmsg
, (size_t)ERRSIZE
, format
, ap
);
118 insert_scrambled_password(struct rad_handle
*h
, size_t srv
)
121 unsigned char md5
[MD5_DIGEST_LENGTH
];
122 const struct rad_server
*srvp
;
123 size_t padded_len
, pos
;
125 srvp
= &h
->servers
[srv
];
126 padded_len
= h
->pass_len
== 0 ? (size_t)16 : (h
->pass_len
+15) & ~0xf;
128 (void)memcpy(md5
, &h
->request
[POS_AUTH
], (size_t)LEN_AUTH
);
129 for (pos
= 0; pos
< padded_len
; pos
+= 16) {
132 /* Calculate the new scrambler */
134 MD5Update(&ctx
, (MD5Buf
)srvp
->secret
,
135 (MD5Len
)strlen(srvp
->secret
));
136 MD5Update(&ctx
, md5
, (MD5Len
)16);
140 * Mix in the current chunk of the password, and copy
141 * the result into the right place in the request. Also
142 * modify the scrambler in place, since we will use this
143 * in calculating the scrambler for next time.
145 for (i
= 0; i
< 16; i
++)
146 h
->request
[h
->pass_pos
+ pos
+ i
] =
147 md5
[i
] ^= h
->pass
[pos
+ i
];
152 insert_request_authenticator(struct rad_handle
*h
, size_t srv
)
155 const struct rad_server
*srvp
;
157 srvp
= &h
->servers
[srv
];
159 /* Create the request authenticator */
161 MD5Update(&ctx
, &h
->request
[POS_CODE
],
162 (MD5Len
)(POS_AUTH
- POS_CODE
));
163 MD5Update(&ctx
, memset(&h
->request
[POS_AUTH
], 0, (size_t)LEN_AUTH
),
165 MD5Update(&ctx
, &h
->request
[POS_ATTRS
],
166 (MD5Len
)(h
->req_len
- POS_ATTRS
));
167 MD5Update(&ctx
, (MD5Buf
)srvp
->secret
,
168 (MD5Len
)strlen(srvp
->secret
));
169 MD5Final(&h
->request
[POS_AUTH
], &ctx
);
174 insert_message_authenticator(struct rad_handle
*h
, size_t srv
)
177 u_char md
[EVP_MAX_MD_SIZE
];
179 const struct rad_server
*srvp
;
181 srvp
= &h
->servers
[srv
];
183 if (h
->authentic_pos
!= 0) {
185 HMAC_Init(&ctx
, srvp
->secret
,
186 (int)strlen(srvp
->secret
), EVP_md5());
187 HMAC_Update(&ctx
, &h
->request
[POS_CODE
], (size_t)(POS_AUTH
- POS_CODE
));
188 HMAC_Update(&ctx
, &h
->request
[POS_AUTH
], (size_t)LEN_AUTH
);
189 HMAC_Update(&ctx
, &h
->request
[POS_ATTRS
],
190 (size_t)(h
->req_len
- POS_ATTRS
));
191 HMAC_Final(&ctx
, md
, &md_len
);
192 HMAC_CTX_cleanup(&ctx
);
194 (void)memcpy(&h
->request
[h
->authentic_pos
+ 2], md
,
201 * Return true if the current response is valid for a request to the
205 is_valid_response(struct rad_handle
*h
, size_t srv
,
206 const struct sockaddr_in
*from
)
209 unsigned char md5
[MD5_DIGEST_LENGTH
];
210 const struct rad_server
*srvp
;
214 u_char resp
[MSGSIZE
], md
[EVP_MAX_MD_SIZE
];
219 srvp
= &h
->servers
[srv
];
221 /* Check the source address */
222 if (from
->sin_family
!= srvp
->addr
.sin_family
||
223 from
->sin_addr
.s_addr
!= srvp
->addr
.sin_addr
.s_addr
||
224 from
->sin_port
!= srvp
->addr
.sin_port
)
227 /* Check the message length */
228 if (h
->resp_len
< POS_ATTRS
)
230 len
= h
->response
[POS_LENGTH
] << 8 | h
->response
[POS_LENGTH
+1];
231 if (len
> h
->resp_len
)
234 /* Check the response authenticator */
236 MD5Update(&ctx
, &h
->response
[POS_CODE
],
237 (MD5Len
)(POS_AUTH
- POS_CODE
));
238 MD5Update(&ctx
, &h
->request
[POS_AUTH
],
240 MD5Update(&ctx
, &h
->response
[POS_ATTRS
],
241 (MD5Len
)(len
- POS_ATTRS
));
242 MD5Update(&ctx
, (MD5Buf
)srvp
->secret
,
243 (MD5Len
)strlen(srvp
->secret
));
245 if (memcmp(&h
->response
[POS_AUTH
], md5
, sizeof md5
) != 0)
250 * For non accounting responses check the message authenticator,
253 if (h
->response
[POS_CODE
] != RAD_ACCOUNTING_RESPONSE
) {
255 (void)memcpy(resp
, h
->response
, (size_t)MSGSIZE
);
258 /* Search and verify the Message-Authenticator */
259 while (pos
< len
- 2) {
261 if (h
->response
[pos
] == RAD_MESSAGE_AUTHENTIC
) {
262 /* zero fill the Message-Authenticator */
263 (void)memset(&resp
[pos
+ 2], 0,
264 (size_t)MD5_DIGEST_LENGTH
);
266 HMAC_CTX_init(&hctx
);
267 HMAC_Init(&hctx
, srvp
->secret
,
268 (int)strlen(srvp
->secret
), EVP_md5());
269 HMAC_Update(&hctx
, &h
->response
[POS_CODE
],
270 (size_t)(POS_AUTH
- POS_CODE
));
271 HMAC_Update(&hctx
, &h
->request
[POS_AUTH
],
273 HMAC_Update(&hctx
, &resp
[POS_ATTRS
],
274 (size_t)(h
->resp_len
- POS_ATTRS
));
275 HMAC_Final(&hctx
, md
, &md_len
);
276 HMAC_CTX_cleanup(&hctx
);
278 if (memcmp(md
, &h
->response
[pos
+ 2],
279 (size_t)MD5_DIGEST_LENGTH
) != 0)
283 pos
+= h
->response
[pos
+ 1];
291 put_password_attr(struct rad_handle
*h
, int type
, const void *value
, size_t len
)
296 if (h
->pass_pos
!= 0) {
297 generr(h
, "Multiple User-Password attributes specified");
302 padded_len
= len
== 0 ? 16 : (len
+ 15) & ~0xf;
303 pad_len
= padded_len
- len
;
306 * Put in a place-holder attribute containing all zeros, and
307 * remember where it is so we can fill it in later.
310 put_raw_attr(h
, type
, h
->pass
, padded_len
);
311 h
->pass_pos
= (int)(h
->req_len
- padded_len
);
313 /* Save the cleartext password, padded as necessary */
314 (void)memcpy(h
->pass
, value
, len
);
316 (void)memset(h
->pass
+ len
, 0, pad_len
);
321 put_raw_attr(struct rad_handle
*h
, int type
, const void *value
, size_t len
)
324 generr(h
, "Attribute too long");
327 if (h
->req_len
+ 2 + len
> MSGSIZE
) {
328 generr(h
, "Maximum message length exceeded");
331 h
->request
[h
->req_len
++] = type
;
332 h
->request
[h
->req_len
++] = (unsigned char)(len
+ 2);
333 (void)memcpy(&h
->request
[h
->req_len
], value
, len
);
339 rad_add_server(struct rad_handle
*h
, const char *host
, int port
,
340 const char *secret
, int timeout
, int tries
)
342 struct rad_server
*srvp
;
344 if (h
->num_servers
>= MAXSERVERS
) {
345 generr(h
, "Too many RADIUS servers specified");
348 srvp
= &h
->servers
[h
->num_servers
];
350 (void)memset(&srvp
->addr
, 0, sizeof srvp
->addr
);
351 srvp
->addr
.sin_len
= sizeof srvp
->addr
;
352 srvp
->addr
.sin_family
= AF_INET
;
353 if (!inet_aton(host
, &srvp
->addr
.sin_addr
)) {
354 struct hostent
*hent
;
356 if ((hent
= gethostbyname(host
)) == NULL
) {
357 generr(h
, "%s: host not found", host
);
360 (void)memcpy(&srvp
->addr
.sin_addr
, hent
->h_addr
,
361 sizeof srvp
->addr
.sin_addr
);
364 srvp
->addr
.sin_port
= htons((u_short
)port
);
366 struct servent
*sent
;
368 if (h
->type
== RADIUS_AUTH
)
369 srvp
->addr
.sin_port
=
370 (sent
= getservbyname("radius", "udp")) != NULL
?
371 sent
->s_port
: htons(RADIUS_PORT
);
373 srvp
->addr
.sin_port
=
374 (sent
= getservbyname("radacct", "udp")) != NULL
?
375 sent
->s_port
: htons(RADACCT_PORT
);
377 if ((srvp
->secret
= strdup(secret
)) == NULL
) {
378 generr(h
, "Out of memory");
381 srvp
->timeout
= timeout
;
382 srvp
->max_tries
= tries
;
389 rad_close(struct rad_handle
*h
)
395 for (srv
= 0; srv
< h
->num_servers
; srv
++) {
396 (void)memset(h
->servers
[srv
].secret
, 0,
397 strlen(h
->servers
[srv
].secret
));
398 free(h
->servers
[srv
].secret
);
405 rad_config(struct rad_handle
*h
, const char *path
)
408 char buf
[MAXCONFLINE
];
413 path
= PATH_RADIUS_CONF
;
414 if ((fp
= fopen(path
, "r")) == NULL
) {
415 generr(h
, "Cannot open \"%s\": %s", path
, strerror(errno
));
420 while (fgets(buf
, (int)sizeof buf
, fp
) != NULL
) {
422 const char *fields
[5];
428 const char *port_str
;
430 const char *timeout_str
;
431 const char *maxtries_str
;
433 const char *wanttype
;
434 unsigned long timeout
;
435 unsigned long maxtries
;
441 /* We know len > 0, else fgets would have returned NULL. */
442 if (buf
[len
- 1] != '\n') {
443 if (len
== sizeof buf
- 1)
444 generr(h
, "%s:%d: line too long", path
,
447 generr(h
, "%s:%d: missing newline", path
,
454 /* Extract the fields from the line. */
456 nfields
= split(buf
, fields
, sizeof(fields
) / sizeof(fields
[0]),
458 if (msg
[0] != '\0') {
459 generr(h
, "%s:%d: %s", path
, linenum
, msg
);
466 * The first field should contain "auth" or "acct" for
467 * authentication or accounting, respectively. But older
468 * versions of the file didn't have that field. Default
469 * it to "auth" for backward compatibility.
471 if (strcmp(fields
[0], "auth") != 0 &&
472 strcmp(fields
[0], "acct") != 0) {
474 generr(h
, "%s:%d: invalid service type", path
,
480 for (i
= nfields
; --i
> 0; )
481 fields
[i
] = fields
[i
- 1];
485 generr(h
, "%s:%d: missing shared secret", path
,
493 timeout_str
= fields
[3];
494 maxtries_str
= fields
[4];
496 /* Ignore the line if it is for the wrong service type. */
497 wanttype
= h
->type
== RADIUS_AUTH
? "auth" : "acct";
498 if (strcmp(type
, wanttype
) != 0)
501 /* Parse and validate the fields. */
502 res
= __UNCONST(host
);
503 host
= strsep(&res
, ":");
504 port_str
= strsep(&res
, ":");
505 if (port_str
!= NULL
) {
506 port
= (int)strtoul(port_str
, &end
, 10);
508 generr(h
, "%s:%d: invalid port", path
,
515 if (timeout_str
!= NULL
) {
516 timeout
= strtoul(timeout_str
, &end
, 10);
518 generr(h
, "%s:%d: invalid timeout", path
,
525 if (maxtries_str
!= NULL
) {
526 maxtries
= strtoul(maxtries_str
, &end
, 10);
528 generr(h
, "%s:%d: invalid maxtries", path
,
536 if (rad_add_server(h
, host
, port
, secret
, (int)timeout
,
537 (int)maxtries
) == -1) {
538 (void)strcpy(msg
, h
->errmsg
);
539 generr(h
, "%s:%d: %s", path
, linenum
, msg
);
544 /* Clear out the buffer to wipe a possible copy of a shared secret */
545 (void)memset(buf
, 0, sizeof buf
);
551 * rad_init_send_request() must have previously been called.
553 * 0 The application should select on *fd with a timeout of tv before
554 * calling rad_continue_send_request again.
559 rad_continue_send_request(struct rad_handle
*h
, int selected
, int *fd
,
565 struct sockaddr_in from
;
569 fromlen
= sizeof from
;
570 rv
= recvfrom(h
->fd
, h
->response
, (size_t)MSGSIZE
,
571 MSG_WAITALL
, (struct sockaddr
*)(void *)&from
, &fromlen
);
573 generr(h
, "recvfrom: %s", strerror(errno
));
577 if (is_valid_response(h
, h
->srv
, &from
)) {
578 h
->resp_len
= h
->response
[POS_LENGTH
] << 8 |
579 h
->response
[POS_LENGTH
+1];
580 h
->resp_pos
= POS_ATTRS
;
581 return h
->response
[POS_CODE
];
585 if (h
->try == h
->total_tries
) {
586 generr(h
, "No valid RADIUS responses received");
591 * Scan round-robin to the next server that has some
592 * tries left. There is guaranteed to be one, or we
593 * would have exited this loop by now.
595 while (h
->servers
[h
->srv
].num_tries
>= h
->servers
[h
->srv
].max_tries
)
596 if (++h
->srv
>= h
->num_servers
)
599 if (h
->request
[POS_CODE
] == RAD_ACCOUNTING_REQUEST
)
600 /* Insert the request authenticator into the request */
601 insert_request_authenticator(h
, h
->srv
);
603 /* Insert the scrambled password into the request */
604 if (h
->pass_pos
!= 0)
605 insert_scrambled_password(h
, h
->srv
);
607 insert_message_authenticator(h
, h
->srv
);
609 /* Send the request */
610 n
= sendto(h
->fd
, h
->request
, h
->req_len
, 0,
611 (const struct sockaddr
*)(void *)&h
->servers
[h
->srv
].addr
,
612 (socklen_t
)sizeof h
->servers
[h
->srv
].addr
);
613 if (n
!= (ssize_t
)h
->req_len
) {
615 generr(h
, "sendto: %s", strerror(errno
));
617 generr(h
, "sendto: short write");
622 h
->servers
[h
->srv
].num_tries
++;
623 tv
->tv_sec
= h
->servers
[h
->srv
].timeout
;
631 rad_create_request(struct rad_handle
*h
, int code
)
635 h
->request
[POS_CODE
] = code
;
636 h
->request
[POS_IDENT
] = ++h
->ident
;
637 /* Create a random authenticator */
638 for (i
= 0; i
< LEN_AUTH
; i
+= 2) {
640 r
= (uint32_t)random();
641 h
->request
[POS_AUTH
+i
] = (u_char
)r
;
642 h
->request
[POS_AUTH
+i
+1] = (u_char
)(r
>> 8);
644 h
->req_len
= POS_ATTRS
;
646 h
->request_created
= 1;
651 rad_cvt_addr(const void *data
)
653 struct in_addr value
;
655 (void)memcpy(&value
.s_addr
, data
, sizeof value
.s_addr
);
660 rad_cvt_int(const void *data
)
664 (void)memcpy(&value
, data
, sizeof value
);
669 rad_cvt_string(const void *data
, size_t len
)
675 (void)memcpy(s
, data
, len
);
682 * Returns the attribute type. If none are left, returns 0. On failure,
686 rad_get_attr(struct rad_handle
*h
, const void **value
, size_t *len
)
690 if (h
->resp_pos
>= h
->resp_len
)
692 if (h
->resp_pos
+ 2 > h
->resp_len
) {
693 generr(h
, "Malformed attribute in response");
696 type
= h
->response
[h
->resp_pos
++];
697 *len
= h
->response
[h
->resp_pos
++] - 2;
698 if (h
->resp_pos
+ (int)*len
> h
->resp_len
) {
699 generr(h
, "Malformed attribute in response");
702 *value
= &h
->response
[h
->resp_pos
];
703 h
->resp_pos
+= (int)*len
;
708 * Returns -1 on error, 0 to indicate no event and >0 for success
711 rad_init_send_request(struct rad_handle
*h
, int *fd
, struct timeval
*tv
)
715 /* Make sure we have a socket to use */
717 struct sockaddr_in saddr
;
719 if ((h
->fd
= socket(PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
)) == -1) {
720 generr(h
, "Cannot create socket: %s", strerror(errno
));
723 (void)memset(&saddr
, 0, sizeof saddr
);
724 saddr
.sin_len
= sizeof saddr
;
725 saddr
.sin_family
= AF_INET
;
726 saddr
.sin_addr
.s_addr
= INADDR_ANY
;
727 saddr
.sin_port
= htons(0);
728 if (bind(h
->fd
, (const struct sockaddr
*)(void *)&saddr
,
729 (socklen_t
)sizeof saddr
) == -1) {
730 generr(h
, "bind: %s", strerror(errno
));
737 if (h
->request
[POS_CODE
] == RAD_ACCOUNTING_REQUEST
) {
738 /* Make sure no password given */
739 if (h
->pass_pos
|| h
->chap_pass
) {
740 generr(h
, "User or Chap Password"
741 " in accounting request");
745 if (h
->eap_msg
== 0) {
746 /* Make sure the user gave us a password */
747 if (h
->pass_pos
== 0 && !h
->chap_pass
) {
748 generr(h
, "No User or Chap Password"
749 " attributes given");
752 if (h
->pass_pos
!= 0 && h
->chap_pass
) {
753 generr(h
, "Both User and Chap Password"
754 " attributes given");
760 /* Fill in the length field in the message */
761 h
->request
[POS_LENGTH
] = (unsigned char)(h
->req_len
>> 8);
762 h
->request
[POS_LENGTH
+1] = (unsigned char)h
->req_len
;
765 * Count the total number of tries we will make, and zero the
766 * counter for each server.
769 for (srv
= 0; srv
< h
->num_servers
; srv
++) {
770 h
->total_tries
+= h
->servers
[srv
].max_tries
;
771 h
->servers
[srv
].num_tries
= 0;
773 if (h
->total_tries
== 0) {
774 generr(h
, "No RADIUS servers specified");
780 return rad_continue_send_request(h
, 0, fd
, tv
);
784 * Create and initialize a rad_handle structure, and return it to the
785 * caller. Can fail only if the necessary memory cannot be allocated.
786 * In that case, it returns NULL.
791 struct rad_handle
*h
;
793 h
= (struct rad_handle
*)malloc(sizeof(struct rad_handle
));
800 (void)memset(h
->pass
, 0, sizeof h
->pass
);
804 h
->authentic_pos
= 0;
805 h
->type
= RADIUS_AUTH
;
806 h
->request_created
= 0;
815 struct rad_handle
*h
;
819 h
->type
= RADIUS_ACCT
;
826 return rad_auth_open();
830 rad_put_addr(struct rad_handle
*h
, int type
, struct in_addr addr
)
832 return rad_put_attr(h
, type
, &addr
.s_addr
, sizeof addr
.s_addr
);
836 rad_put_attr(struct rad_handle
*h
, int type
, const void *value
, size_t len
)
840 if (!h
->request_created
) {
841 generr(h
, "Please call rad_create_request()"
842 " before putting attributes");
846 if (h
->request
[POS_CODE
] == RAD_ACCOUNTING_REQUEST
) {
847 if (type
== RAD_EAP_MESSAGE
) {
848 generr(h
, "EAP-Message attribute is not valid"
849 " in accounting requests");
855 * When proxying EAP Messages, the Message Authenticator
856 * MUST be present; see RFC 3579.
858 if (type
== RAD_EAP_MESSAGE
) {
859 if (rad_put_message_authentic(h
) == -1)
863 if (type
== RAD_USER_PASSWORD
) {
864 result
= put_password_attr(h
, type
, value
, len
);
865 } else if (type
== RAD_MESSAGE_AUTHENTIC
) {
866 result
= rad_put_message_authentic(h
);
868 result
= put_raw_attr(h
, type
, value
, len
);
870 if (type
== RAD_CHAP_PASSWORD
)
872 else if (type
== RAD_EAP_MESSAGE
)
881 rad_put_int(struct rad_handle
*h
, int type
, u_int32_t value
)
885 nvalue
= htonl(value
);
886 return rad_put_attr(h
, type
, &nvalue
, sizeof nvalue
);
890 rad_put_string(struct rad_handle
*h
, int type
, const char *str
)
892 return rad_put_attr(h
, type
, str
, strlen(str
));
896 rad_put_message_authentic(struct rad_handle
*h
)
899 u_char md_zero
[MD5_DIGEST_LENGTH
];
901 if (h
->request
[POS_CODE
] == RAD_ACCOUNTING_REQUEST
) {
902 generr(h
, "Message-Authenticator is not valid"
903 " in accounting requests");
907 if (h
->authentic_pos
== 0) {
908 h
->authentic_pos
= (int)h
->req_len
;
909 (void)memset(md_zero
, 0, sizeof(md_zero
));
910 return (put_raw_attr(h
, RAD_MESSAGE_AUTHENTIC
, md_zero
,
915 generr(h
, "Message Authenticator not supported,"
916 " please recompile libradius with SSL support");
922 * Returns the response type code on success, or -1 on failure.
925 rad_send_request(struct rad_handle
*h
)
927 struct timeval timelimit
;
932 n
= rad_init_send_request(h
, &fd
, &tv
);
937 gettimeofday(&timelimit
, NULL
);
938 timeradd(&tv
, &timelimit
, &timelimit
);
944 FD_SET(fd
, &readfds
);
946 n
= select(fd
+ 1, &readfds
, NULL
, NULL
, &tv
);
949 generr(h
, "select: %s", strerror(errno
));
953 if (!FD_ISSET(fd
, &readfds
)) {
954 /* Compute a new timeout */
955 gettimeofday(&tv
, NULL
);
956 timersub(&timelimit
, &tv
, &tv
);
957 if (tv
.tv_sec
> 0 || (tv
.tv_sec
== 0 && tv
.tv_usec
> 0))
958 /* Continue the select */
962 n
= rad_continue_send_request(h
, n
, &fd
, &tv
);
967 gettimeofday(&timelimit
, NULL
);
968 timeradd(&tv
, &timelimit
, &timelimit
);
973 rad_strerror(struct rad_handle
*h
)
979 * Destructively split a string into fields separated by white space.
980 * `#' at the beginning of a field begins a comment that extends to the
981 * end of the string. Fields may be quoted with `"'. Inside quoted
982 * strings, the backslash escapes `\"' and `\\' are honored.
984 * Pointers to up to the first maxfields fields are stored in the fields
985 * array. Missing fields get NULL pointers.
987 * The return value is the actual number of fields parsed, and is always
990 * On a syntax error, places a message in the msg string, and returns
994 split(char *str
, const char *fields
[], size_t maxfields
, char *msg
,
999 static const char ws
[] = " \t";
1001 for (i
= 0; i
< maxfields
; i
++)
1005 while (*p
!= '\0') {
1007 if (*p
== '#' || *p
== '\0')
1009 if (i
>= maxfields
) {
1010 snprintf(msg
, msglen
, "line has too many fields");
1021 if (*p
!= '"' && *p
!= '\\' &&
1023 snprintf(msg
, msglen
,
1024 "invalid `\\' escape");
1029 snprintf(msg
, msglen
,
1030 "unterminated quoted string");
1037 if (*fields
[i
] == '\0') {
1038 snprintf(msg
, msglen
,
1039 "empty quoted string not permitted");
1042 if (*p
!= '\0' && strspn(p
, ws
) == 0) {
1043 snprintf(msg
, msglen
, "quoted string not"
1044 " followed by white space");
1049 p
+= strcspn(p
, ws
);
1059 rad_get_vendor_attr(u_int32_t
*vendor
, const void **data
, size_t *len
)
1061 const struct vendor_attribute
*attr
;
1063 attr
= (const struct vendor_attribute
*)*data
;
1064 *vendor
= ntohl(attr
->vendor_value
);
1065 *data
= attr
->attrib_data
;
1066 *len
= attr
->attrib_len
- 2;
1068 return (attr
->attrib_type
);
1072 rad_put_vendor_addr(struct rad_handle
*h
, int vendor
, int type
,
1073 struct in_addr addr
)
1075 return (rad_put_vendor_attr(h
, vendor
, type
, &addr
.s_addr
,
1076 sizeof addr
.s_addr
));
1080 rad_put_vendor_attr(struct rad_handle
*h
, int vendor
, int type
,
1081 const void *value
, size_t len
)
1083 struct vendor_attribute
*attr
;
1086 if (!h
->request_created
) {
1087 generr(h
, "Please call rad_create_request()"
1088 " before putting attributes");
1092 if ((attr
= malloc(len
+ 6)) == NULL
) {
1093 generr(h
, "malloc failure (%zu bytes)", len
+ 6);
1097 attr
->vendor_value
= htonl((uint32_t)vendor
);
1098 attr
->attrib_type
= type
;
1099 attr
->attrib_len
= (unsigned char)(len
+ 2);
1100 (void)memcpy(attr
->attrib_data
, value
, len
);
1102 res
= put_raw_attr(h
, RAD_VENDOR_SPECIFIC
, attr
, len
+ 6);
1104 if (res
== 0 && vendor
== RAD_VENDOR_MICROSOFT
1105 && (type
== RAD_MICROSOFT_MS_CHAP_RESPONSE
1106 || type
== RAD_MICROSOFT_MS_CHAP2_RESPONSE
)) {
1113 rad_put_vendor_int(struct rad_handle
*h
, int vendor
, int type
, u_int32_t i
)
1118 return (rad_put_vendor_attr(h
, vendor
, type
, &value
, sizeof value
));
1122 rad_put_vendor_string(struct rad_handle
*h
, int vendor
, int type
,
1125 return (rad_put_vendor_attr(h
, vendor
, type
, str
, strlen(str
)));
1129 rad_request_authenticator(struct rad_handle
*h
, char *buf
, size_t len
)
1133 (void)memcpy(buf
, h
->request
+ POS_AUTH
, (size_t)LEN_AUTH
);
1135 buf
[LEN_AUTH
] = '\0';
1140 rad_demangle(struct rad_handle
*h
, const void *mangled
, size_t mlen
)
1146 u_char b
[MD5_DIGEST_LENGTH
], *demangled
;
1149 if ((mlen
% 16 != 0) || mlen
> 128) {
1150 generr(h
, "Cannot interpret mangled data of length %lu",
1155 C
= (const u_char
*)mangled
;
1157 /* We need the shared secret as Salt */
1158 S
= rad_server_secret(h
);
1160 /* We need the request authenticator */
1161 if (rad_request_authenticator(h
, R
, sizeof R
) != LEN_AUTH
) {
1162 generr(h
, "Cannot obtain the RADIUS request authenticator");
1166 demangled
= malloc(mlen
);
1171 MD5Update(&Context
, (MD5Buf
)S
, (MD5Len
)strlen(S
));
1172 MD5Update(&Context
, (MD5Buf
)R
, (MD5Len
)LEN_AUTH
);
1173 MD5Final(b
, &Context
);
1178 for (i
= 0; i
< 16; i
++)
1179 demangled
[Ppos
++] = C
[i
] ^ b
[i
];
1183 MD5Update(&Context
, (MD5Buf
)S
, (MD5Len
)strlen(S
));
1184 MD5Update(&Context
, (MD5Buf
)C
, (MD5Len
)16);
1185 MD5Final(b
, &Context
);
1195 rad_demangle_mppe_key(struct rad_handle
*h
, const void *mangled
,
1196 size_t mlen
, size_t *len
)
1198 char R
[LEN_AUTH
]; /* variable names as per rfc2548 */
1200 u_char b
[MD5_DIGEST_LENGTH
], *demangled
= NULL
;
1201 const u_char
*A
, *C
;
1203 size_t Slen
, Clen
, i
, Ppos
;
1206 if (mlen
% 16 != SALT_LEN
) {
1207 generr(h
, "Cannot interpret mangled data of length %lu",
1212 /* We need the RADIUS Request-Authenticator */
1213 if (rad_request_authenticator(h
, R
, sizeof R
) != LEN_AUTH
) {
1214 generr(h
, "Cannot obtain the RADIUS request authenticator");
1218 A
= (const u_char
*)mangled
; /* Salt comes first */
1219 C
= (const u_char
*)mangled
+ SALT_LEN
; /* Then the ciphertext */
1220 Clen
= mlen
- SALT_LEN
;
1221 S
= rad_server_secret(h
); /* We need the RADIUS secret */
1223 P
= malloc(Clen
); /* We derive our plaintext */
1226 MD5Update(&Context
, (MD5Buf
)S
, (MD5Len
)Slen
);
1227 MD5Update(&Context
, (MD5Buf
)R
, (MD5Len
)LEN_AUTH
);
1228 MD5Update(&Context
, (MD5Buf
)A
, (MD5Len
)SALT_LEN
);
1229 MD5Final(b
, &Context
);
1235 for (i
= 0; i
< 16; i
++)
1236 P
[Ppos
++] = C
[i
] ^ b
[i
];
1240 MD5Update(&Context
, (MD5Buf
)S
, (MD5Len
)Slen
);
1241 MD5Update(&Context
, (MD5Buf
)C
, (MD5Len
)16);
1242 MD5Final(b
, &Context
);
1249 * The resulting plain text consists of a one-byte length, the text and
1250 * maybe some padding.
1253 if (*len
> mlen
- 1) {
1254 generr(h
, "Mangled data seems to be garbage %zu %zu",
1259 if (*len
> MPPE_KEY_LEN
* 2) {
1260 generr(h
, "Key to long (%zu) for me max. %d",
1261 *len
, MPPE_KEY_LEN
* 2);
1264 demangled
= malloc(*len
);
1268 (void)memcpy(demangled
, P
+ 1, *len
);
1275 rad_server_secret(struct rad_handle
*h
)
1277 return (h
->servers
[h
->srv
].secret
);