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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/types.h>
31 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
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
42 #define MD5_DIGEST_LENGTH 16
46 /* We need the MPPE_KEY_LEN define */
47 #include <netgraph/ng_mppc.h>
58 #include "radlib_private.h"
60 static void clear_password(struct rad_handle
*);
61 static void generr(struct rad_handle
*, const char *, ...)
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);
75 clear_password(struct rad_handle
*h
)
77 if (h
->pass_len
!= 0) {
78 memset(h
->pass
, 0, h
->pass_len
);
85 generr(struct rad_handle
*h
, const char *format
, ...)
90 vsnprintf(h
->errmsg
, ERRSIZE
, format
, ap
);
95 insert_scrambled_password(struct rad_handle
*h
, int srv
)
98 unsigned char md5
[MD5_DIGEST_LENGTH
];
99 const struct rad_server
*srvp
;
103 srvp
= &h
->servers
[srv
];
104 padded_len
= h
->pass_len
== 0 ? 16 : (h
->pass_len
+15) & ~0xf;
106 memcpy(md5
, &h
->request
[POS_AUTH
], LEN_AUTH
);
107 for (pos
= 0; pos
< padded_len
; pos
+= 16) {
110 /* Calculate the new scrambler */
112 MD5Update(&ctx
, srvp
->secret
, strlen(srvp
->secret
));
113 MD5Update(&ctx
, md5
, 16);
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.
122 for (i
= 0; i
< 16; i
++)
123 h
->request
[h
->pass_pos
+ pos
+ i
] =
124 md5
[i
] ^= h
->pass
[pos
+ i
];
129 insert_request_authenticator(struct rad_handle
*h
, int srv
)
132 const struct rad_server
*srvp
;
134 srvp
= &h
->servers
[srv
];
136 /* Create the request authenticator */
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
);
146 insert_message_authenticator(struct rad_handle
*h
, int srv
)
149 u_char md
[EVP_MAX_MD_SIZE
];
151 const struct rad_server
*srvp
;
153 srvp
= &h
->servers
[srv
];
155 if (h
->authentic_pos
!= 0) {
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
);
165 memcpy(&h
->request
[h
->authentic_pos
+ 2], md
, md_len
);
171 * Return true if the current response is valid for a request to the
175 is_valid_response(struct rad_handle
*h
, int srv
,
176 const struct sockaddr_in
*from
)
179 unsigned char md5
[MD5_DIGEST_LENGTH
];
180 const struct rad_server
*srvp
;
184 u_char resp
[MSGSIZE
], md
[EVP_MAX_MD_SIZE
];
189 srvp
= &h
->servers
[srv
];
191 /* Check the source address */
192 if (from
->sin_family
!= srvp
->addr
.sin_family
||
193 from
->sin_addr
.s_addr
!= srvp
->addr
.sin_addr
.s_addr
||
194 from
->sin_port
!= srvp
->addr
.sin_port
)
197 /* Check the message length */
198 if (h
->resp_len
< POS_ATTRS
)
200 len
= h
->response
[POS_LENGTH
] << 8 | h
->response
[POS_LENGTH
+1];
201 if (len
> h
->resp_len
)
204 /* Check the response authenticator */
206 MD5Update(&ctx
, &h
->response
[POS_CODE
], POS_AUTH
- POS_CODE
);
207 MD5Update(&ctx
, &h
->request
[POS_AUTH
], LEN_AUTH
);
208 MD5Update(&ctx
, &h
->response
[POS_ATTRS
], len
- POS_ATTRS
);
209 MD5Update(&ctx
, srvp
->secret
, strlen(srvp
->secret
));
211 if (memcmp(&h
->response
[POS_AUTH
], md5
, sizeof md5
) != 0)
216 * For non accounting responses check the message authenticator,
219 if (h
->response
[POS_CODE
] != RAD_ACCOUNTING_RESPONSE
) {
221 memcpy(resp
, h
->response
, MSGSIZE
);
224 /* Search and verify the Message-Authenticator */
225 while (pos
< len
- 2) {
227 if (h
->response
[pos
] == RAD_MESSAGE_AUTHENTIC
) {
228 /* zero fill the Message-Authenticator */
229 memset(&resp
[pos
+ 2], 0, MD5_DIGEST_LENGTH
);
231 HMAC_CTX_init(&hctx
);
232 HMAC_Init(&hctx
, srvp
->secret
,
233 strlen(srvp
->secret
), EVP_md5());
234 HMAC_Update(&hctx
, &h
->response
[POS_CODE
],
235 POS_AUTH
- POS_CODE
);
236 HMAC_Update(&hctx
, &h
->request
[POS_AUTH
],
238 HMAC_Update(&hctx
, &resp
[POS_ATTRS
],
239 h
->resp_len
- POS_ATTRS
);
240 HMAC_Final(&hctx
, md
, &md_len
);
241 HMAC_CTX_cleanup(&hctx
);
243 if (memcmp(md
, &h
->response
[pos
+ 2],
244 MD5_DIGEST_LENGTH
) != 0)
248 pos
+= h
->response
[pos
+ 1];
256 put_password_attr(struct rad_handle
*h
, int type
, const void *value
, size_t len
)
261 if (h
->pass_pos
!= 0) {
262 generr(h
, "Multiple User-Password attributes specified");
267 padded_len
= len
== 0 ? 16 : (len
+15) & ~0xf;
268 pad_len
= padded_len
- len
;
271 * Put in a place-holder attribute containing all zeros, and
272 * remember where it is so we can fill it in later.
275 put_raw_attr(h
, type
, h
->pass
, padded_len
);
276 h
->pass_pos
= h
->req_len
- padded_len
;
278 /* Save the cleartext password, padded as necessary */
279 memcpy(h
->pass
, value
, len
);
281 memset(h
->pass
+ len
, 0, pad_len
);
286 put_raw_attr(struct rad_handle
*h
, int type
, const void *value
, size_t len
)
289 generr(h
, "Attribute too long");
292 if (h
->req_len
+ 2 + len
> MSGSIZE
) {
293 generr(h
, "Maximum message length exceeded");
296 h
->request
[h
->req_len
++] = type
;
297 h
->request
[h
->req_len
++] = len
+ 2;
298 memcpy(&h
->request
[h
->req_len
], value
, len
);
304 rad_add_server(struct rad_handle
*h
, const char *host
, int port
,
305 const char *secret
, int timeout
, int tries
)
307 struct rad_server
*srvp
;
309 if (h
->num_servers
>= MAXSERVERS
) {
310 generr(h
, "Too many RADIUS servers specified");
313 srvp
= &h
->servers
[h
->num_servers
];
315 memset(&srvp
->addr
, 0, sizeof srvp
->addr
);
316 srvp
->addr
.sin_len
= sizeof srvp
->addr
;
317 srvp
->addr
.sin_family
= AF_INET
;
318 if (!inet_aton(host
, &srvp
->addr
.sin_addr
)) {
319 struct hostent
*hent
;
321 if ((hent
= gethostbyname(host
)) == NULL
) {
322 generr(h
, "%s: host not found", host
);
325 memcpy(&srvp
->addr
.sin_addr
, hent
->h_addr
,
326 sizeof srvp
->addr
.sin_addr
);
329 srvp
->addr
.sin_port
= htons((u_short
)port
);
331 struct servent
*sent
;
333 if (h
->type
== RADIUS_AUTH
)
334 srvp
->addr
.sin_port
=
335 (sent
= getservbyname("radius", "udp")) != NULL
?
336 sent
->s_port
: htons(RADIUS_PORT
);
338 srvp
->addr
.sin_port
=
339 (sent
= getservbyname("radacct", "udp")) != NULL
?
340 sent
->s_port
: htons(RADACCT_PORT
);
342 if ((srvp
->secret
= strdup(secret
)) == NULL
) {
343 generr(h
, "Out of memory");
346 srvp
->timeout
= timeout
;
347 srvp
->max_tries
= tries
;
354 rad_close(struct rad_handle
*h
)
360 for (srv
= 0; srv
< h
->num_servers
; srv
++) {
361 memset(h
->servers
[srv
].secret
, 0,
362 strlen(h
->servers
[srv
].secret
));
363 free(h
->servers
[srv
].secret
);
370 rad_config(struct rad_handle
*h
, const char *path
)
373 char buf
[MAXCONFLINE
];
378 path
= PATH_RADIUS_CONF
;
379 if ((fp
= fopen(path
, "r")) == NULL
) {
380 generr(h
, "Cannot open \"%s\": %s", path
, strerror(errno
));
385 while (fgets(buf
, sizeof buf
, fp
) != NULL
) {
398 unsigned long timeout
;
399 unsigned long maxtries
;
405 /* We know len > 0, else fgets would have returned NULL. */
406 if (buf
[len
- 1] != '\n') {
407 if (len
== sizeof buf
- 1)
408 generr(h
, "%s:%d: line too long", path
,
411 generr(h
, "%s:%d: missing newline", path
,
418 /* Extract the fields from the line. */
419 nfields
= split(buf
, fields
, 5, msg
, sizeof msg
);
421 generr(h
, "%s:%d: %s", path
, linenum
, msg
);
428 * The first field should contain "auth" or "acct" for
429 * authentication or accounting, respectively. But older
430 * versions of the file didn't have that field. Default
431 * it to "auth" for backward compatibility.
433 if (strcmp(fields
[0], "auth") != 0 &&
434 strcmp(fields
[0], "acct") != 0) {
436 generr(h
, "%s:%d: invalid service type", path
,
442 for (i
= nfields
; --i
> 0; )
443 fields
[i
] = fields
[i
- 1];
447 generr(h
, "%s:%d: missing shared secret", path
,
455 timeout_str
= fields
[3];
456 maxtries_str
= fields
[4];
458 /* Ignore the line if it is for the wrong service type. */
459 wanttype
= h
->type
== RADIUS_AUTH
? "auth" : "acct";
460 if (strcmp(type
, wanttype
) != 0)
463 /* Parse and validate the fields. */
465 host
= strsep(&res
, ":");
466 port_str
= strsep(&res
, ":");
467 if (port_str
!= NULL
) {
468 port
= strtoul(port_str
, &end
, 10);
470 generr(h
, "%s:%d: invalid port", path
,
477 if (timeout_str
!= NULL
) {
478 timeout
= strtoul(timeout_str
, &end
, 10);
480 generr(h
, "%s:%d: invalid timeout", path
,
487 if (maxtries_str
!= NULL
) {
488 maxtries
= strtoul(maxtries_str
, &end
, 10);
490 generr(h
, "%s:%d: invalid maxtries", path
,
498 if (rad_add_server(h
, host
, port
, secret
, timeout
, maxtries
) ==
500 strcpy(msg
, h
->errmsg
);
501 generr(h
, "%s:%d: %s", path
, linenum
, msg
);
506 /* Clear out the buffer to wipe a possible copy of a shared secret */
507 memset(buf
, 0, sizeof buf
);
513 * rad_init_send_request() must have previously been called.
515 * 0 The application should select on *fd with a timeout of tv before
516 * calling rad_continue_send_request again.
521 rad_continue_send_request(struct rad_handle
*h
, int selected
, int *fd
,
527 struct sockaddr_in from
;
530 fromlen
= sizeof from
;
531 h
->resp_len
= recvfrom(h
->fd
, h
->response
,
532 MSGSIZE
, MSG_WAITALL
, (struct sockaddr
*)&from
, &fromlen
);
533 if (h
->resp_len
== -1) {
534 generr(h
, "recvfrom: %s", strerror(errno
));
537 if (is_valid_response(h
, h
->srv
, &from
)) {
538 h
->resp_len
= h
->response
[POS_LENGTH
] << 8 |
539 h
->response
[POS_LENGTH
+1];
540 h
->resp_pos
= POS_ATTRS
;
541 return h
->response
[POS_CODE
];
545 if (h
->try == h
->total_tries
) {
546 generr(h
, "No valid RADIUS responses received");
551 * Scan round-robin to the next server that has some
552 * tries left. There is guaranteed to be one, or we
553 * would have exited this loop by now.
555 while (h
->servers
[h
->srv
].num_tries
>= h
->servers
[h
->srv
].max_tries
)
556 if (++h
->srv
>= h
->num_servers
)
559 if (h
->request
[POS_CODE
] == RAD_ACCOUNTING_REQUEST
)
560 /* Insert the request authenticator into the request */
561 insert_request_authenticator(h
, h
->srv
);
563 /* Insert the scrambled password into the request */
564 if (h
->pass_pos
!= 0)
565 insert_scrambled_password(h
, h
->srv
);
567 insert_message_authenticator(h
, h
->srv
);
569 /* Send the request */
570 n
= sendto(h
->fd
, h
->request
, h
->req_len
, 0,
571 (const struct sockaddr
*)&h
->servers
[h
->srv
].addr
,
572 sizeof h
->servers
[h
->srv
].addr
);
573 if (n
!= h
->req_len
) {
575 generr(h
, "sendto: %s", strerror(errno
));
577 generr(h
, "sendto: short write");
582 h
->servers
[h
->srv
].num_tries
++;
583 tv
->tv_sec
= h
->servers
[h
->srv
].timeout
;
591 rad_create_request(struct rad_handle
*h
, int code
)
595 h
->request
[POS_CODE
] = code
;
596 h
->request
[POS_IDENT
] = ++h
->ident
;
597 /* Create a random authenticator */
598 for (i
= 0; i
< LEN_AUTH
; i
+= 2) {
601 h
->request
[POS_AUTH
+i
] = (u_char
)r
;
602 h
->request
[POS_AUTH
+i
+1] = (u_char
)(r
>> 8);
604 h
->req_len
= POS_ATTRS
;
606 h
->request_created
= 1;
611 rad_cvt_addr(const void *data
)
613 struct in_addr value
;
615 memcpy(&value
.s_addr
, data
, sizeof value
.s_addr
);
620 rad_cvt_int(const void *data
)
624 memcpy(&value
, data
, sizeof value
);
629 rad_cvt_string(const void *data
, size_t len
)
635 memcpy(s
, data
, len
);
642 * Returns the attribute type. If none are left, returns 0. On failure,
646 rad_get_attr(struct rad_handle
*h
, const void **value
, size_t *len
)
650 if (h
->resp_pos
>= h
->resp_len
)
652 if (h
->resp_pos
+ 2 > h
->resp_len
) {
653 generr(h
, "Malformed attribute in response");
656 type
= h
->response
[h
->resp_pos
++];
657 *len
= h
->response
[h
->resp_pos
++] - 2;
658 if (h
->resp_pos
+ (int)*len
> h
->resp_len
) {
659 generr(h
, "Malformed attribute in response");
662 *value
= &h
->response
[h
->resp_pos
];
668 * Returns -1 on error, 0 to indicate no event and >0 for success
671 rad_init_send_request(struct rad_handle
*h
, int *fd
, struct timeval
*tv
)
675 /* Make sure we have a socket to use */
677 struct sockaddr_in sin
;
679 if ((h
->fd
= socket(PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
)) == -1) {
680 generr(h
, "Cannot create socket: %s", strerror(errno
));
683 memset(&sin
, 0, sizeof sin
);
684 sin
.sin_len
= sizeof sin
;
685 sin
.sin_family
= AF_INET
;
686 sin
.sin_addr
.s_addr
= INADDR_ANY
;
687 sin
.sin_port
= htons(0);
688 if (bind(h
->fd
, (const struct sockaddr
*)&sin
,
690 generr(h
, "bind: %s", strerror(errno
));
697 if (h
->request
[POS_CODE
] == RAD_ACCOUNTING_REQUEST
) {
698 /* Make sure no password given */
699 if (h
->pass_pos
|| h
->chap_pass
) {
700 generr(h
, "User or Chap Password"
701 " in accounting request");
705 if (h
->eap_msg
== 0) {
706 /* Make sure the user gave us a password */
707 if (h
->pass_pos
== 0 && !h
->chap_pass
) {
708 generr(h
, "No User or Chap Password"
709 " attributes given");
712 if (h
->pass_pos
!= 0 && h
->chap_pass
) {
713 generr(h
, "Both User and Chap Password"
714 " attributes given");
720 /* Fill in the length field in the message */
721 h
->request
[POS_LENGTH
] = h
->req_len
>> 8;
722 h
->request
[POS_LENGTH
+1] = h
->req_len
;
725 * Count the total number of tries we will make, and zero the
726 * counter for each server.
729 for (srv
= 0; srv
< h
->num_servers
; srv
++) {
730 h
->total_tries
+= h
->servers
[srv
].max_tries
;
731 h
->servers
[srv
].num_tries
= 0;
733 if (h
->total_tries
== 0) {
734 generr(h
, "No RADIUS servers specified");
740 return rad_continue_send_request(h
, 0, fd
, tv
);
744 * Create and initialize a rad_handle structure, and return it to the
745 * caller. Can fail only if the necessary memory cannot be allocated.
746 * In that case, it returns NULL.
751 struct rad_handle
*h
;
753 h
= (struct rad_handle
*)malloc(sizeof(struct rad_handle
));
760 memset(h
->pass
, 0, sizeof h
->pass
);
764 h
->authentic_pos
= 0;
765 h
->type
= RADIUS_AUTH
;
766 h
->request_created
= 0;
775 struct rad_handle
*h
;
779 h
->type
= RADIUS_ACCT
;
786 return rad_auth_open();
790 rad_put_addr(struct rad_handle
*h
, int type
, struct in_addr addr
)
792 return rad_put_attr(h
, type
, &addr
.s_addr
, sizeof addr
.s_addr
);
796 rad_put_attr(struct rad_handle
*h
, int type
, const void *value
, size_t len
)
800 if (!h
->request_created
) {
801 generr(h
, "Please call rad_create_request()"
802 " before putting attributes");
806 if (h
->request
[POS_CODE
] == RAD_ACCOUNTING_REQUEST
) {
807 if (type
== RAD_EAP_MESSAGE
) {
808 generr(h
, "EAP-Message attribute is not valid"
809 " in accounting requests");
815 * When proxying EAP Messages, the Message Authenticator
816 * MUST be present; see RFC 3579.
818 if (type
== RAD_EAP_MESSAGE
) {
819 if (rad_put_message_authentic(h
) == -1)
823 if (type
== RAD_USER_PASSWORD
) {
824 result
= put_password_attr(h
, type
, value
, len
);
825 } else if (type
== RAD_MESSAGE_AUTHENTIC
) {
826 result
= rad_put_message_authentic(h
);
828 result
= put_raw_attr(h
, type
, value
, len
);
830 if (type
== RAD_CHAP_PASSWORD
)
832 else if (type
== RAD_EAP_MESSAGE
)
841 rad_put_int(struct rad_handle
*h
, int type
, u_int32_t value
)
845 nvalue
= htonl(value
);
846 return rad_put_attr(h
, type
, &nvalue
, sizeof nvalue
);
850 rad_put_string(struct rad_handle
*h
, int type
, const char *str
)
852 return rad_put_attr(h
, type
, str
, strlen(str
));
856 rad_put_message_authentic(struct rad_handle
*h
)
859 u_char md_zero
[MD5_DIGEST_LENGTH
];
861 if (h
->request
[POS_CODE
] == RAD_ACCOUNTING_REQUEST
) {
862 generr(h
, "Message-Authenticator is not valid"
863 " in accounting requests");
867 if (h
->authentic_pos
== 0) {
868 h
->authentic_pos
= h
->req_len
;
869 memset(md_zero
, 0, sizeof(md_zero
));
870 return (put_raw_attr(h
, RAD_MESSAGE_AUTHENTIC
, md_zero
,
875 generr(h
, "Message Authenticator not supported,"
876 " please recompile libradius with SSL support");
882 * Returns the response type code on success, or -1 on failure.
885 rad_send_request(struct rad_handle
*h
)
887 struct timeval timelimit
;
892 n
= rad_init_send_request(h
, &fd
, &tv
);
897 gettimeofday(&timelimit
, NULL
);
898 timeradd(&tv
, &timelimit
, &timelimit
);
904 FD_SET(fd
, &readfds
);
906 n
= select(fd
+ 1, &readfds
, NULL
, NULL
, &tv
);
909 generr(h
, "select: %s", strerror(errno
));
913 if (!FD_ISSET(fd
, &readfds
)) {
914 /* Compute a new timeout */
915 gettimeofday(&tv
, NULL
);
916 timersub(&timelimit
, &tv
, &tv
);
917 if (tv
.tv_sec
> 0 || (tv
.tv_sec
== 0 && tv
.tv_usec
> 0))
918 /* Continue the select */
922 n
= rad_continue_send_request(h
, n
, &fd
, &tv
);
927 gettimeofday(&timelimit
, NULL
);
928 timeradd(&tv
, &timelimit
, &timelimit
);
933 rad_strerror(struct rad_handle
*h
)
939 * Destructively split a string into fields separated by white space.
940 * `#' at the beginning of a field begins a comment that extends to the
941 * end of the string. Fields may be quoted with `"'. Inside quoted
942 * strings, the backslash escapes `\"' and `\\' are honored.
944 * Pointers to up to the first maxfields fields are stored in the fields
945 * array. Missing fields get NULL pointers.
947 * The return value is the actual number of fields parsed, and is always
950 * On a syntax error, places a message in the msg string, and returns -1.
953 split(char *str
, char *fields
[], int maxfields
, char *msg
, size_t msglen
)
957 static const char ws
[] = " \t";
959 for (i
= 0; i
< maxfields
; i
++)
965 if (*p
== '#' || *p
== '\0')
967 if (i
>= maxfields
) {
968 snprintf(msg
, msglen
, "line has too many fields");
979 if (*p
!= '"' && *p
!= '\\' &&
981 snprintf(msg
, msglen
,
982 "invalid `\\' escape");
987 snprintf(msg
, msglen
,
988 "unterminated quoted string");
995 if (*fields
[i
] == '\0') {
996 snprintf(msg
, msglen
,
997 "empty quoted string not permitted");
1000 if (*p
!= '\0' && strspn(p
, ws
) == 0) {
1001 snprintf(msg
, msglen
, "quoted string not"
1002 " followed by white space");
1007 p
+= strcspn(p
, ws
);
1017 rad_get_vendor_attr(u_int32_t
*vendor
, const void **data
, size_t *len
)
1019 struct vendor_attribute
*attr
;
1021 attr
= (struct vendor_attribute
*)*data
;
1022 *vendor
= ntohl(attr
->vendor_value
);
1023 *data
= attr
->attrib_data
;
1024 *len
= attr
->attrib_len
- 2;
1026 return (attr
->attrib_type
);
1030 rad_put_vendor_addr(struct rad_handle
*h
, int vendor
, int type
,
1031 struct in_addr addr
)
1033 return (rad_put_vendor_attr(h
, vendor
, type
, &addr
.s_addr
,
1034 sizeof addr
.s_addr
));
1038 rad_put_vendor_attr(struct rad_handle
*h
, int vendor
, int type
,
1039 const void *value
, size_t len
)
1041 struct vendor_attribute
*attr
;
1044 if (!h
->request_created
) {
1045 generr(h
, "Please call rad_create_request()"
1046 " before putting attributes");
1050 if ((attr
= malloc(len
+ 6)) == NULL
) {
1051 generr(h
, "malloc failure (%zu bytes)", len
+ 6);
1055 attr
->vendor_value
= htonl(vendor
);
1056 attr
->attrib_type
= type
;
1057 attr
->attrib_len
= len
+ 2;
1058 memcpy(attr
->attrib_data
, value
, len
);
1060 res
= put_raw_attr(h
, RAD_VENDOR_SPECIFIC
, attr
, len
+ 6);
1062 if (res
== 0 && vendor
== RAD_VENDOR_MICROSOFT
1063 && (type
== RAD_MICROSOFT_MS_CHAP_RESPONSE
1064 || type
== RAD_MICROSOFT_MS_CHAP2_RESPONSE
)) {
1071 rad_put_vendor_int(struct rad_handle
*h
, int vendor
, int type
, u_int32_t i
)
1076 return (rad_put_vendor_attr(h
, vendor
, type
, &value
, sizeof value
));
1080 rad_put_vendor_string(struct rad_handle
*h
, int vendor
, int type
,
1083 return (rad_put_vendor_attr(h
, vendor
, type
, str
, strlen(str
)));
1087 rad_request_authenticator(struct rad_handle
*h
, char *buf
, size_t len
)
1091 memcpy(buf
, h
->request
+ POS_AUTH
, LEN_AUTH
);
1093 buf
[LEN_AUTH
] = '\0';
1098 rad_demangle(struct rad_handle
*h
, const void *mangled
, size_t mlen
)
1104 u_char b
[MD5_DIGEST_LENGTH
], *C
, *demangled
;
1106 if ((mlen
% 16 != 0) || mlen
> 128) {
1107 generr(h
, "Cannot interpret mangled data of length %lu",
1112 C
= (u_char
*)mangled
;
1114 /* We need the shared secret as Salt */
1115 S
= rad_server_secret(h
);
1117 /* We need the request authenticator */
1118 if (rad_request_authenticator(h
, R
, sizeof R
) != LEN_AUTH
) {
1119 generr(h
, "Cannot obtain the RADIUS request authenticator");
1123 demangled
= malloc(mlen
);
1128 MD5Update(&Context
, S
, strlen(S
));
1129 MD5Update(&Context
, R
, LEN_AUTH
);
1130 MD5Final(b
, &Context
);
1135 for (i
= 0; i
< 16; i
++)
1136 demangled
[Ppos
++] = C
[i
] ^ b
[i
];
1140 MD5Update(&Context
, S
, strlen(S
));
1141 MD5Update(&Context
, C
, 16);
1142 MD5Final(b
, &Context
);
1152 rad_demangle_mppe_key(struct rad_handle
*h
, const void *mangled
,
1153 size_t mlen
, size_t *len
)
1155 char R
[LEN_AUTH
]; /* variable names as per rfc2548 */
1157 u_char b
[MD5_DIGEST_LENGTH
], *demangled
;
1158 const u_char
*A
, *C
;
1160 int Slen
, i
, Clen
, Ppos
;
1163 if (mlen
% 16 != SALT_LEN
) {
1164 generr(h
, "Cannot interpret mangled data of length %lu",
1169 /* We need the RADIUS Request-Authenticator */
1170 if (rad_request_authenticator(h
, R
, sizeof R
) != LEN_AUTH
) {
1171 generr(h
, "Cannot obtain the RADIUS request authenticator");
1175 A
= (const u_char
*)mangled
; /* Salt comes first */
1176 C
= (const u_char
*)mangled
+ SALT_LEN
; /* Then the ciphertext */
1177 Clen
= mlen
- SALT_LEN
;
1178 S
= rad_server_secret(h
); /* We need the RADIUS secret */
1180 P
= alloca(Clen
); /* We derive our plaintext */
1183 MD5Update(&Context
, S
, Slen
);
1184 MD5Update(&Context
, R
, LEN_AUTH
);
1185 MD5Update(&Context
, A
, SALT_LEN
);
1186 MD5Final(b
, &Context
);
1192 for (i
= 0; i
< 16; i
++)
1193 P
[Ppos
++] = C
[i
] ^ b
[i
];
1197 MD5Update(&Context
, S
, Slen
);
1198 MD5Update(&Context
, C
, 16);
1199 MD5Final(b
, &Context
);
1206 * The resulting plain text consists of a one-byte length, the text and
1207 * maybe some padding.
1210 if (*len
> mlen
- 1) {
1211 generr(h
, "Mangled data seems to be garbage %zu %zu",
1216 if (*len
> MPPE_KEY_LEN
* 2) {
1217 generr(h
, "Key to long (%zu) for me max. %d",
1218 *len
, MPPE_KEY_LEN
* 2);
1221 demangled
= malloc(*len
);
1225 memcpy(demangled
, P
+ 1, *len
);
1230 rad_server_secret(struct rad_handle
*h
)
1232 return (h
->servers
[h
->srv
].secret
);