From: Nuno Antunes Date: Fri, 4 Jul 2014 05:59:13 +0000 (+0100) Subject: libradius(3): Sync with FreeBSD head. X-Git-Tag: v4.1.0~507 X-Git-Url: https://gitweb.dragonflybsd.org/~tuxillo/dragonfly.git/commitdiff_plain/50beab2d46ff14aa2fffee24aa46160398a87f7c libradius(3): Sync with FreeBSD head. Here is a summary of the changes. * Added rad_request_authenticator() which returns the Request-Authenticator relevant to the most recently received RADIUS response. * Added rad_server_secret() which returns the Shared Secret relevant to the most recently received RADIUS response. * Added rad_demangle() for demangling user-passwords (needed for MS-CHAPv1 MPPE-keys). * Added rad_demangle_mppe_key() for demangling mppe-keys (needed for MPPE-keys). * Added some typecasts for avoiding compiler warnings. * Fix: better handle wrong usage of the lib (if the programmer has not called rad_create_request() but rad_put_*(), then a weird error message was returned). * Added a new function for putting the Message-Authenticator. * Verify the Message-Authenticator, if it was found inside a response packet and silently drop the packet, if the validation failed. * Implicitly put the Message-Authenticator, if the EAP-Message attribute was added. * Added some missing defines. * Add simple embedded RADIUS server support to libradius, by extending existing API, keeping backward compatibility. * Add binding support. * Alphabetically sort MLINKS in the Makefile. * Various other bugfixes. Taken-from: FreeBSD (with small adjustments) --- diff --git a/gnu/usr.bin/groff/tmac/mdoc.local b/gnu/usr.bin/groff/tmac/mdoc.local index 80e13bcb97..a072099f66 100644 --- a/gnu/usr.bin/groff/tmac/mdoc.local +++ b/gnu/usr.bin/groff/tmac/mdoc.local @@ -56,7 +56,7 @@ .ds doc-str-Lb-libposix1e POSIX.1e Security API Library (libposix1e, \-lposix1e) .ds doc-str-Lb-libprop Property Container Object Library (libprop, \-lprop) .ds doc-str-Lb-libpuffs puffs Convenience Library (libpuffs, \-lpuffs) -.ds doc-str-Lb-libradius RADIUS Client Library (libradius, \-lradius) +.ds doc-str-Lb-libradius RADIUS Client and Server Library (libradius, \-lradius) .ds doc-str-Lb-librefuse File System in Userspace Convenience Library (librefuse, \-lrefuse) .ds doc-str-Lb-librpcsvc RPC Service Library (librpcsvc, \-lrpcsvc) .ds doc-str-Lb-libsdp Bluetooth Service Discovery Protocol Library (libsdp, \-lsdp) diff --git a/lib/libradius/Makefile b/lib/libradius/Makefile index d05a2edaba..ba1cf5be2b 100644 --- a/lib/libradius/Makefile +++ b/lib/libradius/Makefile @@ -22,30 +22,56 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# $FreeBSD: src/lib/libradius/Makefile,v 1.3.2.2 2002/06/17 02:24:57 brian Exp $ +# $FreeBSD: src/lib/libradius/Makefile,v 1.17 2010/01/02 09:58:07 ed Exp $ LIB= radius SRCS= radlib.c INCS= radlib.h radlib_vs.h -DPADD+= ${LIBMD} -LDADD+= -lmd -SHLIB_MAJOR= 2 + +.if !defined(NO_CRYPT) && !defined(NO_OPENSSL) +DPADD= ${LIBCRYPTO} +LDADD= -lcrypto +CFLAGS+= -DWITH_SSL +.else +DPADD= ${LIBMD} +LDADD= -lmd +.endif + +SHLIB_MAJOR= 3 MAN= libradius.3 radius.conf.5 -MLINKS+= libradius.3 rad_acct_open.3 libradius.3 rad_add_server.3 -MLINKS+= libradius.3 rad_auth_open.3 libradius.3 rad_close.3 +MLINKS+= libradius.3 rad_acct_open.3 +MLINKS+= libradius.3 rad_add_server.3 +MLINKS+= libradius.3 rad_add_server_ex.3 +MLINKS+= libradius.3 rad_auth_open.3 +MLINKS+= libradius.3 rad_bind_to.3 +MLINKS+= libradius.3 rad_close.3 MLINKS+= libradius.3 rad_config.3 MLINKS+= libradius.3 rad_continue_send_request.3 -MLINKS+= libradius.3 rad_create_request.3 libradius.3 rad_cvt_addr.3 -MLINKS+= libradius.3 rad_cvt_int.3 libradius.3 rad_cvt_string.3 -MLINKS+= libradius.3 rad_get_attr.3 libradius.3 rad_get_vendor_attr.3 -MLINKS+= libradius.3 rad_init_send_request.3 libradius.3 rad_put_addr.3 -MLINKS+= libradius.3 rad_put_attr.3 libradius.3 rad_put_int.3 -MLINKS+= libradius.3 rad_put_string.3 libradius.3 rad_put_vendor_addr.3 +MLINKS+= libradius.3 rad_create_request.3 +MLINKS+= libradius.3 rad_create_response.3 +MLINKS+= libradius.3 rad_cvt_addr.3 +MLINKS+= libradius.3 rad_cvt_int.3 +MLINKS+= libradius.3 rad_cvt_string.3 +MLINKS+= libradius.3 rad_demangle.3 +MLINKS+= libradius.3 rad_demangle_mppe_key.3 +MLINKS+= libradius.3 rad_get_attr.3 +MLINKS+= libradius.3 rad_get_vendor_attr.3 +MLINKS+= libradius.3 rad_init_send_request.3 +MLINKS+= libradius.3 rad_put_addr.3 +MLINKS+= libradius.3 rad_put_attr.3 +MLINKS+= libradius.3 rad_put_int.3 +MLINKS+= libradius.3 rad_put_message_authentic.3 +MLINKS+= libradius.3 rad_put_string.3 +MLINKS+= libradius.3 rad_put_vendor_addr.3 MLINKS+= libradius.3 rad_put_vendor_attr.3 MLINKS+= libradius.3 rad_put_vendor_int.3 MLINKS+= libradius.3 rad_put_vendor_string.3 +MLINKS+= libradius.3 rad_receive_request.3 MLINKS+= libradius.3 rad_request_authenticator.3 -MLINKS+= libradius.3 rad_send_request.3 libradius.3 rad_server_secret.3 +MLINKS+= libradius.3 rad_send_request.3 +MLINKS+= libradius.3 rad_send_response.3 +MLINKS+= libradius.3 rad_server_open.3 +MLINKS+= libradius.3 rad_server_secret.3 MLINKS+= libradius.3 rad_strerror.3 .include diff --git a/lib/libradius/libradius.3 b/lib/libradius/libradius.3 index 435575613c..8937f4f380 100644 --- a/lib/libradius/libradius.3 +++ b/lib/libradius/libradius.3 @@ -22,24 +22,23 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: src/lib/libradius/libradius.3,v 1.6.2.6 2002/11/27 17:36:00 archie Exp $ -.\" $DragonFly: src/lib/libradius/libradius.3,v 1.3 2007/09/14 19:47:03 swildner Exp $ +.\" $FreeBSD: src/lib/libradius/libradius.3,v 1.19 2010/08/16 15:18:30 joel Exp $ .\" -.Dd October 30, 1999 +.Dd September 24, 2010 .Dt LIBRADIUS 3 .Os .Sh NAME .Nm libradius -.Nd RADIUS client library +.Nd RADIUS client/server library .Sh LIBRARY .Lb libradius .Sh SYNOPSIS .In radlib.h -.Ft struct rad_handle * +.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 * +.Ft "struct rad_handle *" .Fn rad_auth_open "void" .Ft void .Fn rad_close "struct rad_handle *h" @@ -49,7 +48,9 @@ .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 +.Ft int +.Fn rad_create_response "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" @@ -70,6 +71,8 @@ .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" @@ -80,33 +83,48 @@ .Ft ssize_t .Fn rad_request_authenticator "struct rad_handle *h" "char *buf" "size_t len" .Ft int +.Fn rad_receive_request "struct rad_handle *h" +.Ft int .Fn rad_send_request "struct rad_handle *h" -.Ft const char * +.Ft int +.Fn rad_send_response "struct rad_handle *h" +.Ft "struct rad_handle *" +.Fn rad_server_open "int fd" +.Ft "const char *" .Fn rad_server_secret "struct rad_handle *h" -.Ft const char * +.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 2138 and 2139, +library implements 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. -.Sh INITIALIZATION +.Ss Initialization To use the library, an application must first call .Fn rad_auth_open -or +, .Fn rad_acct_open +or +.Fn rad_server_open to obtain a -.Va struct rad_handle * , +.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 +and +.Fn rad_server_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, @@ -115,7 +133,8 @@ 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 +of the servers it can contact. +The easiest way to configure the library is to call .Fn rad_config . .Fn rad_config @@ -123,7 +142,7 @@ 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 -.Va file +.Fa file argument to .Fn rad_config . This argument may also be given as @@ -132,38 +151,46 @@ 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. +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 -.Va host +.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 -.Va port -parameter specifies the UDP port to contact on the server. If -.Va port +.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 services database, and uses the port found -there. If no entry is found, the library uses the standard RADIUS +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 -.Va secret +.Fa secret parameter. -It may be any NUL-terminated string of bytes. The RADIUS protocol +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 -.Va timeout -parameter, in units of seconds. The maximum number of repeated +.Fa timeout +parameter, in units of seconds. +The maximum number of repeated requests to make before giving up is passed into the -.Va max_tries +.Fa max_tries parameter. .Fn rad_add_server -returns 0 on success, or -1 if an error occurs. +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 @@ -171,56 +198,79 @@ may be called multiple times, and it may be used together with 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 -.Va max_tries +.Fa max_tries limit has been reached. -.Sh CREATING A RADIUS REQUEST +.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 +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 -.Va struct rad_handle * , +.Vt "struct rad_handle *" , this function takes a -.Va code -parameter which specifies the type of the request. Most often this +.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. +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 +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 -.Va type +.Fa type parameter identifying the attribute, and a value which may be -an Internet address, an integer, or a NUL-terminated string, +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 +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 -.Va data +which can be used to supply a raw, uninterpreted attribute. +The +.Fa data argument points to an array of bytes, and the -.Va len +.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. -.Sh SENDING THE REQUEST AND RECEIVING THE RESPONSE +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 @@ -242,19 +292,20 @@ or .Dv RAD_ACCESS_CHALLENGE . If no valid response is received, .Fn rad_send_request -returns -1. +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 +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 -.Ar fd +.Fa fd and -.Ar tv +.Fa tv are set to the descriptor and timeout that should be passed to .Xr select 2 . .Pp @@ -265,19 +316,22 @@ as long as a return value of zero is given. Between each call, the application should call .Xr select 2 , passing -.Ar *fd +.Fa *fd as a read descriptor and timing out after the interval specified by -.Ar tv . -When select returns, +.Fa tv . +When +.Xr select 2 +returns, .Fn rad_continue_send_request should be called with -.Ar selected +.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 +attributes. +After a response has been received successfully by .Fn rad_send_request or .Fn rad_continue_send_request , @@ -288,10 +342,11 @@ Each time 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 -.Va data +.Fa data and -.Va len , -respectively. Note that the data resides in the response itself, +.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 @@ -299,7 +354,7 @@ 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 +If an error such as a malformed attribute is detected, \-1 is returned. .Pp If @@ -310,10 +365,11 @@ returns may be called to determine the vendor. The vendor specific RADIUS attribute type is returned. The reference parameters -.Va data +.Fa data and -.Va len -.Pq as returned from Fn rad_get_attr +.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. @@ -331,13 +387,17 @@ and optionally In the case of .Fn rad_cvt_string , the length -.Va len -must also be given. These functions interpret the attribute as an +.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 NUL-terminated string in dynamically -allocated memory. The application should free the string using +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 @@ -356,36 +416,77 @@ 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 -.Ar buf +.Fa buf of length -.Ar len +.Fa len must be supplied and should be at least 16 bytes. The return value is the number of bytes written to -.Ar buf -or -1 to indicate that -.Ar len +.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. -.Sh OBTAINING ERROR MESSAGES +.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 -.Va struct rad_handle * -argument record an error message if they fail. The error message +.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 -.Va struct rad_handle * . +.Vt "struct rad_handle *" . Thus the message must be copied if it is to be preserved through subsequent library calls using the same handle. -.Sh CLEANUP +.Ss Cleanup To free the resources used by the RADIUS library, call .Fn rad_close . +.Ss Server operation +Server mode operates much alike to client mode, except packet send and receive +steps are swapped. To operate as server you should obtain server context with +.Fn rad_server_open +function, passing opened and bound UDP socket file descriptor as argument. +You should define allowed clients and their secrets using +.Fn rad_add_server +function. port, timeout and max_tries arguments are ignored in server mode. +You should call +.Fn rad_receive_request +function to receive request from client. If you do not want to block on socket +read, you are free to use any poll(), select() or non-blocking sockets for +the socket. +Received request can be parsed with same parsing functions as for client. +To respond to the request you should call +.Fn rad_create_response +and fill response content with same packet writing functions as for client. +When packet is ready, it should be sent with +.Fn rad_send_response .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 +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 @@ -397,6 +498,8 @@ which can be retrieved using .It .Fn rad_create_request .It +.Fn rad_create_response +.It .Fn rad_get_attr .It .Fn rad_put_addr @@ -407,16 +510,21 @@ which can be retrieved using .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 +.It +.Fn rad_send_response .El .Pp The following functions return a .No non- Ns Dv NULL -pointer on success. If they are unable to allocate sufficient +pointer on success. +If they are unable to allocate sufficient virtual memory, they return .Dv NULL , without recording an error message. @@ -427,27 +535,61 @@ without recording an error message. .It .Fn rad_auth_open .It +.Fn rad_server_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 -.Pa /etc/radius.conf +.Bl -tag -width indent +.It Pa /etc/radius.conf +.El .Sh SEE ALSO .Xr radius.conf 5 .Rs -.%A C. Rigney, et al +.%A "C. Rigney, et al" .%T "Remote Authentication Dial In User Service (RADIUS)" -.%O RFC 2138 +.%O "RFC 2865" .Re .Rs -.%A C. Rigney -.%T RADIUS Accounting -.%O RFC 2139 +.%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. -Oleg Semyonov subsequently added the ability to perform RADIUS +.An Oleg Semyonov +subsequently added the ability to perform RADIUS accounting. +Later additions and changes by +.An Michael Bretterklieber . +Server mode support was added by +.An Alexander Motin . diff --git a/lib/libradius/radius.conf.5 b/lib/libradius/radius.conf.5 index f521f223b1..df5e189ffc 100644 --- a/lib/libradius/radius.conf.5 +++ b/lib/libradius/radius.conf.5 @@ -35,14 +35,16 @@ .Sh DESCRIPTION .Nm contains the information necessary to configure the RADIUS client -library. It is parsed by +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 +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: +A RADIUS server is described by three to seven fields on a line: .Pp .Bl -item -offset indent -compact .It @@ -55,15 +57,22 @@ Shared secret Timeout .It Retries +.It +Dead time +.It +Bind address .El .Pp -The fields are separated by white space. The +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, +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 +character. +Within a quoted string, the double quote character can be represented by .Ql \e\&" , and the backslash can be represented by @@ -74,9 +83,12 @@ 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 +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 @@ -88,9 +100,11 @@ 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 +dotted-quad IP address. +The host may optionally be followed by a .Ql \&: -and a numeric port number, without intervening white space. If the +and a numeric port number, without intervening white space. +If the port specification is omitted, it defaults to the .Ql radius or @@ -106,23 +120,36 @@ 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 +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 +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 +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 +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, +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 +The sixth field contains a decimal integer specifying a time interval +in seconds when the server will not requested if it was inaccessible +on the last try. 0 means ask always. +.Pp +The seventh field contains an IP address on multihomed host. All +requests will be binded to this IP. +.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 @@ -145,6 +172,9 @@ acct radius1.domain.com OurLittleSecret # timeout and maximum tries: auth auth.domain.com:1645 "I can't see you" 5 4 +# As above but set dead time and bind address +auth auth.domain.com:1645 "I can't see you" 5 4 60 192.168.1.8 + # A server specified by its IP address: auth 192.168.27.81 $X*#..38947ax-+= .Ed diff --git a/lib/libradius/radlib.c b/lib/libradius/radlib.c index e2fff0f9a9..7a8237382b 100644 --- a/lib/libradius/radlib.c +++ b/lib/libradius/radlib.c @@ -23,18 +23,37 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/lib/libradius/radlib.c,v 1.4.2.3 2002/06/17 02:24:57 brian Exp $ - * $DragonFly: src/lib/libradius/radlib.c,v 1.5 2008/11/02 21:52:46 swildner Exp $ + * $FreeBSD: src/lib/libradius/radlib.c,v 1.15 2009/09/29 19:09:17 mav Exp $ */ -#include +#include + +#include #include #include #include #include +#ifdef WITH_SSL +#include +#include +#define MD5Init MD5_Init +#define MD5Update MD5_Update +#define MD5Final MD5_Final +#else +#define MD5_DIGEST_LENGTH 16 +#include +#endif + +#define MAX_FIELDS 7 + +/* We need the MPPE_KEY_LEN define */ +#ifdef WANT_NETGRAPH7 +#include +#else +#include +#endif #include -#include #include #include #include @@ -50,6 +69,7 @@ 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, @@ -82,7 +102,7 @@ static void insert_scrambled_password(struct rad_handle *h, int srv) { MD5_CTX ctx; - unsigned char md5[16]; + unsigned char md5[MD5_DIGEST_LENGTH]; const struct rad_server *srvp; int padded_len; int pos; @@ -90,7 +110,7 @@ insert_scrambled_password(struct rad_handle *h, int srv) srvp = &h->servers[srv]; padded_len = h->pass_len == 0 ? 16 : (h->pass_len+15) & ~0xf; - memcpy(md5, &h->request[POS_AUTH], LEN_AUTH); + memcpy(md5, &h->out[POS_AUTH], LEN_AUTH); for (pos = 0; pos < padded_len; pos += 16) { int i; @@ -107,26 +127,57 @@ insert_scrambled_password(struct rad_handle *h, int srv) * in calculating the scrambler for next time. */ for (i = 0; i < 16; i++) - h->request[h->pass_pos + pos + i] = + h->out[h->pass_pos + pos + i] = md5[i] ^= h->pass[pos + i]; } } static void -insert_request_authenticator(struct rad_handle *h, int srv) +insert_request_authenticator(struct rad_handle *h, int resp) { MD5_CTX ctx; const struct rad_server *srvp; - srvp = &h->servers[srv]; + srvp = &h->servers[h->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, &h->out[POS_CODE], POS_AUTH - POS_CODE); + if (resp) + MD5Update(&ctx, &h->in[POS_AUTH], LEN_AUTH); + else + MD5Update(&ctx, &h->out[POS_AUTH], LEN_AUTH); + MD5Update(&ctx, &h->out[POS_ATTRS], h->out_len - POS_ATTRS); MD5Update(&ctx, srvp->secret, strlen(srvp->secret)); - MD5Final(&h->request[POS_AUTH], &ctx); + MD5Final(&h->out[POS_AUTH], &ctx); +} + +static void +insert_message_authenticator(struct rad_handle *h, int resp) +{ +#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[h->srv]; + + if (h->authentic_pos != 0) { + HMAC_CTX_init(&ctx); + HMAC_Init(&ctx, srvp->secret, strlen(srvp->secret), EVP_md5()); + HMAC_Update(&ctx, &h->out[POS_CODE], POS_AUTH - POS_CODE); + if (resp) + HMAC_Update(&ctx, &h->in[POS_AUTH], LEN_AUTH); + else + HMAC_Update(&ctx, &h->out[POS_AUTH], LEN_AUTH); + HMAC_Update(&ctx, &h->out[POS_ATTRS], + h->out_len - POS_ATTRS); + HMAC_Final(&ctx, md, &md_len); + HMAC_CTX_cleanup(&ctx); + HMAC_cleanup(&ctx); + memcpy(&h->out[h->authentic_pos + 2], md, md_len); + } +#endif } /* @@ -138,9 +189,15 @@ is_valid_response(struct rad_handle *h, int srv, const struct sockaddr_in *from) { MD5_CTX ctx; - unsigned char md5[16]; + 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]; @@ -151,25 +208,132 @@ is_valid_response(struct rad_handle *h, int srv, return 0; /* Check the message length */ - if (h->resp_len < POS_ATTRS) + if (h->in_len < POS_ATTRS) return 0; - len = h->response[POS_LENGTH] << 8 | h->response[POS_LENGTH+1]; - if (len > h->resp_len) + len = h->in[POS_LENGTH] << 8 | h->in[POS_LENGTH+1]; + if (len > h->in_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, &h->in[POS_CODE], POS_AUTH - POS_CODE); + MD5Update(&ctx, &h->out[POS_AUTH], LEN_AUTH); + MD5Update(&ctx, &h->in[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) + if (memcmp(&h->in[POS_AUTH], md5, sizeof md5) != 0) return 0; +#ifdef WITH_SSL + /* + * For non accounting responses check the message authenticator, + * if any. + */ + if (h->in[POS_CODE] != RAD_ACCOUNTING_RESPONSE) { + + memcpy(resp, h->in, MSGSIZE); + pos = POS_ATTRS; + + /* Search and verify the Message-Authenticator */ + while (pos < len - 2) { + + if (h->in[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->in[POS_CODE], + POS_AUTH - POS_CODE); + HMAC_Update(&hctx, &h->out[POS_AUTH], + LEN_AUTH); + HMAC_Update(&hctx, &resp[POS_ATTRS], + h->in_len - POS_ATTRS); + HMAC_Final(&hctx, md, &md_len); + HMAC_CTX_cleanup(&hctx); + HMAC_cleanup(&hctx); + if (memcmp(md, &h->in[pos + 2], + MD5_DIGEST_LENGTH) != 0) + return 0; + break; + } + pos += h->in[pos + 1]; + } + } +#endif return 1; } +/* + * Return true if the current request is valid for the specified server. + */ +static int +is_valid_request(struct rad_handle *h) +{ + 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[h->srv]; + + /* Check the message length */ + if (h->in_len < POS_ATTRS) + return (0); + len = h->in[POS_LENGTH] << 8 | h->in[POS_LENGTH+1]; + if (len > h->in_len) + return (0); + + if (h->in[POS_CODE] != RAD_ACCESS_REQUEST) { + uint32_t zeroes[4] = { 0, 0, 0, 0 }; + /* Check the request authenticator */ + MD5Init(&ctx); + MD5Update(&ctx, &h->in[POS_CODE], POS_AUTH - POS_CODE); + MD5Update(&ctx, zeroes, LEN_AUTH); + MD5Update(&ctx, &h->in[POS_ATTRS], len - POS_ATTRS); + MD5Update(&ctx, srvp->secret, strlen(srvp->secret)); + MD5Final(md5, &ctx); + if (memcmp(&h->in[POS_AUTH], md5, sizeof md5) != 0) + return (0); + } + +#ifdef WITH_SSL + /* Search and verify the Message-Authenticator */ + pos = POS_ATTRS; + while (pos < len - 2) { + if (h->in[pos] == RAD_MESSAGE_AUTHENTIC) { + memcpy(resp, h->in, MSGSIZE); + /* zero fill the Request-Authenticator */ + if (h->in[POS_CODE] != RAD_ACCESS_REQUEST) + memset(&resp[POS_AUTH], 0, LEN_AUTH); + /* 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, resp, h->in_len); + HMAC_Final(&hctx, md, &md_len); + HMAC_CTX_cleanup(&hctx); + HMAC_cleanup(&hctx); + if (memcmp(md, &h->in[pos + 2], + MD5_DIGEST_LENGTH) != 0) + return (0); + break; + } + pos += h->in[pos + 1]; + } +#endif + return (1); +} + static int put_password_attr(struct rad_handle *h, int type, const void *value, size_t len) { @@ -191,7 +355,7 @@ put_password_attr(struct rad_handle *h, int type, const void *value, size_t len) */ clear_password(h); put_raw_attr(h, type, h->pass, padded_len); - h->pass_pos = h->req_len - padded_len; + h->pass_pos = h->out_len - padded_len; /* Save the cleartext password, padded as necessary */ memcpy(h->pass, value, len); @@ -207,20 +371,32 @@ put_raw_attr(struct rad_handle *h, int type, const void *value, size_t len) generr(h, "Attribute too long"); return -1; } - if (h->req_len + 2 + len > MSGSIZE) { + if (h->out_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; + h->out[h->out_len++] = type; + h->out[h->out_len++] = len + 2; + memcpy(&h->out[h->out_len], value, len); + h->out_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 in_addr bindto; + bindto.s_addr = INADDR_ANY; + + return rad_add_server_ex(h, host, port, secret, timeout, tries, + DEAD_TIME, &bindto); +} + +int +rad_add_server_ex(struct rad_handle *h, const char *host, int port, + const char *secret, int timeout, int tries, int dead_time, + struct in_addr *bindto) { struct rad_server *srvp; @@ -244,7 +420,7 @@ rad_add_server(struct rad_handle *h, const char *host, int port, sizeof srvp->addr.sin_addr); } if (port != 0) - srvp->addr.sin_port = htons(port); + srvp->addr.sin_port = htons((u_short)port); else { struct servent *sent; @@ -264,6 +440,10 @@ rad_add_server(struct rad_handle *h, const char *host, int port, srvp->timeout = timeout; srvp->max_tries = tries; srvp->num_tries = 0; + srvp->is_dead = 0; + srvp->dead_time = dead_time; + srvp->next_probe = 0; + srvp->bindto = bindto->s_addr; h->num_servers++; return 0; } @@ -284,6 +464,13 @@ rad_close(struct rad_handle *h) free(h); } +void +rad_bind_to(struct rad_handle *h, in_addr_t addr) +{ + + h->bindto = addr; +} + int rad_config(struct rad_handle *h, const char *path) { @@ -302,18 +489,25 @@ rad_config(struct rad_handle *h, const char *path) linenum = 0; while (fgets(buf, sizeof buf, fp) != NULL) { int len; - const char *fields[5]; + const char *fields[MAX_FIELDS]; int nfields; char msg[ERRSIZE]; - const char *ohost, *secret, *timeout_str, *maxtries_str; - const char *type, *wanttype; - char *host; - char *res; - char *port_str; + const char *type; + const char *host; + const char *port_str; + const char *secret; + const char *timeout_str; + const char *maxtries_str; + const char *dead_time_str; + const char *bindto_str; + char *res, *host_dup; char *end; + const char *wanttype; unsigned long timeout; unsigned long maxtries; + unsigned long dead_time; int port; + struct in_addr bindto; int i; linenum++; @@ -332,7 +526,7 @@ rad_config(struct rad_handle *h, const char *path) buf[len - 1] = '\0'; /* Extract the fields from the line. */ - nfields = split(buf, fields, 5, msg, sizeof msg); + nfields = split(buf, fields, MAX_FIELDS, msg, sizeof msg); if (nfields == -1) { generr(h, "%s:%d: %s", path, linenum, msg); retval = -1; @@ -348,7 +542,7 @@ rad_config(struct rad_handle *h, const char *path) */ if (strcmp(fields[0], "auth") != 0 && strcmp(fields[0], "acct") != 0) { - if (nfields >= 5) { + if (nfields >= MAX_FIELDS) { generr(h, "%s:%d: invalid service type", path, linenum); retval = -1; @@ -366,10 +560,12 @@ rad_config(struct rad_handle *h, const char *path) break; } type = fields[0]; - ohost = fields[1]; + host = fields[1]; secret = fields[2]; timeout_str = fields[3]; maxtries_str = fields[4]; + dead_time_str = fields[5]; + bindto_str = fields[6]; /* Ignore the line if it is for the wrong service type. */ wanttype = h->type == RADIUS_AUTH ? "auth" : "acct"; @@ -377,17 +573,18 @@ rad_config(struct rad_handle *h, const char *path) continue; /* Parse and validate the fields. */ - if ((res = strdup(ohost)) == NULL) { + if ((host_dup = strdup(host)) == NULL) { generr(h, "%s:%d: malloc failed", path, linenum); retval = -1; break; } + res = host_dup; host = strsep(&res, ":"); port_str = strsep(&res, ":"); if (port_str != NULL) { port = strtoul(port_str, &end, 10); if (*end != '\0') { - free(host); + free(host_dup); generr(h, "%s:%d: invalid port", path, linenum); retval = -1; @@ -398,7 +595,7 @@ rad_config(struct rad_handle *h, const char *path) if (timeout_str != NULL) { timeout = strtoul(timeout_str, &end, 10); if (*end != '\0') { - free(host); + free(host_dup); generr(h, "%s:%d: invalid timeout", path, linenum); retval = -1; @@ -409,7 +606,7 @@ rad_config(struct rad_handle *h, const char *path) if (maxtries_str != NULL) { maxtries = strtoul(maxtries_str, &end, 10); if (*end != '\0') { - free(host); + free(host_dup); generr(h, "%s:%d: invalid maxtries", path, linenum); retval = -1; @@ -418,15 +615,39 @@ rad_config(struct rad_handle *h, const char *path) } else maxtries = MAXTRIES; - if (rad_add_server(h, host, port, secret, timeout, maxtries) == - -1) { - free(host); + if (dead_time_str != NULL) { + dead_time = strtoul(dead_time_str, &end, 10); + if (*end != '\0') { + free(host_dup); + generr(h, "%s:%d: invalid dead_time", path, + linenum); + retval = -1; + break; + } + } else + dead_time = DEAD_TIME; + + if (bindto_str != NULL) { + bindto.s_addr = inet_addr(bindto_str); + if (bindto.s_addr == INADDR_NONE) { + free(host_dup); + generr(h, "%s:%d: invalid bindto", path, + linenum); + retval = -1; + break; + } + } else + bindto.s_addr = INADDR_ANY; + + if (rad_add_server_ex(h, host, port, secret, timeout, maxtries, + dead_time, &bindto) == -1) { + free(host_dup); strcpy(msg, h->errmsg); generr(h, "%s:%d: %s", path, linenum, msg); retval = -1; break; } - free(host); + free(host_dup); } /* Clear out the buffer to wipe a possible copy of a shared secret */ memset(buf, 0, sizeof buf); @@ -446,54 +667,176 @@ int rad_continue_send_request(struct rad_handle *h, int selected, int *fd, struct timeval *tv) { - int n; + int n, cur_srv; + time_t now; + struct sockaddr_in sin; + if (h->type == RADIUS_SERVER) { + generr(h, "denied function call"); + return (-1); + } if (selected) { struct sockaddr_in from; - int fromlen; + socklen_t fromlen; fromlen = sizeof from; - h->resp_len = recvfrom(h->fd, h->response, + h->in_len = recvfrom(h->fd, h->in, MSGSIZE, MSG_WAITALL, (struct sockaddr *)&from, &fromlen); - if (h->resp_len == -1) { + if (h->in_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]; + h->in_len = h->in[POS_LENGTH] << 8 | + h->in[POS_LENGTH+1]; + h->in_pos = POS_ATTRS; + return h->in[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; + cur_srv = h->srv; + now = time(NULL); + if (h->servers[h->srv].num_tries >= h->servers[h->srv].max_tries) { + /* Set next probe time for this server */ + if (h->servers[h->srv].dead_time) { + h->servers[h->srv].is_dead = 1; + h->servers[h->srv].next_probe = now + + h->servers[h->srv].dead_time; + } + do { + h->srv++; + if (h->srv >= h->num_servers) + h->srv = 0; + if (h->servers[h->srv].is_dead == 0) + break; + if (h->servers[h->srv].dead_time && + h->servers[h->srv].next_probe <= now) { + h->servers[h->srv].is_dead = 0; + h->servers[h->srv].num_tries = 0; + break; + } + } while (h->srv != cur_srv); - if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) - /* Insert the request authenticator into the request */ - insert_request_authenticator(h, h->srv); - else + if (h->srv == cur_srv) { + generr(h, "No valid RADIUS responses received"); + return (-1); + } + } + + /* Rebind */ + if (h->bindto != h->servers[h->srv].bindto) { + h->bindto = h->servers[h->srv].bindto; + close(h->fd); + 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 = h->bindto; + sin.sin_port = 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->out[POS_CODE] == RAD_ACCESS_REQUEST) { /* Insert the scrambled password into the request */ if (h->pass_pos != 0) insert_scrambled_password(h, h->srv); + } + insert_message_authenticator(h, 0); + + if (h->out[POS_CODE] != RAD_ACCESS_REQUEST) { + /* Insert the request authenticator into the request */ + memset(&h->out[POS_AUTH], 0, LEN_AUTH); + insert_request_authenticator(h, 0); + } + + /* Send the request */ + n = sendto(h->fd, h->out, h->out_len, 0, + (const struct sockaddr *)&h->servers[h->srv].addr, + sizeof h->servers[h->srv].addr); + if (n != h->out_len) + tv->tv_sec = 1; /* Do not wait full timeout if send failed. */ + else + tv->tv_sec = h->servers[h->srv].timeout; + h->servers[h->srv].num_tries++; + tv->tv_usec = 0; + *fd = h->fd; + + return 0; +} + +int +rad_receive_request(struct rad_handle *h) +{ + struct sockaddr_in from; + socklen_t fromlen; + int n; + + if (h->type != RADIUS_SERVER) { + generr(h, "denied function call"); + return (-1); + } + h->srv = -1; + fromlen = sizeof(from); + h->in_len = recvfrom(h->fd, h->in, + MSGSIZE, MSG_WAITALL, (struct sockaddr *)&from, &fromlen); + if (h->in_len == -1) { + generr(h, "recvfrom: %s", strerror(errno)); + return (-1); + } + for (n = 0; n < h->num_servers; n++) { + if (h->servers[n].addr.sin_addr.s_addr == from.sin_addr.s_addr) { + h->servers[n].addr.sin_port = from.sin_port; + h->srv = n; + break; + } + } + if (h->srv == -1) + return (-2); + if (is_valid_request(h)) { + h->in_len = h->in[POS_LENGTH] << 8 | + h->in[POS_LENGTH+1]; + h->in_pos = POS_ATTRS; + return (h->in[POS_CODE]); + } + return (-3); +} + +int +rad_send_response(struct rad_handle *h) +{ + int n; + + if (h->type != RADIUS_SERVER) { + generr(h, "denied function call"); + return (-1); + } + /* Fill in the length field in the message */ + h->out[POS_LENGTH] = h->out_len >> 8; + h->out[POS_LENGTH+1] = h->out_len; + + insert_message_authenticator(h, + (h->in[POS_CODE] == RAD_ACCESS_REQUEST) ? 1 : 0); + insert_request_authenticator(h, 1); /* Send the request */ - n = sendto(h->fd, h->request, h->req_len, 0, + n = sendto(h->fd, h->out, h->out_len, 0, (const struct sockaddr *)&h->servers[h->srv].addr, sizeof h->servers[h->srv].addr); - if (n != h->req_len) { + if (n != h->out_len) { if (n == -1) generr(h, "sendto: %s", strerror(errno)); else @@ -501,12 +844,6 @@ rad_continue_send_request(struct rad_handle *h, int selected, int *fd, 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; } @@ -515,17 +852,48 @@ 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] = r; - h->request[POS_AUTH+i+1] = r >> 8; + if (h->type == RADIUS_SERVER) { + generr(h, "denied function call"); + return (-1); + } + if (h->num_servers == 0) { + generr(h, "No RADIUS servers specified"); + return (-1); + } + h->out[POS_CODE] = code; + h->out[POS_IDENT] = ++h->ident; + if (code == RAD_ACCESS_REQUEST) { + /* Create a random authenticator */ + for (i = 0; i < LEN_AUTH; i += 2) { + long r; + r = random(); + h->out[POS_AUTH+i] = (u_char)r; + h->out[POS_AUTH+i+1] = (u_char)(r >> 8); + } + } else + memset(&h->out[POS_AUTH], 0, LEN_AUTH); + h->out_len = POS_ATTRS; + clear_password(h); + h->authentic_pos = 0; + h->out_created = 1; + return 0; +} + +int +rad_create_response(struct rad_handle *h, int code) +{ + + if (h->type != RADIUS_SERVER) { + generr(h, "denied function call"); + return (-1); } - h->req_len = POS_ATTRS; + h->out[POS_CODE] = code; + h->out[POS_IDENT] = h->in[POS_IDENT]; + memset(&h->out[POS_AUTH], 0, LEN_AUTH); + h->out_len = POS_ATTRS; clear_password(h); + h->authentic_pos = 0; + h->out_created = 1; return 0; } @@ -538,6 +906,15 @@ rad_cvt_addr(const void *data) return value; } +struct in6_addr +rad_cvt_addr6(const void *data) +{ + struct in6_addr value; + + memcpy(&value.s6_addr, data, sizeof value.s6_addr); + return value; +} + u_int32_t rad_cvt_int(const void *data) { @@ -569,20 +946,20 @@ rad_get_attr(struct rad_handle *h, const void **value, size_t *len) { int type; - if (h->resp_pos >= h->resp_len) + if (h->in_pos >= h->in_len) return 0; - if (h->resp_pos + 2 > h->resp_len) { + if (h->in_pos + 2 > h->in_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) { + type = h->in[h->in_pos++]; + *len = h->in[h->in_pos++] - 2; + if (h->in_pos + (int)*len > h->in_len) { generr(h, "Malformed attribute in response"); return -1; } - *value = &h->response[h->resp_pos]; - h->resp_pos += *len; + *value = &h->in[h->in_pos]; + h->in_pos += *len; return type; } @@ -593,11 +970,15 @@ int rad_init_send_request(struct rad_handle *h, int *fd, struct timeval *tv) { int srv; + time_t now; + struct sockaddr_in sin; + if (h->type == RADIUS_SERVER) { + generr(h, "denied function call"); + return (-1); + } /* 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; @@ -605,7 +986,7 @@ rad_init_send_request(struct rad_handle *h, int *fd, struct timeval *tv) memset(&sin, 0, sizeof sin); sin.sin_len = sizeof sin; sin.sin_family = AF_INET; - sin.sin_addr.s_addr = INADDR_ANY; + sin.sin_addr.s_addr = h->bindto; sin.sin_port = htons(0); if (bind(h->fd, (const struct sockaddr *)&sin, sizeof sin) == -1) { @@ -616,43 +997,57 @@ rad_init_send_request(struct rad_handle *h, int *fd, struct timeval *tv) } } - if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) { + if (h->out[POS_CODE] != RAD_ACCESS_REQUEST) { /* Make sure no password given */ if (h->pass_pos || h->chap_pass) { - generr(h, "User or Chap Password in accounting request"); + generr(h, "User or Chap Password" + " in accounting request"); return -1; } } else { - /* 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; + 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; + h->out[POS_LENGTH] = h->out_len >> 8; + h->out[POS_LENGTH+1] = h->out_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->srv = 0; + now = time(NULL); + for (srv = 0; srv < h->num_servers; srv++) h->servers[srv].num_tries = 0; - } - if (h->total_tries == 0) { - generr(h, "No RADIUS servers specified"); - return -1; + /* Find a first good server. */ + for (srv = 0; srv < h->num_servers; srv++) { + if (h->servers[srv].is_dead == 0) + break; + if (h->servers[srv].dead_time && + h->servers[srv].next_probe <= now) { + h->servers[srv].is_dead = 0; + break; + } + h->srv++; } - h->try = h->srv = 0; + /* If all servers was dead on the last probe, try from beginning */ + if (h->srv == h->num_servers) { + for (srv = 0; srv < h->num_servers; srv++) { + h->servers[srv].is_dead = 0; + h->servers[srv].next_probe = 0; + } + h->srv = 0; + } return rad_continue_send_request(h, 0, fd, tv); } @@ -678,7 +1073,11 @@ rad_auth_open(void) h->pass_len = 0; h->pass_pos = 0; h->chap_pass = 0; + h->authentic_pos = 0; h->type = RADIUS_AUTH; + h->out_created = 0; + h->eap_msg = 0; + h->bindto = INADDR_ANY; } return h; } @@ -694,6 +1093,19 @@ rad_acct_open(void) return h; } +struct rad_handle * +rad_server_open(int fd) +{ + struct rad_handle *h; + + h = rad_open(); + if (h != NULL) { + h->type = RADIUS_SERVER; + h->fd = fd; + } + return h; +} + struct rad_handle * rad_open(void) { @@ -706,17 +1118,53 @@ 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_addr6(struct rad_handle *h, int type, struct in6_addr addr) +{ + + return rad_put_attr(h, type, &addr.s6_addr, sizeof addr.s6_addr); +} + int rad_put_attr(struct rad_handle *h, int type, const void *value, size_t len) { int result; - if (type == RAD_USER_PASSWORD) + if (!h->out_created) { + generr(h, "Please call rad_create_request()" + " before putting attributes"); + return -1; + } + + if (h->out[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 { + } else if (type == RAD_MESSAGE_AUTHENTIC) { + result = rad_put_message_authentic(h); + } else { result = put_raw_attr(h, type, value, len); - if (result == 0 && type == RAD_CHAP_PASSWORD) - h->chap_pass = 1; + if (result == 0) { + if (type == RAD_CHAP_PASSWORD) + h->chap_pass = 1; + else if (type == RAD_EAP_MESSAGE) + h->eap_msg = 1; + } } return result; @@ -737,6 +1185,32 @@ 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->out[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->out_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. */ @@ -893,6 +1367,15 @@ rad_put_vendor_addr(struct rad_handle *h, int vendor, int type, sizeof addr.s_addr)); } +int +rad_put_vendor_addr6(struct rad_handle *h, int vendor, int type, + struct in6_addr addr) +{ + + return (rad_put_vendor_attr(h, vendor, type, &addr.s6_addr, + sizeof addr.s6_addr)); +} + int rad_put_vendor_attr(struct rad_handle *h, int vendor, int type, const void *value, size_t len) @@ -900,6 +1383,12 @@ rad_put_vendor_attr(struct rad_handle *h, int vendor, int type, struct vendor_attribute *attr; int res; + if (!h->out_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; @@ -941,12 +1430,145 @@ 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); + memcpy(buf, h->out + 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], *demangled; + const u_char *C; + + if ((mlen % 16 != 0) || mlen > 128) { + generr(h, "Cannot interpret mangled data of length %lu", + (u_long)mlen); + return NULL; + } + + C = 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) { diff --git a/lib/libradius/radlib.h b/lib/libradius/radlib.h index 672b80d809..5d7ac7dfcd 100644 --- a/lib/libradius/radlib.h +++ b/lib/libradius/radlib.h @@ -23,8 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/lib/libradius/radlib.h,v 1.3.2.1 2002/06/17 02:24:57 brian Exp $ - * $DragonFly: src/lib/libradius/radlib.h,v 1.2 2003/06/17 04:26:51 dillon Exp $ + * $FreeBSD: src/lib/libradius/radlib.h,v 1.8 2009/09/11 11:42:56 mav Exp $ */ #ifndef _RADLIB_H_ @@ -33,6 +32,9 @@ #include #include +/* Limits */ +#define RAD_MAX_ATTR_LEN 253 + /* Message types */ #define RAD_ACCESS_REQUEST 1 #define RAD_ACCESS_ACCEPT 2 @@ -40,6 +42,12 @@ #define RAD_ACCOUNTING_REQUEST 4 #define RAD_ACCOUNTING_RESPONSE 5 #define RAD_ACCESS_CHALLENGE 11 +#define RAD_DISCONNECT_REQUEST 40 +#define RAD_DISCONNECT_ACK 41 +#define RAD_DISCONNECT_NAK 42 +#define RAD_COA_REQUEST 43 +#define RAD_COA_ACK 44 +#define RAD_COA_NAK 45 /* Attribute types and values */ #define RAD_USER_NAME 1 /* String */ @@ -99,6 +107,9 @@ #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 @@ -124,11 +135,21 @@ #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 */ @@ -164,6 +185,8 @@ #define RAD_ACCT_MULTI_SESSION_ID 50 /* String */ #define RAD_ACCT_LINK_COUNT 51 /* Integer */ +#define RAD_ERROR_CAUSE 101 /* Integer */ + struct rad_handle; struct timeval; @@ -171,13 +194,19 @@ __BEGIN_DECLS struct rad_handle *rad_acct_open(void); int rad_add_server(struct rad_handle *, const char *, int, const char *, int, int); +int rad_add_server_ex(struct rad_handle *, + const char *, int, const char *, int, int, + int, struct in_addr *); struct rad_handle *rad_auth_open(void); +void rad_bind_to(struct rad_handle *, in_addr_t); 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); +int rad_create_response(struct rad_handle *, int); struct in_addr rad_cvt_addr(const void *); +struct in6_addr rad_cvt_addr6(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 **, @@ -186,16 +215,24 @@ 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_addr6(struct rad_handle *, int, struct in6_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_receive_request(struct rad_handle *); int rad_send_request(struct rad_handle *); +int rad_send_response(struct rad_handle *); +struct rad_handle *rad_server_open(int fd); 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 index 679eebbbae..6e458dc6d1 100644 --- a/lib/libradius/radlib_private.h +++ b/lib/libradius/radlib_private.h @@ -23,8 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/lib/libradius/radlib_private.h,v 1.4.2.1 2002/06/17 02:24:57 brian Exp $ - * $DragonFly: src/lib/libradius/radlib_private.h,v 1.2 2003/06/17 04:26:51 dillon Exp $ + * $FreeBSD: src/lib/libradius/radlib_private.h,v 1.7 2009/09/11 11:42:56 mav Exp $ */ #ifndef RADLIB_PRIVATE_H @@ -39,6 +38,7 @@ /* Handle types */ #define RADIUS_AUTH 0 /* RADIUS authentication, default */ #define RADIUS_ACCT 1 /* RADIUS accounting */ +#define RADIUS_SERVER 2 /* RADIUS server */ /* Defaults */ #define MAXTRIES 3 @@ -46,6 +46,7 @@ #define RADIUS_PORT 1812 #define RADACCT_PORT 1813 #define TIMEOUT 3 /* In seconds */ +#define DEAD_TIME 0 /* Limits */ #define ERRSIZE 128 /* Maximum error message length */ @@ -68,6 +69,10 @@ struct rad_server { int timeout; /* Timeout in seconds */ int max_tries; /* Number of tries before giving up */ int num_tries; /* Number of tries so far */ + int is_dead; /* The server did not answer last time */ + time_t dead_time; /* Don't try this server for the time period if it is dead */ + time_t next_probe; /* Time of a next probe after failure */ + in_addr_t bindto; /* Bind to address */ }; struct rad_handle { @@ -76,19 +81,21 @@ struct rad_handle { 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 */ - int req_len; /* Length of request */ + unsigned char out[MSGSIZE]; /* Request to send */ + char out_created; /* rad_create_request() called? */ + int out_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 ? */ - 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 */ + 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 in[MSGSIZE]; /* Response received */ + int in_len; /* Length of response */ + int in_pos; /* Current position scanning attrs */ int srv; /* Server number we did last */ int type; /* Handle type */ + in_addr_t bindto; /* Current bind address */ }; struct vendor_attribute { diff --git a/lib/libradius/radlib_vs.h b/lib/libradius/radlib_vs.h index 8284b135f5..131c10fe7b 100644 --- a/lib/libradius/radlib_vs.h +++ b/lib/libradius/radlib_vs.h @@ -23,8 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/lib/libradius/radlib_vs.h,v 1.2.2.1 2002/06/17 02:24:57 brian Exp $ - * $DragonFly: src/lib/libradius/radlib_vs.h,v 1.2 2003/06/17 04:26:51 dillon Exp $ + * $FreeBSD: src/lib/libradius/radlib_vs.h,v 1.3 2004/04/27 15:00:29 ru Exp $ */ #ifndef _RADLIB_VS_H_ @@ -67,15 +66,20 @@ #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 *, +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_addr6(struct rad_handle *, int, int, struct in6_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 *); +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_ */