port to 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 "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         vp = malloc(sizeof(*vp));
75         if (!vp) {
76                 nr_strerror_printf("Out of memory");
77                 return NULL;
78         }
79
80         return nr_vp_init(vp, da);
81 }
82
83 VALUE_PAIR *nr_vp_alloc_raw(unsigned int attr, unsigned int vendor)
84 {
85         VALUE_PAIR *vp = NULL;
86         DICT_ATTR *da;
87
88         vp = malloc(sizeof(*vp) + sizeof(*da) + 64);
89         if (!vp) {
90                 nr_strerror_printf("Out of memory");
91                 return NULL;
92         }
93         memset(vp, 0, sizeof(*vp));
94
95         da = (DICT_ATTR *) (vp + 1);
96
97         if (nr_dict_attr_2struct(da, attr, vendor, (char *) (da + 1), 64) < 0) {
98                 free(vp);
99                 return NULL;
100         }
101
102         vp->da = da;
103
104         return vp;
105 }
106
107 int nr_vp_set_data(VALUE_PAIR *vp, const void *data, size_t sizeof_data)
108 {
109         int rcode = 1;          /* OK */
110
111         if (!vp || !data || (sizeof_data == 0)) return -RSE_INVAL;
112
113         switch (vp->da->type) {
114         case RS_TYPE_BYTE:
115                 vp->vp_integer = *(const uint8_t *) data;
116                 break;
117                 
118         case RS_TYPE_SHORT:
119                 vp->vp_integer = *(const uint16_t *) data;
120                 break;
121                 
122         case RS_TYPE_INTEGER:
123         case RS_TYPE_DATE:
124         case RS_TYPE_IPADDR:
125                 vp->vp_integer = *(const uint32_t *) data;
126                 break;
127                 
128         case RS_TYPE_STRING:
129                 if (sizeof_data >= sizeof(vp->vp_strvalue)) {
130                         sizeof_data = sizeof(vp->vp_strvalue) - 1;
131                         rcode = 0; /* truncated */
132                 }
133
134                 memcpy(vp->vp_strvalue, (const char *) data, sizeof_data);
135                 vp->vp_strvalue[sizeof_data + 1] = '\0';
136                 vp->length = sizeof_data;
137                 break;
138                 
139         case RS_TYPE_OCTETS:
140                 if (sizeof_data > sizeof(vp->vp_octets)) {
141                         sizeof_data = sizeof(vp->vp_octets);
142                         rcode = 0; /* truncated */
143                 }
144                 memcpy(vp->vp_octets, data, sizeof_data);
145                 vp->length = sizeof_data;
146                 break;
147                 
148         default:
149                 return -RSE_ATTR_TYPE_UNKNOWN;
150         }
151
152         return rcode;
153 }
154
155 VALUE_PAIR *nr_vp_create(int attr, int vendor, const void *data, size_t data_len)
156 {
157         const DICT_ATTR *da;
158         VALUE_PAIR *vp;
159
160         da = nr_dict_attr_byvalue(attr, vendor);
161         if (!da) return NULL;
162
163         vp = nr_vp_alloc(da);
164         if (!vp) return NULL;
165         
166         if (nr_vp_set_data(vp, data, data_len) < 0) {
167                 nr_vp_free(&vp);
168                 return NULL;
169         }
170
171         return vp;
172 }
173
174 void nr_vps_append(VALUE_PAIR **head, VALUE_PAIR *tail)
175 {
176         if (!tail) return;
177
178         while (*head) {
179                 head = &((*head)->next);
180         }
181
182         *head = tail;
183 }
184
185 VALUE_PAIR *nr_vps_find(VALUE_PAIR *head,
186                      unsigned int attr, unsigned int vendor)
187 {
188         while (head) {
189                 if ((head->da->attr == attr) &&
190                     (head->da->vendor == vendor)) return head;
191                 head = head->next;
192         }
193
194         return NULL;
195 }