46#include <radcli/radcli.h>
47#include <radcli/radcli2.h>
54struct radcli_request_st {
57 radcli_avp_list *send;
58 char server[AUTH_ID_LEN + 1];
60 char secret[MAX_SECRET_LENGTH + 1];
67 radcli_avp_list *reply_attrs;
73 struct radcli_async_send_st async;
99 rc_handle *rh = (rc_handle *)ctx;
100 struct radcli_request_st *r;
104 radcli_avp_list *send_copy;
111 if (code != RADCLI_CODE_ACCESS_REQUEST && code != RADCLI_CODE_ACCOUNTING_REQUEST) {
112 rc_log(LOG_ERR,
"radcli_request_new: code must be RADCLI_CODE_ACCESS_REQUEST "
113 "or RADCLI_CODE_ACCOUNTING_REQUEST");
120 if (rh->so_type == RC_SOCKET_TLS || rh->so_type == RC_SOCKET_DTLS ||
121 code == RADCLI_CODE_ACCESS_REQUEST) {
122 optname =
"authserver";
125 optname =
"acctserver";
129 servers = radcli2_priv_conf_srv(rh, optname);
130 if (servers == NULL || servers->max == 0) {
131 rc_log(LOG_ERR,
"radcli_request_new: no %s configured", optname);
142 if (servers->max > 1)
143 rc_log(LOG_WARNING,
"radcli_request_new: %d %s entries configured; "
144 "the new API uses only the first (%s) -- redundancy is "
145 "address-level (DNS), not server-list-level",
146 servers->max, optname, servers->name[0]);
153 if (send_copy == NULL)
167 r = calloc(1,
sizeof(*r));
175 strlcpy(r->server, servers->name[0],
sizeof(r->server));
176 r->svc_port = servers->port[0];
177 if (servers->secret[0] != NULL)
178 strlcpy(r->secret, servers->secret[0],
sizeof(r->secret));
180 r->timeout = rc_conf_int_id(rh, OPT_RADIUS_TIMEOUT);
181 r->retries = rc_conf_int_id(rh, OPT_RADIUS_RETRIES);
184 r->code = (uint8_t)code;
227int radcli_encode_request(rc_handle *rh, uint8_t code,
const radcli_avp_list *send,
228 char secret[MAX_SECRET_LENGTH + 1],
229 uint8_t send_buffer[RC_BUFFER_LEN], uint8_t
id,
230 unsigned char vector_out[AUTH_VECTOR_LEN],
int *out_len)
232 AUTH_HDR *auth = (AUTH_HDR *)send_buffer;
233 int encoded_len, total_length;
243 if (rh->so.static_secret)
244 strlcpy(secret, rh->so.static_secret, MAX_SECRET_LENGTH + 1);
249 if (code == RADCLI_CODE_ACCOUNTING_REQUEST) {
253 memset(vector_out, 0, AUTH_VECTOR_LEN);
254 memcpy(auth->vector, vector_out, AUTH_VECTOR_LEN);
256 encoded_len = radcli_avp_encode(rh, send, secret, vector_out,
257 send_buffer + AUTH_HDR_LEN,
258 RC_MAX_PACKET_LEN - AUTH_HDR_LEN, NULL);
261 total_length = AUTH_HDR_LEN + encoded_len;
263 tlen = htons((uint16_t)total_length);
264 memcpy(&auth->length, &tlen,
sizeof(tlen));
266 secretlen = rc_secret_len(secret);
267 memcpy(send_buffer + total_length, secret, secretlen);
268 rc_md5_calc(vector_out, send_buffer, (
size_t)total_length + secretlen);
269 memcpy(auth->vector, vector_out, AUTH_VECTOR_LEN);
271 rc_get_random_bytes(vector_out, AUTH_VECTOR_LEN);
272 memcpy(auth->vector, vector_out, AUTH_VECTOR_LEN);
275 encoded_len = radcli_avp_encode(rh, send, secret, vector_out,
276 send_buffer + AUTH_HDR_LEN,
277 RC_MAX_PACKET_LEN - AUTH_HDR_LEN - (2 + MD5_DIGEST_SIZE), NULL);
280 total_length = AUTH_HDR_LEN + encoded_len;
282 total_length = add_msg_auth_attr(rh, secret, auth, total_length);
283 auth->length = htons((uint16_t)total_length);
286 *out_len = total_length;
318int radcli_do_exchange(rc_handle *rh, uint8_t code,
const radcli_avp_list *send,
319 char *server, uint16_t svc_port,
char secret[MAX_SECRET_LENGTH + 1],
320 int timeout,
int retries,
int no_wait, rc_type type,
321 uint8_t *recv_buffer,
size_t recv_buffer_cap,
size_t *recv_len,
322 unsigned char vector_out[AUTH_VECTOR_LEN], uint8_t *out_reply_code)
324 uint8_t send_buffer[RC_BUFFER_LEN];
330 if (radcli_encode_request(rh, code, send, secret, send_buffer, rc_get_random_byte(),
331 vector_out, &total_length) < 0)
334 return radcli_transport_exchange(rh, NULL, server, svc_port,
335 secret, 0, timeout, retries, no_wait, type,
336 send_buffer, total_length,
337 recv_buffer, recv_buffer_cap, recv_len, out_reply_code);
366 uint8_t recv_buffer[RC_BUFFER_LEN];
367 unsigned char vector[AUTH_VECTOR_LEN];
371 if (r == NULL || r->performed)
376 uint8_t send_buffer[RC_BUFFER_LEN];
384 slot = radcli2_priv_reqreg_reserve(r->rh, &r->async, &
id);
388 if (radcli_encode_request(r->rh, r->code, r->send, r->secret,
389 send_buffer,
id, vector, &send_len) < 0) {
390 radcli2_priv_reqreg_release(r->rh, slot);
394 result = radcli_transport_send_async(r->rh, slot, r->server, r->svc_port, r->secret,
395 r->type, send_buffer, send_len,
396 r->timeout, r->retries, &r->async);
397 if (result != OK_RC) {
398 radcli2_priv_reqreg_release(r->rh, slot);
404 result = radcli_do_exchange(r->rh, r->code, r->send, r->server, r->svc_port, r->secret,
405 r->timeout, r->retries, 0, r->type,
406 recv_buffer,
sizeof(recv_buffer), &recv_len, vector, &r->reply_code);
413 if (radcli_avp_decode(r->rh, r->secret, vector, recv_buffer, recv_len, 0,
414 &r->reply_attrs) != 0)
446 if (r == NULL || !r->async.active)
448 if (!r->async.delivered)
451 r->reply_code = r->async.reply_code;
452 r->reply_attrs = r->async.reply_attrs;
453 r->async.reply_attrs = NULL;
456 switch (r->async.result) {
475 if (r == NULL || !r->performed)
490 return r->reply_attrs;
499 static const char empty[] =
"";
521 radcli_transport_async_abort(&r->async);
524 memset(r->secret, 0,
sizeof(r->secret));
void radcli_avp_list_free(radcli_avp_list *list)
Free a list and every attribute it holds.
radcli_avp_iter radcli_avp_list_iter(const radcli_avp_list *list)
Begin iterating list.
int radcli_avp_add_bytes(radcli_avp_list *list, const radcli_attr_def *def, const void *value, size_t len)
Append an attribute holding an arbitrary byte string.
radcli_avp_list * radcli_avp_list_new(void)
Create an empty attribute-value pair list.
const radcli_attr_def * radcli_avp_def(const radcli_avp *a)
Return the attribute definition of a.
const radcli_avp * radcli_avp_iter_next(radcli_avp_iter *it)
Return the current attribute and advance.
int radcli_avp_get_bytes(const radcli_avp *a, const void **out, size_t *len)
Read an attribute's value as raw bytes.
int radcli_request_perform(radcli_request *r, unsigned flags)
Send a request, optionally waiting for the reply.
const radcli_avp_list * radcli_request_attrs(const radcli_request *r)
Return the reply's decoded attributes.
const char * radcli_request_server(const radcli_request *r)
Return the name of the server a request was (or will be) sent to.
int radcli_request_done(radcli_request *r)
Report r's outcome once radcli_ctx_dispatch() has resolved it – a pure state query,...
radcli_request * radcli_request_new(radcli_ctx *ctx, radcli_code code, const radcli_avp_list *send)
Create a request to send.
void radcli_request_free(radcli_request *r)
Release a request.
radcli_code radcli_request_code(const radcli_request *r)
Return the reply's RADIUS code.
@ RADCLI_TIMEOUT
No reply from any address the server name resolved to.
@ RADCLI_ERROR
Malformed input, a verification failure, or no server configured.
@ RADCLI_OK
A validated reply was received; see radcli_request_code() for which one.
@ RADCLI_REQUEST_SENDONLY