]> git.ipfire.org Git - thirdparty/squid.git/blame - snmplib/snmp_vars.c
SourceFormat Enforcement
[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
f7f3304a 35#include "squid.h"
85269fdf 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
32d002cb 59#if HAVE_STRING_H
85269fdf 60#include <string.h>
61#endif
32d002cb 62#if HAVE_STRINGS_H
85269fdf 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
85269fdf 84#include "asn1.h"
602d9612 85#include "snmp.h"
85269fdf 86#include "snmp_vars.h"
43d4303e 87#if 0
85269fdf 88#include "mibii.h"
43d4303e 89#endif
85269fdf 90#include "snmp_api_error.h"
85269fdf 91#include "snmp_msg.h"
602d9612 92#include "snmp_pdu.h"
85269fdf 93
94#include "util.h"
95
85269fdf 96/* #define DEBUG_VARS 1 */
97/* #define DEBUG_VARS_MALLOC 1 */
98/* #define DEBUG_VARS_DECODE 1 */
99/* #define DEBUG_VARS_ENCODE 1 */
100
85269fdf 101/* Create a new variable_list structure representing oid Name of length Len.
102 *
103 * Returns NULL upon error.
104 */
105
43d4303e 106struct variable_list *
e1381638 107snmp_var_new(oid * Name, int Len) {
43d4303e 108 struct variable_list *New;
85269fdf 109
32d002cb 110#if DEBUG_VARS
43d4303e 111 printf("VARS: Creating.\n");
85269fdf 112#endif
113
736eb6ad 114 New = xmalloc(sizeof(*New));
115 /* XXX xmalloc never returns NULL */
43d4303e 116 if (New == NULL) {
26ac0430
AJ
117 snmp_set_api_error(SNMPERR_OS_ERR);
118 return (NULL);
43d4303e 119 }
120 memset(New, '\0', sizeof(struct variable_list));
121 /* New->next_variable = NULL; */
85269fdf 122
43d4303e 123 New->type = ASN_NULL;
124 New->name_length = Len;
85269fdf 125
43d4303e 126 if (New->name_length == 0) {
26ac0430
AJ
127 New->name = NULL;
128 return (New);
43d4303e 129 }
130 New->name = (oid *) xmalloc(Len * sizeof(oid));
736eb6ad 131 /* XXX xmalloc never returns NULL */
43d4303e 132 if (New->name == NULL) {
26ac0430
AJ
133 xfree(New);
134 snmp_set_api_error(SNMPERR_OS_ERR);
135 return (NULL);
43d4303e 136 }
32d002cb 137#if DEBUG_VARS
43d4303e 138 printf("VARS: Copying name, size (%d)\n", Len);
85269fdf 139#endif
140
43d4303e 141 /* Only copy a name if it was specified. */
142 if (Name)
41d00cd3 143 memcpy((char *) New->name, (char *) Name, Len * sizeof(oid));
85269fdf 144
43d4303e 145 return (New);
85269fdf 146}
147
736eb6ad 148struct variable_list *
e1381638 149snmp_var_new_integer(oid * Name, int Len, int ival, unsigned char type) {
736eb6ad 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
85269fdf 158/* Clone a variable list.
159 *
160 * Returns NULL upon error.
161 */
162
43d4303e 163struct variable_list *
e1381638 164snmp_var_clone(struct variable_list *Src) {
43d4303e 165 struct variable_list *Dest;
85269fdf 166
32d002cb 167#if DEBUG_VARS
43d4303e 168 printf("VARS: Cloning.\n");
85269fdf 169#endif
170
43d4303e 171 Dest = (struct variable_list *) xmalloc(sizeof(struct variable_list));
172 if (Dest == NULL) {
26ac0430
AJ
173 snmp_set_api_error(SNMPERR_OS_ERR);
174 return (NULL);
43d4303e 175 }
32d002cb 176#if DEBUG_VARS
43d4303e 177 printf("VARS: Copying entire variable list. (Size %d)\n",
26ac0430 178 sizeof(struct variable_list));
85269fdf 179#endif
180
41d00cd3 181 memcpy((char *) Dest, (char *) Src, sizeof(struct variable_list));
85269fdf 182
43d4303e 183 if (Src->name != NULL) {
26ac0430
AJ
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 }
32d002cb 190#if DEBUG_VARS
26ac0430 191 printf("VARS: Copying name OID. (Size %d)\n", Src->name_length);
43d4303e 192#endif
41d00cd3 193 memcpy((char *) Dest->name, (char *) Src->name,
e34763f4 194 Src->name_length * sizeof(oid));
85269fdf 195 }
43d4303e 196 /* CISCO Catalyst 2900 returns NULL strings as data of length 0. */
197 if ((Src->val.string != NULL) &&
26ac0430
AJ
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 }
32d002cb 206#if DEBUG_VARS
26ac0430 207 printf("VARS: Copying value (Size %d)\n", Src->val_len);
85269fdf 208#endif
41d00cd3 209 memcpy((char *) Dest->val.string, (char *) Src->val.string, Src->val_len);
43d4303e 210 }
32d002cb 211#if DEBUG_VARS
43d4303e 212 printf("VARS: Cloned %x.\n", (unsigned int) Dest);
85269fdf 213#endif
32d002cb 214#if DEBUG_VARS_MALLOC
43d4303e 215 printf("VARS: Cloned (%x)\n", (unsigned int) Dest);
216 printf("VARS: Name is (%x)\n", (unsigned int) Dest->name);
85269fdf 217#endif
218
43d4303e 219 return (Dest);
85269fdf 220}
221
222/* Free a variable_list.
223 */
736eb6ad 224void
43d4303e 225snmp_var_free(struct variable_list *Ptr)
85269fdf 226{
63f8db1a 227 if (Ptr->name)
26ac0430 228 xfree((char *) Ptr->name);
85269fdf 229
63f8db1a 230 if (Ptr->val.string)
26ac0430 231 xfree((char *) Ptr->val.string);
63f8db1a 232 else if (Ptr->val.integer)
26ac0430 233 xfree((char *) Ptr->val.integer);
85269fdf 234
43d4303e 235 xfree(Ptr);
85269fdf 236}
237
238/**********************************************************************/
239
240/* Build a variable binding.
241 *
242 * RFC 1905: Protocol Operations for SNMPv2
243 *
26ac0430 244 * VarBind ::=
85269fdf 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 */
43d4303e 256u_char *
257snmp_var_EncodeVarBind(u_char * Buffer, int *BufLenP,
26ac0430
AJ
258 variable_list * VarList,
259 int Version)
85269fdf 260{
43d4303e 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
26ac0430
AJ
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);
85269fdf 357
43d4303e 358 }
85269fdf 359
43d4303e 360 /* or the end of the entire thing */
361 return (bufp);
85269fdf 362}
363
85269fdf 364/* Parse all Vars from the buffer */
43d4303e 365u_char *
366snmp_var_DecodeVarBind(u_char * Buffer, int *BufLen,
26ac0430
AJ
367 struct variable_list ** VarP,
368 int Version)
85269fdf 369{
63f8db1a 370 struct variable_list *Var = NULL, **VarLastP;
43d4303e 371 u_char *bufp, *tmp;
372 u_char VarBindType;
373 u_char *DataPtr;
374 int DataLen;
375 oid TmpBuf[MAX_NAME_LEN];
2082bd1c 376 memset(TmpBuf, 0, MAX_NAME_LEN * sizeof(*TmpBuf));
85269fdf 377
43d4303e 378 int AllVarLen = *BufLen;
379 int ThisVarLen = 0;
85269fdf 380
43d4303e 381 VarLastP = VarP;
32d002cb 382#if DEBUG_VARS_DECODE
43d4303e 383 printf("VARS: Decoding buffer of length %d\n", *BufLen);
85269fdf 384#endif
385
43d4303e 386 /* Now parse the variables */
387 bufp = asn_parse_header(Buffer, &AllVarLen, &VarBindType);
388 if (bufp == NULL)
26ac0430 389 return (NULL);
85269fdf 390
43d4303e 391 if (VarBindType != (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
26ac0430
AJ
392 snmp_set_api_error(SNMPERR_PDU_PARSE);
393 return (NULL);
85269fdf 394 }
32d002cb 395#if DEBUG_VARS_DECODE
43d4303e 396 printf("VARS: All Variable length %d\n", AllVarLen);
397#endif
398
63f8db1a 399#define PARSE_ERROR { snmp_var_free(Var); return(NULL); }
400
43d4303e 401 /* We know how long the variable list is. Parse it. */
402 while ((int) AllVarLen > 0) {
403
26ac0430
AJ
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 }
32d002cb 426#if DEBUG_VARS_DECODE
26ac0430 427 printf("VARS: Header type 0x%x (%d bytes left)\n", VarBindType, ThisVarLen);
85269fdf 428#endif
429
26ac0430
AJ
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;
85269fdf 435
26ac0430
AJ
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 }
32d002cb 442#if DEBUG_VARS_DECODE
26ac0430
AJ
443 printf("VARS: Decoded OBJID (%d bytes). (%d bytes left)\n",
444 Var->name_length, ThisVarLen);
85269fdf 445#endif
446
26ac0430
AJ
447 /* Keep a pointer to this object */
448 DataPtr = bufp;
449 DataLen = ThisVarLen;
85269fdf 450
26ac0430
AJ
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;
85269fdf 456
32d002cb 457#if DEBUG_VARS_DECODE
26ac0430 458 printf("VARS: Data type %d\n", Var->type);
85269fdf 459#endif
460
26ac0430 461 /* Parse the type */
85269fdf 462
26ac0430 463 switch ((short) Var->type) {
85269fdf 464
26ac0430
AJ
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);
32d002cb 475#if DEBUG_VARS_DECODE
26ac0430
AJ
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);
32d002cb 494#if DEBUG_VARS_DECODE
26ac0430
AJ
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);
32d002cb 512#if DEBUG_VARS_DECODE
26ac0430
AJ
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) {
41d00cd3 530 memcpy((char *) Var->val.objid, (char *) TmpBuf, Var->val_len);
26ac0430 531 }
32d002cb 532#if DEBUG_VARS_DECODE
26ac0430
AJ
533 printf("VARS: Decoded OBJID (length %d) (%d bytes left)\n",
534 Var->val_len, ThisVarLen);
43d4303e 535#endif
26ac0430 536 break;
85269fdf 537
26ac0430
AJ
538 case ASN_NULL:
539 case SMI_NOSUCHINSTANCE:
540 case SMI_NOSUCHOBJECT:
541 case SMI_ENDOFMIBVIEW:
542 break;
43d4303e 543
26ac0430
AJ
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;
43d4303e 548
26ac0430
AJ
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 */
43d4303e 554
26ac0430
AJ
555 if (bufp == NULL)
556 PARSE_ERROR;
85269fdf 557
32d002cb 558#if DEBUG_VARS_DECODE
26ac0430 559 printf("VARS: Adding to list.\n");
85269fdf 560#endif
26ac0430
AJ
561 /* Add variable to the list */
562 *VarLastP = Var;
563 VarLastP = &(Var->next_variable);
43d4303e 564 }
63f8db1a 565#undef PARSE_ERROR
85269fdf 566
43d4303e 567 return (bufp);
85269fdf 568}