1 /*
2 This file is part of GNU Radius SNMP Library.
3 Copyright (C) 2001,2003,2004,2007 Free Software Foundation, Inc.
4
5 Written by Sergey Poznyakoff
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 3 of the
10 License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; see the file COPYING.LIB. If not,
19 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <snmp/asn1.h>
28 #include <snmp/snmp.h>
29
30 /* free a *single* snmp variable */
31 void
snmp_var_free(struct snmp_var * var)32 snmp_var_free(struct snmp_var *var)
33 {
34 if (!var)
35 return;
36 switch (var->type) {
37 case ASN_BOOLEAN:
38 case ASN_INTEGER:
39 case ASN_NULL:
40 case SMI_COUNTER32:
41 case SMI_GAUGE32:
42 case SMI_TIMETICKS:
43 break;
44 case ASN_OCTET_STR:
45 case SMI_IPADDRESS:
46 case SMI_OPAQUE:
47 case ASN_BIT_STR:
48 snmp_free(var->var_str);
49 break;
50 case ASN_OBJECT_ID:
51 snmp_free(var->var_oid);
52 break;
53 default:
54 abort();
55 }
56 snmp_free(var->name);
57 snmp_free(var);
58 }
59
60 /* free whole snmp variable list */
61 void
snmp_var_free_list(struct snmp_var * var)62 snmp_var_free_list(struct snmp_var *var)
63 {
64 struct snmp_var *next;
65
66 while (var) {
67 next = var->next;
68 snmp_var_free(var);
69 var = next;
70 }
71 }
72
73 struct snmp_var *
snmp_var_create(oid_t oid)74 snmp_var_create(oid_t oid)
75 {
76 struct snmp_var *var;
77
78 var = snmp_alloc(sizeof(*var));
79 if (!var) {
80 SNMP_SET_ERRNO(E_SNMP_NOMEM);
81 return NULL;
82 }
83
84 var->name = oid_dup(oid);
85 if (!var->name) {
86 SNMP_SET_ERRNO(E_SNMP_NOMEM);
87 snmp_free(var);
88 return NULL;
89 }
90 var->type = ASN_NULL;
91 var->next = NULL;
92 return var;
93 }
94
95 struct snmp_var *
snmp_var_dup(struct snmp_var * src)96 snmp_var_dup(struct snmp_var *src)
97 {
98 struct snmp_var *var;
99
100 if ((var = snmp_var_create(src->name)) == NULL)
101 return NULL;
102 var->type = src->type;
103 var->val_length = src->val_length;
104 switch (var->type) {
105 case ASN_BOOLEAN:
106 case ASN_INTEGER:
107 case ASN_NULL:
108 case SMI_COUNTER32:
109 case SMI_GAUGE32:
110 case SMI_TIMETICKS:
111 var->var_int = src->var_int;
112 break;
113 case ASN_OCTET_STR:
114 case SMI_IPADDRESS:
115 case SMI_OPAQUE:
116 case ASN_BIT_STR:
117 var->var_str = snmp_alloc(src->val_length);
118 if (!var->var_str) {
119 SNMP_SET_ERRNO(E_SNMP_NOMEM);
120 snmp_free(var);
121 return NULL;
122 }
123 memcpy(var->var_str, src->var_str, src->val_length);
124 break;
125 case ASN_OBJECT_ID:
126 var->var_oid = oid_dup(src->var_oid);
127 if (!var->var_oid) {
128 SNMP_SET_ERRNO(E_SNMP_NOMEM);
129 snmp_free(var);
130 return NULL;
131 }
132 break;
133 default:
134 abort();
135 }
136 return var;
137 }
138
139 struct snmp_var *
snmp_var_dup_list(struct snmp_var * var)140 snmp_var_dup_list(struct snmp_var *var)
141 {
142 struct snmp_var *var_head, *var_tail, *vp;
143
144 var_head = var_tail = NULL;
145 for (; var; var = var->next) {
146 if ((vp = snmp_var_dup(var)) == NULL) {
147 snmp_var_free_list(var_head);
148 return NULL;
149 }
150 if (var_tail)
151 var_tail->next = vp;
152 else
153 var_head = vp;
154 var_tail = vp;
155 }
156 return var_head;
157 }
158
159 /* RFC 1905: Protocol Operations for SNMPv2
160 VarBind ::= SEQUENCE {
161 name ObjectName
162 CHOICE {
163 value ObjectSyntax
164 unSpecified NULL
165 noSuchObject[0] NULL
166 noSuchInstance[1] NULL
167 endOfMibView[2] NULL
168 }
169 }
170 */
171
172 u_char *
snmp_var_decode(u_char * data,int * length,struct snmp_var ** var_head,int version)173 snmp_var_decode(u_char *data, int *length, struct snmp_var **var_head,
174 int version)
175 {
176 u_char *buf, *tmp;
177 u_char *data_ptr;
178 u_char type;
179 int list_length = *length;
180 int var_length, data_len;
181 subid_t oid[MAX_OID_LEN+1];
182 struct snmp_var *var = NULL, *var_tail;
183
184 /* Determine length of the variable list */
185 buf = asn_decode_header(data, &list_length, &type);
186 if (!buf)
187 return NULL;
188 if (type != (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
189 SNMP_SET_ERRNO(E_SNMP_DECODE);
190 return NULL;
191 }
192
193 *var_head = var_tail = NULL;
194 /* Parse variable list */
195 while (list_length > 0) {
196
197 /* determine length of this variable; */
198 var_length = list_length;
199 tmp = asn_decode_header(buf, &var_length, &type);
200 if (!tmp)
201 goto err;
202
203 /* adjust total length and restore buffer pointer */
204 list_length -= var_length + (tmp - buf);
205 buf = tmp;
206
207 if (type != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
208 SNMP_SET_ERRNO(E_SNMP_DECODE);
209 goto err;
210 }
211
212 /* read oid */
213 OIDLEN(oid) = MAX_OID_LEN;
214 buf = asn_decode_oid(buf, &var_length, &type,
215 OIDPTR(oid), &OIDLEN(oid));
216 if (!buf)
217 goto err;
218
219 if (type != (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID)) {
220 SNMP_SET_ERRNO(E_SNMP_DECODE);
221 goto err;
222 }
223
224 /* allocate variable */
225 var = snmp_var_create(oid);
226
227 /* Preserve pointer to the start of data */
228 data_ptr = buf;
229 data_len = var_length;
230
231 /* read object's header */
232 buf = asn_decode_header(buf, &data_len, &var->type);
233 if (!buf)
234 goto err;
235
236 /* now depending on type ... */
237 switch (var->type) {
238 case ASN_INTEGER:
239 var->val_length = sizeof(var->var_int);
240 buf = asn_decode_int(data_ptr, &var_length,
241 &var->type, &var->var_int,
242 var->val_length);
243 break;
244
245 case SMI_COUNTER32:
246 case SMI_GAUGE32:
247 case SMI_TIMETICKS:
248 var->val_length = sizeof(var->var_int);
249 buf = asn_decode_uint(data_ptr, &var_length,
250 &var->type, &var->var_int,
251 var->val_length);
252 break;
253
254 case ASN_OCTET_STR:
255 case SMI_IPADDRESS:
256 case SMI_OPAQUE:
257 var->val_length = var_length; /* at most ... */
258 var->var_str = snmp_alloc(var->val_length);
259 if (!var->var_str) {
260 SNMP_SET_ERRNO(E_SNMP_NOMEM);
261 goto err;
262 }
263 buf = asn_decode_string(data_ptr, &var_length,
264 &var->type, var->var_str,
265 &var->val_length);
266 break;
267
268 case ASN_OBJECT_ID:
269 var->val_length = MAX_OID_LEN;
270 buf = asn_decode_oid(data_ptr, &var_length,
271 &var->type, OIDPTR(oid),
272 &var->val_length);
273 if (buf) {
274 OIDLEN(oid) = var->val_length;
275 var->var_oid = oid_dup(oid);
276 }
277 break;
278
279 case ASN_NULL:
280 break;
281
282 default:
283 SNMP_SET_ERRNO(E_SNMP_BAD_VARTYPE);
284 break;
285 }
286
287 if (!buf)
288 goto err;
289
290 if (!var_tail)
291 *var_head = var;
292 else
293 var_tail->next = var;
294 var_tail = var;
295 var = NULL;
296 }
297
298 return buf;
299
300 err:
301 snmp_var_free(var);
302 snmp_var_free_list(*var_head);
303 return NULL;
304 }
305
306 u_char *
snmp_var_encode(u_char * data,int * length,struct snmp_var * var,int version)307 snmp_var_encode(u_char *data, int *length, struct snmp_var *var, int version)
308 {
309 u_char *buf = data;
310 u_char *header_ptr, *header_end;
311
312 for (; var; var = var->next) {
313 header_ptr = buf;
314 buf = asn_encode_header(buf, length,
315 (ASN_SEQUENCE | ASN_CONSTRUCTOR),
316 0xffff);
317 if (!buf)
318 return NULL;
319
320 header_end = buf;
321
322 buf = asn_encode_oid(buf, length,
323 (ASN_UNIVERSAL |
324 ASN_PRIMITIVE |
325 ASN_OBJECT_ID),
326 OIDPTR(var->name), OIDLEN(var->name));
327 if (!buf)
328 return NULL;
329
330 switch (var->type) {
331 case ASN_INTEGER:
332 buf = asn_encode_int(buf, length, var->type,
333 var->var_int);
334 break;
335 case SMI_COUNTER32:
336 case SMI_GAUGE32:
337 case SMI_TIMETICKS:
338 buf = asn_encode_uint(buf, length, var->type,
339 var->var_int);
340 break;
341 case ASN_OCTET_STR:
342 case SMI_IPADDRESS:
343 case SMI_OPAQUE:
344 buf = asn_encode_string(buf, length, var->type,
345 var->var_str, var->val_length);
346 break;
347
348 case ASN_OBJECT_ID:
349 buf = asn_encode_oid(buf, length, var->type,
350 OIDPTR(var->var_oid),
351 OIDLEN(var->var_oid));
352 break;
353
354 case ASN_NULL:
355 buf = asn_encode_null(buf, length, var->type);
356 break;
357
358 default:
359 SNMP_SET_ERRNO(E_SNMP_NOT_SUPPORTED);
360 buf = NULL;
361 }
362
363 if (!buf)
364 return NULL;
365
366 asn_recode_length(header_ptr+1,
367 buf - header_end);
368 }
369
370 return buf;
371 }
372