aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Polstra <jdp@FreeBSD.org>1999-10-31 04:47:59 +0000
committerJohn Polstra <jdp@FreeBSD.org>1999-10-31 04:47:59 +0000
commit0981dfef84de4d45eebdb166a51a0fbdd2edfbc4 (patch)
treed4d15db6bf719df595fa6182fa7e744a74223233
parent8308463eba7445bd71c47cfb87c9f900efa0fa3e (diff)
downloadsrc-0981dfef84de4d45eebdb166a51a0fbdd2edfbc4.tar.gz
src-0981dfef84de4d45eebdb166a51a0fbdd2edfbc4.zip
Add support for RADIUS accounting. Note, this changes the format
of the /etc/radius.conf file. But the code contains hacks for backward compatibility, so old files will continue to work. I updated the man pages and made a couple of minor changes, but everything else was submitted by Oleg. PR: misc/14284 Submitted by: Oleg Semyonov <os@altavista.net>
Notes
Notes: svn path=/head/; revision=52709
-rw-r--r--lib/libradius/libradius.356
-rw-r--r--lib/libradius/radius.conf.570
-rw-r--r--lib/libradius/radlib.c125
-rw-r--r--lib/libradius/radlib.h55
-rw-r--r--lib/libradius/radlib_private.h6
5 files changed, 259 insertions, 53 deletions
diff --git a/lib/libradius/libradius.3 b/lib/libradius/libradius.3
index 15e68519faf3..cd06e7e22a69 100644
--- a/lib/libradius/libradius.3
+++ b/lib/libradius/libradius.3
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 29, 1998
+.Dd October 30, 1999
.Dt LIBRADIUS 3
.Os FreeBSD
.Sh NAME
@@ -32,8 +32,12 @@
.Nd RADIUS client library
.Sh SYNOPSIS
.Fd #include <radlib.h>
+.Ft struct rad_handle *
+.Fn rad_acct_open "void"
.Ft int
.Fn rad_add_server "struct rad_handle *h" "const char *host" "int port" "const char *secret" "int timeout" "int max_tries"
+.Ft struct rad_handle *
+.Fn rad_auth_open "void"
.Ft void
.Fn rad_close "struct rad_handle *h"
.Ft int
@@ -52,8 +56,6 @@
.Fn rad_get_attr "struct rad_handle *h" "const void **data" "size_t *len"
.Ft int
.Fn rad_init_send_request "struct rad_handle *h" "int *fd" "struct timeval *tv"
-.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
@@ -69,23 +71,31 @@
.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.
+library implements the client side of the Remote Authentication Dial
+In User Service (RADIUS). RADIUS, defined in RFCs 2138 and 2139,
+allows clients to perform authentication and accounting by means of
+network requests to remote servers.
.Sh INITIALIZATION
To use the library, an application must first call
-.Fn rad_open
+.Fn rad_auth_open
+or
+.Fn rad_acct_open
to obtain a
.Va 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_open
+.Fn rad_auth_open
+and
+.Fn rad_acct_open
always succeed unless insufficient virtual memory is available. If
-the necessary memory cannot be allocated,
-.Fn rad_open
-returns
+the necessary memory cannot be allocated, the functions return
.Dv NULL .
+For compatibility with earlier versions of this library,
+.Fn rad_open
+is provided as a synonym for
+.Fn rad_auth_open .
.Pp
Before issuing any RADIUS requests, the library must be made aware
of the servers it can contact. The easiest way to configure the
@@ -119,9 +129,12 @@ 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
+or
+.Ql radacct/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
+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
parameter.
It may be any NUL-terminated string of bytes. The RADIUS protocol
@@ -346,9 +359,11 @@ without recording an error message.
.Pp
.Bl -item -offset indent -compact
.It
-.Fn rad_cvt_string
+.Fn rad_acct_open
.It
-.Fn rad_open
+.Fn rad_auth_open
+.It
+.Fn rad_cvt_string
.El
.Sh FILES
.Pa /etc/radius.conf
@@ -359,7 +374,14 @@ without recording an error message.
.%T Remote Authentication Dial In User Service (RADIUS)
.%O RFC 2138
.Re
+.Rs
+.%A C. Rigney
+.%T RADIUS Accounting
+.%O RFC 2139
+.Re
.Sh AUTHORS
-This software was written by
+This software was originally written by
.An John Polstra ,
and donated to the FreeBSD project by Juniper Networks, Inc.
+Oleg Semyonov subsequently added the ability to perform RADIUS
+accounting.
diff --git a/lib/libradius/radius.conf.5 b/lib/libradius/radius.conf.5
index 5c0143934e6e..f05f1b7a5ad8 100644
--- a/lib/libradius/radius.conf.5
+++ b/lib/libradius/radius.conf.5
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 29, 1998
+.Dd October 30, 1999
.Dt RADIUS.CONF 5
.Os FreeBSD
.Sh NAME
@@ -42,8 +42,22 @@ 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
+A RADIUS server is described by three to five fields on a line:
+.Pp
+.Bl -item -offset indent -compact
+.It
+Service type
+.It
+Server host
+.It
+Shared secret
+.It
+Timeout
+.It
+Retries
+.El
+.Pp
+The fields are separated by white space. The
.Ql #
character at the beginning of a field begins a comment, which extends
to the end of the line. A field may be enclosed in double quotes,
@@ -56,19 +70,43 @@ and the backslash can be represented by
.Ql \e\e .
No other escape sequences are supported.
.Pp
-The first field specifies
+.Pp
+The first field gives the service type, either
+.Ql auth
+for RADIUS authentication or
+.Ql acct
+for RADIUS accounting. If a single server provides both services, two
+lines are required in the file. Earlier versions of this file did
+not include a service type. For backward compatibility, if the first
+field is not
+.Ql auth
+or
+.Ql acct
+the library behaves as if
+.Ql auth
+were specified, and interprets the fields in the line as if they
+were fields two through five.
+.Pp
+The second field specifies
the server host, either as a fully qualified domain name or as a
dotted-quad IP address. The host may optionally be followed by a
.Ql \&:
and a numeric port number, without intervening white space. If the
port specification is omitted, it defaults to the
.Ql radius
+or
+.Ql radacct
service in the
.Pa /etc/services
-file, or to the standard RADIUS port 1812 if there is no such entry in
-.Pa /etc/services .
+file for service types
+.Ql auth
+and
+.Ql acct ,
+respectively.
+If no such entry is present, the standard ports 1812 and 1813 are
+used.
.Pp
-The second field contains the shared secret, which should be known
+The third field contains the shared secret, which should be known
only to the client and server hosts. It is an arbitrary string of
characters, though it must be enclosed in double quotes if it
contains white space. The shared secret may be
@@ -77,16 +115,17 @@ 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
+The fourth field contains a decimal integer specifying the timeout in
seconds for receiving a valid reply from the server. If this field
is omitted, it defaults to 3 seconds.
.Pp
-The fourth field contains a decimal integer specifying the maximum
+The fifth field contains a decimal integer specifying the maximum
number of attempts that will be made to authenticate with the server
before giving up. If omitted, it defaults to 3 attempts. Note,
this is the total number of attempts and not the number of retries.
.Pp
-Up to 10 RADIUS servers may be specified. The servers are tried in
+Up to 10 RADIUS servers may be specified for each service type.
+The servers are tried in
round-robin fashion, until a valid response is received or the
maximum number of tries has been reached for all servers.
.Pp
@@ -101,14 +140,14 @@ shared secrets, it should not be readable except by root.
.Sh EXAMPLES
.Bd -literal
# A simple entry using all the defaults:
-radius1.domain.com OurLittleSecret
+acct 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
+auth auth.domain.com:1645 "I can't see you" 5 4
# A server specified by its IP address:
-192.168.27.81 $X*#..38947ax-+=
+auth 192.168.27.81 $X*#..38947ax-+=
.Ed
.Sh SEE ALSO
.Xr libradius 3
@@ -117,6 +156,11 @@ auth.domain.com:1645 "I can't see you, but I know you're there" 5 4
.%T Remote Authentication Dial In User Service (RADIUS)
.%O RFC 2138
.Re
+.Rs
+.%A C. Rigney
+.%T RADIUS Accounting
+.%O RFC 2139
+.Re
.Sh AUTHORS
This documentation was written by
.An John Polstra ,
diff --git a/lib/libradius/radlib.c b/lib/libradius/radlib.c
index a58aa6376866..1860fedd9ee3 100644
--- a/lib/libradius/radlib.c
+++ b/lib/libradius/radlib.c
@@ -48,6 +48,7 @@ static void clear_password(struct rad_handle *);
static void generr(struct rad_handle *, const char *, ...)
__printflike(2, 3);
static void insert_scrambled_password(struct rad_handle *, int);
+static void insert_request_authenticator(struct rad_handle *, int);
static int is_valid_response(struct rad_handle *, int,
const struct sockaddr_in *);
static int put_password_attr(struct rad_handle *, int,
@@ -110,6 +111,23 @@ insert_scrambled_password(struct rad_handle *h, int srv)
}
}
+static void
+insert_request_authenticator(struct rad_handle *h, int srv)
+{
+ MD5_CTX ctx;
+ const struct rad_server *srvp;
+
+ srvp = &h->servers[srv];
+
+ /* Create the request authenticator */
+ MD5Init(&ctx);
+ MD5Update(&ctx, &h->request[POS_CODE], POS_AUTH - POS_CODE);
+ MD5Update(&ctx, memset(&h->request[POS_AUTH], 0, LEN_AUTH), LEN_AUTH);
+ MD5Update(&ctx, &h->request[POS_ATTRS], h->req_len - POS_ATTRS);
+ MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
+ MD5Final(&h->request[POS_AUTH], &ctx);
+}
+
/*
* Return true if the current response is valid for a request to the
* specified server.
@@ -229,9 +247,14 @@ rad_add_server(struct rad_handle *h, const char *host, int port,
else {
struct servent *sent;
- srvp->addr.sin_port =
- (sent = getservbyname("radius", "udp")) != NULL ?
- sent->s_port : htons(RADIUS_PORT);
+ if (h->type == RADIUS_AUTH)
+ srvp->addr.sin_port =
+ (sent = getservbyname("radius", "udp")) != NULL ?
+ sent->s_port : htons(RADIUS_PORT);
+ else
+ srvp->addr.sin_port =
+ (sent = getservbyname("radacct", "udp")) != NULL ?
+ sent->s_port : htons(RADACCT_PORT);
}
if ((srvp->secret = strdup(secret)) == NULL) {
generr(h, "Out of memory");
@@ -278,18 +301,21 @@ rad_config(struct rad_handle *h, const char *path)
linenum = 0;
while (fgets(buf, sizeof buf, fp) != NULL) {
int len;
- char *fields[4];
+ char *fields[5];
int nfields;
char msg[ERRSIZE];
+ char *type;
char *host;
char *port_str;
char *secret;
char *timeout_str;
char *maxtries_str;
char *end;
+ char *wanttype;
unsigned long timeout;
unsigned long maxtries;
int port;
+ int i;
linenum++;
len = strlen(buf);
@@ -307,7 +333,7 @@ rad_config(struct rad_handle *h, const char *path)
buf[len - 1] = '\0';
/* Extract the fields from the line. */
- nfields = split(buf, fields, 4, msg, sizeof msg);
+ nfields = split(buf, fields, 5, msg, sizeof msg);
if (nfields == -1) {
generr(h, "%s:%d: %s", path, linenum, msg);
retval = -1;
@@ -315,16 +341,41 @@ rad_config(struct rad_handle *h, const char *path)
}
if (nfields == 0)
continue;
- if (nfields < 2) {
+ /*
+ * The first field should contain "auth" or "acct" for
+ * authentication or accounting, respectively. But older
+ * versions of the file didn't have that field. Default
+ * it to "auth" for backward compatibility.
+ */
+ if (strcmp(fields[0], "auth") != 0 &&
+ strcmp(fields[0], "acct") != 0) {
+ if (nfields >= 5) {
+ generr(h, "%s:%d: invalid service type", path,
+ linenum);
+ retval = -1;
+ break;
+ }
+ nfields++;
+ for (i = nfields; --i > 0; )
+ fields[i] = fields[i - 1];
+ fields[0] = "auth";
+ }
+ if (nfields < 3) {
generr(h, "%s:%d: missing shared secret", path,
linenum);
retval = -1;
break;
}
- host = fields[0];
- secret = fields[1];
- timeout_str = fields[2];
- maxtries_str = fields[3];
+ type = fields[0];
+ host = fields[1];
+ secret = fields[2];
+ timeout_str = fields[3];
+ maxtries_str = fields[4];
+
+ /* Ignore the line if it is for the wrong service type. */
+ wanttype = h->type == RADIUS_AUTH ? "auth" : "acct";
+ if (strcmp(type, wanttype) != 0)
+ continue;
/* Parse and validate the fields. */
host = strtok(host, ":");
@@ -421,9 +472,13 @@ rad_continue_send_request(struct rad_handle *h, int selected, int *fd,
if (++h->srv >= h->num_servers)
h->srv = 0;
- /* Insert the scrambled password into the request */
- if (h->pass_pos != 0)
- insert_scrambled_password(h, h->srv);
+ if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST)
+ /* Insert the request authenticator into the request */
+ insert_request_authenticator(h, h->srv);
+ else
+ /* Insert the scrambled password into the request */
+ if (h->pass_pos != 0)
+ insert_scrambled_password(h, h->srv);
/* Send the request */
n = sendto(h->fd, h->request, h->req_len, 0,
@@ -552,14 +607,22 @@ rad_init_send_request(struct rad_handle *h, int *fd, struct timeval *tv)
}
}
- /* 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->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) {
+ /* Make sure no password given */
+ if (h->pass_pos || h->chap_pass) {
+ generr(h, "User or Chap Password in accounting request");
+ return -1;
+ }
+ } else {
+ /* 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 */
@@ -591,7 +654,7 @@ rad_init_send_request(struct rad_handle *h, int *fd, struct timeval *tv)
* In that case, it returns NULL.
*/
struct rad_handle *
-rad_open(void)
+rad_auth_open(void)
{
struct rad_handle *h;
@@ -606,10 +669,28 @@ rad_open(void)
h->pass_len = 0;
h->pass_pos = 0;
h->chap_pass = 0;
+ h->type = RADIUS_AUTH;
}
return h;
}
+struct rad_handle *
+rad_acct_open(void)
+{
+ struct rad_handle *h;
+
+ h = rad_open();
+ if (h != NULL)
+ h->type = RADIUS_ACCT;
+ return h;
+}
+
+struct rad_handle *
+rad_open(void)
+{
+ return rad_auth_open();
+}
+
int
rad_put_addr(struct rad_handle *h, int type, struct in_addr addr)
{
diff --git a/lib/libradius/radlib.h b/lib/libradius/radlib.h
index 5e0ce9f01ac1..ccf300662f52 100644
--- a/lib/libradius/radlib.h
+++ b/lib/libradius/radlib.h
@@ -36,6 +36,8 @@
#define RAD_ACCESS_REQUEST 1
#define RAD_ACCESS_ACCEPT 2
#define RAD_ACCESS_REJECT 3
+#define RAD_ACCOUNTING_REQUEST 4
+#define RAD_ACCOUNTING_RESPONSE 5
#define RAD_ACCESS_CHALLENGE 11
/* Attribute types and values */
@@ -66,6 +68,9 @@
#define RAD_FILTER_ID 11 /* String */
#define RAD_FRAMED_MTU 12 /* Integer */
#define RAD_FRAMED_COMPRESSION 13 /* Integer */
+ #define RAD_COMP_NONE 0
+ #define RAD_COMP_VJ 1
+ #define RAD_COMP_IPXHDR 2
#define RAD_LOGIN_IP_HOST 14 /* IP address */
#define RAD_LOGIN_SERVICE 15 /* Integer */
#define RAD_LOGIN_TCP_PORT 16 /* Integer */
@@ -95,15 +100,63 @@
/* reserved for accounting 40-59 */
#define RAD_CHAP_CHALLENGE 60 /* String */
#define RAD_NAS_PORT_TYPE 61 /* Integer */
+ #define RAD_ASYNC 0
+ #define RAD_SYNC 1
+ #define RAD_ISDN_SYNC 2
+ #define RAD_ISDN_ASYNC_V120 3
+ #define RAD_ISDN_ASYNC_V110 4
+ #define RAD_VIRTUAL 5
#define RAD_PORT_LIMIT 62 /* Integer */
#define RAD_LOGIN_LAT_PORT 63 /* Integer */
+#define RAD_CONNECT_INFO 77 /* String */
+
+/* Accounting attribute types and values */
+#define RAD_ACCT_STATUS_TYPE 40 /* Integer */
+ #define RAD_START 1
+ #define RAD_STOP 2
+ #define RAD_ACCOUNTING_ON 7
+ #define RAD_ACCOUNTING_OFF 8
+#define RAD_ACCT_DELAY_TIME 41 /* Integer */
+#define RAD_ACCT_INPUT_OCTETS 42 /* Integer */
+#define RAD_ACCT_OUTPUT_OCTETS 43 /* Integer */
+#define RAD_ACCT_SESSION_ID 44 /* String */
+#define RAD_ACCT_AUTHENTIC 45 /* Integer */
+ #define RAD_AUTH_RADIUS 1
+ #define RAD_AUTH_LOCAL 2
+ #define RAD_AUTH_REMOTE 3
+#define RAD_ACCT_SESSION_TIME 46 /* Integer */
+#define RAD_ACCT_INPUT_PACKETS 47 /* Integer */
+#define RAD_ACCT_OUTPUT_PACKETS 48 /* Integer */
+#define RAD_ACCT_TERMINATE_CAUSE 49 /* Integer */
+ #define RAD_TERM_USER_REQUEST 1
+ #define RAD_TERM_LOST_CARRIER 2
+ #define RAD_TERM_LOST_SERVICE 3
+ #define RAD_TERM_IDLE_TIMEOUT 4
+ #define RAD_TERM_SESSION_TIMEOUT 5
+ #define RAD_TERM_ADMIN_RESET 6
+ #define RAD_TERM_ADMIN_REBOOT 7
+ #define RAD_TERM_PORT_ERROR 8
+ #define RAD_TERM_NAS_ERROR 9
+ #define RAD_TERM_NAS_REQUEST 10
+ #define RAD_TERM_NAS_REBOOT 11
+ #define RAD_TERM_PORT_UNNEEDED 12
+ #define RAD_TERM_PORT_PREEMPTED 13
+ #define RAD_TERM_PORT_SUSPENDED 14
+ #define RAD_TERM_SERVICE_UNAVAILABLE 15
+ #define RAD_TERM_CALLBACK 16
+ #define RAD_TERM_USER_ERROR 17
+ #define RAD_TERM_HOST_REQUEST 18
+#define RAD_ACCT_MULTI_SESSION_ID 50 /* String */
+#define RAD_ACCT_LINK_COUNT 51 /* Integer */
struct rad_handle;
struct timeval;
__BEGIN_DECLS
+struct rad_handle *rad_acct_open(void);
int rad_add_server(struct rad_handle *,
const char *, int, const char *, int, int);
+struct rad_handle *rad_auth_open(void);
void rad_close(struct rad_handle *);
int rad_config(struct rad_handle *, const char *);
int rad_continue_send_request(struct rad_handle *, int,
@@ -116,7 +169,7 @@ int rad_get_attr(struct rad_handle *, const void **,
size_t *);
int rad_init_send_request(struct rad_handle *, int *,
struct timeval *);
-struct rad_handle *rad_open(void);
+struct rad_handle *rad_open(void); /* Deprecated, == rad_auth_open */
int rad_put_addr(struct rad_handle *, int, struct in_addr);
int rad_put_attr(struct rad_handle *, int,
const void *, size_t);
diff --git a/lib/libradius/radlib_private.h b/lib/libradius/radlib_private.h
index 21ef9cb2da35..af169704bdbf 100644
--- a/lib/libradius/radlib_private.h
+++ b/lib/libradius/radlib_private.h
@@ -34,10 +34,15 @@
#include "radlib.h"
+/* Handle types */
+#define RADIUS_AUTH 0 /* RADIUS authentication, default */
+#define RADIUS_ACCT 1 /* RADIUS accounting */
+
/* Defaults */
#define MAXTRIES 3
#define PATH_RADIUS_CONF "/etc/radius.conf"
#define RADIUS_PORT 1812
+#define RADACCT_PORT 1813
#define TIMEOUT 3 /* In seconds */
/* Limits */
@@ -81,6 +86,7 @@ struct rad_handle {
int total_tries; /* How many requests we'll send */
int try; /* How many requests we've sent */
int srv; /* Server number we did last */
+ int type; /* Handle type */
};
#endif