Radcli library 2.0.0
A simple radius library -- new API reference
Loading...
Searching...
No Matches
dict2.c
1/*
2 * Copyright (C) 2026 Nikos Mavrogiannopoulos
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
36
37#include <config.h>
38#include <includes.h>
39#include <limits.h>
40#include <radcli/radcli.h>
41#include <radcli/radcli2.h>
42#include "dict2.h"
43#include "util.h"
44
45/*- Free rh's dictionary and every attribute/value/vendor/flags/gigawords
46 * entry it holds.
47 *
48 * @param rh a handle whose dictionary is to be freed.
49 -*/
50void radcli2_priv_dict_free(rc_handle *rh)
51{
52 struct radcli_dict_attr *a, *atmp;
53 struct radcli_dict_value *v, *vtmp;
54 struct radcli_dict_vendor *w, *wtmp;
55 struct radcli_dict_flags *fl, *fltmp;
56 struct radcli_dict_gigawords *gw, *gwtmp;
57 struct radcli_dict *d = rh->dict;
58
59 if (d == NULL)
60 return;
61
62 /* HASH_DELETE() is skipped under __clang_analyzer__ (never in a real
63 * build -- dynamically verified LSan/ASan/UBSan-clean, and this
64 * function is exercised via radcli2_priv_destroy() throughout the test suite).
65 * Clang Static Analyzer's unix.Malloc checker misreads ordinary
66 * HASH_ITER()+HASH_DELETE()+free() teardown as a use-after-free: a
67 * confirmed false positive, reported against uthash itself and closed
68 * as a checker limitation -- github.com/troydhanson/uthash#128. The
69 * free() calls stay visible to the analyzer in every build, so the
70 * leak checker still sees every allocation matched with a
71 * deallocation; only the macro shape that misleads the
72 * use-after-free checker is hidden. */
73 HASH_ITER(hh_name, d->attrs_by_name, a, atmp) {
74#ifndef __clang_analyzer__
75 HASH_DELETE(hh_name, d->attrs_by_name, a);
76 HASH_DELETE(hh_id, d->attrs_by_id, a);
77#endif
78 free(a->legacy);
79 free(a);
80 }
81 HASH_ITER(hh_name, d->values_by_name, v, vtmp) {
82#ifndef __clang_analyzer__
83 HASH_DELETE(hh_name, d->values_by_name, v);
84 HASH_DELETE(hh_attr, d->values_by_attr, v);
85 HASH_DELETE(hh_attr_name, d->values_by_attr_name, v);
86#endif
87 free(v->legacy);
88 free(v);
89 }
90 HASH_ITER(hh_name, d->vendors_by_name, w, wtmp) {
91#ifndef __clang_analyzer__
92 HASH_DELETE(hh_name, d->vendors_by_name, w);
93 HASH_DELETE(hh_pec, d->vendors_by_pec, w);
94#endif
95 free(w->legacy);
96 free(w);
97 }
98 HASH_ITER(hh, d->flags_by_attr_id, fl, fltmp) {
99#ifndef __clang_analyzer__
100 HASH_DELETE(hh, d->flags_by_attr_id, fl);
101#endif
102 free(fl);
103 }
104 HASH_ITER(hh, d->gigawords_by_attr_id, gw, gwtmp) {
105#ifndef __clang_analyzer__
106 HASH_DELETE(hh, d->gigawords_by_attr_id, gw);
107#endif
108 free(gw);
109 }
110
111 free(d);
112 rh->dict = NULL;
113 /* rh->first_dict_read is intentionally left untouched -- see
114 * REQ-DICT-DATA-008; owned/released by radcli2_priv_config_free() instead. */
115}
116
117/*- Look up a dictionary attribute by its case-insensitive name.
118 *
119 * @param rh a handle to parsed configuration.
120 * @param name the attribute name.
121 * @return the attribute, or NULL if rh/name is NULL, rh has no dictionary,
122 * or no such attribute is loaded.
123 -*/
124struct radcli_dict_attr *radcli_dict_attr_by_name(rc_handle const *rh, const char *name)
125{
126 /* dict2_lc() only fills up to its NUL terminator; zero the tail so
127 * the whole buffer is initialized before HASH_FIND() hashes it
128 * (bounded to strlen(key) either way, but not provably so to Clang
129 * Static Analyzer -- MemorySanitizer confirms it's a false concern). */
130 char key[RC_DICT2_KEY_LEN] = {0};
131 struct radcli_dict_attr *out;
132
133 if (rh == NULL || rh->dict == NULL || name == NULL)
134 return NULL;
135
136 dict2_lc(key, sizeof(key), name);
137 HASH_FIND(hh_name, rh->dict->attrs_by_name, key, strlen(key), out);
138 return out;
139}
140
141/*- Look up a dictionary attribute by its RADCLI_VENDOR_ATTR_SET-combined
142 * attribute/vendor ID.
143 *
144 * @param rh a handle to parsed configuration.
145 * @param value the combined attribute/vendor ID.
146 * @return the attribute, or NULL if rh is NULL, rh has no dictionary, or
147 * no such attribute is loaded.
148 -*/
149struct radcli_dict_attr *radcli_dict_attr_by_id(rc_handle const *rh, uint64_t value)
150{
151 struct radcli_dict_attr *out;
152
153 if (rh == NULL || rh->dict == NULL)
154 return NULL;
155
156 HASH_FIND(hh_id, rh->dict->attrs_by_id, &value, sizeof(value), out);
157 return out;
158}
159
160/*- Look up a dictionary VALUE by its case-insensitive name, across every
161 * attribute.
162 *
163 * @param rh a handle to parsed configuration.
164 * @param name the VALUE's name.
165 * @return the VALUE, or NULL if rh/name is NULL, rh has no dictionary, or
166 * no such VALUE is loaded.
167 -*/
168struct radcli_dict_value *radcli_dict_value_by_name(rc_handle const *rh, const char *name)
169{
170 /* dict2_lc() only fills up to its NUL terminator; zero the tail so
171 * the whole buffer is initialized before HASH_FIND() hashes it
172 * (bounded to strlen(key) either way, but not provably so to Clang
173 * Static Analyzer -- MemorySanitizer confirms it's a false concern). */
174 char key[RC_DICT2_KEY_LEN] = {0};
175 struct radcli_dict_value *out;
176
177 if (rh == NULL || rh->dict == NULL || name == NULL)
178 return NULL;
179
180 dict2_lc(key, sizeof(key), name);
181 HASH_FIND(hh_name, rh->dict->values_by_name, key, strlen(key), out);
182 return out;
183}
184
185/*- Look up a dictionary VALUE by its attribute name and numeric value.
186 *
187 * @param rh a handle to parsed configuration.
188 * @param attrname the attribute the VALUE belongs to.
189 * @param value the VALUE's numeric value.
190 * @return the VALUE, or NULL if rh/attrname is NULL, rh has no dictionary,
191 * or no such VALUE is loaded.
192 -*/
193struct radcli_dict_value *radcli_dict_value_by_attr(rc_handle const *rh, const char *attrname, uint32_t value)
194{
195 struct radcli_dict_value_key key;
196 struct radcli_dict_value *out;
197
198 if (rh == NULL || rh->dict == NULL || attrname == NULL)
199 return NULL;
200
201 memset(&key, 0, sizeof(key));
202 dict2_lc(key.attrname_key, sizeof(key.attrname_key), attrname);
203 key.value = value;
204
205 HASH_FIND(hh_attr, rh->dict->values_by_attr, &key, sizeof(key), out);
206 return out;
207}
208
209/*- Look up a dictionary VALUE by its attribute name and its own name.
210 *
211 * @param rh a handle to parsed configuration.
212 * @param attrname the attribute the VALUE belongs to.
213 * @param name the VALUE's name.
214 * @return the VALUE, or NULL if rh/attrname/name is NULL, rh has no
215 * dictionary, or no such VALUE is loaded.
216 -*/
217struct radcli_dict_value *radcli_dict_value_by_attr_name(rc_handle const *rh, const char *attrname, const char *name)
218{
219 struct radcli_dict_value_name_key key;
220 struct radcli_dict_value *out;
221
222 if (rh == NULL || rh->dict == NULL || attrname == NULL || name == NULL)
223 return NULL;
224
225 memset(&key, 0, sizeof(key));
226 dict2_lc(key.attrname_key, sizeof(key.attrname_key), attrname);
227 dict2_lc(key.name_key, sizeof(key.name_key), name);
228
229 HASH_FIND(hh_attr_name, rh->dict->values_by_attr_name, &key, sizeof(key), out);
230 return out;
231}
232
233/*- Look up a dictionary vendor by its case-insensitive name.
234 *
235 * @param rh a handle to parsed configuration.
236 * @param name the vendor name.
237 * @return the vendor, or NULL if rh/name is NULL, rh has no dictionary, or
238 * no such vendor is loaded.
239 -*/
240struct radcli_dict_vendor *radcli_dict_vendor_by_name(rc_handle const *rh, const char *name)
241{
242 /* dict2_lc() only fills up to its NUL terminator; zero the tail so
243 * the whole buffer is initialized before HASH_FIND() hashes it
244 * (bounded to strlen(key) either way, but not provably so to Clang
245 * Static Analyzer -- MemorySanitizer confirms it's a false concern). */
246 char key[RC_DICT2_KEY_LEN] = {0};
247 struct radcli_dict_vendor *out;
248
249 if (rh == NULL || rh->dict == NULL || name == NULL)
250 return NULL;
251
252 dict2_lc(key, sizeof(key), name);
253 HASH_FIND(hh_name, rh->dict->vendors_by_name, key, strlen(key), out);
254 return out;
255}
256
257/*- Look up a dictionary vendor by its IANA Private Enterprise Number.
258 *
259 * @param rh a handle to parsed configuration.
260 * @param pec the vendor's PEN.
261 * @return the vendor, or NULL if rh is NULL, rh has no dictionary, or no
262 * such vendor is loaded.
263 -*/
264struct radcli_dict_vendor *radcli_dict_vendor_by_pec(rc_handle const *rh, uint32_t pec)
265{
266 struct radcli_dict_vendor *out;
267
268 if (rh == NULL || rh->dict == NULL)
269 return NULL;
270
271 HASH_FIND(hh_pec, rh->dict->vendors_by_pec, &pec, sizeof(pec), out);
272 return out;
273}
274
275/*- Look up an attribute's dictionary flags (e.g. encrypt=) by its combined
276 * attribute/vendor ID.
277 *
278 * @param rh a handle to parsed configuration.
279 * @param attr_id the combined attribute/vendor ID.
280 * @return the flags entry, or NULL if rh is NULL, rh has no dictionary, or
281 * the attribute has no flags entry.
282 -*/
283struct radcli_dict_flags *radcli_dict_flags_by_id(rc_handle const *rh, uint64_t attr_id)
284{
285 struct radcli_dict_flags *out;
286
287 if (rh == NULL || rh->dict == NULL)
288 return NULL;
289
290 HASH_FIND(hh, rh->dict->flags_by_attr_id, &attr_id, sizeof(attr_id), out);
291 return out;
292}
293
294/*- Look up an Input/Output-Octets-style attribute's paired Gigawords
295 * attribute, by the octets attribute's combined attribute/vendor ID.
296 *
297 * @param rh a handle to parsed configuration.
298 * @param attr_id the octets attribute's combined attribute/vendor ID.
299 * @return the gigawords entry, or NULL if rh is NULL, rh has no
300 * dictionary, or the attribute has no paired gigawords entry.
301 -*/
302struct radcli_dict_gigawords *radcli_dict_gigawords_by_id(rc_handle const *rh, uint64_t attr_id)
303{
304 struct radcli_dict_gigawords *out;
305
306 if (rh == NULL || rh->dict == NULL)
307 return NULL;
308
309 HASH_FIND(hh, rh->dict->gigawords_by_attr_id, &attr_id, sizeof(attr_id), out);
310 return out;
311}
312
313/*- Look up an Input/Output-Octets-style attribute's paired Gigawords
314 * attribute definition.
315 *
316 * @param rh a handle to parsed configuration.
317 * @param octets the octets attribute definition.
318 * @return the gigawords attribute, or NULL if rh/octets is NULL or the
319 * attribute has no paired gigawords entry.
320 -*/
321struct radcli_dict_attr *radcli_dict_attr_gigawords(rc_handle const *rh, const struct radcli_dict_attr *octets)
322{
323 struct radcli_dict_gigawords *gw;
324
325 if (rh == NULL || octets == NULL)
326 return NULL;
327
328 gw = radcli_dict_gigawords_by_id(rh, octets->value);
329 if (gw == NULL)
330 return NULL;
331
332 return radcli_dict_attr_by_id(rh, gw->gigawords_attrid);
333}
334
335/*- Return a's legacy DICT_ATTR shadow struct, lazily materializing and
336 * caching it on first call.
337 *
338 * @param a the dictionary attribute to project.
339 * @return the cached legacy struct, or NULL if a is NULL or allocation
340 * failed.
341 -*/
342DICT_ATTR *radcli_dict_attr_to_legacy(struct radcli_dict_attr *a)
343{
344 if (a == NULL)
345 return NULL;
346
347 if (a->legacy == NULL) {
348 a->legacy = malloc(sizeof(*a->legacy));
349 if (a->legacy == NULL) {
350 rc_log(LOG_CRIT, "radcli_dict_attr_to_legacy: out of memory");
351 return NULL;
352 }
353 strlcpy(a->legacy->name, a->name, sizeof(a->legacy->name));
354 a->legacy->value = a->value;
355 a->legacy->type = radcli_dict_type_to_legacy(a->type);
356 a->legacy->next = NULL;
357 }
358 return a->legacy;
359}
360
361/*- Return v's legacy DICT_VALUE shadow struct, lazily materializing and
362 * caching it on first call.
363 *
364 * @param v the dictionary VALUE to project.
365 * @return the cached legacy struct, or NULL if v is NULL or allocation
366 * failed.
367 -*/
368DICT_VALUE *radcli_dict_value_to_legacy(struct radcli_dict_value *v)
369{
370 if (v == NULL)
371 return NULL;
372
373 if (v->legacy == NULL) {
374 v->legacy = malloc(sizeof(*v->legacy));
375 if (v->legacy == NULL) {
376 rc_log(LOG_CRIT, "radcli_dict_value_to_legacy: out of memory");
377 return NULL;
378 }
379 strlcpy(v->legacy->attrname, v->attrname, sizeof(v->legacy->attrname));
380 strlcpy(v->legacy->name, v->name, sizeof(v->legacy->name));
381 v->legacy->value = v->value;
382 v->legacy->next = NULL;
383 }
384 return v->legacy;
385}
386
387/*- Return v's legacy DICT_VENDOR shadow struct, lazily materializing and
388 * caching it on first call.
389 *
390 * @param v the dictionary vendor to project.
391 * @return the cached legacy struct, or NULL if v is NULL or allocation
392 * failed.
393 -*/
394DICT_VENDOR *radcli_dict_vendor_to_legacy(struct radcli_dict_vendor *v)
395{
396 if (v == NULL)
397 return NULL;
398
399 if (v->legacy == NULL) {
400 v->legacy = malloc(sizeof(*v->legacy));
401 if (v->legacy == NULL) {
402 rc_log(LOG_CRIT, "radcli_dict_vendor_to_legacy: out of memory");
403 return NULL;
404 }
405 strlcpy(v->legacy->vendorname, v->name, sizeof(v->legacy->vendorname));
406 v->legacy->vendorpec = v->pec;
407 v->legacy->next = NULL;
408 }
409 return v->legacy;
410}
411
417
418/* radcli_attr_def is never given its own storage: a dictionary attribute
419 * definition is a struct radcli_dict_attr, and the "opaque handle" is that
420 * same pointer under a name radcli2.h does not define. This keeps the new
421 * lookup API from duplicating the dictionary
422 * (contrib/ai/personas/radcli-core-dev.md, Design Review / Dependency
423 * growth). Unlike lib/dict.c's rc_dict_findattr()/rc_dict_getattr(), these
424 * go straight to the lookup functions above -- no legacy DICT_ATTR shadow
425 * is ever materialized for a radcli2.h caller. lib/avp.c casts a
426 * radcli_attr_def straight to struct radcli_dict_attr (not DICT_ATTR) to
427 * match. */
428
429/*- Map a dictionary's internal rc_attr_type wire type to the public
430 * radcli_attr_type enum.
431 *
432 * @param t the internal wire type, including dict2-parse.c's
433 * internal-only RFC 8044 sentinel types.
434 * @return the corresponding radcli_attr_type.
435 -*/
436static radcli_attr_type dict_type_to_radcli(rc_attr_type t)
437{
438 /* switch on the underlying int, not the rc_attr_type enum directly:
439 * the "integer64"/"ipv4prefix" sentinels below are deliberately not
440 * legal rc_attr_type enumerators (see their case comments), and
441 * -Wswitch flags any case value outside the switched-on enum's own
442 * value set when switching on an enum-typed expression. */
443 switch ((int)t) {
444 case PW_TYPE_STRING:
445 return RADCLI_TYPE_STRING;
446 case PW_TYPE_INTEGER:
447 return RADCLI_TYPE_INTEGER;
448 case PW_TYPE_IPADDR:
449 return RADCLI_TYPE_IPADDR;
450 case PW_TYPE_DATE:
451 return RADCLI_TYPE_DATE;
452 case PW_TYPE_IPV6ADDR:
454 case PW_TYPE_IPV6PREFIX:
456 case PW_TYPE_MAX:
457 /* The internal-only "integer64" sentinel -- see the "integer64"
458 * keyword's comment above. rc_dict_addattr() (the public,
459 * programmatic attribute API) still rejects type >= PW_TYPE_MAX,
460 * so this value can only ever come from the bundled dictionary
461 * file. */
463 case PW_TYPE_MAX + 1:
464 /* The internal-only "ipv4prefix" sentinel -- see lib/dict2-parse.c's
465 * "ipv4prefix" keyword comment. Same rc_dict_addattr() rejection as
466 * PW_TYPE_MAX above. */
468 case PW_TYPE_MAX + 2:
469 /* The internal-only "text" sentinel -- see lib/dict2-parse.c's
470 * "text" keyword comment. Same rc_dict_addattr() rejection as
471 * PW_TYPE_MAX above. */
472 return RADCLI_TYPE_TEXT;
473 case PW_TYPE_MAX + 3:
474 /* The internal-only "ifid" sentinel -- see lib/dict2-parse.c's
475 * "ifid" keyword comment. Same rc_dict_addattr() rejection as
476 * PW_TYPE_MAX above. */
477 return RADCLI_TYPE_IFID;
478 default:
479 /* unreachable: every legal DICT_ATTR.type value (0..PW_TYPE_MAX + 3
480 * inclusive) is handled above. */
481 return RADCLI_TYPE_STRING;
482 }
483}
484
485/* 5 = the deepest RFC 6929 form this parser accepts, even though the
486 * bundled dictionary can only resolve the 1- and 3-component ones today:
487 * vendor(26) . vendor-id . extended-type(241) . ext-attr . tlv-type. */
488#define RADCLI_OID_MAX_COMPONENTS 5
489
490/*- Parse a dot-separated OID ("1", "26.311.11") into uint32_t components.
491 *
492 * @param oid the OID text to parse.
493 * @param comp set to the parsed components, up to
494 * RADCLI_OID_MAX_COMPONENTS of them.
495 * @return the component count, or -1 if oid is NULL/empty, a component is
496 * not a plain unsigned integer, a component overflows uint32_t, or more
497 * components than fit in comp are present.
498 -*/
499static int parse_oid(const char *oid, uint32_t comp[RADCLI_OID_MAX_COMPONENTS])
500{
501 const char *p = oid;
502 int n = 0;
503
504 if (oid == NULL || *oid == '\0')
505 return -1;
506
507 while (1) {
508 char *end;
509 unsigned long v;
510
511 if (n >= RADCLI_OID_MAX_COMPONENTS)
512 return -1;
513
514 errno = 0;
515 v = strtoul(p, &end, 10);
516 if (end == p || (v == ULONG_MAX && errno == ERANGE))
517 return -1;
518#if ULONG_MAX > UINT32_MAX
519 if (v > UINT32_MAX)
520 return -1;
521#endif
522
523 comp[n++] = (uint32_t)v;
524
525 if (*end == '\0')
526 break;
527 if (*end != '.')
528 return -1;
529 p = end + 1;
530 }
531 return n;
532}
533
542const radcli_attr_def *radcli_dict_lookup(const radcli_ctx *ctx, const char *name)
543{
544 if (ctx == NULL || name == NULL)
545 return NULL;
546 return (const radcli_attr_def *)radcli_dict_attr_by_name((rc_handle const *)ctx, name);
547}
548
564const radcli_attr_def *radcli_dict_lookup_num(const radcli_ctx *ctx, uint32_t attrid, uint32_t vendor)
565{
566 if (ctx == NULL)
567 return NULL;
568 return (const radcli_attr_def *)radcli_dict_attr_by_id((rc_handle const *)ctx,
569 RADCLI_VENDOR_ATTR_SET(attrid, vendor));
570}
571
586const radcli_attr_def *radcli_dict_lookup_oid(const radcli_ctx *ctx, const char *oid)
587{
588 uint32_t comp[RADCLI_OID_MAX_COMPONENTS];
589 int n;
590
591 if (ctx == NULL)
592 return NULL;
593
594 n = parse_oid(oid, comp);
595 if (n <= 0)
596 return NULL;
597
598 if (n == 1)
599 return radcli_dict_lookup_num(ctx, comp[0], 0);
600
601 if (n == 3 && comp[0] == PW_VENDOR_SPECIFIC)
602 return radcli_dict_lookup_num(ctx, comp[2], comp[1]);
603
604 /* "26.<vendor>" alone names a vendor, not an attribute; longer forms
605 * name an RFC 6929 extended/TLV attribute the bundled dictionary does
606 * not yet carry. Both are well-formed OIDs that simply match nothing
607 * today. */
608 return NULL;
609}
610
615const char *radcli_attr_def_name(const radcli_attr_def *def)
616{
617 const struct radcli_dict_attr *a = (const struct radcli_dict_attr *)def;
618 return a ? a->name : NULL;
619}
620
624radcli_attr_type radcli_attr_def_type(const radcli_attr_def *def)
625{
626 const struct radcli_dict_attr *a = (const struct radcli_dict_attr *)def;
627 return dict_type_to_radcli(a ? a->type : PW_TYPE_STRING);
628}
629
638int radcli_attr_def_oid(const radcli_attr_def *def, char *buf, size_t buflen)
639{
640 const struct radcli_dict_attr *a = (const struct radcli_dict_attr *)def;
641 uint32_t vendor, attrid;
642
643 if (a == NULL)
644 return -1;
645
646 vendor = VENDOR(a->value);
647 attrid = ATTRID(a->value);
648
649 if (vendor == 0)
650 return snprintf(buf, buflen, "%u", attrid);
651 return snprintf(buf, buflen, "26.%u.%u", vendor, attrid);
652}
653
674int radcli_dict_lookup_value(const radcli_ctx *ctx, const radcli_attr_def *def,
675 const char *name, uint32_t *out)
676{
677 const struct radcli_dict_attr *a = (const struct radcli_dict_attr *)def;
678 const struct radcli_dict_value *v;
679
680 if (ctx == NULL || a == NULL || name == NULL || out == NULL)
681 return -1;
682
683 v = radcli_dict_value_by_attr_name((rc_handle const *)ctx, a->name, name);
684 if (v == NULL)
685 return -1;
686
687 *out = v->value;
688 return 0;
689}
690
const radcli_attr_def * radcli_dict_lookup(const radcli_ctx *ctx, const char *name)
Look up a dictionary attribute by its canonical name.
Definition dict2.c:542
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.
Definition dict2.c:564
const char * radcli_attr_def_name(const radcli_attr_def *def)
Return an attribute definition's canonical name.
Definition dict2.c:615
radcli_attr_type
Definition radcli2.h:173
const radcli_attr_def * radcli_dict_lookup_oid(const radcli_ctx *ctx, const char *oid)
Look up a dictionary attribute by RFC 6929 §2.7 OID notation.
Definition dict2.c:586
radcli_attr_type radcli_attr_def_type(const radcli_attr_def *def)
Return an attribute definition's wire type.
Definition dict2.c:624
int radcli_attr_def_oid(const radcli_attr_def *def, char *buf, size_t buflen)
Render an attribute definition's RFC 6929 §2.7 OID notation.
Definition dict2.c:638
int radcli_dict_lookup_value(const radcli_ctx *ctx, const radcli_attr_def *def, const char *name, uint32_t *out)
Resolve a dictionary VALUE by name, scoped to one attribute.
Definition dict2.c:674
@ RADCLI_TYPE_IPV6PREFIX
Definition radcli2.h:200
@ RADCLI_TYPE_TEXT
Definition radcli2.h:215
@ RADCLI_TYPE_STRING
Definition radcli2.h:174
@ RADCLI_TYPE_DATE
Definition radcli2.h:190
@ RADCLI_TYPE_IFID
Definition radcli2.h:224
@ RADCLI_TYPE_INTEGER64
Definition radcli2.h:205
@ RADCLI_TYPE_IPADDR
Definition radcli2.h:183
@ RADCLI_TYPE_IPV6ADDR
Definition radcli2.h:197
@ RADCLI_TYPE_IPV4PREFIX
Definition radcli2.h:211
@ RADCLI_TYPE_INTEGER
Definition radcli2.h:180