Radcli library 2.0.0
A simple radius library -- legacy API reference
Loading...
Searching...
No Matches
avp-legacy-bridge.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
37
38#include <includes.h>
39#include <radcli/radcli.h>
40#include <radcli/radcli2.h>
41#include "dict2.h"
42#include "util.h"
43
44/* --- projection between radcli_avp_list and VALUE_PAIR (internal only) ---
45 *
46 * Not part of the public radcli2 API -- declared in lib/avp.h.
47 * Lets a VALUE_PAIR-based caller and a radcli_avp_list-based caller
48 * exchange attribute lists without either side needing to know the other's
49 * representation. Both directions are pure re-copies through the public
50 * accessors/constructors of whichever side they are producing -- no shared
51 * storage, no aliasing, one direction does not undo what the other did.
52 *
53 * radcli_avp_list_to_value_pairs() omits an attribute VALUE_PAIR's fixed-
54 * size fields cannot hold (a string/IPv6-prefix value over the wire length
55 * VALUE_PAIR's 253-octet strvalue allows, or a value whose stored length
56 * does not match its type's fixed size), logging why exactly as
57 * rc_avpair_gen() itself does (lib/avpair.c) for an attribute it does not
58 * recognise. This means a VALUE_PAIR list produced this way is
59 * never longer, and is byte-identical for every attribute it does carry, to
60 * what the legacy decoder would have produced from the same wire data
61 * directly -- including a decrypted Tunnel-Password or MS-MPPE-*-Key
62 * attribute, which arrives here as an ordinary plaintext string, already
63 * decrypted by whichever radcli_avp_decode() call produced the source list.
64 *
65 * radcli_value_pairs_to_avp_list() is the reverse: encryption is not a
66 * concern in this direction, since it happens later, in
67 * radcli_avp_encode() itself, driven by the same dictionary encrypt=N flag
68 * regardless of which representation the caller started from.
69 */
70
71/*- Convert a radcli_avp_list into a VALUE_PAIR list, byte-identical to what
72 * the legacy decoder would have produced from the same wire data.
73 *
74 * @param rh a handle to parsed configuration.
75 * @param l the attribute list to convert.
76 * @param out set to the newly allocated VALUE_PAIR list (possibly NULL/
77 * empty) on success.
78 * @return 0 on success, -1 if rh or out is NULL, or on allocation failure.
79 -*/
80int radcli_avp_list_to_value_pairs(rc_handle const *rh, const radcli_avp_list *l, VALUE_PAIR **out)
81{
82 radcli_avp_iter it;
83 const radcli_avp *a;
84 VALUE_PAIR *head = NULL, **tail = &head;
85
86 if (rh == NULL || out == NULL)
87 return -1;
88
89 /* Walked via the same public radcli_avp_list_iter()/radcli_avp_iter_next()/
90 * radcli_avp_def()/radcli_avp_get_bytes() API any other libradcli2
91 * caller uses -- l is a NULL-safe, empty iterator per
92 * radcli_avp_list_iter()'s own contract, so no separate NULL check is
93 * needed here. def is cast to lib/dict2.h's concrete struct
94 * radcli_dict_attr the same way lib/avp.c itself already does
95 * (radcli_dict_attr_gigawords()/radcli_dict_flags_by_id() call sites)
96 * -- radcli_attr_def is that struct's public, opaque name. */
97 it = radcli_avp_list_iter(l);
98 while ((a = radcli_avp_iter_next(&it)) != NULL) {
99 const struct radcli_dict_attr *def = (const struct radcli_dict_attr *)radcli_avp_def(a);
100 /* def->type may be one of dict2-parse.c's RFC 8044 sentinel types
101 * (integer64/ipv4prefix/text/ifid) for a bundled-dictionary
102 * attribute (e.g. User-Name as "text") -- narrow to the legacy
103 * rc_attr_type these switch()es and vp->type actually handle;
104 * see radcli_dict_type_to_legacy()'s comment (lib/dict2.h). */
105 rc_attr_type type = radcli_dict_type_to_legacy(def->type);
106 unsigned max_vlen = (VENDOR(def->value) != 0) ? (AUTH_STRING_LEN - VSA_HDR_LEN) : AUTH_STRING_LEN;
107 const void *data;
108 size_t len;
109 VALUE_PAIR *vp;
110
111 radcli_avp_get_bytes(a, &data, &len);
112
113 switch (type) {
114 case PW_TYPE_STRING:
116 if (len > max_vlen) {
117 rc_log(LOG_WARNING, "radcli_avp_list_to_value_pairs: %s: "
118 "%zu bytes exceeds VALUE_PAIR's %u-byte limit, omitting",
119 def->name, len, max_vlen);
120 continue; /* omitted: does not fit VALUE_PAIR's wire limit */
121 }
122 break;
123 case PW_TYPE_IPV6ADDR:
124 if (len != 16) {
125 rc_log(LOG_WARNING, "radcli_avp_list_to_value_pairs: %s: "
126 "%zu bytes, expected 16, omitting", def->name, len);
127 continue;
128 }
129 break;
130 case PW_TYPE_INTEGER:
131 case PW_TYPE_IPADDR:
132 case PW_TYPE_DATE:
133 if (len != sizeof(uint32_t)) {
134 rc_log(LOG_WARNING, "radcli_avp_list_to_value_pairs: %s: "
135 "%zu bytes, expected 4, omitting", def->name, len);
136 continue;
137 }
138 break;
139 default:
140 continue; /* unreachable: radcli_attr_type has no other value */
141 }
142
143 vp = calloc(1, sizeof(*vp));
144 if (vp == NULL) {
145 rc_log(LOG_CRIT, "radcli_avp_list_to_value_pairs: out of memory");
146 rc_avpair_free(head);
147 return -1;
148 }
149 strlcpy(vp->name, def->name, sizeof(vp->name));
150 vp->attribute = def->value;
151 vp->type = type;
152
153 switch (type) {
154 case PW_TYPE_STRING:
156 memcpy(vp->strvalue, data, len);
157 vp->lvalue = (uint32_t)len;
158 break;
159 case PW_TYPE_IPV6ADDR:
160 memcpy(vp->strvalue, data, 16);
161 vp->lvalue = 16;
162 break;
163 case PW_TYPE_INTEGER:
164 case PW_TYPE_IPADDR:
165 case PW_TYPE_DATE:
166 memcpy(&vp->lvalue, data, sizeof(uint32_t));
167 break;
168 default:
169 break;
170 }
171
172 *tail = vp;
173 tail = &vp->next;
174 }
175
176 *out = head;
177 return 0;
178}
179
180/*- Convert a VALUE_PAIR list into a radcli_avp_list.
181 *
182 * @param rh a handle to parsed configuration.
183 * @param vp the VALUE_PAIR list to convert.
184 * @param out set to the newly allocated radcli_avp_list on success.
185 * @return 0 on success, -1 if rh or out is NULL, or on allocation failure.
186 -*/
187int radcli_value_pairs_to_avp_list(rc_handle const *rh, VALUE_PAIR *vp, radcli_avp_list **out)
188{
189 radcli_avp_list *list;
190
191 if (rh == NULL || out == NULL)
192 return -1;
193
194 list = radcli_avp_list_new();
195 if (list == NULL)
196 return -1;
197
198 for (; vp != NULL; vp = vp->next) {
199 const radcli_attr_def *def = radcli_dict_lookup_num(rh, (uint32_t)ATTRID(vp->attribute),
200 (uint32_t)VENDOR(vp->attribute));
201
202 if (def == NULL) {
203 /* Defensive only: a VALUE_PAIR built via rc_avpair_add()/
204 * rc_avpair_gen() against this same rh always has one. */
205 continue;
206 }
207
208 switch (vp->type) {
209 case PW_TYPE_STRING:
210 case PW_TYPE_IPV6ADDR:
212 if (radcli_avp_add_bytes(list, def, vp->strvalue, vp->lvalue) != 0) {
213 radcli_avp_list_free(list);
214 return -1;
215 }
216 break;
217 case PW_TYPE_INTEGER:
218 case PW_TYPE_IPADDR:
219 case PW_TYPE_DATE:
220 if (radcli_avp_add_bytes(list, def, &vp->lvalue, sizeof(vp->lvalue)) != 0) {
221 radcli_avp_list_free(list);
222 return -1;
223 }
224 break;
225 default:
226 break;
227 }
228 }
229
230 *out = list;
231 return 0;
232}
void rc_avpair_free(VALUE_PAIR *pair)
Frees all value_pairs in the list.
Definition avpair.c:569
rc_attr_type
Definition radcli.h:127
@ PW_TYPE_IPADDR
The attribute is an IPv4 address in host-byte order.
Definition radcli.h:130
@ PW_TYPE_IPV6ADDR
The attribute is an 128-bit IPv6 address.
Definition radcli.h:132
@ PW_TYPE_IPV6PREFIX
The attribute is an IPv6 prefix; the lvalue will indicate its size.
Definition radcli.h:133
@ PW_TYPE_INTEGER
The attribute is a 32-bit integer.
Definition radcli.h:129
@ PW_TYPE_DATE
The attribute contains a 32-bit number indicating the seconds since epoch.
Definition radcli.h:131
@ PW_TYPE_STRING
The attribute is a printable string.
Definition radcli.h:128
rc_attr_type type
attribute type.
Definition radcli.h:258
uint64_t attribute
attribute numeric value of type rc_attr_id including vendor; use VENDOR() and ATTRID() to separate.
Definition radcli.h:257
uint32_t lvalue
attribute value if type is PW_TYPE_INTEGER, PW_TYPE_DATE or PW_TYPE_IPADDR.
Definition radcli.h:259
char strvalue[AUTH_STRING_LEN+1]
contains attribute value in other cases.
Definition radcli.h:260
char name[RC_NAME_LENGTH+1]
attribute name if known.
Definition radcli.h:256