mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-11-28 13:22:48 +00:00
Add simple embedded RADIUS server support to libradius, by extending existing
API, keeping backward compatibility. First consumer for this functionality is going to become forthcoming MPD-5.4, supporting CoA and DR of RFC 3576: Dynamic Authorization Extensions to RADIUS. MFC after: 1 month
This commit is contained in:
parent
493d6f54bc
commit
3fc0b61c51
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=197086
@ -1,4 +1,5 @@
|
||||
.\" Copyright 1998 Juniper Networks, Inc.
|
||||
.\" Copyright 2009 Alexander Motin <mav@FreeBSD.org>.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
@ -24,12 +25,12 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd April 27, 2004
|
||||
.Dd August 5, 2009
|
||||
.Dt LIBRADIUS 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm libradius
|
||||
.Nd RADIUS client library
|
||||
.Nd RADIUS client/server library
|
||||
.Sh SYNOPSIS
|
||||
.In radlib.h
|
||||
.Ft "struct rad_handle *"
|
||||
@ -46,6 +47,8 @@
|
||||
.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 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
|
||||
@ -79,7 +82,13 @@
|
||||
.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 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 u_char *
|
||||
@ -91,16 +100,17 @@
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
library implements the client side of the Remote Authentication Dial
|
||||
In User Service (RADIUS).
|
||||
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.
|
||||
.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
|
||||
.Vt "struct rad_handle *" ,
|
||||
which provides the context for subsequent operations.
|
||||
@ -108,8 +118,10 @@ 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
|
||||
and
|
||||
.Fn rad_server_open
|
||||
always succeed unless insufficient virtual memory is available.
|
||||
If
|
||||
the necessary memory cannot be allocated, the functions return
|
||||
@ -451,6 +463,25 @@ subsequent library calls using the same handle.
|
||||
.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 receieve
|
||||
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
|
||||
@ -466,6 +497,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
|
||||
@ -483,6 +516,8 @@ which can be retrieved using
|
||||
.Fn rad_continue_send_request
|
||||
.It
|
||||
.Fn rad_send_request
|
||||
.It
|
||||
.Fn rad_send_response
|
||||
.El
|
||||
.Pp
|
||||
The following functions return a
|
||||
@ -499,6 +534,8 @@ without recording an error message.
|
||||
.It
|
||||
.Fn rad_auth_open
|
||||
.It
|
||||
.Fn rad_server_open
|
||||
.It
|
||||
.Fn rad_cvt_string
|
||||
.El
|
||||
.Pp
|
||||
@ -553,3 +590,5 @@ 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 .
|
||||
|
@ -103,7 +103,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;
|
||||
|
||||
@ -120,49 +120,55 @@ 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 srv)
|
||||
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[srv];
|
||||
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->request[POS_CODE], POS_AUTH - POS_CODE);
|
||||
HMAC_Update(&ctx, &h->request[POS_AUTH], LEN_AUTH);
|
||||
HMAC_Update(&ctx, &h->request[POS_ATTRS],
|
||||
h->req_len - POS_ATTRS);
|
||||
HMAC_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->request[h->authentic_pos + 2], md, md_len);
|
||||
memcpy(&h->out[h->authentic_pos + 2], md, md_len);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -195,20 +201,20 @@ 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
|
||||
@ -216,42 +222,111 @@ is_valid_response(struct rad_handle *h, int srv,
|
||||
* For non accounting responses check the message authenticator,
|
||||
* if any.
|
||||
*/
|
||||
if (h->response[POS_CODE] != RAD_ACCOUNTING_RESPONSE) {
|
||||
if (h->in[POS_CODE] != RAD_ACCOUNTING_RESPONSE) {
|
||||
|
||||
memcpy(resp, h->response, MSGSIZE);
|
||||
memcpy(resp, h->in, MSGSIZE);
|
||||
pos = POS_ATTRS;
|
||||
|
||||
/* Search and verify the Message-Authenticator */
|
||||
while (pos < len - 2) {
|
||||
|
||||
if (h->response[pos] == RAD_MESSAGE_AUTHENTIC) {
|
||||
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->response[POS_CODE],
|
||||
HMAC_Update(&hctx, &h->in[POS_CODE],
|
||||
POS_AUTH - POS_CODE);
|
||||
HMAC_Update(&hctx, &h->request[POS_AUTH],
|
||||
HMAC_Update(&hctx, &h->out[POS_AUTH],
|
||||
LEN_AUTH);
|
||||
HMAC_Update(&hctx, &resp[POS_ATTRS],
|
||||
h->resp_len - POS_ATTRS);
|
||||
h->in_len - POS_ATTRS);
|
||||
HMAC_Final(&hctx, md, &md_len);
|
||||
HMAC_CTX_cleanup(&hctx);
|
||||
HMAC_cleanup(&hctx);
|
||||
if (memcmp(md, &h->response[pos + 2],
|
||||
if (memcmp(md, &h->in[pos + 2],
|
||||
MD5_DIGEST_LENGTH) != 0)
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
pos += h->response[pos + 1];
|
||||
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)
|
||||
{
|
||||
@ -273,7 +348,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);
|
||||
@ -289,14 +364,14 @@ 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;
|
||||
}
|
||||
|
||||
@ -523,22 +598,26 @@ rad_continue_send_request(struct rad_handle *h, int selected, int *fd,
|
||||
{
|
||||
int n;
|
||||
|
||||
if (h->type == RADIUS_SERVER) {
|
||||
generr(h, "denied function call");
|
||||
return (-1);
|
||||
}
|
||||
if (selected) {
|
||||
struct sockaddr_in from;
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
@ -556,21 +635,22 @@ rad_continue_send_request(struct rad_handle *h, int selected, int *fd,
|
||||
if (++h->srv >= h->num_servers)
|
||||
h->srv = 0;
|
||||
|
||||
if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST)
|
||||
/* Insert the request authenticator into the request */
|
||||
insert_request_authenticator(h, h->srv);
|
||||
else
|
||||
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, h->srv);
|
||||
}
|
||||
insert_message_authenticator(h, 0);
|
||||
if (h->out[POS_CODE] != RAD_ACCESS_REQUEST) {
|
||||
/* Insert the request authenticator into the request */
|
||||
insert_request_authenticator(h, h->srv);
|
||||
}
|
||||
|
||||
/* 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
|
||||
@ -587,23 +667,118 @@ rad_continue_send_request(struct rad_handle *h, int selected, int *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->out, h->out_len, 0,
|
||||
(const struct sockaddr *)&h->servers[h->srv].addr,
|
||||
sizeof h->servers[h->srv].addr);
|
||||
if (n != h->out_len) {
|
||||
if (n == -1)
|
||||
generr(h, "sendto: %s", strerror(errno));
|
||||
else
|
||||
generr(h, "sendto: short write");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rad_create_request(struct rad_handle *h, int code)
|
||||
{
|
||||
int i;
|
||||
|
||||
h->request[POS_CODE] = code;
|
||||
h->request[POS_IDENT] = ++h->ident;
|
||||
/* Create a random authenticator */
|
||||
for (i = 0; i < LEN_AUTH; i += 2) {
|
||||
long r;
|
||||
r = random();
|
||||
h->request[POS_AUTH+i] = (u_char)r;
|
||||
h->request[POS_AUTH+i+1] = (u_char)(r >> 8);
|
||||
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->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->request_created = 1;
|
||||
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->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;
|
||||
}
|
||||
|
||||
@ -647,20 +822,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;
|
||||
}
|
||||
|
||||
@ -672,6 +847,10 @@ rad_init_send_request(struct rad_handle *h, int *fd, struct timeval *tv)
|
||||
{
|
||||
int srv;
|
||||
|
||||
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;
|
||||
@ -694,7 +873,7 @@ 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"
|
||||
@ -718,8 +897,8 @@ rad_init_send_request(struct rad_handle *h, int *fd, struct timeval *tv)
|
||||
}
|
||||
|
||||
/* 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
|
||||
@ -763,7 +942,7 @@ rad_auth_open(void)
|
||||
h->chap_pass = 0;
|
||||
h->authentic_pos = 0;
|
||||
h->type = RADIUS_AUTH;
|
||||
h->request_created = 0;
|
||||
h->out_created = 0;
|
||||
h->eap_msg = 0;
|
||||
}
|
||||
return h;
|
||||
@ -780,6 +959,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)
|
||||
{
|
||||
@ -797,13 +989,13 @@ rad_put_attr(struct rad_handle *h, int type, const void *value, size_t len)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (!h->request_created) {
|
||||
if (!h->out_created) {
|
||||
generr(h, "Please call rad_create_request()"
|
||||
" before putting attributes");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) {
|
||||
if (h->out[POS_CODE] == RAD_ACCOUNTING_REQUEST) {
|
||||
if (type == RAD_EAP_MESSAGE) {
|
||||
generr(h, "EAP-Message attribute is not valid"
|
||||
" in accounting requests");
|
||||
@ -858,14 +1050,14 @@ rad_put_message_authentic(struct rad_handle *h)
|
||||
#ifdef WITH_SSL
|
||||
u_char md_zero[MD5_DIGEST_LENGTH];
|
||||
|
||||
if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) {
|
||||
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->req_len;
|
||||
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)));
|
||||
@ -1041,7 +1233,7 @@ rad_put_vendor_attr(struct rad_handle *h, int vendor, int type,
|
||||
struct vendor_attribute *attr;
|
||||
int res;
|
||||
|
||||
if (!h->request_created) {
|
||||
if (!h->out_created) {
|
||||
generr(h, "Please call rad_create_request()"
|
||||
" before putting attributes");
|
||||
return -1;
|
||||
@ -1088,7 +1280,7 @@ 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);
|
||||
|
@ -42,6 +42,12 @@
|
||||
#define RAD_ACCOUNTING_REQUEST 4
|
||||
#define RAD_ACCOUNTING_RESPONSE 5
|
||||
#define RAD_ACCESS_CHALLENGE 11
|
||||
#define RAD_DISCONNECT_REQUEST 40
|
||||
#define RAD_DISCONNECT_ACK 41
|
||||
#define RAD_DISCONNECT_NAK 42
|
||||
#define RAD_COA_REQUEST 43
|
||||
#define RAD_COA_ACK 44
|
||||
#define RAD_COA_NAK 45
|
||||
|
||||
/* Attribute types and values */
|
||||
#define RAD_USER_NAME 1 /* String */
|
||||
@ -179,6 +185,8 @@
|
||||
#define RAD_ACCT_MULTI_SESSION_ID 50 /* String */
|
||||
#define RAD_ACCT_LINK_COUNT 51 /* Integer */
|
||||
|
||||
#define RAD_ERROR_CAUSE 101 /* Integer */
|
||||
|
||||
struct rad_handle;
|
||||
struct timeval;
|
||||
|
||||
@ -192,6 +200,7 @@ 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 *);
|
||||
u_int32_t rad_cvt_int(const void *);
|
||||
char *rad_cvt_string(const void *, size_t);
|
||||
@ -209,7 +218,10 @@ int rad_put_string(struct rad_handle *, int,
|
||||
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 *,
|
||||
|
@ -38,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
|
||||
@ -75,18 +76,18 @@ 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 */
|
||||
char request_created; /* rad_create_request() called? */
|
||||
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 ? */
|
||||
char chap_pass; /* Have we got a CHAP_PASSWORD ? */
|
||||
int authentic_pos; /* Position of message authenticator */
|
||||
char eap_msg; /* Are we an EAP Proxy? */
|
||||
unsigned char response[MSGSIZE]; /* Response received */
|
||||
int resp_len; /* Length of response */
|
||||
int resp_pos; /* Current position scanning attrs */
|
||||
unsigned char in[MSGSIZE]; /* Response received */
|
||||
int in_len; /* Length of response */
|
||||
int in_pos; /* Current position scanning attrs */
|
||||
int total_tries; /* How many requests we'll send */
|
||||
int try; /* How many requests we've sent */
|
||||
int srv; /* Server number we did last */
|
||||
|
Loading…
Reference in New Issue
Block a user