27#include <radcli/radcli.h>
28#include <radcli/radcli2.h>
29#include <ccan/list/list.h>
30#include <utf8decode/utf8decode.h>
90 const radcli_attr_def *def;
91 struct list_node node;
96struct radcli_avp_list_st {
97 struct list_head head;
113static inline bool avp_list_node_is_last(
const struct list_node *n,
const struct list_head *h)
115 return n->next == &h->n;
133static int avp_list_fail(radcli_avp_list *l)
135 struct radcli_avp_list_st *list = (
struct radcli_avp_list_st *)l;
147 struct radcli_avp_list_st *list = calloc(1,
sizeof(*list));
149 rc_log(LOG_CRIT,
"radcli_avp_list_new: out of memory");
152 list_head_init(&list->head);
153 return (radcli_avp_list *)list;
161 struct list_node *n, *next;
171 (void)list_debug(&list->head);
202 for (n = list->head.n.next; n != &list->head.n; n = next) {
203 struct radcli_avp_st *a = list_entry(n,
struct radcli_avp_st, node);
226 struct radcli_avp_st *a;
228 if (list == NULL || def == NULL)
229 return avp_list_fail(list);
230 if (len > 0 && value == NULL)
231 return avp_list_fail(list);
239 a = calloc(1,
sizeof(*a) + len + 1);
241 rc_log(LOG_CRIT,
"radcli_avp_add_bytes: out of memory");
242 return avp_list_fail(list);
246 memcpy(a->data, value, len);
250 list_add_tail(&list->head, &a->node);
266static int is_valid_utf8(
const void *buf,
size_t len)
268 const unsigned char *p = buf;
269 uint32_t state = UTF8_ACCEPT, codep = 0;
272 for (i = 0; i < len; i++) {
275 if (decode(&state, &codep, p[i]) == UTF8_REJECT)
278 return state == UTF8_ACCEPT;
303 if (def == NULL || value == NULL)
304 return avp_list_fail(list);
307 return avp_list_fail(list);
313 return avp_list_fail(list);
328 return avp_list_fail(list);
331 return avp_list_fail(list);
350 return avp_list_fail(list);
353 return avp_list_fail(list);
368 return avp_list_fail(list);
369 hostval = ntohl(value.s_addr);
387 const struct in6_addr *value,
unsigned prefix)
390 unsigned char buf[18];
392 if (def == NULL || value == NULL)
393 return avp_list_fail(list);
398 return avp_list_fail(list);
403 return avp_list_fail(list);
405 buf[1] = (
unsigned char)prefix;
406 memcpy(buf + 2, value, 16);
409 return avp_list_fail(list);
430 struct in_addr value,
unsigned prefix)
432 unsigned char buf[6];
435 return avp_list_fail(list);
437 return avp_list_fail(list);
439 buf[1] = (
unsigned char)prefix;
444 memcpy(buf + 2, &value.s_addr, 4);
467 uint32_t attrid, uint32_t vendor,
468 const void *value,
size_t len)
473 return avp_list_fail(list);
486 uint32_t attrid, uint32_t vendor,
const char *value)
491 return avp_list_fail(list);
504 uint32_t attrid, uint32_t vendor, uint32_t value)
509 return avp_list_fail(list);
522 uint32_t attrid, uint32_t vendor, uint64_t value)
527 return avp_list_fail(list);
540 uint32_t attrid, uint32_t vendor,
struct in_addr value)
545 return avp_list_fail(list);
559 uint32_t attrid, uint32_t vendor,
560 const struct in6_addr *value,
unsigned prefix)
565 return avp_list_fail(list);
579 uint32_t attrid, uint32_t vendor,
580 struct in_addr value,
unsigned prefix)
585 return avp_list_fail(list);
611 const char *username,
const char *realm)
618 if (def == NULL || username == NULL)
619 return avp_list_fail(list);
622 realm = rc_conf_str_id((rc_handle
const *)ctx, OPT_DEFAULT_REALM);
624 if (strchr(username,
'@') != NULL || realm == NULL || realm[0] == 0)
627 len = strlen(username) + 1 + strlen(realm) + 1;
628 composed = malloc(len);
629 if (composed == NULL)
630 return avp_list_fail(list);
631 snprintf(composed, len,
"%s@%s", username, realm);
644const radcli_avp *
radcli_avp_get(
const radcli_avp_list *list,
const radcli_attr_def *def,
unsigned idx)
646 const struct radcli_avp_st *a = NULL;
649 if (list == NULL || def == NULL)
652 list_for_each(&list->head, a, node) {
655 return (
const radcli_avp *)a;
671 it.cur = list ? (
const radcli_avp *)list_top(&list->head,
struct radcli_avp_st, node) : NULL;
682 const struct radcli_avp_st *avp = (
const struct radcli_avp_st *)it->cur;
683 const radcli_avp *ret = it->cur;
692 const struct radcli_avp_list_st *list = (
const struct radcli_avp_list_st *)it->list;
694 if (avp_list_node_is_last(&avp->node, &list->head))
697 it->cur = (
const radcli_avp *)list_entry(avp->node.next,
struct radcli_avp_st, node);
705 const struct radcli_avp_st *avp = (
const struct radcli_avp_st *)a;
706 return avp ? avp->def : NULL;
718 const struct radcli_avp_st *avp = (
const struct radcli_avp_st *)a;
721 if (avp == NULL || avp->def == NULL)
726 if (avp->len !=
sizeof(uint32_t))
730 memcpy(out, avp->data,
sizeof(uint32_t));
744 const struct radcli_avp_st *avp = (
const struct radcli_avp_st *)a;
747 if (avp == NULL || avp->def == NULL)
752 if (avp->len !=
sizeof(uint64_t))
756 memcpy(out, avp->data,
sizeof(uint64_t));
771 const struct radcli_avp_st *avp = (
const struct radcli_avp_st *)a;
774 if (avp == NULL || avp->def == NULL)
782 memcpy(out, avp->data, 16);
788 const unsigned char *p = avp->data;
791 if (avp->len < 2 || avp->len > 18)
793 addrbytes = avp->len - 2;
797 memcpy(out, p + 2, addrbytes);
815 const struct radcli_avp_st *avp = (
const struct radcli_avp_st *)a;
816 const unsigned char *p;
819 if (avp == NULL || avp->def == NULL)
827 if (avp->len < 2 || avp->len > 6)
830 addrbytes = avp->len - 2;
833 memset(out, 0,
sizeof(*out));
834 memcpy(out, p + 2, addrbytes);
855 const struct radcli_avp_st *avp = (
const struct radcli_avp_st *)a;
898 const struct radcli_avp_st *avp = (
const struct radcli_avp_st *)a;
909 if (avp->len > 0 && memchr(avp->data, 0, avp->len) != NULL) {
910 rc_log(LOG_WARNING,
"radcli_avp_get_cstr: %s contains an embedded "
911 "NUL byte, refusing to return a C string",
925 !is_valid_utf8(avp->data, avp->len)) {
926 rc_log(LOG_WARNING,
"radcli_avp_get_cstr: %s contains invalid "
927 "UTF-8, refusing to return a C string",
934 return (
const char *)avp->data;
953 uint32_t attrid, uint32_t vendor,
unsigned idx)
971 uint32_t attrid, uint32_t vendor, uint32_t *out)
989 uint32_t attrid, uint32_t vendor, uint64_t *out)
1008 uint32_t attrid, uint32_t vendor,
1009 struct in6_addr *out,
unsigned *prefix)
1028 uint32_t attrid, uint32_t vendor,
1029 struct in_addr *out,
unsigned *prefix)
1048 uint32_t attrid, uint32_t vendor,
1049 const void **out,
size_t *len)
1069 uint32_t attrid, uint32_t vendor)
1118 const radcli_attr_def *def,
const char *sep)
1120 const radcli_avp *a;
1122 size_t used = 0, total = 0;
1123 size_t seplen = sep ? strlen(sep) : 0;
1124 int truncated = (buf == NULL || buflen == 0);
1129 if (buf != NULL && buflen > 0)
1132 for (idx = 0; (a =
radcli_avp_get(list, def, idx)) != NULL; idx++) {
1140 if (total > 0 && seplen > 0) {
1143 if (used + seplen >= buflen) {
1146 memcpy(buf + used, sep, seplen);
1154 if (used + slen >= buflen) {
1157 memcpy(buf + used, s, slen);
1190 const radcli_ctx *ctx, uint32_t attrid, uint32_t vendor,
1196 if (buf != NULL && buflen > 0)
1235 return list->error ? 1 : 0;
1272 const radcli_attr_def *octets, uint64_t value)
1274 rc_handle *rh = (rc_handle *)ctx;
1275 const radcli_attr_def *gigawords;
1278 return avp_list_fail(list);
1280 gigawords = (
const radcli_attr_def *)radcli_dict_attr_gigawords(rh, (
const struct radcli_dict_attr *)octets);
1281 if (gigawords == NULL) {
1282 rc_log(LOG_ERR,
"radcli_avp_add_gigawords64: %s has no gigawords= "
1284 return avp_list_fail(list);
1289 if (value > UINT32_MAX) {
1313 const radcli_attr_def *octets, uint64_t *out)
1315 const rc_handle *rh = (
const rc_handle *)ctx;
1316 const radcli_attr_def *gigawords;
1317 const radcli_avp *a;
1318 uint32_t lo, hi = 0;
1320 if (rh == NULL || octets == NULL)
1323 gigawords = (
const radcli_attr_def *)radcli_dict_attr_gigawords(rh, (
const struct radcli_dict_attr *)octets);
1324 if (gigawords == NULL)
1336 *out = ((uint64_t)hi << 32) | lo;
1356 uint32_t attrid, uint32_t vendor, uint64_t value)
1361 return avp_list_fail(list);
1374 uint32_t attrid, uint32_t vendor, uint64_t *out)
1454static void salt_decrypt(
unsigned char *plaintext,
const unsigned char *ciphertext,
size_t len,
1455 const char *secret,
const unsigned char request_authenticator[AUTH_VECTOR_LEN],
1456 const unsigned char salt[2])
1458 unsigned char keybuf[MAX_SECRET_LENGTH + AUTH_VECTOR_LEN + 2];
1459 unsigned char b[16];
1460 size_t secretlen = rc_secret_len(secret);
1463 memcpy(keybuf, secret, secretlen);
1464 memcpy(keybuf + secretlen, request_authenticator, AUTH_VECTOR_LEN);
1465 memcpy(keybuf + secretlen + AUTH_VECTOR_LEN, salt, 2);
1466 rc_md5_calc(b, keybuf, secretlen + AUTH_VECTOR_LEN + 2);
1468 for (i = 0; i < len; i += 16) {
1472 memcpy(keybuf, secret, secretlen);
1473 memcpy(keybuf + secretlen, ciphertext + i - 16, 16);
1474 rc_md5_calc(b, keybuf, secretlen + 16);
1476 for (j = 0; j < 16; j++)
1477 plaintext[i + j] = ciphertext[i + j] ^ b[j];
1501static void user_password_encrypt(
unsigned char *ciphertext,
const unsigned char *plaintext,
size_t len,
1503 const unsigned char request_authenticator[AUTH_VECTOR_LEN])
1505 unsigned char keybuf[MAX_SECRET_LENGTH + AUTH_VECTOR_LEN];
1506 unsigned char b[16];
1507 size_t secretlen = rc_secret_len(secret);
1510 memcpy(keybuf, secret, secretlen);
1511 memcpy(keybuf + secretlen, request_authenticator, AUTH_VECTOR_LEN);
1512 rc_md5_calc(b, keybuf, secretlen + AUTH_VECTOR_LEN);
1514 for (i = 0; i < len; i += 16) {
1518 memcpy(keybuf, secret, secretlen);
1519 memcpy(keybuf + secretlen, ciphertext + i - 16, 16);
1520 rc_md5_calc(b, keybuf, secretlen + 16);
1522 for (j = 0; j < 16; j++)
1523 ciphertext[i + j] = plaintext[i + j] ^ b[j];
1540static int avp_decode_into(rc_handle
const *rh,
const char *secret,
1541 const uint8_t request_authenticator[AUTH_VECTOR_LEN],
1542 struct radcli_avp_list_st *list,
1543 const uint8_t *ptr_in,
size_t length, uint32_t vendorspec)
1546 const uint8_t *attr_data, *ptr;
1549 const radcli_attr_def *def;
1551 pb_init_read(&pb, (
void *)(uintptr_t)ptr_in, length, length);
1553 while (pb_len(&pb) > 0) {
1554 if (pb_len(&pb) < 2) {
1555 rc_log(LOG_ERR,
"radcli_avp_decode: received attribute with invalid length");
1558 attrlen = pb.data[1];
1559 if (attrlen < 2 || (
size_t)attrlen > pb_len(&pb)) {
1560 rc_log(LOG_ERR,
"radcli_avp_decode: received attribute with invalid length");
1564 attr_data = pb.data;
1565 if (pb_pull(&pb, attrlen) != 0) {
1566 rc_log(LOG_ERR,
"radcli_avp_decode: internal pb_pull failure");
1570 ptr = attr_data + 2;
1573 if (vendorspec == 0 && attr_data[0] == PW_VENDOR_SPECIFIC) {
1575 rc_log(LOG_WARNING,
"radcli_avp_decode: received VSA attribute with invalid length");
1578 memcpy(&lvalue, ptr, 4);
1579 lvalue = ntohl(lvalue);
1580 if (radcli_dict_vendor_by_pec(rh, lvalue) == NULL) {
1581 rc_log(LOG_WARNING,
"radcli_avp_decode: received VSA attribute "
1582 "with unknown Vendor-Id %u", lvalue);
1585 if (avp_decode_into(rh, secret, request_authenticator, list,
1586 ptr + 4, (
size_t)(attrlen - 4), lvalue) < 0)
1593 if (vendorspec == 0)
1594 rc_log(LOG_WARNING,
"radcli_avp_decode: received unknown "
1595 "attribute %u of length %d", (
unsigned)attr_data[0], attrlen + 2);
1597 rc_log(LOG_WARNING,
"radcli_avp_decode: received unknown VSA "
1598 "attribute %u, vendor %u of length %d",
1599 (
unsigned)attr_data[0], vendorspec, attrlen + 2);
1604 struct radcli_dict_flags *fl = radcli_dict_flags_by_id(rh, ((
const struct radcli_dict_attr *)def)->value);
1606 if (fl != NULL && fl->encrypt_type == 2) {
1617 size_t off = fl->has_tag ? 1 : 0;
1619 if (secret == NULL || request_authenticator == NULL) {
1620 rc_log(LOG_WARNING,
"radcli_avp_decode: %s is salt-encrypted "
1621 "but no secret/request authenticator was supplied; skipping",
1623 }
else if ((
size_t)attrlen < off + 2 + 16 ||
1624 ((
size_t)attrlen - off - 2) % 16 != 0) {
1625 rc_log(LOG_WARNING,
"radcli_avp_decode: %s has an invalid "
1628 size_t ctlen = (size_t)attrlen - off - 2;
1629 unsigned char plain[AUTH_STRING_LEN];
1630 unsigned char salt[2];
1631 unsigned char lenoct;
1633 memcpy(salt, ptr + off, 2);
1634 salt_decrypt(plain, ptr + off + 2, ctlen, secret,
1635 request_authenticator, salt);
1637 if (lenoct > ctlen - 1) {
1638 rc_log(LOG_WARNING,
"radcli_avp_decode: %s decrypted to "
1641 plain + 1, lenoct) != 0) {
1665 if (attrlen != (
int)
sizeof(uint64_t)) {
1666 rc_log(LOG_WARNING,
"radcli_avp_decode: %s has an invalid "
1667 "integer64/ifid length (%d, expected 8)",
1671 memcpy(&hi, ptr,
sizeof(hi));
1672 memcpy(&lo, ptr +
sizeof(hi),
sizeof(lo));
1673 hostval = ((uint64_t)ntohl(hi) << 32) | ntohl(lo);
1675 &hostval,
sizeof(hostval)) != 0)
1682 uint32_t netval, hostval;
1684 if (attrlen != (
int)
sizeof(uint32_t)) {
1685 rc_log(LOG_WARNING,
"radcli_avp_decode: %s has an invalid "
1686 "integer/ipaddr/date length (%d, expected 4)",
1690 memcpy(&netval, ptr,
sizeof(netval));
1691 hostval = ntohl(netval);
1693 &hostval,
sizeof(hostval)) != 0)
1727int radcli_avp_decode(rc_handle
const *rh,
const char *secret,
1728 const uint8_t request_authenticator[AUTH_VECTOR_LEN],
1729 const uint8_t *ptr,
size_t length,
1730 uint32_t vendorspec, radcli_avp_list **out)
1732 struct radcli_avp_list_st *list;
1734 if (rh == NULL || out == NULL)
1741 if (avp_decode_into(rh, secret, request_authenticator, list, ptr, length, vendorspec) != 0) {
1746 *out = (radcli_avp_list *)list;
1789int radcli_avp_encode(rc_handle
const *rh,
const radcli_avp_list *l,
const char *secret,
1790 const uint8_t request_authenticator[AUTH_VECTOR_LEN],
1791 uint8_t *buf,
size_t buflen,
size_t *n_encrypted)
1793 const struct radcli_avp_list_st *list = (
const struct radcli_avp_list_st *)l;
1794 const struct radcli_avp_st *a = NULL;
1796 uint8_t *attr_start, *attr_len_ptr, *vsa_len_ptr;
1797 uint32_t vendor, attrid, netval;
1800 if (rh == NULL || list == NULL)
1803 if (n_encrypted != NULL)
1806 pb_init(&pb, buf, buflen);
1808 list_for_each(&list->head, a, node) {
1809 const struct radcli_dict_attr *def = (
const struct radcli_dict_attr *)a->def;
1810 struct radcli_dict_flags *fl = radcli_dict_flags_by_id(rh, def->value);
1812 vendor = VENDOR(def->value);
1813 attrid = ATTRID(def->value);
1826 switch (fl ? fl->encrypt_type : 0) {
1830 unsigned char passbuf[AUTH_PASS_LEN];
1831 unsigned char cipher[AUTH_PASS_LEN];
1834 if (secret == NULL || request_authenticator == NULL) {
1835 rc_log(LOG_ERR,
"radcli_avp_encode: %s requires the shared "
1836 "secret and request authenticator, which were not supplied",
1840 if (a->len > AUTH_PASS_LEN) {
1846 rc_log(LOG_ERR,
"radcli_avp_encode: %s is %zu bytes, longer "
1847 "than the %d-byte RFC 2865 SS5.2 maximum",
1848 def->name, a->len, AUTH_PASS_LEN);
1852 padded_len = ((a->len + (AUTH_VECTOR_LEN - 1)) / AUTH_VECTOR_LEN) * AUTH_VECTOR_LEN;
1853 if (padded_len == 0)
1854 padded_len = AUTH_VECTOR_LEN;
1859 memset(passbuf, 0,
sizeof(passbuf));
1861 memcpy(passbuf, a->data, a->len);
1862 user_password_encrypt(cipher, passbuf, padded_len, secret, request_authenticator);
1864 attr_start = pb.tail;
1865 if (pb_put_byte(&pb, (uint8_t)(attrid & 0xff)) < 0)
goto too_large;
1866 attr_len_ptr = pb.tail;
1867 if (pb_put_byte(&pb, 2) < 0)
goto too_large;
1868 if (pb_put_bytes(&pb, cipher, (
int)padded_len) < 0)
goto too_large;
1869 *attr_len_ptr = (uint8_t)(pb.tail - attr_start);
1870 if (n_encrypted != NULL)
1875 rc_log(LOG_ERR,
"radcli_avp_encode: %s requires per-request "
1876 "encryption, which this function does not perform", def->name);
1880 if (vendor == 0 && attrid > 0xff) {
1886 rc_log(LOG_ERR,
"radcli_avp_encode: %s has an attribute number "
1887 "outside the classic RADIUS TLV range", def->name);
1893 if (pb_put_byte(&pb, PW_VENDOR_SPECIFIC) < 0)
goto too_large;
1894 vsa_len_ptr = pb.tail;
1895 if (pb_put_byte(&pb, 6) < 0)
goto too_large;
1896 netval = htonl(vendor);
1897 if (pb_put_bytes(&pb, &netval,
sizeof(netval)) < 0)
goto too_large;
1900 attr_start = pb.tail;
1901 if (pb_put_byte(&pb, (uint8_t)(attrid & 0xff)) < 0)
goto too_large;
1902 attr_len_ptr = pb.tail;
1903 if (pb_put_byte(&pb, 2) < 0)
goto too_large;
1912 if (a->len !=
sizeof(uint64_t)) {
1913 rc_log(LOG_ERR,
"radcli_avp_encode: %s has the wrong stored "
1914 "length for its type", def->name);
1917 memcpy(&hostval, a->data,
sizeof(hostval));
1918 hi = htonl((uint32_t)(hostval >> 32));
1919 lo = htonl((uint32_t)hostval);
1920 if (pb_put_bytes(&pb, &hi,
sizeof(hi)) < 0)
goto too_large;
1921 if (pb_put_bytes(&pb, &lo,
sizeof(lo)) < 0)
goto too_large;
1925 if (a->len !=
sizeof(uint32_t)) {
1926 rc_log(LOG_ERR,
"radcli_avp_encode: %s has the wrong stored "
1927 "length for its type", def->name);
1930 memcpy(&hostval, a->data,
sizeof(hostval));
1931 netval = htonl(hostval);
1932 if (pb_put_bytes(&pb, &netval,
sizeof(netval)) < 0)
goto too_large;
1934 if (a->len > AUTH_STRING_LEN - (vendor != 0 ? VSA_HDR_LEN : 0)) {
1935 rc_log(LOG_ERR,
"radcli_avp_encode: %s value too long (%zu bytes)",
1939 if (pb_put_bytes(&pb, a->data, (
int)a->len) < 0)
goto too_large;
1942 *attr_len_ptr = (uint8_t)(pb.tail - attr_start);
1943 if (vsa_len_ptr != NULL)
1944 *vsa_len_ptr += *attr_len_ptr;
1947 return (
int)pb_written(&pb);
1950 rc_log(LOG_ERR,
"radcli_avp_encode: attribute value too large or buffer "
1951 "would exceed %zu bytes", buflen);
int radcli_avp_add_ip4prefix(radcli_avp_list *list, const radcli_attr_def *def, struct in_addr value, unsigned prefix)
Append an IPv4-prefix-typed attribute.
int radcli_avp_get_uint64(const radcli_avp *a, uint64_t *out)
Read an attribute's value as a 64-bit integer or ifid.
int radcli_avp_add_username(radcli_avp_list *list, const radcli_ctx *ctx, const char *username, const char *realm)
Append a User-Name AVP, appending a realm as "username@realm" unless username already contains one.
int radcli_avp_concat_str(char *buf, size_t buflen, const radcli_avp_list *list, const radcli_attr_def *def, const char *sep)
Concatenate every occurrence of an attribute into a bounded buffer.
int radcli_avp_get_uint64_by_num(const radcli_avp_list *list, const radcli_ctx *ctx, uint32_t attrid, uint32_t vendor, uint64_t *out)
Look up a 64-bit integer-typed attribute by legacy numeric ID and read its first occurrence.
int radcli_avp_get_gigawords64_by_num(const radcli_ctx *ctx, const radcli_avp_list *list, uint32_t attrid, uint32_t vendor, uint64_t *out)
Look up the octets attribute by legacy numeric ID and reassemble a 64-bit counter from an Octets/Giga...
const radcli_avp * radcli_avp_get_by_num(const radcli_avp_list *list, const radcli_ctx *ctx, uint32_t attrid, uint32_t vendor, unsigned idx)
Look up the idx-th occurrence of an attribute by legacy numeric ID.
int radcli_avp_add_ip6_by_num(radcli_avp_list *list, const radcli_ctx *ctx, uint32_t attrid, uint32_t vendor, const struct in6_addr *value, unsigned prefix)
Look up an IPv6-address or IPv6-prefix-typed attribute by legacy numeric ID and append it.
int radcli_avp_list_error(const radcli_avp_list *list)
Check whether any radcli_avp_add_*()/_by_num() call on list has ever failed.
int radcli_avp_get_ip4prefix_by_num(const radcli_avp_list *list, const radcli_ctx *ctx, uint32_t attrid, uint32_t vendor, struct in_addr *out, unsigned *prefix)
Look up an IPv4-prefix-typed attribute by legacy numeric ID and read its first occurrence.
void radcli_avp_list_free(radcli_avp_list *list)
Free a list and every attribute it holds.
int radcli_avp_add_uint32_by_num(radcli_avp_list *list, const radcli_ctx *ctx, uint32_t attrid, uint32_t vendor, uint32_t value)
Look up an integer/IPv4-address/date-typed attribute by legacy numeric ID and append it.
int radcli_avp_add_uint64_by_num(radcli_avp_list *list, const radcli_ctx *ctx, uint32_t attrid, uint32_t vendor, uint64_t value)
Look up a 64-bit integer-typed attribute by legacy numeric ID and append it.
int radcli_avp_concat_str_by_num(char *buf, size_t buflen, const radcli_avp_list *list, const radcli_ctx *ctx, uint32_t attrid, uint32_t vendor, const char *sep)
Look up an attribute by legacy numeric ID and concatenate every occurrence into a bounded buffer.
radcli_avp_iter radcli_avp_list_iter(const radcli_avp_list *list)
Begin iterating list.
int radcli_avp_add_bytes_by_num(radcli_avp_list *list, const radcli_ctx *ctx, uint32_t attrid, uint32_t vendor, const void *value, size_t len)
Look up an attribute by legacy numeric ID and append its bytes.
int radcli_avp_add_str_by_num(radcli_avp_list *list, const radcli_ctx *ctx, uint32_t attrid, uint32_t vendor, const char *value)
Look up a string-typed attribute by legacy numeric ID and append it.
const radcli_avp * radcli_avp_get(const radcli_avp_list *list, const radcli_attr_def *def, unsigned idx)
Find the idx-th occurrence of an attribute in a list.
int radcli_avp_get_ip6(const radcli_avp *a, struct in6_addr *out, unsigned *prefix)
Read an attribute's value as an IPv6 address or prefix.
int radcli_avp_get_uint32_by_num(const radcli_avp_list *list, const radcli_ctx *ctx, uint32_t attrid, uint32_t vendor, uint32_t *out)
Look up an integer/IPv4-address/date-typed attribute by legacy numeric ID and read its first occurren...
int radcli_avp_add_ip4prefix_by_num(radcli_avp_list *list, const radcli_ctx *ctx, uint32_t attrid, uint32_t vendor, struct in_addr value, unsigned prefix)
Look up an IPv4-prefix-typed attribute by legacy numeric ID and append it.
int radcli_avp_add_ip6(radcli_avp_list *list, const radcli_attr_def *def, const struct in6_addr *value, unsigned prefix)
Append an IPv6-address or IPv6-prefix-typed attribute.
int radcli_avp_get_gigawords64(const radcli_ctx *ctx, const radcli_avp_list *list, const radcli_attr_def *octets, uint64_t *out)
Reassemble a 64-bit counter from an Octets/Gigawords attribute pair.
int radcli_avp_add_ip4(radcli_avp_list *list, const radcli_attr_def *def, struct in_addr value)
Append an IPv4-address-typed attribute from a struct in_addr.
int radcli_avp_get_ip4prefix(const radcli_avp *a, struct in_addr *out, unsigned *prefix)
Read an attribute's value as an IPv4 prefix.
const char * radcli_avp_get_cstr_by_num(const radcli_avp_list *list, const radcli_ctx *ctx, uint32_t attrid, uint32_t vendor)
Look up an attribute by legacy numeric ID and read its first occurrence as a NUL-terminated string.
int radcli_avp_add_gigawords64(radcli_ctx *ctx, radcli_avp_list *list, const radcli_attr_def *octets, uint64_t value)
Append a 64-bit counter as an Octets/Gigawords attribute pair.
int radcli_avp_get_bytes_by_num(const radcli_avp_list *list, const radcli_ctx *ctx, uint32_t attrid, uint32_t vendor, const void **out, size_t *len)
Look up an attribute by legacy numeric ID and read its first occurrence's raw bytes.
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.
int radcli_avp_get_uint32(const radcli_avp *a, uint32_t *out)
Read an attribute's value as an integer/IPv4-address/date.
int radcli_avp_add_ip4_by_num(radcli_avp_list *list, const radcli_ctx *ctx, uint32_t attrid, uint32_t vendor, struct in_addr value)
Look up an IPv4-address-typed attribute by legacy numeric ID and append it.
radcli_avp_list * radcli_avp_list_new(void)
Create an empty attribute-value pair list.
int radcli_avp_add_gigawords64_by_num(radcli_ctx *ctx, radcli_avp_list *list, uint32_t attrid, uint32_t vendor, uint64_t value)
Look up the octets attribute by legacy numeric ID and append a 64-bit counter as an Octets/Gigawords ...
const radcli_attr_def * radcli_avp_def(const radcli_avp *a)
Return the attribute definition of a.
int radcli_avp_add_uint32(radcli_avp_list *list, const radcli_attr_def *def, uint32_t value)
Append an integer/IPv4-address/date-typed attribute.
int radcli_avp_get_ip6_by_num(const radcli_avp_list *list, const radcli_ctx *ctx, uint32_t attrid, uint32_t vendor, struct in6_addr *out, unsigned *prefix)
Look up an IPv6-address or IPv6-prefix-typed attribute by legacy numeric ID and read its first occurr...
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_avp_add_str(radcli_avp_list *list, const radcli_attr_def *def, const char *value)
Append a string- or text-typed attribute.
int radcli_avp_add_uint64(radcli_avp_list *list, const radcli_attr_def *def, uint64_t value)
Append a 64-bit integer- or ifid-typed attribute.
const char * radcli_avp_get_cstr(const radcli_avp *a)
Read an attribute's value as a NUL-terminated string, with no allocation or copy.
const radcli_attr_def * radcli_dict_lookup_num(const radcli_ctx *ctx, uint32_t attrid, uint32_t vendor)
Look up a dictionary attribute by its legacy numeric ID and vendor.
const char * radcli_attr_def_name(const radcli_attr_def *def)
Return an attribute definition's canonical name.
radcli_attr_type radcli_attr_def_type(const radcli_attr_def *def)
Return an attribute definition's wire type.