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