libradius(3): Sync with FreeBSD head.
authorNuno Antunes <nuno.antunes@gmail.com>
Fri, 4 Jul 2014 05:59:13 +0000 (06:59 +0100)
committerNuno Antunes <nuno.antunes@gmail.com>
Fri, 4 Jul 2014 06:08:22 +0000 (07:08 +0100)
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)

gnu/usr.bin/groff/tmac/mdoc.local
lib/libradius/Makefile
lib/libradius/libradius.3
lib/libradius/radius.conf.5
lib/libradius/radlib.c
lib/libradius/radlib.h
lib/libradius/radlib_private.h
lib/libradius/radlib_vs.h

index 80e13bc..a072099 100644 (file)
@@ -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)
index d05a2ed..ba1cf5b 100644 (file)
 # 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 <bsd.lib.mk>
index 4355756..8937f4f 100644 (file)
 .\" 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"
 .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 .
index f521f22..df5e189 100644 (file)
 .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
index e2fff0f..7a82373 100644 (file)
  * 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 <sys/param.h>
+#include <sys/cdefs.h>
+
+#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
+
+#define        MAX_FIELDS      7
+
+/* We need the MPPE_KEY_LEN define */
+#ifdef WANT_NETGRAPH7
+#include <netgraph7/mppc/ng_mppc.h>
+#else
+#include <netgraph/mppc/ng_mppc.h>
+#endif
 
 #include <errno.h>
-#include <md5.h>
 #include <netdb.h>
 #include <stdarg.h>
 #include <stddef.h>
@@ -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)
 {
index 672b80d..5d7ac7d 100644 (file)
@@ -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 <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_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 */
 #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_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_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_ */
index 679eebb..6e458dc 100644 (file)
@@ -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 {
index 8284b13..131c10f 100644 (file)
@@ -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_
        #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_ */