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

 

Introduction

Documentation

Support

Miscellaneous