diff options
Diffstat (limited to 'lib/libradius')
-rw-r--r-- | lib/libradius/Makefile | 45 | ||||
-rw-r--r-- | lib/libradius/libradius.3 | 555 | ||||
-rw-r--r-- | lib/libradius/radius.conf.5 | 185 | ||||
-rw-r--r-- | lib/libradius/radlib.c | 1233 | ||||
-rw-r--r-- | lib/libradius/radlib.h | 220 | ||||
-rw-r--r-- | lib/libradius/radlib_private.h | 103 | ||||
-rw-r--r-- | lib/libradius/radlib_vs.h | 84 |
7 files changed, 2425 insertions, 0 deletions
diff --git a/lib/libradius/Makefile b/lib/libradius/Makefile new file mode 100644 index 0000000..f4855dc --- /dev/null +++ b/lib/libradius/Makefile @@ -0,0 +1,45 @@ +# Copyright 1998 Juniper Networks, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ + +.include <bsd.own.mk> + +LIB= radius +SRCS= radlib.c +INCS= radlib.h radlib_vs.h +CFLAGS+= -Wall +SHLIB_MAJOR= 3 +MAN= libradius.3 radius.conf.5 + +.if ${MK_OPENSSL} == "no" +DPADD= ${LIBMD} +LDADD= -lmd +.else +DPADD= ${LIBCRYPTO} +LDADD= -lcrypto +CFLAGS+= -DWITH_SSL +.endif + +.include <bsd.lib.mk> diff --git a/lib/libradius/libradius.3 b/lib/libradius/libradius.3 new file mode 100644 index 0000000..095d6e9 --- /dev/null +++ b/lib/libradius/libradius.3 @@ -0,0 +1,555 @@ +.\" Copyright 1998 Juniper Networks, Inc. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd April 27, 2004 +.Dt LIBRADIUS 3 +.Os +.Sh NAME +.Nm libradius +.Nd RADIUS client library +.Sh SYNOPSIS +.In radlib.h +.Ft "struct rad_handle *" +.Fn rad_acct_open "void" +.Ft int +.Fn rad_add_server "struct rad_handle *h" "const char *host" "int port" "const char *secret" "int timeout" "int max_tries" +.Ft "struct rad_handle *" +.Fn rad_auth_open "void" +.Ft void +.Fn rad_close "struct rad_handle *h" +.Ft int +.Fn rad_config "struct rad_handle *h" "const char *file" +.Ft int +.Fn rad_continue_send_request "struct rad_handle *h" "int selected" "int *fd" "struct timeval *tv" +.Ft int +.Fn rad_create_request "struct rad_handle *h" "int code" +.Ft "struct in_addr" +.Fn rad_cvt_addr "const void *data" +.Ft u_int32_t +.Fn rad_cvt_int "const void *data" +.Ft char * +.Fn rad_cvt_string "const void *data" "size_t len" +.Ft int +.Fn rad_get_attr "struct rad_handle *h" "const void **data" "size_t *len" +.Ft int +.Fn rad_get_vendor_attr "u_int32_t *vendor" "const void **data" "size_t *len" +.Ft int +.Fn rad_init_send_request "struct rad_handle *h" "int *fd" "struct timeval *tv" +.Ft int +.Fn rad_put_addr "struct rad_handle *h" "int type" "struct in_addr addr" +.Ft int +.Fn rad_put_attr "struct rad_handle *h" "int type" "const void *data" "size_t len" +.Ft int +.Fn rad_put_int "struct rad_handle *h" "int type" "u_int32_t value" +.Ft int +.Fn rad_put_string "struct rad_handle *h" "int type" "const char *str" +.Ft int +.Fn rad_put_message_authentic "struct rad_handle *h" +.Ft int +.Fn rad_put_vendor_addr "struct rad_handle *h" "int vendor" "int type" "struct in_addr addr" +.Ft int +.Fn rad_put_vendor_attr "struct rad_handle *h" "int vendor" "int type" "const void *data" "size_t len" +.Ft int +.Fn rad_put_vendor_int "struct rad_handle *h" "int vendor" "int type" "u_int32_t value" +.Ft int +.Fn rad_put_vendor_string "struct rad_handle *h" "int vendor" "int type" "const char *str" +.Ft ssize_t +.Fn rad_request_authenticator "struct rad_handle *h" "char *buf" "size_t len" +.Ft int +.Fn rad_send_request "struct rad_handle *h" +.Ft "const char *" +.Fn rad_server_secret "struct rad_handle *h" +.Ft u_char * +.Fn rad_demangle "struct rad_handle *h" "const void *mangled" "size_t mlen" +.Ft u_char * +.Fn rad_demangle_mppe_key "struct rad_handle *h" "const void *mangled" "size_t mlen" "size_t *len" +.Ft "const char *" +.Fn rad_strerror "struct rad_handle *h" +.Sh DESCRIPTION +The +.Nm +library implements the client side of the Remote Authentication Dial +In User Service (RADIUS). +RADIUS, defined in RFCs 2865 and 2866, +allows clients to perform authentication and accounting by means of +network requests to remote servers. +.Ss Initialization +To use the library, an application must first call +.Fn rad_auth_open +or +.Fn rad_acct_open +to obtain a +.Vt "struct rad_handle *" , +which provides the context for subsequent operations. +The former function is used for RADIUS authentication and the +latter is used for RADIUS accounting. +Calls to +.Fn rad_auth_open +and +.Fn rad_acct_open +always succeed unless insufficient virtual memory is available. +If +the necessary memory cannot be allocated, the functions return +.Dv NULL . +For compatibility with earlier versions of this library, +.Fn rad_open +is provided as a synonym for +.Fn rad_auth_open . +.Pp +Before issuing any RADIUS requests, the library must be made aware +of the servers it can contact. +The easiest way to configure the +library is to call +.Fn rad_config . +.Fn rad_config +causes the library to read a configuration file whose format is +described in +.Xr radius.conf 5 . +The pathname of the configuration file is passed as the +.Fa file +argument to +.Fn rad_config . +This argument may also be given as +.Dv NULL , +in which case the standard configuration file +.Pa /etc/radius.conf +is used. +.Fn rad_config +returns 0 on success, or \-1 if an error occurs. +.Pp +The library can also be configured programmatically by calls to +.Fn rad_add_server . +The +.Fa host +parameter specifies the server host, either as a fully qualified +domain name or as a dotted-quad IP address in text form. +The +.Fa port +parameter specifies the UDP port to contact on the server. +If +.Fa port +is given as 0, the library looks up the +.Ql radius/udp +or +.Ql radacct/udp +service in the network +.Xr services 5 +database, and uses the port found +there. +If no entry is found, the library uses the standard RADIUS +ports, 1812 for authentication and 1813 for accounting. +The shared secret for the server host is passed to the +.Fa secret +parameter. +It may be any +.Dv NUL Ns -terminated +string of bytes. +The RADIUS protocol +ignores all but the leading 128 bytes of the shared secret. +The timeout for receiving replies from the server is passed to the +.Fa timeout +parameter, in units of seconds. +The maximum number of repeated +requests to make before giving up is passed into the +.Fa max_tries +parameter. +.Fn rad_add_server +returns 0 on success, or \-1 if an error occurs. +.Pp +.Fn rad_add_server +may be called multiple times, and it may be used together with +.Fn rad_config . +At most 10 servers may be specified. +When multiple servers are given, they are tried in round-robin +fashion until a valid response is received, or until each server's +.Fa max_tries +limit has been reached. +.Ss Creating a RADIUS Request +A RADIUS request consists of a code specifying the kind of request, +and zero or more attributes which provide additional information. +To +begin constructing a new request, call +.Fn rad_create_request . +In addition to the usual +.Vt "struct rad_handle *" , +this function takes a +.Fa code +parameter which specifies the type of the request. +Most often this +will be +.Dv RAD_ACCESS_REQUEST . +.Fn rad_create_request +returns 0 on success, or \-1 on if an error occurs. +.Pp +After the request has been created with +.Fn rad_create_request , +attributes can be attached to it. +This is done through calls to +.Fn rad_put_addr , +.Fn rad_put_int , +and +.Fn rad_put_string . +Each accepts a +.Fa type +parameter identifying the attribute, and a value which may be +an Internet address, an integer, or a +.Dv NUL Ns -terminated +string, +respectively. +Alternatively, +.Fn rad_put_vendor_addr , +.Fn rad_put_vendor_int +or +.Fn rad_put_vendor_string +may be used to specify vendor specific attributes. +Vendor specific +definitions may be found in +.In radlib_vs.h +.Pp +The library also provides a function +.Fn rad_put_attr +which can be used to supply a raw, uninterpreted attribute. +The +.Fa data +argument points to an array of bytes, and the +.Fa len +argument specifies its length. +.Pp +It is possible adding the Message-Authenticator to the request. +This is an HMAC-MD5 hash of the entire Access-Request packet (see RFC 3579). +This attribute must be present in any packet that includes an EAP-Message +attribute. +It can be added by using the +.Fn rad_put_message_authentic +function. +The +.Nm +library +calculates the HMAC-MD5 hash implicitly before sending the request. +If the Message-Authenticator was found inside the response packet, +then the packet is silently dropped, if the validation failed. +In order to get this feature, the library should be compiled with +OpenSSL support. +.Pp +The +.Fn rad_put_X +functions return 0 on success, or \-1 if an error occurs. +.Ss Sending the Request and Receiving the Response +After the RADIUS request has been constructed, it is sent either by means of +.Fn rad_send_request +or by a combination of calls to +.Fn rad_init_send_request +and +.Fn rad_continue_send_request . +.Pp +The +.Fn rad_send_request +function sends the request and waits for a valid reply, +retrying the defined servers in round-robin fashion as necessary. +If a valid response is received, +.Fn rad_send_request +returns the RADIUS code which specifies the type of the response. +This will typically be +.Dv RAD_ACCESS_ACCEPT , +.Dv RAD_ACCESS_REJECT , +or +.Dv RAD_ACCESS_CHALLENGE . +If no valid response is received, +.Fn rad_send_request +returns \-1. +.Pp +As an alternative, if you do not wish to block waiting for a response, +.Fn rad_init_send_request +and +.Fn rad_continue_send_request +may be used instead. +If a reply is received from the RADIUS server or a +timeout occurs, these functions return a value as described for +.Fn rad_send_request . +Otherwise, a value of zero is returned and the values pointed to by +.Fa fd +and +.Fa tv +are set to the descriptor and timeout that should be passed to +.Xr select 2 . +.Pp +.Fn rad_init_send_request +must be called first, followed by repeated calls to +.Fn rad_continue_send_request +as long as a return value of zero is given. +Between each call, the application should call +.Xr select 2 , +passing +.Fa *fd +as a read descriptor and timing out after the interval specified by +.Fa tv . +When +.Xr select 2 +returns, +.Fn rad_continue_send_request +should be called with +.Fa selected +set to a non-zero value if +.Xr select 2 +indicated that the descriptor is readable. +.Pp +Like RADIUS requests, each response may contain zero or more +attributes. +After a response has been received successfully by +.Fn rad_send_request +or +.Fn rad_continue_send_request , +its attributes can be extracted one by one using +.Fn rad_get_attr . +Each time +.Fn rad_get_attr +is called, it gets the next attribute from the current response, and +stores a pointer to the data and the length of the data via the +reference parameters +.Fa data +and +.Fa len , +respectively. +Note that the data resides in the response itself, +and must not be modified. +A successful call to +.Fn rad_get_attr +returns the RADIUS attribute type. +If no more attributes remain in the current response, +.Fn rad_get_attr +returns 0. +If an error such as a malformed attribute is detected, \-1 is +returned. +.Pp +If +.Fn rad_get_attr +returns +.Dv RAD_VENDOR_SPECIFIC , +.Fn rad_get_vendor_attr +may be called to determine the vendor. +The vendor specific RADIUS attribute type is returned. +The reference parameters +.Fa data +and +.Fa len +(as returned from +.Fn rad_get_attr ) +are passed to +.Fn rad_get_vendor_attr , +and are adjusted to point to the vendor specific attribute data. +.Pp +The common types of attributes can be decoded using +.Fn rad_cvt_addr , +.Fn rad_cvt_int , +and +.Fn rad_cvt_string . +These functions accept a pointer to the attribute data, which should +have been obtained using +.Fn rad_get_attr +and optionally +.Fn rad_get_vendor_attr . +In the case of +.Fn rad_cvt_string , +the length +.Fa len +must also be given. +These functions interpret the attribute as an +Internet address, an integer, or a string, respectively, and return +its value. +.Fn rad_cvt_string +returns its value as a +.Dv NUL Ns -terminated +string in dynamically +allocated memory. +The application should free the string using +.Xr free 3 +when it is no longer needed. +.Pp +If insufficient virtual memory is available, +.Fn rad_cvt_string +returns +.Dv NULL . +.Fn rad_cvt_addr +and +.Fn rad_cvt_int +cannot fail. +.Pp +The +.Fn rad_request_authenticator +function may be used to obtain the Request-Authenticator attribute value +associated with the current RADIUS server according to the supplied +rad_handle. +The target buffer +.Fa buf +of length +.Fa len +must be supplied and should be at least 16 bytes. +The return value is the number of bytes written to +.Fa buf +or \-1 to indicate that +.Fa len +was not large enough. +.Pp +The +.Fn rad_server_secret +returns the secret shared with the current RADIUS server according to the +supplied rad_handle. +.Pp +The +.Fn rad_demangle +function demangles attributes containing passwords and MS-CHAPv1 MPPE-Keys. +The return value is +.Dv NULL +on failure, or the plaintext attribute. +This value should be freed using +.Xr free 3 +when it is no longer needed. +.Pp +The +.Fn rad_demangle_mppe_key +function demangles the send- and recv-keys when using MPPE (see RFC 2548). +The return value is +.Dv NULL +on failure, or the plaintext attribute. +This value should be freed using +.Xr free 3 +when it is no longer needed. +.Ss Obtaining Error Messages +Those functions which accept a +.Vt "struct rad_handle *" +argument record an error message if they fail. +The error message +can be retrieved by calling +.Fn rad_strerror . +The message text is overwritten on each new error for the given +.Vt "struct rad_handle *" . +Thus the message must be copied if it is to be preserved through +subsequent library calls using the same handle. +.Ss Cleanup +To free the resources used by the RADIUS library, call +.Fn rad_close . +.Sh RETURN VALUES +The following functions return a non-negative value on success. +If +they detect an error, they return \-1 and record an error message +which can be retrieved using +.Fn rad_strerror . +.Pp +.Bl -item -offset indent -compact +.It +.Fn rad_add_server +.It +.Fn rad_config +.It +.Fn rad_create_request +.It +.Fn rad_get_attr +.It +.Fn rad_put_addr +.It +.Fn rad_put_attr +.It +.Fn rad_put_int +.It +.Fn rad_put_string +.It +.Fn rad_put_message_authentic +.It +.Fn rad_init_send_request +.It +.Fn rad_continue_send_request +.It +.Fn rad_send_request +.El +.Pp +The following functions return a +.No non- Ns Dv NULL +pointer on success. +If they are unable to allocate sufficient +virtual memory, they return +.Dv NULL , +without recording an error message. +.Pp +.Bl -item -offset indent -compact +.It +.Fn rad_acct_open +.It +.Fn rad_auth_open +.It +.Fn rad_cvt_string +.El +.Pp +The following functions return a +.No non- Ns Dv NULL +pointer on success. +If they fail, they return +.Dv NULL , +with recording an error message. +.Pp +.Bl -item -offset indent -compact +.It +.Fn rad_demangle +.It +.Fn rad_demangle_mppe_key +.El +.Sh FILES +.Bl -tag -width indent +.It Pa /etc/radius.conf +.El +.Sh SEE ALSO +.Xr radius.conf 5 +.Rs +.%A "C. Rigney, et al" +.%T "Remote Authentication Dial In User Service (RADIUS)" +.%O "RFC 2865" +.Re +.Rs +.%A "C. Rigney" +.%T "RADIUS Accounting" +.%O "RFC 2866" +.Re +.Rs +.%A G. Zorn +.%T "Microsoft Vendor-specific RADIUS attributes" +.%O RFC 2548 +.Re +.Rs +.%A C. Rigney, et al +.%T "RADIUS extensions" +.%O RFC 2869 +.Re +.Sh AUTHORS +.An -nosplit +This software was originally written by +.An John Polstra , +and donated to the +.Fx +project by Juniper Networks, Inc. +.An Oleg Semyonov +subsequently added the ability to perform RADIUS +accounting. +Later additions and changes by +.An Michael Bretterklieber . diff --git a/lib/libradius/radius.conf.5 b/lib/libradius/radius.conf.5 new file mode 100644 index 0000000..6fa5cd7 --- /dev/null +++ b/lib/libradius/radius.conf.5 @@ -0,0 +1,185 @@ +.\" Copyright 1998 Juniper Networks, Inc. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd October 30, 1999 +.Dt RADIUS.CONF 5 +.Os +.Sh NAME +.Nm radius.conf +.Nd RADIUS client configuration file +.Sh SYNOPSIS +.Pa /etc/radius.conf +.Sh DESCRIPTION +.Nm +contains the information necessary to configure the RADIUS client +library. +It is parsed by +.Xr rad_config 3 . +The file contains one or more lines of text, each describing a +single RADIUS server which will be used by the library. +Leading +white space is ignored, as are empty lines and lines containing +only comments. +.Pp +A RADIUS server is described by three to five fields on a line: +.Pp +.Bl -item -offset indent -compact +.It +Service type +.It +Server host +.It +Shared secret +.It +Timeout +.It +Retries +.El +.Pp +The fields are separated by white space. +The +.Ql # +character at the beginning of a field begins a comment, which extends +to the end of the line. +A field may be enclosed in double quotes, +in which case it may contain white space and/or begin with the +.Ql # +character. +Within a quoted string, the double quote character can +be represented by +.Ql \e\&" , +and the backslash can be represented by +.Ql \e\e . +No other escape sequences are supported. +.Pp +.Pp +The first field gives the service type, either +.Ql auth +for RADIUS authentication or +.Ql acct +for RADIUS accounting. +If a single server provides both services, two +lines are required in the file. +Earlier versions of this file did +not include a service type. +For backward compatibility, if the first +field is not +.Ql auth +or +.Ql acct +the library behaves as if +.Ql auth +were specified, and interprets the fields in the line as if they +were fields two through five. +.Pp +The second field specifies +the server host, either as a fully qualified domain name or as a +dotted-quad IP address. +The host may optionally be followed by a +.Ql \&: +and a numeric port number, without intervening white space. +If the +port specification is omitted, it defaults to the +.Ql radius +or +.Ql radacct +service in the +.Pa /etc/services +file for service types +.Ql auth +and +.Ql acct , +respectively. +If no such entry is present, the standard ports 1812 and 1813 are +used. +.Pp +The third field contains the shared secret, which should be known +only to the client and server hosts. +It is an arbitrary string of +characters, though it must be enclosed in double quotes if it +contains white space. +The shared secret may be +any length, but the RADIUS protocol uses only the first 128 +characters. +N.B., some popular RADIUS servers have bugs which +prevent them from working properly with secrets longer than 16 +characters. +.Pp +The fourth field contains a decimal integer specifying the timeout in +seconds for receiving a valid reply from the server. +If this field +is omitted, it defaults to 3 seconds. +.Pp +The fifth field contains a decimal integer specifying the maximum +number of attempts that will be made to authenticate with the server +before giving up. +If omitted, it defaults to 3 attempts. +Note, +this is the total number of attempts and not the number of retries. +.Pp +Up to 10 RADIUS servers may be specified for each service type. +The servers are tried in +round-robin fashion, until a valid response is received or the +maximum number of tries has been reached for all servers. +.Pp +The standard location for this file is +.Pa /etc/radius.conf . +But an alternate pathname may be specified in the call to +.Xr rad_config 3 . +Since the file contains sensitive information in the form of the +shared secrets, it should not be readable except by root. +.Sh FILES +.Pa /etc/radius.conf +.Sh EXAMPLES +.Bd -literal +# A simple entry using all the defaults: +acct radius1.domain.com OurLittleSecret + +# A server still using the obsolete RADIUS port, with increased +# timeout and maximum tries: +auth auth.domain.com:1645 "I can't see you" 5 4 + +# A server specified by its IP address: +auth 192.168.27.81 $X*#..38947ax-+= +.Ed +.Sh SEE ALSO +.Xr libradius 3 +.Rs +.%A C. Rigney, et al +.%T "Remote Authentication Dial In User Service (RADIUS)" +.%O RFC 2138 +.Re +.Rs +.%A C. Rigney +.%T RADIUS Accounting +.%O RFC 2139 +.Re +.Sh AUTHORS +This documentation was written by +.An John Polstra , +and donated to the +.Fx +project by Juniper Networks, Inc. diff --git a/lib/libradius/radlib.c b/lib/libradius/radlib.c new file mode 100644 index 0000000..b21447e --- /dev/null +++ b/lib/libradius/radlib.c @@ -0,0 +1,1233 @@ +/*- + * Copyright 1998 Juniper Networks, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#ifdef WITH_SSL +#include <openssl/hmac.h> +#include <openssl/md5.h> +#define MD5Init MD5_Init +#define MD5Update MD5_Update +#define MD5Final MD5_Final +#else +#define MD5_DIGEST_LENGTH 16 +#include <md5.h> +#endif + +/* We need the MPPE_KEY_LEN define */ +#include <netgraph/ng_mppc.h> + +#include <errno.h> +#include <netdb.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "radlib_private.h" + +static void clear_password(struct rad_handle *); +static void generr(struct rad_handle *, const char *, ...) + __printflike(2, 3); +static void insert_scrambled_password(struct rad_handle *, int); +static void insert_request_authenticator(struct rad_handle *, int); +static void insert_message_authenticator(struct rad_handle *, int); +static int is_valid_response(struct rad_handle *, int, + const struct sockaddr_in *); +static int put_password_attr(struct rad_handle *, int, + const void *, size_t); +static int put_raw_attr(struct rad_handle *, int, + const void *, size_t); +static int split(char *, char *[], int, char *, size_t); + +static void +clear_password(struct rad_handle *h) +{ + if (h->pass_len != 0) { + memset(h->pass, 0, h->pass_len); + h->pass_len = 0; + } + h->pass_pos = 0; +} + +static void +generr(struct rad_handle *h, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vsnprintf(h->errmsg, ERRSIZE, format, ap); + va_end(ap); +} + +static void +insert_scrambled_password(struct rad_handle *h, int srv) +{ + MD5_CTX ctx; + unsigned char md5[MD5_DIGEST_LENGTH]; + const struct rad_server *srvp; + int padded_len; + int pos; + + srvp = &h->servers[srv]; + padded_len = h->pass_len == 0 ? 16 : (h->pass_len+15) & ~0xf; + + memcpy(md5, &h->request[POS_AUTH], LEN_AUTH); + for (pos = 0; pos < padded_len; pos += 16) { + int i; + + /* Calculate the new scrambler */ + MD5Init(&ctx); + MD5Update(&ctx, srvp->secret, strlen(srvp->secret)); + MD5Update(&ctx, md5, 16); + MD5Final(md5, &ctx); + + /* + * Mix in the current chunk of the password, and copy + * the result into the right place in the request. Also + * modify the scrambler in place, since we will use this + * in calculating the scrambler for next time. + */ + for (i = 0; i < 16; i++) + h->request[h->pass_pos + pos + i] = + md5[i] ^= h->pass[pos + i]; + } +} + +static void +insert_request_authenticator(struct rad_handle *h, int srv) +{ + MD5_CTX ctx; + const struct rad_server *srvp; + + srvp = &h->servers[srv]; + + /* Create the request authenticator */ + MD5Init(&ctx); + MD5Update(&ctx, &h->request[POS_CODE], POS_AUTH - POS_CODE); + MD5Update(&ctx, memset(&h->request[POS_AUTH], 0, LEN_AUTH), LEN_AUTH); + MD5Update(&ctx, &h->request[POS_ATTRS], h->req_len - POS_ATTRS); + MD5Update(&ctx, srvp->secret, strlen(srvp->secret)); + MD5Final(&h->request[POS_AUTH], &ctx); +} + +static void +insert_message_authenticator(struct rad_handle *h, int srv) +{ +#ifdef WITH_SSL + u_char md[EVP_MAX_MD_SIZE]; + u_int md_len; + const struct rad_server *srvp; + HMAC_CTX ctx; + srvp = &h->servers[srv]; + + if (h->authentic_pos != 0) { + HMAC_CTX_init(&ctx); + HMAC_Init(&ctx, srvp->secret, strlen(srvp->secret), EVP_md5()); + HMAC_Update(&ctx, &h->request[POS_CODE], POS_AUTH - POS_CODE); + HMAC_Update(&ctx, &h->request[POS_AUTH], LEN_AUTH); + HMAC_Update(&ctx, &h->request[POS_ATTRS], + h->req_len - POS_ATTRS); + HMAC_Final(&ctx, md, &md_len); + HMAC_CTX_cleanup(&ctx); + HMAC_cleanup(&ctx); + memcpy(&h->request[h->authentic_pos + 2], md, md_len); + } +#endif +} + +/* + * Return true if the current response is valid for a request to the + * specified server. + */ +static int +is_valid_response(struct rad_handle *h, int srv, + const struct sockaddr_in *from) +{ + MD5_CTX ctx; + unsigned char md5[MD5_DIGEST_LENGTH]; + const struct rad_server *srvp; + int len; +#ifdef WITH_SSL + HMAC_CTX hctx; + u_char resp[MSGSIZE], md[EVP_MAX_MD_SIZE]; + u_int md_len; + int pos; +#endif + + srvp = &h->servers[srv]; + + /* Check the source address */ + if (from->sin_family != srvp->addr.sin_family || + from->sin_addr.s_addr != srvp->addr.sin_addr.s_addr || + from->sin_port != srvp->addr.sin_port) + return 0; + + /* Check the message length */ + if (h->resp_len < POS_ATTRS) + return 0; + len = h->response[POS_LENGTH] << 8 | h->response[POS_LENGTH+1]; + if (len > h->resp_len) + return 0; + + /* Check the response authenticator */ + MD5Init(&ctx); + MD5Update(&ctx, &h->response[POS_CODE], POS_AUTH - POS_CODE); + MD5Update(&ctx, &h->request[POS_AUTH], LEN_AUTH); + MD5Update(&ctx, &h->response[POS_ATTRS], len - POS_ATTRS); + MD5Update(&ctx, srvp->secret, strlen(srvp->secret)); + MD5Final(md5, &ctx); + if (memcmp(&h->response[POS_AUTH], md5, sizeof md5) != 0) + return 0; + +#ifdef WITH_SSL + /* + * For non accounting responses check the message authenticator, + * if any. + */ + if (h->response[POS_CODE] != RAD_ACCOUNTING_RESPONSE) { + + memcpy(resp, h->response, MSGSIZE); + pos = POS_ATTRS; + + /* Search and verify the Message-Authenticator */ + while (pos < len - 2) { + + if (h->response[pos] == RAD_MESSAGE_AUTHENTIC) { + /* zero fill the Message-Authenticator */ + memset(&resp[pos + 2], 0, MD5_DIGEST_LENGTH); + + HMAC_CTX_init(&hctx); + HMAC_Init(&hctx, srvp->secret, + strlen(srvp->secret), EVP_md5()); + HMAC_Update(&hctx, &h->response[POS_CODE], + POS_AUTH - POS_CODE); + HMAC_Update(&hctx, &h->request[POS_AUTH], + LEN_AUTH); + HMAC_Update(&hctx, &resp[POS_ATTRS], + h->resp_len - POS_ATTRS); + HMAC_Final(&hctx, md, &md_len); + HMAC_CTX_cleanup(&hctx); + HMAC_cleanup(&hctx); + if (memcmp(md, &h->response[pos + 2], + MD5_DIGEST_LENGTH) != 0) + return 0; + break; + } + pos += h->response[pos + 1]; + } + } +#endif + return 1; +} + +static int +put_password_attr(struct rad_handle *h, int type, const void *value, size_t len) +{ + int padded_len; + int pad_len; + + if (h->pass_pos != 0) { + generr(h, "Multiple User-Password attributes specified"); + return -1; + } + if (len > PASSSIZE) + len = PASSSIZE; + padded_len = len == 0 ? 16 : (len+15) & ~0xf; + pad_len = padded_len - len; + + /* + * Put in a place-holder attribute containing all zeros, and + * remember where it is so we can fill it in later. + */ + clear_password(h); + put_raw_attr(h, type, h->pass, padded_len); + h->pass_pos = h->req_len - padded_len; + + /* Save the cleartext password, padded as necessary */ + memcpy(h->pass, value, len); + h->pass_len = len; + memset(h->pass + len, 0, pad_len); + return 0; +} + +static int +put_raw_attr(struct rad_handle *h, int type, const void *value, size_t len) +{ + if (len > 253) { + generr(h, "Attribute too long"); + return -1; + } + if (h->req_len + 2 + len > MSGSIZE) { + generr(h, "Maximum message length exceeded"); + return -1; + } + h->request[h->req_len++] = type; + h->request[h->req_len++] = len + 2; + memcpy(&h->request[h->req_len], value, len); + h->req_len += len; + return 0; +} + +int +rad_add_server(struct rad_handle *h, const char *host, int port, + const char *secret, int timeout, int tries) +{ + struct rad_server *srvp; + + if (h->num_servers >= MAXSERVERS) { + generr(h, "Too many RADIUS servers specified"); + return -1; + } + srvp = &h->servers[h->num_servers]; + + memset(&srvp->addr, 0, sizeof srvp->addr); + srvp->addr.sin_len = sizeof srvp->addr; + srvp->addr.sin_family = AF_INET; + if (!inet_aton(host, &srvp->addr.sin_addr)) { + struct hostent *hent; + + if ((hent = gethostbyname(host)) == NULL) { + generr(h, "%s: host not found", host); + return -1; + } + memcpy(&srvp->addr.sin_addr, hent->h_addr, + sizeof srvp->addr.sin_addr); + } + if (port != 0) + srvp->addr.sin_port = htons((u_short)port); + else { + struct servent *sent; + + if (h->type == RADIUS_AUTH) + srvp->addr.sin_port = + (sent = getservbyname("radius", "udp")) != NULL ? + sent->s_port : htons(RADIUS_PORT); + else + srvp->addr.sin_port = + (sent = getservbyname("radacct", "udp")) != NULL ? + sent->s_port : htons(RADACCT_PORT); + } + if ((srvp->secret = strdup(secret)) == NULL) { + generr(h, "Out of memory"); + return -1; + } + srvp->timeout = timeout; + srvp->max_tries = tries; + srvp->num_tries = 0; + h->num_servers++; + return 0; +} + +void +rad_close(struct rad_handle *h) +{ + int srv; + + if (h->fd != -1) + close(h->fd); + for (srv = 0; srv < h->num_servers; srv++) { + memset(h->servers[srv].secret, 0, + strlen(h->servers[srv].secret)); + free(h->servers[srv].secret); + } + clear_password(h); + free(h); +} + +int +rad_config(struct rad_handle *h, const char *path) +{ + FILE *fp; + char buf[MAXCONFLINE]; + int linenum; + int retval; + + if (path == NULL) + path = PATH_RADIUS_CONF; + if ((fp = fopen(path, "r")) == NULL) { + generr(h, "Cannot open \"%s\": %s", path, strerror(errno)); + return -1; + } + retval = 0; + linenum = 0; + while (fgets(buf, sizeof buf, fp) != NULL) { + int len; + char *fields[5]; + int nfields; + char msg[ERRSIZE]; + char *type; + char *host, *res; + char *port_str; + char *secret; + char *timeout_str; + char *maxtries_str; + char *end; + char *wanttype; + unsigned long timeout; + unsigned long maxtries; + int port; + int i; + + linenum++; + len = strlen(buf); + /* We know len > 0, else fgets would have returned NULL. */ + if (buf[len - 1] != '\n') { + if (len == sizeof buf - 1) + generr(h, "%s:%d: line too long", path, + linenum); + else + generr(h, "%s:%d: missing newline", path, + linenum); + retval = -1; + break; + } + buf[len - 1] = '\0'; + + /* Extract the fields from the line. */ + nfields = split(buf, fields, 5, msg, sizeof msg); + if (nfields == -1) { + generr(h, "%s:%d: %s", path, linenum, msg); + retval = -1; + break; + } + if (nfields == 0) + continue; + /* + * The first field should contain "auth" or "acct" for + * authentication or accounting, respectively. But older + * versions of the file didn't have that field. Default + * it to "auth" for backward compatibility. + */ + if (strcmp(fields[0], "auth") != 0 && + strcmp(fields[0], "acct") != 0) { + if (nfields >= 5) { + generr(h, "%s:%d: invalid service type", path, + linenum); + retval = -1; + break; + } + nfields++; + for (i = nfields; --i > 0; ) + fields[i] = fields[i - 1]; + fields[0] = "auth"; + } + if (nfields < 3) { + generr(h, "%s:%d: missing shared secret", path, + linenum); + retval = -1; + break; + } + type = fields[0]; + host = fields[1]; + secret = fields[2]; + timeout_str = fields[3]; + maxtries_str = fields[4]; + + /* Ignore the line if it is for the wrong service type. */ + wanttype = h->type == RADIUS_AUTH ? "auth" : "acct"; + if (strcmp(type, wanttype) != 0) + continue; + + /* Parse and validate the fields. */ + res = host; + host = strsep(&res, ":"); + port_str = strsep(&res, ":"); + if (port_str != NULL) { + port = strtoul(port_str, &end, 10); + if (*end != '\0') { + generr(h, "%s:%d: invalid port", path, + linenum); + retval = -1; + break; + } + } else + port = 0; + if (timeout_str != NULL) { + timeout = strtoul(timeout_str, &end, 10); + if (*end != '\0') { + generr(h, "%s:%d: invalid timeout", path, + linenum); + retval = -1; + break; + } + } else + timeout = TIMEOUT; + if (maxtries_str != NULL) { + maxtries = strtoul(maxtries_str, &end, 10); + if (*end != '\0') { + generr(h, "%s:%d: invalid maxtries", path, + linenum); + retval = -1; + break; + } + } else + maxtries = MAXTRIES; + + if (rad_add_server(h, host, port, secret, timeout, maxtries) == + -1) { + strcpy(msg, h->errmsg); + generr(h, "%s:%d: %s", path, linenum, msg); + retval = -1; + break; + } + } + /* Clear out the buffer to wipe a possible copy of a shared secret */ + memset(buf, 0, sizeof buf); + fclose(fp); + return retval; +} + +/* + * rad_init_send_request() must have previously been called. + * Returns: + * 0 The application should select on *fd with a timeout of tv before + * calling rad_continue_send_request again. + * < 0 Failure + * > 0 Success + */ +int +rad_continue_send_request(struct rad_handle *h, int selected, int *fd, + struct timeval *tv) +{ + int n; + + if (selected) { + struct sockaddr_in from; + socklen_t fromlen; + + fromlen = sizeof from; + h->resp_len = recvfrom(h->fd, h->response, + MSGSIZE, MSG_WAITALL, (struct sockaddr *)&from, &fromlen); + if (h->resp_len == -1) { + generr(h, "recvfrom: %s", strerror(errno)); + return -1; + } + if (is_valid_response(h, h->srv, &from)) { + h->resp_len = h->response[POS_LENGTH] << 8 | + h->response[POS_LENGTH+1]; + h->resp_pos = POS_ATTRS; + return h->response[POS_CODE]; + } + } + + if (h->try == h->total_tries) { + generr(h, "No valid RADIUS responses received"); + return -1; + } + + /* + * Scan round-robin to the next server that has some + * tries left. There is guaranteed to be one, or we + * would have exited this loop by now. + */ + while (h->servers[h->srv].num_tries >= h->servers[h->srv].max_tries) + if (++h->srv >= h->num_servers) + h->srv = 0; + + if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) + /* Insert the request authenticator into the request */ + insert_request_authenticator(h, h->srv); + else + /* Insert the scrambled password into the request */ + if (h->pass_pos != 0) + insert_scrambled_password(h, h->srv); + + insert_message_authenticator(h, h->srv); + + /* Send the request */ + n = sendto(h->fd, h->request, h->req_len, 0, + (const struct sockaddr *)&h->servers[h->srv].addr, + sizeof h->servers[h->srv].addr); + if (n != h->req_len) { + if (n == -1) + generr(h, "sendto: %s", strerror(errno)); + else + generr(h, "sendto: short write"); + return -1; + } + + h->try++; + h->servers[h->srv].num_tries++; + tv->tv_sec = h->servers[h->srv].timeout; + tv->tv_usec = 0; + *fd = h->fd; + + return 0; +} + +int +rad_create_request(struct rad_handle *h, int code) +{ + int i; + + h->request[POS_CODE] = code; + h->request[POS_IDENT] = ++h->ident; + /* Create a random authenticator */ + for (i = 0; i < LEN_AUTH; i += 2) { + long r; + r = random(); + h->request[POS_AUTH+i] = (u_char)r; + h->request[POS_AUTH+i+1] = (u_char)(r >> 8); + } + h->req_len = POS_ATTRS; + clear_password(h); + h->request_created = 1; + return 0; +} + +struct in_addr +rad_cvt_addr(const void *data) +{ + struct in_addr value; + + memcpy(&value.s_addr, data, sizeof value.s_addr); + return value; +} + +u_int32_t +rad_cvt_int(const void *data) +{ + u_int32_t value; + + memcpy(&value, data, sizeof value); + return ntohl(value); +} + +char * +rad_cvt_string(const void *data, size_t len) +{ + char *s; + + s = malloc(len + 1); + if (s != NULL) { + memcpy(s, data, len); + s[len] = '\0'; + } + return s; +} + +/* + * Returns the attribute type. If none are left, returns 0. On failure, + * returns -1. + */ +int +rad_get_attr(struct rad_handle *h, const void **value, size_t *len) +{ + int type; + + if (h->resp_pos >= h->resp_len) + return 0; + if (h->resp_pos + 2 > h->resp_len) { + generr(h, "Malformed attribute in response"); + return -1; + } + type = h->response[h->resp_pos++]; + *len = h->response[h->resp_pos++] - 2; + if (h->resp_pos + (int)*len > h->resp_len) { + generr(h, "Malformed attribute in response"); + return -1; + } + *value = &h->response[h->resp_pos]; + h->resp_pos += *len; + return type; +} + +/* + * Returns -1 on error, 0 to indicate no event and >0 for success + */ +int +rad_init_send_request(struct rad_handle *h, int *fd, struct timeval *tv) +{ + int srv; + + /* Make sure we have a socket to use */ + if (h->fd == -1) { + struct sockaddr_in sin; + + if ((h->fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { + generr(h, "Cannot create socket: %s", strerror(errno)); + return -1; + } + memset(&sin, 0, sizeof sin); + sin.sin_len = sizeof sin; + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = INADDR_ANY; + sin.sin_port = htons(0); + if (bind(h->fd, (const struct sockaddr *)&sin, + sizeof sin) == -1) { + generr(h, "bind: %s", strerror(errno)); + close(h->fd); + h->fd = -1; + return -1; + } + } + + if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) { + /* Make sure no password given */ + if (h->pass_pos || h->chap_pass) { + generr(h, "User or Chap Password" + " in accounting request"); + return -1; + } + } else { + if (h->eap_msg == 0) { + /* Make sure the user gave us a password */ + if (h->pass_pos == 0 && !h->chap_pass) { + generr(h, "No User or Chap Password" + " attributes given"); + return -1; + } + if (h->pass_pos != 0 && h->chap_pass) { + generr(h, "Both User and Chap Password" + " attributes given"); + return -1; + } + } + } + + /* Fill in the length field in the message */ + h->request[POS_LENGTH] = h->req_len >> 8; + h->request[POS_LENGTH+1] = h->req_len; + + /* + * Count the total number of tries we will make, and zero the + * counter for each server. + */ + h->total_tries = 0; + for (srv = 0; srv < h->num_servers; srv++) { + h->total_tries += h->servers[srv].max_tries; + h->servers[srv].num_tries = 0; + } + if (h->total_tries == 0) { + generr(h, "No RADIUS servers specified"); + return -1; + } + + h->try = h->srv = 0; + + return rad_continue_send_request(h, 0, fd, tv); +} + +/* + * Create and initialize a rad_handle structure, and return it to the + * caller. Can fail only if the necessary memory cannot be allocated. + * In that case, it returns NULL. + */ +struct rad_handle * +rad_auth_open(void) +{ + struct rad_handle *h; + + h = (struct rad_handle *)malloc(sizeof(struct rad_handle)); + if (h != NULL) { + srandomdev(); + h->fd = -1; + h->num_servers = 0; + h->ident = random(); + h->errmsg[0] = '\0'; + memset(h->pass, 0, sizeof h->pass); + h->pass_len = 0; + h->pass_pos = 0; + h->chap_pass = 0; + h->authentic_pos = 0; + h->type = RADIUS_AUTH; + h->request_created = 0; + h->eap_msg = 0; + } + return h; +} + +struct rad_handle * +rad_acct_open(void) +{ + struct rad_handle *h; + + h = rad_open(); + if (h != NULL) + h->type = RADIUS_ACCT; + return h; +} + +struct rad_handle * +rad_open(void) +{ + return rad_auth_open(); +} + +int +rad_put_addr(struct rad_handle *h, int type, struct in_addr addr) +{ + return rad_put_attr(h, type, &addr.s_addr, sizeof addr.s_addr); +} + +int +rad_put_attr(struct rad_handle *h, int type, const void *value, size_t len) +{ + int result; + + if (!h->request_created) { + generr(h, "Please call rad_create_request()" + " before putting attributes"); + return -1; + } + + if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) { + if (type == RAD_EAP_MESSAGE) { + generr(h, "EAP-Message attribute is not valid" + " in accounting requests"); + return -1; + } + } + + /* + * When proxying EAP Messages, the Message Authenticator + * MUST be present; see RFC 3579. + */ + if (type == RAD_EAP_MESSAGE) { + if (rad_put_message_authentic(h) == -1) + return -1; + } + + if (type == RAD_USER_PASSWORD) { + result = put_password_attr(h, type, value, len); + } else if (type == RAD_MESSAGE_AUTHENTIC) { + result = rad_put_message_authentic(h); + } else { + result = put_raw_attr(h, type, value, len); + if (result == 0) { + if (type == RAD_CHAP_PASSWORD) + h->chap_pass = 1; + else if (type == RAD_EAP_MESSAGE) + h->eap_msg = 1; + } + } + + return result; +} + +int +rad_put_int(struct rad_handle *h, int type, u_int32_t value) +{ + u_int32_t nvalue; + + nvalue = htonl(value); + return rad_put_attr(h, type, &nvalue, sizeof nvalue); +} + +int +rad_put_string(struct rad_handle *h, int type, const char *str) +{ + return rad_put_attr(h, type, str, strlen(str)); +} + +int +rad_put_message_authentic(struct rad_handle *h) +{ +#ifdef WITH_SSL + u_char md_zero[MD5_DIGEST_LENGTH]; + + if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) { + generr(h, "Message-Authenticator is not valid" + " in accounting requests"); + return -1; + } + + if (h->authentic_pos == 0) { + h->authentic_pos = h->req_len; + memset(md_zero, 0, sizeof(md_zero)); + return (put_raw_attr(h, RAD_MESSAGE_AUTHENTIC, md_zero, + sizeof(md_zero))); + } + return 0; +#else + generr(h, "Message Authenticator not supported," + " please recompile libradius with SSL support"); + return -1; +#endif +} + +/* + * Returns the response type code on success, or -1 on failure. + */ +int +rad_send_request(struct rad_handle *h) +{ + struct timeval timelimit; + struct timeval tv; + int fd; + int n; + + n = rad_init_send_request(h, &fd, &tv); + + if (n != 0) + return n; + + gettimeofday(&timelimit, NULL); + timeradd(&tv, &timelimit, &timelimit); + + for ( ; ; ) { + fd_set readfds; + + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + n = select(fd + 1, &readfds, NULL, NULL, &tv); + + if (n == -1) { + generr(h, "select: %s", strerror(errno)); + return -1; + } + + if (!FD_ISSET(fd, &readfds)) { + /* Compute a new timeout */ + gettimeofday(&tv, NULL); + timersub(&timelimit, &tv, &tv); + if (tv.tv_sec > 0 || (tv.tv_sec == 0 && tv.tv_usec > 0)) + /* Continue the select */ + continue; + } + + n = rad_continue_send_request(h, n, &fd, &tv); + + if (n != 0) + return n; + + gettimeofday(&timelimit, NULL); + timeradd(&tv, &timelimit, &timelimit); + } +} + +const char * +rad_strerror(struct rad_handle *h) +{ + return h->errmsg; +} + +/* + * Destructively split a string into fields separated by white space. + * `#' at the beginning of a field begins a comment that extends to the + * end of the string. Fields may be quoted with `"'. Inside quoted + * strings, the backslash escapes `\"' and `\\' are honored. + * + * Pointers to up to the first maxfields fields are stored in the fields + * array. Missing fields get NULL pointers. + * + * The return value is the actual number of fields parsed, and is always + * <= maxfields. + * + * On a syntax error, places a message in the msg string, and returns -1. + */ +static int +split(char *str, char *fields[], int maxfields, char *msg, size_t msglen) +{ + char *p; + int i; + static const char ws[] = " \t"; + + for (i = 0; i < maxfields; i++) + fields[i] = NULL; + p = str; + i = 0; + while (*p != '\0') { + p += strspn(p, ws); + if (*p == '#' || *p == '\0') + break; + if (i >= maxfields) { + snprintf(msg, msglen, "line has too many fields"); + return -1; + } + if (*p == '"') { + char *dst; + + dst = ++p; + fields[i] = dst; + while (*p != '"') { + if (*p == '\\') { + p++; + if (*p != '"' && *p != '\\' && + *p != '\0') { + snprintf(msg, msglen, + "invalid `\\' escape"); + return -1; + } + } + if (*p == '\0') { + snprintf(msg, msglen, + "unterminated quoted string"); + return -1; + } + *dst++ = *p++; + } + *dst = '\0'; + p++; + if (*fields[i] == '\0') { + snprintf(msg, msglen, + "empty quoted string not permitted"); + return -1; + } + if (*p != '\0' && strspn(p, ws) == 0) { + snprintf(msg, msglen, "quoted string not" + " followed by white space"); + return -1; + } + } else { + fields[i] = p; + p += strcspn(p, ws); + if (*p != '\0') + *p++ = '\0'; + } + i++; + } + return i; +} + +int +rad_get_vendor_attr(u_int32_t *vendor, const void **data, size_t *len) +{ + struct vendor_attribute *attr; + + attr = (struct vendor_attribute *)*data; + *vendor = ntohl(attr->vendor_value); + *data = attr->attrib_data; + *len = attr->attrib_len - 2; + + return (attr->attrib_type); +} + +int +rad_put_vendor_addr(struct rad_handle *h, int vendor, int type, + struct in_addr addr) +{ + return (rad_put_vendor_attr(h, vendor, type, &addr.s_addr, + sizeof addr.s_addr)); +} + +int +rad_put_vendor_attr(struct rad_handle *h, int vendor, int type, + const void *value, size_t len) +{ + struct vendor_attribute *attr; + int res; + + if (!h->request_created) { + generr(h, "Please call rad_create_request()" + " before putting attributes"); + return -1; + } + + if ((attr = malloc(len + 6)) == NULL) { + generr(h, "malloc failure (%zu bytes)", len + 6); + return -1; + } + + attr->vendor_value = htonl(vendor); + attr->attrib_type = type; + attr->attrib_len = len + 2; + memcpy(attr->attrib_data, value, len); + + res = put_raw_attr(h, RAD_VENDOR_SPECIFIC, attr, len + 6); + free(attr); + if (res == 0 && vendor == RAD_VENDOR_MICROSOFT + && (type == RAD_MICROSOFT_MS_CHAP_RESPONSE + || type == RAD_MICROSOFT_MS_CHAP2_RESPONSE)) { + h->chap_pass = 1; + } + return (res); +} + +int +rad_put_vendor_int(struct rad_handle *h, int vendor, int type, u_int32_t i) +{ + u_int32_t value; + + value = htonl(i); + return (rad_put_vendor_attr(h, vendor, type, &value, sizeof value)); +} + +int +rad_put_vendor_string(struct rad_handle *h, int vendor, int type, + const char *str) +{ + return (rad_put_vendor_attr(h, vendor, type, str, strlen(str))); +} + +ssize_t +rad_request_authenticator(struct rad_handle *h, char *buf, size_t len) +{ + if (len < LEN_AUTH) + return (-1); + memcpy(buf, h->request + POS_AUTH, LEN_AUTH); + if (len > LEN_AUTH) + buf[LEN_AUTH] = '\0'; + return (LEN_AUTH); +} + +u_char * +rad_demangle(struct rad_handle *h, const void *mangled, size_t mlen) +{ + char R[LEN_AUTH]; + const char *S; + int i, Ppos; + MD5_CTX Context; + u_char b[MD5_DIGEST_LENGTH], *C, *demangled; + + if ((mlen % 16 != 0) || mlen > 128) { + generr(h, "Cannot interpret mangled data of length %lu", + (u_long)mlen); + return NULL; + } + + C = (u_char *)mangled; + + /* We need the shared secret as Salt */ + S = rad_server_secret(h); + + /* We need the request authenticator */ + if (rad_request_authenticator(h, R, sizeof R) != LEN_AUTH) { + generr(h, "Cannot obtain the RADIUS request authenticator"); + return NULL; + } + + demangled = malloc(mlen); + if (!demangled) + return NULL; + + MD5Init(&Context); + MD5Update(&Context, S, strlen(S)); + MD5Update(&Context, R, LEN_AUTH); + MD5Final(b, &Context); + Ppos = 0; + while (mlen) { + + mlen -= 16; + for (i = 0; i < 16; i++) + demangled[Ppos++] = C[i] ^ b[i]; + + if (mlen) { + MD5Init(&Context); + MD5Update(&Context, S, strlen(S)); + MD5Update(&Context, C, 16); + MD5Final(b, &Context); + } + + C += 16; + } + + return demangled; +} + +u_char * +rad_demangle_mppe_key(struct rad_handle *h, const void *mangled, + size_t mlen, size_t *len) +{ + char R[LEN_AUTH]; /* variable names as per rfc2548 */ + const char *S; + u_char b[MD5_DIGEST_LENGTH], *demangled; + const u_char *A, *C; + MD5_CTX Context; + int Slen, i, Clen, Ppos; + u_char *P; + + if (mlen % 16 != SALT_LEN) { + generr(h, "Cannot interpret mangled data of length %lu", + (u_long)mlen); + return NULL; + } + + /* We need the RADIUS Request-Authenticator */ + if (rad_request_authenticator(h, R, sizeof R) != LEN_AUTH) { + generr(h, "Cannot obtain the RADIUS request authenticator"); + return NULL; + } + + A = (const u_char *)mangled; /* Salt comes first */ + C = (const u_char *)mangled + SALT_LEN; /* Then the ciphertext */ + Clen = mlen - SALT_LEN; + S = rad_server_secret(h); /* We need the RADIUS secret */ + Slen = strlen(S); + P = alloca(Clen); /* We derive our plaintext */ + + MD5Init(&Context); + MD5Update(&Context, S, Slen); + MD5Update(&Context, R, LEN_AUTH); + MD5Update(&Context, A, SALT_LEN); + MD5Final(b, &Context); + Ppos = 0; + + while (Clen) { + Clen -= 16; + + for (i = 0; i < 16; i++) + P[Ppos++] = C[i] ^ b[i]; + + if (Clen) { + MD5Init(&Context); + MD5Update(&Context, S, Slen); + MD5Update(&Context, C, 16); + MD5Final(b, &Context); + } + + C += 16; + } + + /* + * The resulting plain text consists of a one-byte length, the text and + * maybe some padding. + */ + *len = *P; + if (*len > mlen - 1) { + generr(h, "Mangled data seems to be garbage %zu %zu", + *len, mlen-1); + return NULL; + } + + if (*len > MPPE_KEY_LEN * 2) { + generr(h, "Key to long (%zu) for me max. %d", + *len, MPPE_KEY_LEN * 2); + return NULL; + } + demangled = malloc(*len); + if (!demangled) + return NULL; + + memcpy(demangled, P + 1, *len); + return demangled; +} + +const char * +rad_server_secret(struct rad_handle *h) +{ + return (h->servers[h->srv].secret); +} diff --git a/lib/libradius/radlib.h b/lib/libradius/radlib.h new file mode 100644 index 0000000..2c42c3a --- /dev/null +++ b/lib/libradius/radlib.h @@ -0,0 +1,220 @@ +/*- + * Copyright 1998 Juniper Networks, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _RADLIB_H_ +#define _RADLIB_H_ + +#include <sys/types.h> +#include <netinet/in.h> + +/* Limits */ +#define RAD_MAX_ATTR_LEN 253 + +/* Message types */ +#define RAD_ACCESS_REQUEST 1 +#define RAD_ACCESS_ACCEPT 2 +#define RAD_ACCESS_REJECT 3 +#define RAD_ACCOUNTING_REQUEST 4 +#define RAD_ACCOUNTING_RESPONSE 5 +#define RAD_ACCESS_CHALLENGE 11 + +/* Attribute types and values */ +#define RAD_USER_NAME 1 /* String */ +#define RAD_USER_PASSWORD 2 /* String */ +#define RAD_CHAP_PASSWORD 3 /* String */ +#define RAD_NAS_IP_ADDRESS 4 /* IP address */ +#define RAD_NAS_PORT 5 /* Integer */ +#define RAD_SERVICE_TYPE 6 /* Integer */ + #define RAD_LOGIN 1 + #define RAD_FRAMED 2 + #define RAD_CALLBACK_LOGIN 3 + #define RAD_CALLBACK_FRAMED 4 + #define RAD_OUTBOUND 5 + #define RAD_ADMINISTRATIVE 6 + #define RAD_NAS_PROMPT 7 + #define RAD_AUTHENTICATE_ONLY 8 + #define RAD_CALLBACK_NAS_PROMPT 9 +#define RAD_FRAMED_PROTOCOL 7 /* Integer */ + #define RAD_PPP 1 + #define RAD_SLIP 2 + #define RAD_ARAP 3 /* Appletalk */ + #define RAD_GANDALF 4 + #define RAD_XYLOGICS 5 +#define RAD_FRAMED_IP_ADDRESS 8 /* IP address */ +#define RAD_FRAMED_IP_NETMASK 9 /* IP address */ +#define RAD_FRAMED_ROUTING 10 /* Integer */ +#define RAD_FILTER_ID 11 /* String */ +#define RAD_FRAMED_MTU 12 /* Integer */ +#define RAD_FRAMED_COMPRESSION 13 /* Integer */ + #define RAD_COMP_NONE 0 + #define RAD_COMP_VJ 1 + #define RAD_COMP_IPXHDR 2 +#define RAD_LOGIN_IP_HOST 14 /* IP address */ +#define RAD_LOGIN_SERVICE 15 /* Integer */ +#define RAD_LOGIN_TCP_PORT 16 /* Integer */ + /* unassiged 17 */ +#define RAD_REPLY_MESSAGE 18 /* String */ +#define RAD_CALLBACK_NUMBER 19 /* String */ +#define RAD_CALLBACK_ID 20 /* String */ + /* unassiged 21 */ +#define RAD_FRAMED_ROUTE 22 /* String */ +#define RAD_FRAMED_IPX_NETWORK 23 /* IP address */ +#define RAD_STATE 24 /* String */ +#define RAD_CLASS 25 /* Integer */ +#define RAD_VENDOR_SPECIFIC 26 /* Integer */ +#define RAD_SESSION_TIMEOUT 27 /* Integer */ +#define RAD_IDLE_TIMEOUT 28 /* Integer */ +#define RAD_TERMINATION_ACTION 29 /* Integer */ +#define RAD_CALLED_STATION_ID 30 /* String */ +#define RAD_CALLING_STATION_ID 31 /* String */ +#define RAD_NAS_IDENTIFIER 32 /* Integer */ +#define RAD_PROXY_STATE 33 /* Integer */ +#define RAD_LOGIN_LAT_SERVICE 34 /* Integer */ +#define RAD_LOGIN_LAT_NODE 35 /* Integer */ +#define RAD_LOGIN_LAT_GROUP 36 /* Integer */ +#define RAD_FRAMED_APPLETALK_LINK 37 /* Integer */ +#define RAD_FRAMED_APPLETALK_NETWORK 38 /* Integer */ +#define RAD_FRAMED_APPLETALK_ZONE 39 /* Integer */ + /* reserved for accounting 40-59 */ +#define RAD_ACCT_INPUT_GIGAWORDS 52 +#define RAD_ACCT_OUTPUT_GIGAWORDS 53 + +#define RAD_CHAP_CHALLENGE 60 /* String */ +#define RAD_NAS_PORT_TYPE 61 /* Integer */ + #define RAD_ASYNC 0 + #define RAD_SYNC 1 + #define RAD_ISDN_SYNC 2 + #define RAD_ISDN_ASYNC_V120 3 + #define RAD_ISDN_ASYNC_V110 4 + #define RAD_VIRTUAL 5 + #define RAD_PIAFS 6 + #define RAD_HDLC_CLEAR_CHANNEL 7 + #define RAD_X_25 8 + #define RAD_X_75 9 + #define RAD_G_3_FAX 10 + #define RAD_SDSL 11 + #define RAD_ADSL_CAP 12 + #define RAD_ADSL_DMT 13 + #define RAD_IDSL 14 + #define RAD_ETHERNET 15 + #define RAD_XDSL 16 + #define RAD_CABLE 17 + #define RAD_WIRELESS_OTHER 18 + #define RAD_WIRELESS_IEEE_802_11 19 +#define RAD_PORT_LIMIT 62 /* Integer */ +#define RAD_LOGIN_LAT_PORT 63 /* Integer */ +#define RAD_CONNECT_INFO 77 /* String */ +#define RAD_EAP_MESSAGE 79 /* Octets */ +#define RAD_MESSAGE_AUTHENTIC 80 /* Octets */ +#define RAD_ACCT_INTERIM_INTERVAL 85 /* Integer */ +#define RAD_NAS_IPV6_ADDRESS 95 /* IPv6 address */ +#define RAD_FRAMED_INTERFACE_ID 96 /* 8 octets */ +#define RAD_FRAMED_IPV6_PREFIX 97 /* Octets */ +#define RAD_LOGIN_IPV6_HOST 98 /* IPv6 address */ +#define RAD_FRAMED_IPV6_ROUTE 99 /* String */ +#define RAD_FRAMED_IPV6_POOL 100 /* String */ + +/* Accounting attribute types and values */ +#define RAD_ACCT_STATUS_TYPE 40 /* Integer */ + #define RAD_START 1 + #define RAD_STOP 2 + #define RAD_UPDATE 3 + #define RAD_ACCOUNTING_ON 7 + #define RAD_ACCOUNTING_OFF 8 +#define RAD_ACCT_DELAY_TIME 41 /* Integer */ +#define RAD_ACCT_INPUT_OCTETS 42 /* Integer */ +#define RAD_ACCT_OUTPUT_OCTETS 43 /* Integer */ +#define RAD_ACCT_SESSION_ID 44 /* String */ +#define RAD_ACCT_AUTHENTIC 45 /* Integer */ + #define RAD_AUTH_RADIUS 1 + #define RAD_AUTH_LOCAL 2 + #define RAD_AUTH_REMOTE 3 +#define RAD_ACCT_SESSION_TIME 46 /* Integer */ +#define RAD_ACCT_INPUT_PACKETS 47 /* Integer */ +#define RAD_ACCT_OUTPUT_PACKETS 48 /* Integer */ +#define RAD_ACCT_TERMINATE_CAUSE 49 /* Integer */ + #define RAD_TERM_USER_REQUEST 1 + #define RAD_TERM_LOST_CARRIER 2 + #define RAD_TERM_LOST_SERVICE 3 + #define RAD_TERM_IDLE_TIMEOUT 4 + #define RAD_TERM_SESSION_TIMEOUT 5 + #define RAD_TERM_ADMIN_RESET 6 + #define RAD_TERM_ADMIN_REBOOT 7 + #define RAD_TERM_PORT_ERROR 8 + #define RAD_TERM_NAS_ERROR 9 + #define RAD_TERM_NAS_REQUEST 10 + #define RAD_TERM_NAS_REBOOT 11 + #define RAD_TERM_PORT_UNNEEDED 12 + #define RAD_TERM_PORT_PREEMPTED 13 + #define RAD_TERM_PORT_SUSPENDED 14 + #define RAD_TERM_SERVICE_UNAVAILABLE 15 + #define RAD_TERM_CALLBACK 16 + #define RAD_TERM_USER_ERROR 17 + #define RAD_TERM_HOST_REQUEST 18 +#define RAD_ACCT_MULTI_SESSION_ID 50 /* String */ +#define RAD_ACCT_LINK_COUNT 51 /* Integer */ + +struct rad_handle; +struct timeval; + +__BEGIN_DECLS +struct rad_handle *rad_acct_open(void); +int rad_add_server(struct rad_handle *, + const char *, int, const char *, int, int); +struct rad_handle *rad_auth_open(void); +void rad_close(struct rad_handle *); +int rad_config(struct rad_handle *, const char *); +int rad_continue_send_request(struct rad_handle *, int, + int *, struct timeval *); +int rad_create_request(struct rad_handle *, int); +struct in_addr rad_cvt_addr(const void *); +u_int32_t rad_cvt_int(const void *); +char *rad_cvt_string(const void *, size_t); +int rad_get_attr(struct rad_handle *, const void **, + size_t *); +int rad_init_send_request(struct rad_handle *, int *, + struct timeval *); +struct rad_handle *rad_open(void); /* Deprecated, == rad_auth_open */ +int rad_put_addr(struct rad_handle *, int, struct in_addr); +int rad_put_attr(struct rad_handle *, int, + const void *, size_t); +int rad_put_int(struct rad_handle *, int, u_int32_t); +int rad_put_string(struct rad_handle *, int, + const char *); +int rad_put_message_authentic(struct rad_handle *); +ssize_t rad_request_authenticator(struct rad_handle *, char *, + size_t); +int rad_send_request(struct rad_handle *); +const char *rad_server_secret(struct rad_handle *); +const char *rad_strerror(struct rad_handle *); +u_char *rad_demangle(struct rad_handle *, const void *, + size_t); + +__END_DECLS + +#endif /* _RADLIB_H_ */ diff --git a/lib/libradius/radlib_private.h b/lib/libradius/radlib_private.h new file mode 100644 index 0000000..d323cbd --- /dev/null +++ b/lib/libradius/radlib_private.h @@ -0,0 +1,103 @@ +/*- + * Copyright 1998 Juniper Networks, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef RADLIB_PRIVATE_H +#define RADLIB_PRIVATE_H + +#include <sys/types.h> +#include <netinet/in.h> + +#include "radlib.h" +#include "radlib_vs.h" + +/* Handle types */ +#define RADIUS_AUTH 0 /* RADIUS authentication, default */ +#define RADIUS_ACCT 1 /* RADIUS accounting */ + +/* Defaults */ +#define MAXTRIES 3 +#define PATH_RADIUS_CONF "/etc/radius.conf" +#define RADIUS_PORT 1812 +#define RADACCT_PORT 1813 +#define TIMEOUT 3 /* In seconds */ + +/* Limits */ +#define ERRSIZE 128 /* Maximum error message length */ +#define MAXCONFLINE 1024 /* Maximum config file line length */ +#define MAXSERVERS 10 /* Maximum number of servers to try */ +#define MSGSIZE 4096 /* Maximum RADIUS message */ +#define PASSSIZE 128 /* Maximum significant password chars */ + +/* Positions of fields in RADIUS messages */ +#define POS_CODE 0 /* Message code */ +#define POS_IDENT 1 /* Identifier */ +#define POS_LENGTH 2 /* Message length */ +#define POS_AUTH 4 /* Authenticator */ +#define LEN_AUTH 16 /* Length of authenticator */ +#define POS_ATTRS 20 /* Start of attributes */ + +struct rad_server { + struct sockaddr_in addr; /* Address of server */ + char *secret; /* Shared secret */ + int timeout; /* Timeout in seconds */ + int max_tries; /* Number of tries before giving up */ + int num_tries; /* Number of tries so far */ +}; + +struct rad_handle { + int fd; /* Socket file descriptor */ + struct rad_server servers[MAXSERVERS]; /* Servers to contact */ + int num_servers; /* Number of valid server entries */ + int ident; /* Current identifier value */ + char errmsg[ERRSIZE]; /* Most recent error message */ + unsigned char request[MSGSIZE]; /* Request to send */ + char request_created; /* rad_create_request() called? */ + int req_len; /* Length of request */ + char pass[PASSSIZE]; /* Cleartext password */ + int pass_len; /* Length of cleartext password */ + int pass_pos; /* Position of scrambled password */ + char chap_pass; /* Have we got a CHAP_PASSWORD ? */ + int authentic_pos; /* Position of message authenticator */ + char eap_msg; /* Are we an EAP Proxy? */ + unsigned char response[MSGSIZE]; /* Response received */ + int resp_len; /* Length of response */ + int resp_pos; /* Current position scanning attrs */ + int total_tries; /* How many requests we'll send */ + int try; /* How many requests we've sent */ + int srv; /* Server number we did last */ + int type; /* Handle type */ +}; + +struct vendor_attribute { + u_int32_t vendor_value; + u_char attrib_type; + u_char attrib_len; + u_char attrib_data[1]; +}; + +#endif diff --git a/lib/libradius/radlib_vs.h b/lib/libradius/radlib_vs.h new file mode 100644 index 0000000..8b3a75e --- /dev/null +++ b/lib/libradius/radlib_vs.h @@ -0,0 +1,84 @@ +/*- + * Copyright (c) 2002 Brian Somers <brian@Awfulhak.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _RADLIB_VS_H_ +#define _RADLIB_VS_H_ + +#include <sys/types.h> +#include <netinet/in.h> + +#define RAD_VENDOR_MICROSOFT 311 /* rfc2548 */ + #define RAD_MICROSOFT_MS_CHAP_RESPONSE 1 + #define RAD_MICROSOFT_MS_CHAP_ERROR 2 + #define RAD_MICROSOFT_MS_CHAP_PW_1 3 + #define RAD_MICROSOFT_MS_CHAP_PW_2 4 + #define RAD_MICROSOFT_MS_CHAP_LM_ENC_PW 5 + #define RAD_MICROSOFT_MS_CHAP_NT_ENC_PW 6 + #define RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY 7 + #define RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES 8 + #define RAD_MICROSOFT_MS_RAS_VENDOR 9 + #define RAD_MICROSOFT_MS_CHAP_DOMAIN 10 + #define RAD_MICROSOFT_MS_CHAP_CHALLENGE 11 + #define RAD_MICROSOFT_MS_CHAP_MPPE_KEYS 12 + #define RAD_MICROSOFT_MS_BAP_USAGE 13 + #define RAD_MICROSOFT_MS_LINK_UTILIZATION_THRESHOLD 14 + #define RAD_MICROSOFT_MS_LINK_DROP_TIME_LIMIT 15 + #define RAD_MICROSOFT_MS_MPPE_SEND_KEY 16 + #define RAD_MICROSOFT_MS_MPPE_RECV_KEY 17 + #define RAD_MICROSOFT_MS_RAS_VERSION 18 + #define RAD_MICROSOFT_MS_OLD_ARAP_PASSWORD 19 + #define RAD_MICROSOFT_MS_NEW_ARAP_PASSWORD 20 + #define RAD_MICROSOFT_MS_ARAP_PASSWORD_CHANGE_REASON 21 + #define RAD_MICROSOFT_MS_FILTER 22 + #define RAD_MICROSOFT_MS_ACCT_AUTH_TYPE 23 + #define RAD_MICROSOFT_MS_ACCT_EAP_TYPE 24 + #define RAD_MICROSOFT_MS_CHAP2_RESPONSE 25 + #define RAD_MICROSOFT_MS_CHAP2_SUCCESS 26 + #define RAD_MICROSOFT_MS_CHAP2_PW 27 + #define RAD_MICROSOFT_MS_PRIMARY_DNS_SERVER 28 + #define RAD_MICROSOFT_MS_SECONDARY_DNS_SERVER 29 + #define RAD_MICROSOFT_MS_PRIMARY_NBNS_SERVER 30 + #define RAD_MICROSOFT_MS_SECONDARY_NBNS_SERVER 31 + #define RAD_MICROSOFT_MS_ARAP_CHALLENGE 33 + +#define SALT_LEN 2 + +struct rad_handle; + +__BEGIN_DECLS +int rad_get_vendor_attr(u_int32_t *, const void **, size_t *); +int rad_put_vendor_addr(struct rad_handle *, int, int, struct in_addr); +int rad_put_vendor_attr(struct rad_handle *, int, int, const void *, + size_t); +int rad_put_vendor_int(struct rad_handle *, int, int, u_int32_t); +int rad_put_vendor_string(struct rad_handle *, int, int, const char *); +u_char *rad_demangle_mppe_key(struct rad_handle *, const void *, size_t, + size_t *); +__END_DECLS + +#endif /* _RADLIB_VS_H_ */ |