]> git.ipfire.org Git - thirdparty/squid.git/blob - snmplib/snmp_vars.c
0ace96c1ed829e4aa02384244ac63a605ff99063
[thirdparty/squid.git] / snmplib / snmp_vars.c
1
2 /*
3 * SNMP Variable Binding. Complies with:
4 *
5 * RFC 1905: Protocol Operations for SNMPv2
6 *
7 */
8
9 /**********************************************************************
10 *
11 * Copyright 1997 by Carnegie Mellon University
12 *
13 * All Rights Reserved
14 *
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of CMU not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
22 *
23 * CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29 * SOFTWARE.
30 *
31 * Author: Ryan Troll <ryan+@andrew.cmu.edu>
32 *
33 **********************************************************************/
34
35 #include "squid.h"
36
37 #include <stdio.h>
38
39 #if HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42 #if HAVE_STDLIB_H
43 #include <stdlib.h>
44 #endif
45 #if HAVE_SYS_TYPES_H
46 #include <sys/types.h>
47 #endif
48 #if HAVE_CTYPE_H
49 #include <ctype.h>
50 #endif
51 #if HAVE_GNUMALLOC_H
52 #include <gnumalloc.h>
53 #elif HAVE_MALLOC_H
54 #include <malloc.h>
55 #endif
56 #if HAVE_MEMORY_H
57 #include <memory.h>
58 #endif
59 #if HAVE_STRING_H
60 #include <string.h>
61 #endif
62 #if HAVE_STRINGS_H
63 #include <strings.h>
64 #endif
65 #if HAVE_BSTRING_H
66 #include <bstring.h>
67 #endif
68 #if HAVE_SYS_SOCKET_H
69 #include <sys/socket.h>
70 #endif
71 #if HAVE_NETINET_IN_H
72 #include <netinet/in.h>
73 #endif
74 #if HAVE_ARPA_INET_H
75 #include <arpa/inet.h>
76 #endif
77 #if HAVE_SYS_TIME_H
78 #include <sys/time.h>
79 #endif
80 #if HAVE_NETDB_H
81 #include <netdb.h>
82 #endif
83
84 #include "snmp.h"
85 #include "asn1.h"
86 #include "snmp_vars.h"
87 #if 0
88 #include "mibii.h"
89 #endif
90 #include "snmp_api_error.h"
91 #include "snmp_pdu.h"
92 #include "snmp_msg.h"
93
94 #include "util.h"
95
96 /* #define DEBUG_VARS 1 */
97 /* #define DEBUG_VARS_MALLOC 1 */
98 /* #define DEBUG_VARS_DECODE 1 */
99 /* #define DEBUG_VARS_ENCODE 1 */
100
101 /* Create a new variable_list structure representing oid Name of length Len.
102 *
103 * Returns NULL upon error.
104 */
105
106 struct variable_list *
107 snmp_var_new(oid * Name, int Len) {
108 struct variable_list *New;
109
110 #if DEBUG_VARS
111 printf("VARS: Creating.\n");
112 #endif
113
114 New = xmalloc(sizeof(*New));
115 /* XXX xmalloc never returns NULL */
116 if (New == NULL) {
117 snmp_set_api_error(SNMPERR_OS_ERR);
118 return (NULL);
119 }
120 memset(New, '\0', sizeof(struct variable_list));
121 /* New->next_variable = NULL; */
122
123 New->type = ASN_NULL;
124 New->name_length = Len;
125
126 if (New->name_length == 0) {
127 New->name = NULL;
128 return (New);
129 }
130 New->name = (oid *) xmalloc(Len * sizeof(oid));
131 /* XXX xmalloc never returns NULL */
132 if (New->name == NULL) {
133 xfree(New);
134 snmp_set_api_error(SNMPERR_OS_ERR);
135 return (NULL);
136 }
137 #if DEBUG_VARS
138 printf("VARS: Copying name, size (%d)\n", Len);
139 #endif
140
141 /* Only copy a name if it was specified. */
142 if (Name)
143 memcpy((char *) New->name, (char *) Name, Len * sizeof(oid));
144
145 return (New);
146 }
147
148 struct variable_list *
149 snmp_var_new_integer(oid * Name, int Len, int ival, unsigned char type) {
150 variable_list *v = snmp_var_new(Name, Len);
151 v->val_len = sizeof(int);
152 v->val.integer = xmalloc(sizeof(int));
153 v->type = type;
154 *(v->val.integer) = ival;
155 return v;
156 }
157
158 /* Clone a variable list.
159 *
160 * Returns NULL upon error.
161 */
162
163 struct variable_list *
164 snmp_var_clone(struct variable_list *Src) {
165 struct variable_list *Dest;
166
167 #if DEBUG_VARS
168 printf("VARS: Cloning.\n");
169 #endif
170
171 Dest = (struct variable_list *) xmalloc(sizeof(struct variable_list));
172 if (Dest == NULL) {
173 snmp_set_api_error(SNMPERR_OS_ERR);
174 return (NULL);
175 }
176 #if DEBUG_VARS
177 printf("VARS: Copying entire variable list. (Size %d)\n",
178 sizeof(struct variable_list));
179 #endif
180
181 memcpy((char *) Dest, (char *) Src, sizeof(struct variable_list));
182
183 if (Src->name != NULL) {
184 Dest->name = (oid *) xmalloc(Src->name_length * sizeof(oid));
185 if (Dest->name == NULL) {
186 snmp_set_api_error(SNMPERR_OS_ERR);
187 xfree(Dest);
188 return (NULL);
189 }
190 #if DEBUG_VARS
191 printf("VARS: Copying name OID. (Size %d)\n", Src->name_length);
192 #endif
193 memcpy((char *) Dest->name, (char *) Src->name,
194 Src->name_length * sizeof(oid));
195 }
196 /* CISCO Catalyst 2900 returns NULL strings as data of length 0. */
197 if ((Src->val.string != NULL) &&
198 (Src->val_len)) {
199 Dest->val.string = (u_char *) xmalloc(Src->val_len);
200 if (Dest->val.string == NULL) {
201 snmp_set_api_error(SNMPERR_OS_ERR);
202 xfree(Dest->name);
203 xfree(Dest);
204 return (NULL);
205 }
206 #if DEBUG_VARS
207 printf("VARS: Copying value (Size %d)\n", Src->val_len);
208 #endif
209 memcpy((char *) Dest->val.string, (char *) Src->val.string, Src->val_len);
210 }
211 #if DEBUG_VARS
212 printf("VARS: Cloned %x.\n", (unsigned int) Dest);
213 #endif
214 #if DEBUG_VARS_MALLOC
215 printf("VARS: Cloned (%x)\n", (unsigned int) Dest);
216 printf("VARS: Name is (%x)\n", (unsigned int) Dest->name);
217 #endif
218
219 return (Dest);
220 }
221
222 /* Free a variable_list.
223 */
224 void
225 snmp_var_free(struct variable_list *Ptr)
226 {
227 if (Ptr->name)
228 xfree((char *) Ptr->name);
229
230 if (Ptr->val.string)
231 xfree((char *) Ptr->val.string);
232 else if (Ptr->val.integer)
233 xfree((char *) Ptr->val.integer);
234
235 xfree(Ptr);
236 }
237
238 /**********************************************************************/
239
240 /* Build a variable binding.
241 *
242 * RFC 1905: Protocol Operations for SNMPv2
243 *
244 * VarBind ::=
245 * SEQUENCE {
246 * name ObjectName
247 * CHOICE {
248 * value ObjectSyntax
249 * unSpecified NULL
250 * noSuchObject[0] NULL
251 * noSuchInstance[1] NULL
252 * endOfMibView[2] NULL
253 * }
254 * }
255 */
256 u_char *
257 snmp_var_EncodeVarBind(u_char * Buffer, int *BufLenP,
258 variable_list * VarList,
259 int Version)
260 {
261 struct variable_list *Vars;
262 u_char *bufp;
263 u_char *HeaderStart;
264 u_char *HeaderEnd;
265 int FakeArg = *BufLenP;
266
267 bufp = Buffer;
268
269 for (Vars = VarList; Vars; Vars = Vars->next_variable) {
270
271 /* Build the header for this variable
272 *
273 * Use Maximum size.
274 */
275 HeaderStart = bufp;
276 HeaderEnd = asn_build_header(HeaderStart, BufLenP,
277 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
278 FakeArg);
279 if (HeaderEnd == NULL)
280 return (NULL);
281
282 /* Now, let's put the Object Identifier into the buffer */
283 bufp = asn_build_objid(HeaderEnd, BufLenP,
284 (u_char) (ASN_UNIVERSAL |
285 ASN_PRIMITIVE |
286 ASN_OBJECT_ID),
287 Vars->name, Vars->name_length);
288 if (bufp == NULL)
289 return (NULL);
290
291 /* Now put the data in */
292 switch (Vars->type) {
293
294 case ASN_INTEGER:
295 bufp = asn_build_int(bufp,
296 BufLenP, Vars->type,
297 (int *) Vars->val.integer, Vars->val_len);
298 break;
299
300 case SMI_COUNTER32:
301 case SMI_GAUGE32:
302 /* case SMI_UNSIGNED32: */
303 case SMI_TIMETICKS:
304 bufp = asn_build_unsigned_int(bufp, BufLenP,
305 Vars->type,
306 (u_int *) Vars->val.integer, Vars->val_len);
307 break;
308
309 case ASN_OCTET_STR:
310 case SMI_IPADDRESS:
311 case SMI_OPAQUE:
312 bufp = asn_build_string(bufp, BufLenP, Vars->type,
313 Vars->val.string, Vars->val_len);
314 break;
315
316 case ASN_OBJECT_ID:
317 bufp = asn_build_objid(bufp, BufLenP, Vars->type,
318 (oid *) Vars->val.objid, Vars->val_len / sizeof(oid));
319 break;
320
321 case SMI_NOSUCHINSTANCE:
322 case SMI_NOSUCHOBJECT:
323 case SMI_ENDOFMIBVIEW:
324 if (Version == SNMP_VERSION_1) {
325 /* SNMP Version 1 does not support these error codes. */
326 bufp = asn_build_null(bufp, BufLenP, SMI_NOSUCHOBJECT);
327 } else {
328 bufp = asn_build_exception(bufp, BufLenP, Vars->type);
329 }
330 break;
331
332 case ASN_NULL:
333 bufp = asn_build_null(bufp, BufLenP, Vars->type);
334 break;
335
336 case SMI_COUNTER64:
337 snmplib_debug(2, "Unable to encode type SMI_COUNTER64!\n");
338 /* Fall through */
339
340 default:
341 snmp_set_api_error(SNMPERR_UNSUPPORTED_TYPE);
342 return (NULL);
343 }
344
345 /* ASSERT: bufp should now point to the next valid byte. */
346 if (bufp == NULL)
347 return (NULL);
348
349 /* Rebuild the header with the appropriate length */
350 HeaderEnd = asn_build_header(HeaderStart, &FakeArg,
351 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
352 (bufp - HeaderEnd));
353
354 /* Returns NULL */
355 if (HeaderEnd == NULL)
356 return (NULL);
357
358 }
359
360 /* or the end of the entire thing */
361 return (bufp);
362 }
363
364 /* Parse all Vars from the buffer */
365 u_char *
366 snmp_var_DecodeVarBind(u_char * Buffer, int *BufLen,
367 struct variable_list ** VarP,
368 int Version)
369 {
370 struct variable_list *Var = NULL, **VarLastP;
371 u_char *bufp, *tmp;
372 u_char VarBindType;
373 u_char *DataPtr;
374 int DataLen;
375 oid TmpBuf[MAX_NAME_LEN];
376 memset(TmpBuf, 0, MAX_NAME_LEN * sizeof(*TmpBuf));
377
378 int AllVarLen = *BufLen;
379 int ThisVarLen = 0;
380
381 VarLastP = VarP;
382 #if DEBUG_VARS_DECODE
383 printf("VARS: Decoding buffer of length %d\n", *BufLen);
384 #endif
385
386 /* Now parse the variables */
387 bufp = asn_parse_header(Buffer, &AllVarLen, &VarBindType);
388 if (bufp == NULL)
389 return (NULL);
390
391 if (VarBindType != (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
392 snmp_set_api_error(SNMPERR_PDU_PARSE);
393 return (NULL);
394 }
395 #if DEBUG_VARS_DECODE
396 printf("VARS: All Variable length %d\n", AllVarLen);
397 #endif
398
399 #define PARSE_ERROR { snmp_var_free(Var); return(NULL); }
400
401 /* We know how long the variable list is. Parse it. */
402 while ((int) AllVarLen > 0) {
403
404 /* Create a new variable */
405 Var = snmp_var_new(NULL, MAX_NAME_LEN);
406 if (Var == NULL)
407 return (NULL);
408
409 /* Parse the header to find out the length of this variable. */
410 ThisVarLen = AllVarLen;
411 tmp = asn_parse_header(bufp, &ThisVarLen, &VarBindType);
412 if (tmp == NULL)
413 PARSE_ERROR;
414
415 /* Now that we know the length , figure out how it relates to
416 * the entire variable list
417 */
418 AllVarLen = AllVarLen - (ThisVarLen + (tmp - bufp));
419 bufp = tmp;
420
421 /* Is it valid? */
422 if (VarBindType != (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
423 snmp_set_api_error(SNMPERR_PDU_PARSE);
424 PARSE_ERROR;
425 }
426 #if DEBUG_VARS_DECODE
427 printf("VARS: Header type 0x%x (%d bytes left)\n", VarBindType, ThisVarLen);
428 #endif
429
430 /* Parse the OBJID */
431 bufp = asn_parse_objid(bufp, &ThisVarLen, &VarBindType,
432 Var->name, &(Var->name_length));
433 if (bufp == NULL)
434 PARSE_ERROR;
435
436 if (VarBindType != (u_char) (ASN_UNIVERSAL |
437 ASN_PRIMITIVE |
438 ASN_OBJECT_ID)) {
439 snmp_set_api_error(SNMPERR_PDU_PARSE);
440 PARSE_ERROR;
441 }
442 #if DEBUG_VARS_DECODE
443 printf("VARS: Decoded OBJID (%d bytes). (%d bytes left)\n",
444 Var->name_length, ThisVarLen);
445 #endif
446
447 /* Keep a pointer to this object */
448 DataPtr = bufp;
449 DataLen = ThisVarLen;
450
451 /* find out type of object */
452 bufp = asn_parse_header(bufp, &ThisVarLen, &(Var->type));
453 if (bufp == NULL)
454 PARSE_ERROR;
455 ThisVarLen = DataLen;
456
457 #if DEBUG_VARS_DECODE
458 printf("VARS: Data type %d\n", Var->type);
459 #endif
460
461 /* Parse the type */
462
463 switch ((short) Var->type) {
464
465 case ASN_INTEGER:
466 Var->val.integer = (int *) xmalloc(sizeof(int));
467 if (Var->val.integer == NULL) {
468 snmp_set_api_error(SNMPERR_OS_ERR);
469 PARSE_ERROR;
470 }
471 Var->val_len = sizeof(int);
472 bufp = asn_parse_int(DataPtr, &ThisVarLen,
473 &Var->type, (int *) Var->val.integer,
474 Var->val_len);
475 #if DEBUG_VARS_DECODE
476 printf("VARS: Decoded integer '%d' (%d bytes left)\n",
477 *(Var->val.integer), ThisVarLen);
478 #endif
479 break;
480
481 case SMI_COUNTER32:
482 case SMI_GAUGE32:
483 /* case SMI_UNSIGNED32: */
484 case SMI_TIMETICKS:
485 Var->val.integer = (int *) xmalloc(sizeof(u_int));
486 if (Var->val.integer == NULL) {
487 snmp_set_api_error(SNMPERR_OS_ERR);
488 PARSE_ERROR;
489 }
490 Var->val_len = sizeof(u_int);
491 bufp = asn_parse_unsigned_int(DataPtr, &ThisVarLen,
492 &Var->type, (u_int *) Var->val.integer,
493 Var->val_len);
494 #if DEBUG_VARS_DECODE
495 printf("VARS: Decoded timeticks '%d' (%d bytes left)\n",
496 *(Var->val.integer), ThisVarLen);
497 #endif
498 break;
499
500 case ASN_OCTET_STR:
501 case SMI_IPADDRESS:
502 case SMI_OPAQUE:
503 Var->val_len = *&ThisVarLen; /* String is this at most */
504 Var->val.string = (u_char *) xmalloc((unsigned) Var->val_len);
505 if (Var->val.string == NULL) {
506 snmp_set_api_error(SNMPERR_OS_ERR);
507 PARSE_ERROR;
508 }
509 bufp = asn_parse_string(DataPtr, &ThisVarLen,
510 &Var->type, Var->val.string,
511 &Var->val_len);
512 #if DEBUG_VARS_DECODE
513 printf("VARS: Decoded string '%s' (length %d) (%d bytes left)\n",
514 (Var->val.string), Var->val_len, ThisVarLen);
515 #endif
516 break;
517
518 case ASN_OBJECT_ID:
519 Var->val_len = MAX_NAME_LEN;
520 bufp = asn_parse_objid(DataPtr, &ThisVarLen,
521 &Var->type, TmpBuf, &Var->val_len);
522 Var->val_len *= sizeof(oid);
523 Var->val.objid = (oid *) xmalloc((unsigned) Var->val_len);
524 if (Var->val.integer == NULL) {
525 snmp_set_api_error(SNMPERR_OS_ERR);
526 PARSE_ERROR;
527 }
528 /* Only copy if we successfully decoded something */
529 if (bufp) {
530 memcpy((char *) Var->val.objid, (char *) TmpBuf, Var->val_len);
531 }
532 #if DEBUG_VARS_DECODE
533 printf("VARS: Decoded OBJID (length %d) (%d bytes left)\n",
534 Var->val_len, ThisVarLen);
535 #endif
536 break;
537
538 case ASN_NULL:
539 case SMI_NOSUCHINSTANCE:
540 case SMI_NOSUCHOBJECT:
541 case SMI_ENDOFMIBVIEW:
542 break;
543
544 case SMI_COUNTER64:
545 snmplib_debug(2, "Unable to parse type SMI_COUNTER64!\n");
546 snmp_set_api_error(SNMPERR_UNSUPPORTED_TYPE);
547 PARSE_ERROR;
548
549 default:
550 snmplib_debug(2, "bad type returned (%x)\n", Var->type);
551 snmp_set_api_error(SNMPERR_PDU_PARSE);
552 PARSE_ERROR;
553 } /* End of var type switch */
554
555 if (bufp == NULL)
556 PARSE_ERROR;
557
558 #if DEBUG_VARS_DECODE
559 printf("VARS: Adding to list.\n");
560 #endif
561 /* Add variable to the list */
562 *VarLastP = Var;
563 VarLastP = &(Var->next_variable);
564 }
565 #undef PARSE_ERROR
566
567 return (bufp);
568 }