25 RCSID(
"$Id: 7f8aab3f8a75c54077bed48ae18e2d3647dc3f3f $")
27 #include <freeradius-devel/radius/client.h>
28 #include <freeradius-devel/radius/client_udp.h>
29 #include <freeradius-devel/radius/client_tcp.h>
30 #include <freeradius-devel/radius/client_priv.h>
32 #include <freeradius-devel/protocol/radius/rfc2865.h>
33 #include <freeradius-devel/protocol/radius/rfc2866.h>
92 if (!
my->codes[i])
goto fail;
110 my->reply_socket =
my->info.fd_info->socket;
111 if ((
my->reply_socket.af == AF_INET) || (
my->reply_socket.af == AF_INET6)) {
116 if (!
my->mem)
goto fail;
128 if (!
my->retry)
goto fail;
130 my->retry->uctx =
my;
135 my->common.bio =
my->retry;
141 my->common.bio =
my->mem;
161 my->info.connected =
false;
176 .secret = (
char const *)
my->cfg.verify.secret,
177 .secret_length =
my->cfg.verify.secret_len,
178 .secure_transport =
false,
179 .proxy_state =
my->cfg.proxy_state,
198 if (!
my->codes[packet->
code]) {
211 my->all_ids_used =
true;
216 if (
my->common.cb.write_blocked)
my->common.cb.write_blocked(&
my->common);
223 if (!id_ctx)
goto all_ids_used;
240 .common = &my->proto_ctx,
241 .request_authenticator = NULL,
242 .rand_ctx = (fr_fast_rand_t) {
246 .code = packet->
code,
248 .add_proxy_state =
my->cfg.add_proxy_state,
257 packet->data_len = slen;
260 (
uint8_t const *)
my->cfg.verify.secret,
my->cfg.verify.secret_len);
261 if (slen < 0)
goto fail;
270 slen =
fr_bio_write(
my->common.bio, &packet->socket,
my->buffer, packet->data_len);
278 fr_assert((
size_t) slen == packet->data_len);
284 packet->data = talloc_array(packet,
uint8_t, packet->data_len);
285 if (!packet->data)
goto fail;
290 memcpy(packet->data,
my->buffer, packet->data_len);
322 my->cfg.packet_cb_cfg.retry(&
my->common, id_ctx->
packet);
355 retry_ctx->
uctx = id_ctx;
369 (
uint8_t const *)
my->cfg.verify.secret,
my->cfg.verify.secret_len);
374 if (
my->cfg.packet_cb_cfg.retry)
my->cfg.packet_cb_cfg.retry(&
my->common, id_ctx->
packet);
395 id_ctx->
packet = packet_ctx;
398 retry_ctx->
uctx = id_ctx;
402 my->info.outstanding++;
404 if (
fr_time_lteq(
my->info.first_sent,
my->info.last_idle))
my->info.first_sent =
my->info.last_sent;
424 if (
data[0] == FR_ACCT_DELAY_TIME)
break;
429 if ((
data == end) || (
data[1] != 6))
return;
465 if (!code)
return false;
473 if (!id_ctx)
return false;
482 my->cfg.verify.secret,
my->cfg.verify.secret_len,
483 my->cfg.verify.require_message_authenticator,
484 my->cfg.verify.limit_proxy_state) < 0) {
488 retry = *retry_ctx_p = id_ctx->
retry_ctx;
542 my->info.outstanding--;
547 if (
my->all_ids_used) {
548 my->all_ids_used =
false;
553 if (
my->common.cb.write_resume)
my->common.cb.write_resume(&
my->common);
555 }
else if (!
my->info.outstanding) {
573 if (!id_ctx || !id_ctx->
retry_ctx)
return 0;
576 if (!
my->retry)
goto done;
611 original = response.
uctx;
617 if (!reply)
return -1;
625 reply->
data = talloc_memdup(reply,
my->buffer, slen);
633 reply->
id = reply->
data[1];
640 original->
vector, (
char const *)
my->cfg.verify.secret) < 0) {
645 *pctx_p = original->
uctx;
658 if (!
my->retry)
return 0;
680 if ((
id < 0) || (
id > 256)) {
697 if (
my->common.cb.failed)
my->common.cb.failed(&
my->common);
714 if (
my->info.connected)
return;
static int const char char buffer[256]
static ssize_t fr_bio_write(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
Write raw data to a bio.
static ssize_t fr_bio_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Read raw data from a bio.
void * uctx
user ctx, caller can manually set it.
fr_bio_packet_signal_t retry
fr_bio_t * fr_bio_retry_alloc(TALLOC_CTX *ctx, size_t max_saved, fr_bio_retry_sent_t sent, fr_bio_retry_response_t response, fr_bio_retry_rewrite_t rewrite, fr_bio_retry_release_t release, fr_bio_retry_config_t const *cfg, fr_bio_t *next)
Allocate a fr_bio_retry_t.
int fr_bio_retry_entry_init(UNUSED fr_bio_t *bio, fr_bio_retry_entry_t *item, fr_retry_config_t const *cfg)
Set a per-packet retry config.
size_t fr_bio_retry_outstanding(fr_bio_t *bio)
int fr_bio_retry_entry_cancel(fr_bio_t *bio, fr_bio_retry_entry_t *item)
Cancel one item.
ssize_t fr_bio_retry_rewrite(fr_bio_t *bio, fr_bio_retry_entry_t *item, const void *buffer, size_t size)
Resend a packet.
fr_bio_retry_info_t const * fr_bio_retry_info(fr_bio_t *bio)
void * rewrite_ctx
context specifically for rewriting this packet
fr_retry_t retry
retry timers and counters
fr_bio_retry_release_reason_t
ssize_t(* fr_bio_retry_rewrite_t)(fr_bio_t *bio, fr_bio_retry_entry_t *retry_ctx, const void *buffer, size_t size)
fr_event_list_t * el
event list
void * packet_ctx
packet_ctx from the write() call
fr_bio_retry_rewrite_t rewrite
per-packet rewrite callback
void * uctx
user-writable context
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
fr_bio_packet_t * fr_radius_client_tcp_bio_alloc(TALLOC_CTX *ctx, fr_radius_client_config_t *cfg, fr_bio_fd_config_t const *fd_cfg)
Allocate a RADIUS bio for writing client packets.
fr_bio_packet_t * fr_radius_client_udp_bio_alloc(TALLOC_CTX *ctx, fr_radius_client_config_t *cfg, fr_bio_fd_config_t const *fd_cfg)
Allocate a RADIUS bio for writing client packets.
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
fr_dcursor_eval_t void const * uctx
fr_radius_packet_code_t
RADIUS packet codes.
@ FR_RADIUS_CODE_ACCESS_CHALLENGE
RFC2865 - Access-Challenge.
@ FR_RADIUS_CODE_ACCESS_REQUEST
RFC2865 - Access-Request.
@ FR_RADIUS_CODE_DISCONNECT_REQUEST
RFC3575/RFC5176 - Disconnect-Request.
@ FR_RADIUS_CODE_MAX
Maximum possible protocol code.
@ FR_RADIUS_CODE_DISCONNECT_ACK
RFC3575/RFC5176 - Disconnect-Ack (positive)
@ FR_RADIUS_CODE_STATUS_SERVER
RFC2865/RFC5997 - Status Server (request)
@ FR_RADIUS_CODE_COA_REQUEST
RFC3575/RFC5176 - CoA-Request.
@ FR_RADIUS_CODE_ACCESS_ACCEPT
RFC2865 - Access-Accept.
@ FR_RADIUS_CODE_ACCOUNTING_RESPONSE
RFC2866 - Accounting-Response.
@ FR_RADIUS_CODE_COA_NAK
RFC3575/RFC5176 - CoA-Nak (not willing to perform)
@ FR_RADIUS_CODE_COA_ACK
RFC3575/RFC5176 - CoA-Ack (positive)
@ FR_RADIUS_CODE_DISCONNECT_NAK
RFC3575/RFC5176 - Disconnect-Nak (not willing to perform)
@ FR_RADIUS_CODE_PROTOCOL_ERROR
RFC7930 - Protocol-Error (generic NAK)
@ FR_RADIUS_CODE_ACCOUNTING_REQUEST
RFC2866 - Accounting-Request.
@ FR_RADIUS_CODE_ACCESS_REJECT
RFC2865 - Access-Reject.
#define fr_event_timer_in(...)
fr_bio_t * fr_bio_fd_alloc(TALLOC_CTX *ctx, fr_bio_fd_config_t const *cfg, size_t offset)
Allocate a FD bio.
fr_bio_fd_info_t const * fr_bio_fd_info(fr_bio_t *bio)
Returns a pointer to the bio-specific information.
@ FR_BIO_FD_CONNECTED
connected client sockets (UDP or TCP)
@ FR_BIO_FD_STATE_CONNECTING
@ FR_BIO_FD_STATE_OPEN
error states must be before this
fr_bio_fd_type_t type
accept, connected, unconnected, etc.
char const * path
for Unix domain sockets
char const * filename
for files
#define fr_bio_fd_connect(_x)
int socket_type
SOCK_STREAM or SOCK_DGRAM.
Configuration for sockets.
int fr_bio_free(fr_bio_t *bio)
Free this bio, and everything it calls.
int fr_bio_shutdown(fr_bio_t *bio)
Shut down a set of BIOs.
fr_bio_t * fr_bio_mem_alloc(TALLOC_CTX *ctx, size_t read_size, size_t write_size, fr_bio_t *next)
Allocate a memory buffer bio.
void fr_bio_packet_init(fr_bio_packet_t *my)
void fr_bio_packet_connected(fr_bio_t *bio)
Called when a particular BIO is connected.
Stores all information relating to an event list.
fr_packet_t * fr_packet_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new fr_packet_t.
static uint32_t fr_nbo_to_uint32(uint8_t const data[static sizeof(uint32_t)])
Read an unsigned 32bit integer from wire format (big endian)
static void fr_nbo_from_uint32(uint8_t out[static sizeof(uint32_t)], uint32_t num)
Write out an unsigned 32bit integer in wire format (big endian)
#define RADIUS_HEADER_LENGTH
#define RADIUS_AUTH_VECTOR_LENGTH
int fr_radius_sign(uint8_t *packet, uint8_t const *vector, uint8_t const *secret, size_t secret_len)
Sign a previously encoded packet.
int fr_radius_verify(uint8_t *packet, uint8_t const *vector, uint8_t const *secret, size_t secret_len, bool require_message_authenticator, bool limit_proxy_state)
Verify a request / response packet.
ssize_t fr_radius_decode_simple(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t *packet, size_t packet_len, uint8_t const *vector, char const *secret)
Simple wrapper for callers who just need a shared secret.
ssize_t fr_radius_encode(fr_dbuff_t *dbuff, fr_pair_list_t *vps, fr_radius_encode_ctx_t *packet_ctx)
char const * fr_radius_packet_name[FR_RADIUS_CODE_MAX]
fr_bio_retry_config_t retry_cfg
fr_bio_packet_cb_funcs_t packet_cb_cfg
bool outgoing[FR_RADIUS_CODE_MAX]
allowed outgoing packet types
fr_time_delta_t connection_timeout
fr_radius_id_t * fr_radius_id_alloc(TALLOC_CTX *ctx)
Allocate a tracking structure for one packet code.
static void fr_radius_code_id_push(fr_radius_code_id_t codes, fr_packet_t const *packet)
static fr_radius_id_ctx_t * fr_radius_code_id_pop(fr_radius_code_id_t codes, fr_packet_t *packet)
void * retry_ctx
to find the retry information
void * request_ctx
for the application to track
fr_packet_t * packet
outgoing packet
fr_packet_t * response
response to outgoing packet
static fr_radius_id_ctx_t * fr_radius_code_id_find(fr_radius_code_id_t codes, int code, int id)
static int fr_radius_code_id_force(fr_radius_code_id_t codes, int code, int id)
fr_radius_client_fd_bio_t * fr_radius_client_fd_bio_alloc(TALLOC_CTX *ctx, size_t read_size, fr_radius_client_config_t *cfg, fr_bio_fd_config_t const *fd_cfg)
static int _radius_client_fd_bio_free(fr_radius_client_fd_bio_t *my)
static void radius_client_retry_release(fr_bio_t *bio, fr_bio_retry_entry_t *retry_ctx, UNUSED fr_bio_retry_release_reason_t reason)
static ssize_t radius_client_retry(fr_bio_t *bio, fr_bio_retry_entry_t *retry_ctx, UNUSED const void *buffer, NDEBUG_UNUSED size_t size)
fr_bio_packet_t * fr_radius_client_bio_alloc(TALLOC_CTX *ctx, fr_radius_client_config_t *cfg, fr_bio_fd_config_t const *fd_cfg)
static bool radius_client_retry_response(fr_bio_t *bio, fr_bio_retry_entry_t **retry_ctx_p, UNUSED void *packet_ctx, const void *buffer, UNUSED size_t size)
static void radius_client_retry_sent(fr_bio_t *bio, void *packet_ctx, const void *buffer, UNUSED size_t size, fr_bio_retry_entry_t *retry_ctx)
void fr_radius_client_bio_connect(NDEBUG_UNUSED fr_event_list_t *el, NDEBUG_UNUSED int fd, UNUSED int flags, void *uctx)
static ssize_t radius_client_rewrite_acct(fr_bio_t *bio, fr_bio_retry_entry_t *retry_ctx, UNUSED const void *buffer, NDEBUG_UNUSED size_t size)
static const fr_radius_packet_code_t allowed_replies[FR_RADIUS_CODE_MAX]
int fr_radius_client_fd_bio_cancel(fr_bio_packet_t *bio, fr_packet_t *packet)
Cancel one packet.
size_t offset
offset to Acct-Delay-Time value
int fr_radius_client_bio_force_id(fr_bio_packet_t *bio, int code, int id)
uint32_t initial
initial value
fr_radius_client_bio_info_t const * fr_radius_client_bio_info(fr_bio_packet_t *bio)
static void fr_radius_client_bio_connect_timer(fr_event_list_t *el, fr_time_t now, void *uctx)
int fr_radius_client_fd_bio_read(fr_bio_packet_t *bio, void **pctx_p, fr_packet_t **packet_p, UNUSED TALLOC_CTX *out_ctx, fr_pair_list_t *out)
size_t fr_radius_client_bio_outstanding(fr_bio_packet_t *bio)
uint32_t start
Unix time we started sending this packet.
int fr_radius_client_fd_bio_write(fr_radius_client_fd_bio_t *my, void *pctx, fr_packet_t *packet, fr_pair_list_t *list)
#define fr_time()
Allow us to arbitrarily manipulate time.
static int64_t fr_time_to_sec(fr_time_t when)
Convert an fr_time_t (internal time) to number of sec since the unix epoch (wallclock time)
#define fr_time_lteq(_a, _b)
#define fr_time_delta_ispos(_a)
#define fr_time_gt(_a, _b)
static fr_event_list_t * el
unsigned int code
Packet code (type).
fr_socket_t socket
This packet was received on.
int id
Packet ID (used to link requests/responses).
uint8_t * data
Packet data (body).
size_t data_len
Length of packet data.
uint8_t vector[RADIUS_AUTH_VECTOR_LENGTH]
RADIUS authentication vector.
fr_time_t timestamp
When we received the packet.
fr_time_t start
when we started the retransmission
fr_time_t updated
last update, really a cached "now".
static void fr_socket_addr_swap(fr_socket_t *dst, fr_socket_t const *src)
Swap src/dst information of a fr_socket_t.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
static size_t char ** out