Initial import of RADIUS client library donated by Juniper Networks, Inc.
This commit is contained in:
parent
d551f05381
commit
082bfe6741
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/cvs2svn/branches/JUNIPER/; revision=41118
41
lib/libradius/Makefile
Normal file
41
lib/libradius/Makefile
Normal file
@ -0,0 +1,41 @@
|
||||
# Copyright 1998 Juniper Networks, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
#
|
||||
# $FreeBSD$
|
||||
|
||||
LIB= radius
|
||||
SRCS= radlib.c
|
||||
CFLAGS+= -Wall
|
||||
DPADD+= ${LIBMD}
|
||||
LDADD+= -lmd
|
||||
SHLIB_MAJOR= 1
|
||||
SHLIB_MINOR= 0
|
||||
MAN3+= libradius.3
|
||||
MAN5+= radius.conf.5
|
||||
|
||||
beforeinstall:
|
||||
${INSTALL} ${COPY} -o ${BINOWN} -g ${BINGRP} -m 444 \
|
||||
${.CURDIR}/radlib.h ${DESTDIR}/usr/include
|
||||
|
||||
.include <bsd.lib.mk>
|
317
lib/libradius/libradius.3
Normal file
317
lib/libradius/libradius.3
Normal file
@ -0,0 +1,317 @@
|
||||
.\" Copyright 1998 Juniper Networks, Inc.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 29, 1998
|
||||
.Dt LIBRADIUS 3
|
||||
.Os FreeBSD
|
||||
.Sh NAME
|
||||
.Nm libradius
|
||||
.Nd RADIUS client library
|
||||
.Sh SYNOPSIS
|
||||
.Fd #include <radlib.h>
|
||||
.Ft int
|
||||
.Fn rad_add_server "struct rad_handle *h" "const char *host" "int port" "const char *secret" "int timeout" "int max_tries"
|
||||
.Ft void
|
||||
.Fn rad_close "struct rad_handle *h"
|
||||
.Ft int
|
||||
.Fn rad_config "struct rad_handle *h" "const char *file"
|
||||
.Ft int
|
||||
.Fn rad_create_request "struct rad_handle *h" "int code"
|
||||
.Ft struct in_addr
|
||||
.Fn rad_cvt_addr "const void *data"
|
||||
.Ft u_int32_t
|
||||
.Fn rad_cvt_int "const void *data"
|
||||
.Ft char *
|
||||
.Fn rad_cvt_string "const void *data" "size_t len"
|
||||
.Ft int
|
||||
.Fn rad_get_attr "struct rad_handle *h" "const void **data" "size_t *len"
|
||||
.Ft struct rad_handle *
|
||||
.Fn rad_open "void"
|
||||
.Ft int
|
||||
.Fn rad_put_addr "struct rad_handle *h" "int type" "struct in_addr addr"
|
||||
.Ft int
|
||||
.Fn rad_put_attr "struct rad_handle *h" "int type" "const void *data" "size_t len"
|
||||
.Ft int
|
||||
.Fn rad_put_int "struct rad_handle *h" "int type" "u_int32_t value"
|
||||
.Ft int
|
||||
.Fn rad_put_string "struct rad_handle *h" "int type" "const char *str"
|
||||
.Ft int
|
||||
.Fn rad_send_request "struct rad_handle *h"
|
||||
.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 RFC 2138, allows
|
||||
clients to perform authentication by means of network requests to
|
||||
remote authentication servers.
|
||||
.Sh INITIALIZATION
|
||||
To use the library, an application must first call
|
||||
.Fn rad_open
|
||||
to obtain a
|
||||
.Va struct rad_handle * ,
|
||||
which provides the context for subsequent operations.
|
||||
Calls to
|
||||
.Fn rad_open
|
||||
always succeed unless insufficient virtual memory is available. If
|
||||
the necessary memory cannot be allocated,
|
||||
.Fn rad_open
|
||||
returns
|
||||
.Dv NULL .
|
||||
.Pp
|
||||
Before issuing any RADIUS requests, the library must be made aware
|
||||
of the servers it can contact. The easiest way to configure the
|
||||
library is to call
|
||||
.Fn rad_config .
|
||||
.Fn rad_config
|
||||
causes the library to read a configuration file whose format is
|
||||
described in
|
||||
.Xr radius.conf 5 .
|
||||
The pathname of the configuration file is passed as the
|
||||
.Va file
|
||||
argument to
|
||||
.Fn rad_config .
|
||||
This argument may also be given as
|
||||
.Dv NULL ,
|
||||
in which case the standard configuration file
|
||||
.Pa /etc/radius.conf
|
||||
is used.
|
||||
.Fn rad_config
|
||||
returns 0 on success, or -1 if an error occurs.
|
||||
.Pp
|
||||
The library can also be configured programmatically by calls to
|
||||
.Fn rad_add_server .
|
||||
The
|
||||
.Va 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
|
||||
is given as 0, the library looks up the
|
||||
.Ql radius/udp
|
||||
service in the network services database, and uses the port found
|
||||
there. If no entry is found, the library uses port 1812, the standard
|
||||
RADIUS port. The shared secret for the server host is passed to the
|
||||
.Va secret
|
||||
parameter.
|
||||
It may be any NUL-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
|
||||
requests to make before giving up is passed into the
|
||||
.Va max_tries
|
||||
parameter.
|
||||
.Fn rad_add_server
|
||||
returns 0 on success, or -1 if an error occurs.
|
||||
.Pp
|
||||
.Fn rad_add_server
|
||||
may be called multiple times, and it may be used together with
|
||||
.Fn rad_config .
|
||||
At most 10 servers may be specified.
|
||||
When multiple servers are given, they are tried in round-robin
|
||||
fashion until a valid response is received, or until each server's
|
||||
.Va max_tries
|
||||
limit has been reached.
|
||||
.Sh CREATING A RADIUS REQUEST
|
||||
A RADIUS request consists of a code specifying the kind of request,
|
||||
and zero or more attributes which provide additional information. To
|
||||
begin constructing a new request, call
|
||||
.Fn rad_create_request .
|
||||
In addition to the usual
|
||||
.Va struct rad_handle * ,
|
||||
this function takes a
|
||||
.Va code
|
||||
parameter which specifies the type of the request. Most often this
|
||||
will be
|
||||
.Dv RAD_ACCESS_REQUEST .
|
||||
.Fn rad_create_request
|
||||
returns 0 on success, or -1 on if an error occurs.
|
||||
.Pp
|
||||
After the request has been created with
|
||||
.Fn rad_create request ,
|
||||
attributes can be attached to it. This is done through calls to
|
||||
.Fn rad_put_addr ,
|
||||
.Fn rad_put_int ,
|
||||
and
|
||||
.Fn rad_put_string .
|
||||
Each accepts a
|
||||
.Va type
|
||||
parameter identifying the attribute, and a value which may be
|
||||
an Internet address, an integer, or a NUL-terminated string,
|
||||
respectively.
|
||||
.Pp
|
||||
The library also provides a function
|
||||
.Fn rad_put_attr
|
||||
which can be used to supply a raw, uninterpreted attribute. The
|
||||
.Va data
|
||||
argument points to an array of bytes, and the
|
||||
.Va len
|
||||
argument specifies its length.
|
||||
.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
|
||||
After the RADIUS request has been constructed, it is sent by means
|
||||
of
|
||||
.Fn rad_send_request .
|
||||
This function sends the request and waits for a valid reply,
|
||||
retrying the defined servers in round-robin fashion as necessary.
|
||||
If a valid response is received,
|
||||
.Fn rad_send_request
|
||||
returns the RADIUS code which specifies the type of the response.
|
||||
This will typically be
|
||||
.Dv RAD_ACCESS_ACCEPT ,
|
||||
.Dv RAD_ACCESS_REJECT ,
|
||||
or
|
||||
.Dv RAD_ACCESS_CHALLENGE .
|
||||
If no valid response is received,
|
||||
.Fn rad_send_request
|
||||
returns -1.
|
||||
.Pp
|
||||
Like RADIUS requests, each response may contain zero or more
|
||||
attributes. After a response has been received successfully by
|
||||
.Fn rad_send_request ,
|
||||
its attributes can be extracted one by one using
|
||||
.Fn rad_get_attr .
|
||||
Each time
|
||||
.Fn rad_get_attr
|
||||
is called, it gets the next attribute from the current response, and
|
||||
stores a pointer to the data and the length of the data via the
|
||||
reference parameters
|
||||
.Va data
|
||||
and
|
||||
.Va len ,
|
||||
respectively. Note that the data resides in the response itself,
|
||||
and must not be modified.
|
||||
A successful call to
|
||||
.Fn rad_get_attr
|
||||
returns the RADIUS attribute type.
|
||||
If no more attributes remain in the current response,
|
||||
.Fn rad_get_attr
|
||||
returns 0.
|
||||
If an error such as a malformed attribute is detected, -1 is
|
||||
returned.
|
||||
.Pp
|
||||
The common types of attributes can be decoded using
|
||||
.Fn rad_cvt_addr ,
|
||||
.Fn rad_cvt_int ,
|
||||
and
|
||||
.Fn rad_cvt_string .
|
||||
These functions accept a pointer to the attribute data, which should
|
||||
have been obtained using
|
||||
.Fn rad_get_attr .
|
||||
In the case of
|
||||
.Fn rad_cvt_string ,
|
||||
the length
|
||||
.Va 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
|
||||
.Xr free 3
|
||||
when it is no longer needed.
|
||||
.Pp
|
||||
If insufficient virtual memory is available,
|
||||
.Fn rad_cvt_string
|
||||
returns
|
||||
.Dv NULL .
|
||||
.Fn rad_cvt_addr
|
||||
and
|
||||
.Fn rad_cvt_int
|
||||
cannot fail.
|
||||
.Sh OBTAINING ERROR MESSAGES
|
||||
Those functions which accept a
|
||||
.Va 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 * .
|
||||
Thus the message must be copied if it is to be preserved through
|
||||
subsequent library calls using the same handle.
|
||||
.Sh CLEANUP
|
||||
To free the resources used by the RADIUS library, call
|
||||
.Fn rad_close .
|
||||
.Sh RETURN VALUES
|
||||
The following functions return a non-negative value on success. If
|
||||
they detect an error, they return -1 and record an error message
|
||||
which can be retrieved using
|
||||
.Fn rad_strerror .
|
||||
.Pp
|
||||
.Bl -item -offset indent -compact
|
||||
.It
|
||||
.Fn rad_add_server
|
||||
.It
|
||||
.Fn rad_config
|
||||
.It
|
||||
.Fn rad_create_request
|
||||
.It
|
||||
.Fn rad_get_attr
|
||||
.It
|
||||
.Fn rad_put_addr
|
||||
.It
|
||||
.Fn rad_put_attr
|
||||
.It
|
||||
.Fn rad_put_int
|
||||
.It
|
||||
.Fn rad_put_string
|
||||
.It
|
||||
.Fn rad_send_request
|
||||
.El
|
||||
.Pp
|
||||
The following functions return a
|
||||
.No non- Ns Dv NULL
|
||||
pointer on success. If they are unable to allocate sufficient
|
||||
virtual memory, they return
|
||||
.Dv NULL ,
|
||||
without recording an error message.
|
||||
.Pp
|
||||
.Bl -item -offset indent -compact
|
||||
.It
|
||||
.Fn rad_cvt_string
|
||||
.It
|
||||
.Fn rad_open
|
||||
.El
|
||||
.Sh FILES
|
||||
.Pa /etc/radius.conf
|
||||
.Sh SEE ALSO
|
||||
.Xr radius.conf 5
|
||||
.Rs
|
||||
.%A C. Rigney, et al
|
||||
.%T Remote Authentication Dial In User Service (RADIUS)
|
||||
.%O RFC 2138
|
||||
.Re
|
||||
.Sh AUTHORS
|
||||
This software was written by
|
||||
.An John Polstra ,
|
||||
and donated to the FreeBSD project by Juniper Networks, Inc.
|
123
lib/libradius/radius.conf.5
Normal file
123
lib/libradius/radius.conf.5
Normal file
@ -0,0 +1,123 @@
|
||||
.\" Copyright 1998 Juniper Networks, Inc.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 29, 1998
|
||||
.Dt RADIUS.CONF 5
|
||||
.Os FreeBSD
|
||||
.Sh NAME
|
||||
.Nm radius.conf
|
||||
.Nd RADIUS client configuration file
|
||||
.Sh SYNOPSIS
|
||||
.Pa /etc/radius.conf
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
contains the information necessary to configure the RADIUS client
|
||||
library. It is parsed by
|
||||
.Xr rad_config 3 .
|
||||
The file contains one or more lines of text, each describing a
|
||||
single RADIUS server which will be used by the library. Leading
|
||||
white space is ignored, as are empty lines and lines containing
|
||||
only comments.
|
||||
.Pp
|
||||
A RADIUS server is described by two to four fields on a line. The
|
||||
fields are separated by white space. The
|
||||
.Ql #
|
||||
character at the beginning of a field begins a comment, which extends
|
||||
to the end of the line. A field may be enclosed in double quotes,
|
||||
in which case it may contain white space and/or begin with the
|
||||
.Ql #
|
||||
character. Within a quoted string, the double quote character can
|
||||
be represented by
|
||||
.Ql \e\&" ,
|
||||
and the backslash can be represented by
|
||||
.Ql \e\e .
|
||||
No other escape sequences are supported.
|
||||
.Pp
|
||||
The first field specifies
|
||||
the server host, either as a fully qualified domain name or as a
|
||||
dotted-quad IP address. The host may optionally be followed by a
|
||||
.Ql \&:
|
||||
and a numeric port number, without intervening white space. If the
|
||||
port specification is omitted, it defaults to the
|
||||
.Ql radius
|
||||
service in the
|
||||
.Pa /etc/services
|
||||
file, or to the standard RADIUS port 1812 if there is no such entry in
|
||||
.Pa /etc/services .
|
||||
.Pp
|
||||
The second field contains the shared secret, which should be known
|
||||
only to the client and server hosts. It is an arbitrary string of
|
||||
characters, though it must be enclosed in double quotes if it
|
||||
contains white space. The shared secret may be
|
||||
any length, but the RADIUS protocol uses only the first 128
|
||||
characters. N.B., some popular RADIUS servers have bugs which
|
||||
prevent them from working properly with secrets longer than 16
|
||||
characters.
|
||||
.Pp
|
||||
The third field contains a decimal integer specifying the timeout in
|
||||
seconds for receiving a valid reply from the server. If this field
|
||||
is omitted, it defaults to 3 seconds.
|
||||
.Pp
|
||||
The fourth field contains a decimal integer specifying the maximum
|
||||
number of attempts that will be made to authenticate with the server
|
||||
before giving up. If omitted, it defaults to 3 attempts. Note,
|
||||
this is the total number of attempts and not the number of retries.
|
||||
.Pp
|
||||
Up to 10 RADIUS servers may be specified. The servers are tried in
|
||||
round-robin fashion, until a valid response is received or the
|
||||
maximum number of tries has been reached for all servers.
|
||||
.Pp
|
||||
The standard location for this file is
|
||||
.Pa /etc/radius.conf .
|
||||
But an alternate pathname may be specified in the call to
|
||||
.Xr rad_config 3 .
|
||||
Since the file contains sensitive information in the form of the
|
||||
shared secrets, it should not be readable except by root.
|
||||
.Sh FILES
|
||||
.Pa /etc/radius.conf
|
||||
.Sh EXAMPLES
|
||||
.Bd -literal
|
||||
# A simple entry using all the defaults:
|
||||
radius1.domain.com OurLittleSecret
|
||||
|
||||
# A server still using the obsolete RADIUS port, with increased
|
||||
# timeout and maximum tries:
|
||||
auth.domain.com:1645 "I can't see you, but I know you're there" 5 4
|
||||
|
||||
# A server specified by its IP address:
|
||||
192.168.27.81 $X*#..38947ax-+=
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr libradius 3
|
||||
.Rs
|
||||
.%A C. Rigney, et al
|
||||
.%T Remote Authentication Dial In User Service (RADIUS)
|
||||
.%O RFC 2138
|
||||
.Re
|
||||
.Sh AUTHORS
|
||||
This documentation was written by
|
||||
.An John Polstra ,
|
||||
and donated to the FreeBSD project by Juniper Networks, Inc.
|
737
lib/libradius/radlib.c
Normal file
737
lib/libradius/radlib.c
Normal file
@ -0,0 +1,737 @@
|
||||
/*-
|
||||
* Copyright 1998 Juniper Networks, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <md5.h>
|
||||
#include <netdb.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "radlib_private.h"
|
||||
|
||||
static void clear_password(struct rad_handle *);
|
||||
static void generr(struct rad_handle *, const char *, ...)
|
||||
__printflike(2, 3);
|
||||
static void insert_scrambled_password(struct rad_handle *, int);
|
||||
static int is_valid_response(struct rad_handle *, int,
|
||||
const struct sockaddr_in *);
|
||||
static int put_password_attr(struct rad_handle *, int,
|
||||
const void *, size_t);
|
||||
static int put_raw_attr(struct rad_handle *, int,
|
||||
const void *, size_t);
|
||||
static int split(char *, char *[], int, char *, size_t);
|
||||
|
||||
static void
|
||||
clear_password(struct rad_handle *h)
|
||||
{
|
||||
if (h->pass_len != 0) {
|
||||
memset(h->pass, 0, h->pass_len);
|
||||
h->pass_len = 0;
|
||||
h->pass_pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
generr(struct rad_handle *h, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
vsnprintf(h->errmsg, ERRSIZE, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static void
|
||||
insert_scrambled_password(struct rad_handle *h, int srv)
|
||||
{
|
||||
MD5_CTX ctx;
|
||||
unsigned char md5[16];
|
||||
const struct rad_server *srvp;
|
||||
int padded_len;
|
||||
int pos;
|
||||
|
||||
srvp = &h->servers[srv];
|
||||
padded_len = h->pass_len == 0 ? 16 : (h->pass_len+15) & ~0xf;
|
||||
|
||||
memcpy(md5, &h->request[POS_AUTH], LEN_AUTH);
|
||||
for (pos = 0; pos < padded_len; pos += 16) {
|
||||
int i;
|
||||
|
||||
/* Calculate the new scrambler */
|
||||
MD5Init(&ctx);
|
||||
MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
|
||||
MD5Update(&ctx, md5, 16);
|
||||
MD5Final(md5, &ctx);
|
||||
|
||||
/*
|
||||
* Mix in the current chunk of the password, and copy
|
||||
* the result into the right place in the request. Also
|
||||
* modify the scrambler in place, since we will use this
|
||||
* in calculating the scrambler for next time.
|
||||
*/
|
||||
for (i = 0; i < 16; i++)
|
||||
h->request[h->pass_pos + pos + i] =
|
||||
md5[i] ^= h->pass[pos + i];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if the current response is valid for a request to the
|
||||
* specified server.
|
||||
*/
|
||||
static int
|
||||
is_valid_response(struct rad_handle *h, int srv,
|
||||
const struct sockaddr_in *from)
|
||||
{
|
||||
MD5_CTX ctx;
|
||||
unsigned char md5[16];
|
||||
const struct rad_server *srvp;
|
||||
int len;
|
||||
|
||||
srvp = &h->servers[srv];
|
||||
|
||||
/* Check the source address */
|
||||
if (from->sin_family != srvp->addr.sin_family ||
|
||||
from->sin_addr.s_addr != srvp->addr.sin_addr.s_addr ||
|
||||
from->sin_port != srvp->addr.sin_port)
|
||||
return 0;
|
||||
|
||||
/* Check the message length */
|
||||
if (h->resp_len < POS_ATTRS)
|
||||
return 0;
|
||||
len = h->response[POS_LENGTH] << 8 | h->response[POS_LENGTH+1];
|
||||
if (len > h->resp_len)
|
||||
return 0;
|
||||
|
||||
/* Check the response authenticator */
|
||||
MD5Init(&ctx);
|
||||
MD5Update(&ctx, &h->response[POS_CODE], POS_AUTH - POS_CODE);
|
||||
MD5Update(&ctx, &h->request[POS_AUTH], LEN_AUTH);
|
||||
MD5Update(&ctx, &h->response[POS_ATTRS], len - POS_ATTRS);
|
||||
MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
|
||||
MD5Final(md5, &ctx);
|
||||
if (memcmp(&h->response[POS_AUTH], md5, sizeof md5) != 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
put_password_attr(struct rad_handle *h, int type, const void *value, size_t len)
|
||||
{
|
||||
int padded_len;
|
||||
int pad_len;
|
||||
|
||||
if (h->pass_pos != 0) {
|
||||
generr(h, "Multiple User-Password attributes specified");
|
||||
return -1;
|
||||
}
|
||||
if (len > PASSSIZE)
|
||||
len = PASSSIZE;
|
||||
padded_len = len == 0 ? 16 : (len+15) & ~0xf;
|
||||
pad_len = padded_len - len;
|
||||
|
||||
/*
|
||||
* Put in a place-holder attribute containing all zeros, and
|
||||
* remember where it is so we can fill it in later.
|
||||
*/
|
||||
clear_password(h);
|
||||
put_raw_attr(h, type, h->pass, padded_len);
|
||||
h->pass_pos = h->req_len - padded_len;
|
||||
|
||||
/* Save the cleartext password, padded as necessary */
|
||||
memcpy(h->pass, value, len);
|
||||
h->pass_len = len;
|
||||
memset(h->pass + len, 0, pad_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
put_raw_attr(struct rad_handle *h, int type, const void *value, size_t len)
|
||||
{
|
||||
if (len > 253) {
|
||||
generr(h, "Attribute too long");
|
||||
return -1;
|
||||
}
|
||||
if (h->req_len + 2 + len > MSGSIZE) {
|
||||
generr(h, "Maximum message length exceeded");
|
||||
return -1;
|
||||
}
|
||||
h->request[h->req_len++] = type;
|
||||
h->request[h->req_len++] = len + 2;
|
||||
memcpy(&h->request[h->req_len], value, len);
|
||||
h->req_len += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rad_add_server(struct rad_handle *h, const char *host, int port,
|
||||
const char *secret, int timeout, int tries)
|
||||
{
|
||||
struct rad_server *srvp;
|
||||
|
||||
if (h->num_servers >= MAXSERVERS) {
|
||||
generr(h, "Too many RADIUS servers specified");
|
||||
return -1;
|
||||
}
|
||||
srvp = &h->servers[h->num_servers];
|
||||
|
||||
memset(&srvp->addr, 0, sizeof srvp->addr);
|
||||
srvp->addr.sin_len = sizeof srvp->addr;
|
||||
srvp->addr.sin_family = AF_INET;
|
||||
if (!inet_aton(host, &srvp->addr.sin_addr)) {
|
||||
struct hostent *hent;
|
||||
|
||||
if ((hent = gethostbyname(host)) == NULL) {
|
||||
generr(h, "%s: host not found", host);
|
||||
return -1;
|
||||
}
|
||||
memcpy(&srvp->addr.sin_addr, hent->h_addr,
|
||||
sizeof srvp->addr.sin_addr);
|
||||
}
|
||||
if (port != 0)
|
||||
srvp->addr.sin_port = htons(port);
|
||||
else {
|
||||
struct servent *sent;
|
||||
|
||||
srvp->addr.sin_port =
|
||||
(sent = getservbyname("radius", "udp")) != NULL ?
|
||||
sent->s_port : htons(RADIUS_PORT);
|
||||
}
|
||||
if ((srvp->secret = strdup(secret)) == NULL) {
|
||||
generr(h, "Out of memory");
|
||||
return -1;
|
||||
}
|
||||
srvp->timeout = timeout;
|
||||
srvp->max_tries = tries;
|
||||
srvp->num_tries = 0;
|
||||
h->num_servers++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
rad_close(struct rad_handle *h)
|
||||
{
|
||||
int srv;
|
||||
|
||||
if (h->fd != -1)
|
||||
close(h->fd);
|
||||
for (srv = 0; srv < h->num_servers; srv++) {
|
||||
memset(h->servers[srv].secret, 0,
|
||||
strlen(h->servers[srv].secret));
|
||||
free(h->servers[srv].secret);
|
||||
}
|
||||
clear_password(h);
|
||||
free(h);
|
||||
}
|
||||
|
||||
int
|
||||
rad_config(struct rad_handle *h, const char *path)
|
||||
{
|
||||
FILE *fp;
|
||||
char buf[MAXCONFLINE];
|
||||
int linenum;
|
||||
int retval;
|
||||
|
||||
if (path == NULL)
|
||||
path = PATH_RADIUS_CONF;
|
||||
if ((fp = fopen(path, "r")) == NULL) {
|
||||
generr(h, "Cannot open \"%s\": %s", path, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
retval = 0;
|
||||
linenum = 0;
|
||||
while (fgets(buf, sizeof buf, fp) != NULL) {
|
||||
int len;
|
||||
char *fields[4];
|
||||
int nfields;
|
||||
char msg[ERRSIZE];
|
||||
char *host;
|
||||
char *port_str;
|
||||
char *secret;
|
||||
char *timeout_str;
|
||||
char *maxtries_str;
|
||||
char *end;
|
||||
unsigned long timeout;
|
||||
unsigned long maxtries;
|
||||
int port;
|
||||
|
||||
linenum++;
|
||||
len = strlen(buf);
|
||||
/* We know len > 0, else fgets would have returned NULL. */
|
||||
if (buf[len - 1] != '\n') {
|
||||
if (len == sizeof buf - 1)
|
||||
generr(h, "%s:%d: line too long", path,
|
||||
linenum);
|
||||
else
|
||||
generr(h, "%s:%d: missing newline", path,
|
||||
linenum);
|
||||
retval = -1;
|
||||
break;
|
||||
}
|
||||
buf[len - 1] = '\0';
|
||||
|
||||
/* Extract the fields from the line. */
|
||||
nfields = split(buf, fields, 4, msg, sizeof msg);
|
||||
if (nfields == -1) {
|
||||
generr(h, "%s:%d: %s", path, linenum, msg);
|
||||
retval = -1;
|
||||
break;
|
||||
}
|
||||
if (nfields == 0)
|
||||
continue;
|
||||
if (nfields < 2) {
|
||||
generr(h, "%s:%d: missing shared secret", path,
|
||||
linenum);
|
||||
retval = -1;
|
||||
break;
|
||||
}
|
||||
host = fields[0];
|
||||
secret = fields[1];
|
||||
timeout_str = fields[2];
|
||||
maxtries_str = fields[3];
|
||||
|
||||
/* Parse and validate the fields. */
|
||||
host = strtok(host, ":");
|
||||
port_str = strtok(NULL, ":");
|
||||
if (port_str != NULL) {
|
||||
port = strtoul(port_str, &end, 10);
|
||||
if (*end != '\0') {
|
||||
generr(h, "%s:%d: invalid port", path,
|
||||
linenum);
|
||||
retval = -1;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
port = 0;
|
||||
if (timeout_str != NULL) {
|
||||
timeout = strtoul(timeout_str, &end, 10);
|
||||
if (*end != '\0') {
|
||||
generr(h, "%s:%d: invalid timeout", path,
|
||||
linenum);
|
||||
retval = -1;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
timeout = TIMEOUT;
|
||||
if (maxtries_str != NULL) {
|
||||
maxtries = strtoul(maxtries_str, &end, 10);
|
||||
if (*end != '\0') {
|
||||
generr(h, "%s:%d: invalid maxtries", path,
|
||||
linenum);
|
||||
retval = -1;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
maxtries = MAXTRIES;
|
||||
|
||||
if (rad_add_server(h, host, port, secret, timeout, maxtries) ==
|
||||
-1) {
|
||||
char msg[ERRSIZE];
|
||||
|
||||
strcpy(msg, h->errmsg);
|
||||
generr(h, "%s:%d: %s", path, linenum, msg);
|
||||
retval = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Clear out the buffer to wipe a possible copy of a shared secret */
|
||||
memset(buf, 0, sizeof buf);
|
||||
fclose(fp);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
rad_create_request(struct rad_handle *h, int code)
|
||||
{
|
||||
int i;
|
||||
|
||||
h->request[POS_CODE] = code;
|
||||
h->request[POS_IDENT] = ++h->ident;
|
||||
/* Create a random authenticator */
|
||||
for (i = 0; i < LEN_AUTH; i += 2) {
|
||||
long r;
|
||||
r = random();
|
||||
h->request[POS_AUTH+i] = r;
|
||||
h->request[POS_AUTH+i+1] = r >> 8;
|
||||
}
|
||||
h->req_len = POS_ATTRS;
|
||||
clear_password(h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct in_addr
|
||||
rad_cvt_addr(const void *data)
|
||||
{
|
||||
struct in_addr value;
|
||||
|
||||
memcpy(&value.s_addr, data, sizeof value.s_addr);
|
||||
return value;
|
||||
}
|
||||
|
||||
u_int32_t
|
||||
rad_cvt_int(const void *data)
|
||||
{
|
||||
u_int32_t value;
|
||||
|
||||
memcpy(&value, data, sizeof value);
|
||||
return ntohl(value);
|
||||
}
|
||||
|
||||
char *
|
||||
rad_cvt_string(const void *data, size_t len)
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = malloc(len + 1);
|
||||
if (s != NULL) {
|
||||
memcpy(s, data, len);
|
||||
s[len] = '\0';
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the attribute type. If none are left, returns 0. On failure,
|
||||
* returns -1.
|
||||
*/
|
||||
int
|
||||
rad_get_attr(struct rad_handle *h, const void **value, size_t *len)
|
||||
{
|
||||
int type;
|
||||
|
||||
if (h->resp_pos >= h->resp_len)
|
||||
return 0;
|
||||
if (h->resp_pos + 2 > h->resp_len) {
|
||||
generr(h, "Malformed attribute in response");
|
||||
return -1;
|
||||
}
|
||||
type = h->response[h->resp_pos++];
|
||||
*len = h->response[h->resp_pos++] - 2;
|
||||
if (h->resp_pos + *len > h->resp_len) {
|
||||
generr(h, "Malformed attribute in response");
|
||||
return -1;
|
||||
}
|
||||
*value = &h->response[h->resp_pos];
|
||||
h->resp_pos += *len;
|
||||
return type;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create and initialize a rad_handle structure, and return it to the
|
||||
* caller. Can fail only if the necessary memory cannot be allocated.
|
||||
* In that case, it returns NULL.
|
||||
*/
|
||||
struct rad_handle *
|
||||
rad_open(void)
|
||||
{
|
||||
struct rad_handle *h;
|
||||
|
||||
h = (struct rad_handle *)malloc(sizeof(struct rad_handle));
|
||||
if (h != NULL) {
|
||||
srandomdev();
|
||||
h->fd = -1;
|
||||
h->num_servers = 0;
|
||||
h->ident = random();
|
||||
h->errmsg[0] = '\0';
|
||||
memset(h->pass, 0, sizeof h->pass);
|
||||
h->pass_len = 0;
|
||||
h->pass_pos = 0;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
int
|
||||
rad_put_addr(struct rad_handle *h, int type, struct in_addr addr)
|
||||
{
|
||||
return rad_put_attr(h, type, &addr.s_addr, sizeof addr.s_addr);
|
||||
}
|
||||
|
||||
int
|
||||
rad_put_attr(struct rad_handle *h, int type, const void *value, size_t len)
|
||||
{
|
||||
return type == RAD_USER_PASSWORD ?
|
||||
put_password_attr(h, type, value, len) :
|
||||
put_raw_attr(h, type, value, len);
|
||||
}
|
||||
|
||||
int
|
||||
rad_put_int(struct rad_handle *h, int type, u_int32_t value)
|
||||
{
|
||||
u_int32_t nvalue;
|
||||
|
||||
nvalue = htonl(value);
|
||||
return rad_put_attr(h, type, &nvalue, sizeof nvalue);
|
||||
}
|
||||
|
||||
int
|
||||
rad_put_string(struct rad_handle *h, int type, const char *str)
|
||||
{
|
||||
return rad_put_attr(h, type, str, strlen(str));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the response type code on success, or -1 on failure.
|
||||
*/
|
||||
int
|
||||
rad_send_request(struct rad_handle *h)
|
||||
{
|
||||
int total_tries;
|
||||
int try;
|
||||
int srv;
|
||||
int n;
|
||||
int got_valid_response;
|
||||
|
||||
/* Make sure we have a socket to use */
|
||||
if (h->fd == -1) {
|
||||
struct sockaddr_in sin;
|
||||
|
||||
if ((h->fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
|
||||
generr(h, "Cannot create socket: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
memset(&sin, 0, sizeof sin);
|
||||
sin.sin_len = sizeof sin;
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = INADDR_ANY;
|
||||
sin.sin_port = htons(0);
|
||||
if (bind(h->fd, (const struct sockaddr *)&sin,
|
||||
sizeof sin) == -1) {
|
||||
generr(h, "bind: %s", strerror(errno));
|
||||
close(h->fd);
|
||||
h->fd = -1;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure the user gave us a password */
|
||||
if (h->pass_pos == 0) {
|
||||
generr(h, "No User-Password attribute given");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Fill in the length field in the message */
|
||||
h->request[POS_LENGTH] = h->req_len >> 8;
|
||||
h->request[POS_LENGTH+1] = h->req_len;
|
||||
|
||||
/*
|
||||
* Count the total number of tries we will make, and zero the
|
||||
* counter for each server.
|
||||
*/
|
||||
total_tries = 0;
|
||||
for (srv = 0; srv < h->num_servers; srv++) {
|
||||
total_tries += h->servers[srv].max_tries;
|
||||
h->servers[srv].num_tries = 0;
|
||||
}
|
||||
if (total_tries == 0) {
|
||||
generr(h, "No RADIUS servers specified");
|
||||
return -1;
|
||||
}
|
||||
|
||||
srv = 0;
|
||||
got_valid_response = 0;
|
||||
for (try = 0; try < total_tries; try++) {
|
||||
struct timeval timelimit;
|
||||
struct timeval tv;
|
||||
|
||||
/*
|
||||
* 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[srv].num_tries >=
|
||||
h->servers[srv].max_tries)
|
||||
if (++srv >= h->num_servers)
|
||||
srv = 0;
|
||||
|
||||
/* Insert the scrambled password into the request */
|
||||
insert_scrambled_password(h, srv);
|
||||
|
||||
/* Send the request */
|
||||
n = sendto(h->fd, h->request, h->req_len, 0,
|
||||
(const struct sockaddr *)&h->servers[srv].addr,
|
||||
sizeof h->servers[srv].addr);
|
||||
if (n != h->req_len) {
|
||||
if (n == -1)
|
||||
generr(h, "sendto: %s", strerror(errno));
|
||||
else
|
||||
generr(h, "sendto: short write");
|
||||
return -1;
|
||||
}
|
||||
h->servers[srv].num_tries++;
|
||||
|
||||
/* Wait for a valid response */
|
||||
gettimeofday(&timelimit, NULL);
|
||||
timelimit.tv_sec += h->servers[srv].timeout;
|
||||
|
||||
tv.tv_sec = h->servers[srv].timeout;
|
||||
tv.tv_usec = 0;
|
||||
for ( ; ; ) {
|
||||
fd_set readfds;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(h->fd, &readfds);
|
||||
n = select(h->fd + 1, &readfds, NULL, NULL, &tv);
|
||||
if (n == -1) {
|
||||
generr(h, "select: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (n == 0) /* Timed out */
|
||||
break;
|
||||
if (FD_ISSET(h->fd, &readfds)) {
|
||||
struct sockaddr_in from;
|
||||
int fromlen;
|
||||
|
||||
fromlen = sizeof from;
|
||||
h->resp_len = recvfrom(h->fd, h->response,
|
||||
MSGSIZE, MSG_WAITALL,
|
||||
(struct sockaddr *)&from, &fromlen);
|
||||
if (h->resp_len == -1) {
|
||||
generr(h, "recvfrom: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (is_valid_response(h, srv, &from)) {
|
||||
got_valid_response = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Compute a new timeout */
|
||||
gettimeofday(&tv, NULL);
|
||||
timersub(&timelimit, &tv, &tv);
|
||||
if (tv.tv_sec < 0) /* Still poll once more */
|
||||
timerclear(&tv);
|
||||
}
|
||||
if (got_valid_response)
|
||||
break;
|
||||
/* Advance to the next server */
|
||||
if (++srv >= h->num_servers)
|
||||
srv = 0;
|
||||
}
|
||||
if (!got_valid_response) {
|
||||
generr(h, "No valid RADIUS responses received");
|
||||
return -1;
|
||||
}
|
||||
h->resp_len = h->response[POS_LENGTH] << 8 | h->response[POS_LENGTH+1];
|
||||
h->resp_pos = POS_ATTRS;
|
||||
return h->response[POS_CODE];
|
||||
}
|
||||
|
||||
const char *
|
||||
rad_strerror(struct rad_handle *h)
|
||||
{
|
||||
return h->errmsg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destructively split a string into fields separated by white space.
|
||||
* `#' at the beginning of a field begins a comment that extends to the
|
||||
* end of the string. Fields may be quoted with `"'. Inside quoted
|
||||
* strings, the backslash escapes `\"' and `\\' are honored.
|
||||
*
|
||||
* Pointers to up to the first maxfields fields are stored in the fields
|
||||
* array. Missing fields get NULL pointers.
|
||||
*
|
||||
* The return value is the actual number of fields parsed, and is always
|
||||
* <= maxfields.
|
||||
*
|
||||
* On a syntax error, places a message in the msg string, and returns -1.
|
||||
*/
|
||||
static int
|
||||
split(char *str, char *fields[], int maxfields, char *msg, size_t msglen)
|
||||
{
|
||||
char *p;
|
||||
int i;
|
||||
static const char ws[] = " \t";
|
||||
|
||||
for (i = 0; i < maxfields; i++)
|
||||
fields[i] = NULL;
|
||||
p = str;
|
||||
i = 0;
|
||||
while (*p != '\0') {
|
||||
p += strspn(p, ws);
|
||||
if (*p == '#' || *p == '\0')
|
||||
break;
|
||||
if (i >= maxfields) {
|
||||
snprintf(msg, msglen, "line has too many fields");
|
||||
return -1;
|
||||
}
|
||||
if (*p == '"') {
|
||||
char *dst;
|
||||
|
||||
dst = ++p;
|
||||
fields[i] = dst;
|
||||
while (*p != '"') {
|
||||
if (*p == '\\') {
|
||||
p++;
|
||||
if (*p != '"' && *p != '\\' &&
|
||||
*p != '\0') {
|
||||
snprintf(msg, msglen,
|
||||
"invalid `\\' escape");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (*p == '\0') {
|
||||
snprintf(msg, msglen,
|
||||
"unterminated quoted string");
|
||||
return -1;
|
||||
}
|
||||
*dst++ = *p++;
|
||||
}
|
||||
*dst = '\0';
|
||||
p++;
|
||||
if (*fields[i] == '\0') {
|
||||
snprintf(msg, msglen,
|
||||
"empty quoted string not permitted");
|
||||
return -1;
|
||||
}
|
||||
if (*p != '\0' && strspn(p, ws) == 0) {
|
||||
snprintf(msg, msglen, "quoted string not"
|
||||
" followed by white space");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
fields[i] = p;
|
||||
p += strcspn(p, ws);
|
||||
if (*p != '\0')
|
||||
*p++ = '\0';
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
125
lib/libradius/radlib.h
Normal file
125
lib/libradius/radlib.h
Normal file
@ -0,0 +1,125 @@
|
||||
/*-
|
||||
* Copyright 1998 Juniper Networks, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _RADLIB_H_
|
||||
#define _RADLIB_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
/* Message types */
|
||||
#define RAD_ACCESS_REQUEST 1
|
||||
#define RAD_ACCESS_ACCEPT 2
|
||||
#define RAD_ACCESS_REJECT 3
|
||||
#define RAD_ACCESS_CHALLENGE 11
|
||||
|
||||
/* Attribute types and values */
|
||||
#define RAD_USER_NAME 1 /* String */
|
||||
#define RAD_USER_PASSWORD 2 /* String */
|
||||
#define RAD_CHAP_PASSWORD 3 /* String */
|
||||
#define RAD_NAS_IP_ADDRESS 4 /* IP address */
|
||||
#define RAD_NAS_PORT 5 /* Integer */
|
||||
#define RAD_SERVICE_TYPE 6 /* Integer */
|
||||
#define RAD_LOGIN 1
|
||||
#define RAD_FRAMED 2
|
||||
#define RAD_CALLBACK_LOGIN 3
|
||||
#define RAD_CALLBACK_FRAMED 4
|
||||
#define RAD_OUTBOUND 5
|
||||
#define RAD_ADMINISTRATIVE 6
|
||||
#define RAD_NAS_PROMPT 7
|
||||
#define RAD_AUTHENTICATE_ONLY 8
|
||||
#define RAD_CALLBACK_NAS_PROMPT 9
|
||||
#define RAD_FRAMED_PROTOCOL 7 /* Integer */
|
||||
#define RAD_PPP 1
|
||||
#define RAD_SLIP 2
|
||||
#define RAD_ARAP 3 /* Appletalk */
|
||||
#define RAD_GANDALF 4
|
||||
#define RAD_XYLOGICS 5
|
||||
#define RAD_FRAMED_IP_ADDRESS 8 /* IP address */
|
||||
#define RAD_FRAMED_IP_NETMASK 9 /* IP address */
|
||||
#define RAD_FRAMED_ROUTING 10 /* Integer */
|
||||
#define RAD_FILTER_ID 11 /* String */
|
||||
#define RAD_FRAMED_MTU 12 /* Integer */
|
||||
#define RAD_FRAMED_COMPRESSION 13 /* Integer */
|
||||
#define RAD_LOGIN_IP_HOST 14 /* IP address */
|
||||
#define RAD_LOGIN_SERVICE 15 /* Integer */
|
||||
#define RAD_LOGIN_TCP_PORT 16 /* Integer */
|
||||
/* unassiged 17 */
|
||||
#define RAD_REPLY_MESSAGE 18 /* String */
|
||||
#define RAD_CALLBACK_NUMBER 19 /* String */
|
||||
#define RAD_CALLBACK_ID 20 /* String */
|
||||
/* unassiged 21 */
|
||||
#define RAD_FRAMED_ROUTE 22 /* String */
|
||||
#define RAD_FRAMED_IPX_NETWORK 23 /* IP address */
|
||||
#define RAD_STATE 24 /* String */
|
||||
#define RAD_CLASS 25 /* Integer */
|
||||
#define RAD_VENDOR_SPECIFIC 26 /* Integer */
|
||||
#define RAD_SESSION_TIMEOUT 27 /* Integer */
|
||||
#define RAD_IDLE_TIMEOUT 28 /* Integer */
|
||||
#define RAD_TERMINATION_ACTION 29 /* Integer */
|
||||
#define RAD_CALLED_STATION_ID 30 /* String */
|
||||
#define RAD_CALLING_STATION_ID 31 /* String */
|
||||
#define RAD_NAS_IDENTIFIER 32 /* Integer */
|
||||
#define RAD_PROXY_STATE 33 /* Integer */
|
||||
#define RAD_LOGIN_LAT_SERVICE 34 /* Integer */
|
||||
#define RAD_LOGIN_LAT_NODE 35 /* Integer */
|
||||
#define RAD_LOGIN_LAT_GROUP 36 /* Integer */
|
||||
#define RAD_FRAMED_APPLETALK_LINK 37 /* Integer */
|
||||
#define RAD_FRAMED_APPLETALK_NETWORK 38 /* Integer */
|
||||
#define RAD_FRAMED_APPLETALK_ZONE 39 /* Integer */
|
||||
/* reserved for accounting 40-59 */
|
||||
#define RAD_CHAP_CHALLENGE 60 /* String */
|
||||
#define RAD_NAS_PORT_TYPE 61 /* Integer */
|
||||
#define RAD_PORT_LIMIT 62 /* Integer */
|
||||
#define RAD_LOGIN_LAT_PORT 63 /* Integer */
|
||||
|
||||
struct rad_handle;
|
||||
|
||||
__BEGIN_DECLS
|
||||
int rad_add_server(struct rad_handle *,
|
||||
const char *, int, const char *, int, int);
|
||||
void rad_close(struct rad_handle *);
|
||||
int rad_config(struct rad_handle *, const char *);
|
||||
int rad_create_request(struct rad_handle *, int);
|
||||
struct in_addr rad_cvt_addr(const void *);
|
||||
u_int32_t rad_cvt_int(const void *);
|
||||
char *rad_cvt_string(const void *, size_t);
|
||||
int rad_get_attr(struct rad_handle *, const void **,
|
||||
size_t *);
|
||||
struct rad_handle *rad_open(void);
|
||||
int rad_put_addr(struct rad_handle *, int, struct in_addr);
|
||||
int rad_put_attr(struct rad_handle *, int,
|
||||
const void *, size_t);
|
||||
int rad_put_int(struct rad_handle *, int, u_int32_t);
|
||||
int rad_put_string(struct rad_handle *, int,
|
||||
const char *);
|
||||
int rad_send_request(struct rad_handle *);
|
||||
const char *rad_strerror(struct rad_handle *);
|
||||
__END_DECLS
|
||||
|
||||
#endif /* _RADLIB_H_ */
|
82
lib/libradius/radlib_private.h
Normal file
82
lib/libradius/radlib_private.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*-
|
||||
* Copyright 1998 Juniper Networks, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef RADLIB_PRIVATE_H
|
||||
#define RADLIB_PRIVATE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "radlib.h"
|
||||
|
||||
/* Defaults */
|
||||
#define MAXTRIES 3
|
||||
#define PATH_RADIUS_CONF "/etc/radius.conf"
|
||||
#define RADIUS_PORT 1812
|
||||
#define TIMEOUT 3 /* In seconds */
|
||||
|
||||
/* Limits */
|
||||
#define ERRSIZE 128 /* Maximum error message length */
|
||||
#define MAXCONFLINE 1024 /* Maximum config file line length */
|
||||
#define MAXSERVERS 10 /* Maximum number of servers to try */
|
||||
#define MSGSIZE 4096 /* Maximum RADIUS message */
|
||||
#define PASSSIZE 128 /* Maximum significant password chars */
|
||||
|
||||
/* Positions of fields in RADIUS messages */
|
||||
#define POS_CODE 0 /* Message code */
|
||||
#define POS_IDENT 1 /* Identifier */
|
||||
#define POS_LENGTH 2 /* Message length */
|
||||
#define POS_AUTH 4 /* Authenticator */
|
||||
#define LEN_AUTH 16 /* Length of authenticator */
|
||||
#define POS_ATTRS 20 /* Start of attributes */
|
||||
|
||||
struct rad_server {
|
||||
struct sockaddr_in addr; /* Address of server */
|
||||
char *secret; /* Shared secret */
|
||||
int timeout; /* Timeout in seconds */
|
||||
int max_tries; /* Number of tries before giving up */
|
||||
int num_tries; /* Number of tries so far */
|
||||
};
|
||||
|
||||
struct rad_handle {
|
||||
int fd; /* Socket file descriptor */
|
||||
struct rad_server servers[MAXSERVERS]; /* Servers to contact */
|
||||
int num_servers; /* Number of valid server entries */
|
||||
int ident; /* Current identifier value */
|
||||
char errmsg[ERRSIZE]; /* Most recent error message */
|
||||
unsigned char request[MSGSIZE]; /* Request to send */
|
||||
int req_len; /* Length of request */
|
||||
char pass[PASSSIZE]; /* Cleartext password */
|
||||
int pass_len; /* Length of cleartext password */
|
||||
int pass_pos; /* Position of scrambled password */
|
||||
unsigned char response[MSGSIZE]; /* Response received */
|
||||
int resp_len; /* Length of response */
|
||||
int resp_pos; /* Current position scanning attrs */
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user