add new RADIUS client library
[radsecproxy.git] / lib / radius / valuepair.c
1 /*
2 Copyright (c) 2011, Network RADIUS SARL
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7     * Redistributions of source code must retain the above copyright
8       notice, this list of conditions and the following disclaimer.
9     * 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     * Neither the name of the <organization> nor the
13       names of its contributors may be used to endorse or promote products
14       derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 /** \file valuepair.c
29  *  \brief Functions to manipulate C structure versions of RADIUS attributes.
30  */
31
32 #include <networkradius-devel/client.h>
33
34 void nr_vp_free(VALUE_PAIR **head)
35 {
36         VALUE_PAIR      *next, *vp;
37
38         if (!head || !*head) return;
39
40         vp = *head;
41         do {
42                 if (vp) next = vp->next;
43                 if (vp->da->flags.encrypt) {
44                         memset(vp, 0, sizeof(vp));
45                 }
46                 free(vp);
47                 vp = next;
48         } while (next);
49
50         *head = NULL;
51 }
52
53
54 VALUE_PAIR *nr_vp_init(VALUE_PAIR *vp, const DICT_ATTR *da)
55 {
56         memset(vp, 0, sizeof(*vp));
57         
58         vp->da = da;
59         vp->length = da->flags.length;
60
61         return vp;
62 }
63
64
65 VALUE_PAIR *nr_vp_alloc(const DICT_ATTR *da)
66 {
67         VALUE_PAIR *vp = NULL;
68
69         if (!da) {
70                 nr_strerror_printf("Unknown attribute");
71                 return NULL;
72         }
73
74 #ifndef NR_NO_MALLOC
75         vp = malloc(sizeof(*vp));
76 #endif
77         if (!vp) {
78                 nr_strerror_printf("Out of memory");
79                 return NULL;
80         }
81
82         return nr_vp_init(vp, da);
83 }
84
85 VALUE_PAIR *nr_vp_alloc_raw(unsigned int attr, unsigned int vendor)
86 {
87         VALUE_PAIR *vp = NULL;
88         DICT_ATTR *da;
89
90 #ifndef NR_NO_MALLOC
91         vp = malloc(sizeof(*vp) + sizeof(*da) + 64);
92 #endif
93         if (!vp) {
94                 nr_strerror_printf("Out of memory");
95                 return NULL;
96         }
97         memset(vp, 0, sizeof(*vp));
98
99         da = (DICT_ATTR *) (vp + 1);
100
101         if (nr_dict_attr_2struct(da, attr, vendor, (char *) (da + 1), 64) < 0) {
102                 free(vp);
103                 return NULL;
104         }
105
106         vp->da = da;
107
108         return vp;
109 }
110
111 int nr_vp_set_data(VALUE_PAIR *vp, const void *data, size_t sizeof_data)
112 {
113         int rcode = 1;          /* OK */
114
115         if (!vp || !data || (sizeof_data == 0)) return -NR_ERR_INVALID_ARG;
116
117         switch (vp->da->type) {
118         case NR_TYPE_BYTE:
119                 vp->vp_integer = *(const uint8_t *) data;
120                 break;
121                 
122         case NR_TYPE_SHORT:
123                 vp->vp_integer = *(const uint16_t *) data;
124                 break;
125                 
126         case NR_TYPE_INTEGER:
127         case NR_TYPE_DATE:
128         case NR_TYPE_IPADDR:
129                 vp->vp_integer = *(const uint32_t *) data;
130                 break;
131                 
132         case NR_TYPE_STRING:
133                 if (sizeof_data >= sizeof(vp->vp_strvalue)) {
134                         sizeof_data = sizeof(vp->vp_strvalue) - 1;
135                         rcode = 0; /* truncated */
136                 }
137
138                 memcpy(vp->vp_strvalue, (const char *) data, sizeof_data);
139                 vp->vp_strvalue[sizeof_data + 1] = '\0';
140                 vp->length = sizeof_data;
141                 break;
142                 
143         case NR_TYPE_OCTETS:
144                 if (sizeof_data > sizeof(vp->vp_octets)) {
145                         sizeof_data = sizeof(vp->vp_octets);
146                         rcode = 0; /* truncated */
147                 }
148                 memcpy(vp->vp_octets, data, sizeof_data);
149                 vp->length = sizeof_data;
150                 break;
151                 
152         default:
153                 return -NR_ERR_ATTR_TYPE_UNKNOWN;
154         }
155
156         return rcode;
157 }
158
159 VALUE_PAIR *nr_vp_create(int attr, int vendor, const void *data, size_t data_len)
160 {
161         const DICT_ATTR *da;
162         VALUE_PAIR *vp;
163
164         da = nr_dict_attr_byvalue(attr, vendor);
165         if (!da) return NULL;
166
167         vp = nr_vp_alloc(da);
168         if (!vp) return NULL;
169         
170         if (nr_vp_set_data(vp, data, data_len) < 0) {
171                 nr_vp_free(&vp);
172                 return NULL;
173         }
174
175         return vp;
176 }
177
178 void nr_vps_append(VALUE_PAIR **head, VALUE_PAIR *tail)
179 {
180         if (!tail) return;
181
182         while (*head) {
183                 head = &((*head)->next);
184         }
185
186         *head = tail;
187 }
188
189 VALUE_PAIR *nr_vps_find(VALUE_PAIR *head,
190                      unsigned int attr, unsigned int vendor)
191 {
192         while (head) {
193                 if ((head->da->attr == attr) &&
194                     (head->da->vendor == vendor)) return head;
195                 head = head->next;
196         }
197
198         return NULL;
199 }