port to new RADIUS client library
[radsecproxy.git] / lib / avp.c
1 /* Copyright 2011 PADL Software Pty Ltd. All rights reserved.
2    See the file COPYING for licensing information.  */
3
4 #if defined HAVE_CONFIG_H
5 #include <config.h>
6 #endif
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stdint.h>
11 #include <string.h>
12 #include <libgen.h>
13 #include <assert.h>
14
15 #include <radsec/radsec.h>
16 #include <radius/client.h>
17
18 #define RS_ERR(err) ((err) < 0 ? -err : RSE_OK)
19
20 void
21 rs_avp_free (rs_avp **vps)
22 {
23   nr_vp_free (vps);
24 }
25
26 size_t
27 rs_avp_length (rs_const_avp *vp)
28 {
29   assert (vp != NULL);
30   return vp->length;
31 }
32
33 rs_attr_type_t
34 rs_avp_typeof (rs_const_avp *vp)
35 {
36   return vp ? vp->da->type : RS_TYPE_INVALID;
37 }
38
39 void
40 rs_avp_attrid (rs_const_avp *vp,
41                unsigned int *attr,
42                unsigned int *vendor)
43 {
44   *attr = vp->da->attr;
45   *vendor = vp->da->vendor;
46 }
47
48 const char *
49 rs_avp_name (rs_const_avp *vp)
50 {
51   return vp ? vp->da->name : NULL;
52 }
53
54 void
55 rs_avp_append (rs_avp **head, rs_avp *tail)
56 {
57   return nr_vps_append (head, tail);
58 }
59
60 rs_avp *
61 rs_avp_find (rs_avp *vp, unsigned int attr, unsigned int vendor)
62 {
63   if (vp == NULL)
64     return NULL;
65
66   return nr_vps_find (vp, attr, vendor);
67 }
68
69 rs_const_avp *
70 rs_avp_find_const (rs_const_avp *vp,
71                    unsigned int attr, unsigned int vendor)
72 {
73   if (vp == NULL)
74     return NULL;
75
76   return nr_vps_find ((rs_avp *)vp, attr, vendor);
77 }
78
79 rs_avp *
80 rs_avp_alloc (unsigned int attr, unsigned int vendor)
81 {
82   const DICT_ATTR *da;
83   VALUE_PAIR *vp;
84
85   da = nr_dict_attr_byvalue (attr, vendor);
86   if (da == NULL) {
87     vp = nr_vp_alloc_raw (attr, vendor);
88   } else {
89     vp = nr_vp_alloc (da);
90   }
91
92   if (vp == NULL)
93     return NULL;
94
95   return vp;
96 }
97
98 rs_avp *
99 rs_avp_dup (rs_const_avp *vp)
100 {
101   rs_avp *vp2;
102
103   vp2 = nr_vp_alloc (vp->da);
104   if (vp2 == NULL)
105     return NULL;
106
107   vp2->length = vp->length;
108   vp2->tag = vp->tag;
109   vp2->next = NULL;
110
111 #ifdef RS_TYPE_TLV
112   if (rs_avp_is_tlv (vp)) {
113     vp2->vp_tlv = malloc (vp->length);
114     if (vp2->vp_tlv == NULL) {
115       rs_avp_free (vp2);
116       return NULL;
117     }
118     memcpy (vp2->vp_tlv, vp->vp_tlv, vp->length);
119     return vp2;
120   }
121 #endif
122
123   memcpy (vp2->vp_strvalue, vp->vp_strvalue, vp->length);
124   if (rs_avp_is_string (vp))
125     vp2->vp_strvalue[vp->length] = '\0';
126
127   return vp2;
128 }
129
130 rs_avp *
131 rs_avp_next (rs_avp *avp)
132 {
133   return avp ? avp->next : NULL;
134 }
135
136 rs_const_avp *
137 rs_avp_next_const (rs_const_avp *avp)
138 {
139   return avp ? avp->next : NULL;
140 }
141
142 int
143 rs_avp_delete (rs_avp **first,
144                unsigned int attr, unsigned int vendor)
145 {
146   int found = 0;
147   rs_avp **p;
148
149   for (p = first; *p != NULL; p++) {
150     if ((*p)->da->attr == attr &&
151         (*p)->da->vendor == vendor) {
152       rs_avp *next = (*p)->next;
153
154       (*p)->next = NULL;
155       rs_avp_free (p);
156
157       *p = next;
158       found++;
159     }
160   }
161
162   return found ? RSE_OK : RSE_ATTR_UNKNOWN;
163 }
164
165 const char *
166 rs_avp_string_value (rs_const_avp *vp)
167 {
168   if (!rs_avp_is_string (vp))
169     return NULL;
170
171   return vp->vp_strvalue;
172 }
173
174 int
175 rs_avp_string_set (rs_avp *vp, const char *str)
176 {
177   int err;
178
179   if (vp == NULL)
180     return RSE_INVAL;
181   if (!rs_avp_is_string (vp))
182     return RSE_ATTR_INVALID;
183
184   err = nr_vp_set_data (vp, str, strlen (str));
185   return RS_ERR(err);
186 }
187
188 uint32_t
189 rs_avp_integer_value (rs_const_avp *vp)
190 {
191   if (!rs_avp_is_integer (vp))
192     return 0;
193   return vp->vp_integer;
194 }
195
196 int
197 rs_avp_integer_set (rs_avp *vp, uint32_t val)
198 {
199   int err;
200
201   if (vp == NULL)
202     return RSE_INVAL;
203   if (!rs_avp_is_integer (vp))
204     return RSE_ATTR_INVALID;
205
206   err = nr_vp_set_data (vp, &val, sizeof (val));
207   return RS_ERR(err);
208 }
209
210 uint32_t
211 rs_avp_ipaddr_value (rs_const_avp *vp)
212 {
213   if (!rs_avp_is_ipaddr (vp))
214     return 0;
215   return vp->vp_ipaddr;
216 }
217
218 int
219 rs_avp_ipaddr_set (rs_avp *vp, struct in_addr in)
220 {
221   int err;
222
223   if (vp == NULL)
224     return RSE_INVAL;
225   if (!rs_avp_is_ipaddr (vp))
226     return RSE_ATTR_INVALID;
227
228   err = nr_vp_set_data (vp, &in, sizeof (in));
229   return RS_ERR(err);
230 }
231
232 time_t
233 rs_avp_date_value (rs_const_avp *vp)
234 {
235   if (!rs_avp_is_date (vp))
236     return 0;
237   return vp->vp_date;
238 }
239
240 int
241 rs_avp_date_set (rs_avp *vp, time_t date)
242 {
243   uint32_t date32;
244   int err;
245
246   if (vp == NULL)
247     return RSE_INVAL;
248   if (!rs_avp_is_date (vp))
249     return RSE_ATTR_INVALID;
250   if (date > 0xFFFFFFFF)
251     return RSE_ATTR_INVALID;
252
253   date32 = (uint32_t)date;
254   err = nr_vp_set_data (vp, &date32, sizeof (date32));
255
256   return RS_ERR(err);
257 }
258
259 const unsigned char *
260 rs_avp_octets_value_const_ptr (rs_const_avp *vp)
261 {
262   return rs_avp_octets_value_ptr ((rs_avp *)vp);
263 }
264
265 unsigned char *
266 rs_avp_octets_value_ptr (rs_avp *vp)
267 {
268   if (vp == NULL)
269     return NULL;
270
271 #ifdef RS_TYPE_TLV
272   if (rs_avp_is_tlv (vp))
273     return vp->vp_tlv;
274 #endif
275
276   return vp->vp_octets;
277 }
278
279 int
280 rs_avp_octets_value_byref (rs_avp *vp,
281                            unsigned char **p,
282                            size_t *len)
283 {
284   if (vp == NULL)
285     return RSE_INVAL;
286
287   *len = vp->length;
288   *p = (unsigned char *)rs_avp_octets_value_ptr (vp);
289
290   return RSE_OK;
291 }
292
293 int
294 rs_avp_octets_value (rs_const_avp *vp,
295                      unsigned char *buf,
296                      size_t *len)
297 {
298   if (vp == NULL)
299     return RSE_INVAL;
300
301   if (vp->length > *len) {
302     *len = vp->length;
303     return RSE_ATTR_TOO_SMALL;
304   }
305
306   *len = vp->length;
307
308 #ifdef RS_TYPE_TLV
309   if (rs_avp_is_tlv (vp))
310     memcpy (buf, vp->vp_tlv, vp->length);
311   else
312 #endif
313     memcpy (buf, vp->vp_octets, vp->length);
314
315   return RSE_OK;
316 }
317
318 int
319 rs_avp_fragmented_value (rs_const_avp *vps,
320                          unsigned char *buf,
321                          size_t *len)
322 {
323   size_t total_len = 0;
324   unsigned char *p;
325   rs_const_avp *vp;
326
327   if (vps == NULL)
328     return RSE_INVAL;
329
330   if (!rs_avp_is_octets (vps) &&
331       !rs_avp_is_string (vps))
332     return RSE_ATTR_INVALID;
333
334   for (vp = vps;
335        vp != NULL;
336        vp = rs_avp_find_const (vp->next, vp->da->attr, vp->da->vendor))
337     total_len += vp->length;
338
339   if (*len < total_len) {
340     *len = total_len;
341     return RSE_ATTR_TOO_SMALL;
342   }
343
344   for (vp = vps, p = buf;
345        vp != NULL;
346        vp = rs_avp_find_const (vp->next, vp->da->attr, vp->da->vendor)) {
347     memcpy (p, vp->vp_octets, vp->length);
348     p += vp->length;
349   }
350
351   *len = total_len;
352
353   return RSE_OK;
354 }
355
356 int
357 rs_avp_octets_set (rs_avp *vp,
358                    const unsigned char *buf,
359                    size_t len)
360 {
361   int err;
362
363   if (!rs_avp_is_octets (vp))
364     return RSE_ATTR_INVALID;
365
366   err = nr_vp_set_data (vp, buf, len);
367
368   return RS_ERR(err);
369 }
370
371 int
372 rs_avp_ifid_value (rs_const_avp *vp, uint8_t val[8])
373 {
374   if (!rs_avp_is_ifid (vp))
375     return RSE_ATTR_INVALID;
376
377   memcpy (val, vp->vp_ifid, 8);
378
379   return RSE_OK;
380 }
381
382 int
383 rs_avp_ifid_set (rs_avp *vp, const uint8_t val[8])
384 {
385   int err;
386
387   if (!rs_avp_is_ifid (vp))
388     return RSE_ATTR_INVALID;
389
390   err = nr_vp_set_data (vp, val, 8);
391   return RS_ERR(err);
392 }
393
394 uint8_t
395 rs_avp_byte_value (rs_const_avp *vp)
396 {
397   if (!rs_avp_is_byte (vp))
398     return 0;
399   return vp->vp_integer;
400 }
401
402 int
403 rs_avp_byte_set (rs_avp *vp, uint8_t val)
404 {
405   int err;
406
407   if (!rs_avp_is_byte (vp))
408     return RSE_ATTR_INVALID;
409
410   err = nr_vp_set_data (vp, &val, sizeof (val));
411   return RS_ERR(err);
412 }
413
414 uint16_t
415 rs_avp_short_value (rs_const_avp *vp)
416 {
417   if (!rs_avp_is_short (vp))
418     return 0;
419   return vp->vp_integer;
420 }
421
422 int
423 rs_avp_short_set (rs_avp *vp, uint16_t val)
424 {
425   int err;
426
427   if (!rs_avp_is_short (vp))
428     return RSE_ATTR_INVALID;
429
430   err = nr_vp_set_data (vp, &val, sizeof (val));
431   return RS_ERR(err);
432 }
433
434 int
435 rs_attr_find (const char *name,
436               unsigned int *attr,
437               unsigned int *vendor)
438 {
439   const DICT_ATTR *da;
440
441   da = nr_dict_attr_byname (name);
442   if (da == NULL)
443     return RSE_ATTR_UNKNOWN;
444
445   *attr = da->attr;
446   *vendor = da->vendor;
447
448   return RSE_OK;
449 }
450
451 size_t
452 rs_avp_display_value (rs_const_avp *vp,
453                       char *buffer,
454                       size_t buflen)
455 {
456   return nr_vp_snprintf_value (buffer, buflen, vp);
457 }