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