snmp_vars.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2017 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_vars.h"
92 #if 0
93 #include "mibii.h"
94 #endif
95 #include "snmp_api_error.h"
96 #include "snmp_msg.h"
97 #include "snmp_pdu.h"
98 
99 #include "util.h"
100 
101 /* #define DEBUG_VARS 1 */
102 /* #define DEBUG_VARS_MALLOC 1 */
103 /* #define DEBUG_VARS_DECODE 1 */
104 /* #define DEBUG_VARS_ENCODE 1 */
105 
106 /* Create a new variable_list structure representing oid Name of length Len.
107  *
108  * Returns NULL upon error.
109  */
110 
111 struct variable_list *
112 snmp_var_new(oid * Name, int Len) {
113  struct variable_list *New;
114 
115 #if DEBUG_VARS
116  printf("VARS: Creating.\n");
117 #endif
118 
119  New = xmalloc(sizeof(*New));
120  /* XXX xmalloc never returns NULL */
121  if (New == NULL) {
123  return (NULL);
124  }
125  memset(New, '\0', sizeof(struct variable_list));
126  /* New->next_variable = NULL; */
127 
128  New->type = ASN_NULL;
129  New->name_length = Len;
130 
131  if (New->name_length == 0) {
132  New->name = NULL;
133  return (New);
134  }
135  New->name = (oid *) xmalloc(Len * sizeof(oid));
136  /* XXX xmalloc never returns NULL */
137  if (New->name == NULL) {
138  xfree(New);
140  return (NULL);
141  }
142 #if DEBUG_VARS
143  printf("VARS: Copying name, size (%d)\n", Len);
144 #endif
145 
146  /* Only copy a name if it was specified. */
147  if (Name)
148  memcpy((char *) New->name, (char *) Name, Len * sizeof(oid));
149 
150  return (New);
151 }
152 
153 struct variable_list *
154 snmp_var_new_integer(oid * Name, int Len, int ival, unsigned char type) {
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 
163 /* Clone a variable list.
164  *
165  * Returns NULL upon error.
166  */
167 
168 struct variable_list *
170  struct variable_list *Dest;
171 
172 #if DEBUG_VARS
173  printf("VARS: Cloning.\n");
174 #endif
175 
176  Dest = (struct variable_list *) xmalloc(sizeof(struct variable_list));
177  if (Dest == NULL) {
179  return (NULL);
180  }
181 #if DEBUG_VARS
182  printf("VARS: Copying entire variable list. (Size %d)\n",
183  sizeof(struct variable_list));
184 #endif
185 
186  memcpy((char *) Dest, (char *) Src, sizeof(struct variable_list));
187 
188  if (Src->name != NULL) {
189  Dest->name = (oid *) xmalloc(Src->name_length * sizeof(oid));
190  if (Dest->name == NULL) {
192  xfree(Dest);
193  return (NULL);
194  }
195 #if DEBUG_VARS
196  printf("VARS: Copying name OID. (Size %d)\n", Src->name_length);
197 #endif
198  memcpy((char *) Dest->name, (char *) Src->name,
199  Src->name_length * sizeof(oid));
200  }
201  /* CISCO Catalyst 2900 returns NULL strings as data of length 0. */
202  if ((Src->val.string != NULL) &&
203  (Src->val_len)) {
204  Dest->val.string = (u_char *) xmalloc(Src->val_len);
205  if (Dest->val.string == NULL) {
207  xfree(Dest->name);
208  xfree(Dest);
209  return (NULL);
210  }
211 #if DEBUG_VARS
212  printf("VARS: Copying value (Size %d)\n", Src->val_len);
213 #endif
214  memcpy((char *) Dest->val.string, (char *) Src->val.string, Src->val_len);
215  }
216 #if DEBUG_VARS
217  printf("VARS: Cloned %x.\n", (unsigned int) Dest);
218 #endif
219 #if DEBUG_VARS_MALLOC
220  printf("VARS: Cloned (%x)\n", (unsigned int) Dest);
221  printf("VARS: Name is (%x)\n", (unsigned int) Dest->name);
222 #endif
223 
224  return (Dest);
225 }
226 
227 /* Free a variable_list.
228  */
229 void
231 {
232  if (Ptr->name)
233  xfree((char *) Ptr->name);
234 
235  if (Ptr->val.string)
236  xfree((char *) Ptr->val.string);
237  else if (Ptr->val.integer)
238  xfree((char *) Ptr->val.integer);
239 
240  xfree(Ptr);
241 }
242 
243 /**********************************************************************/
244 
245 /* Build a variable binding.
246  *
247  * RFC 1905: Protocol Operations for SNMPv2
248  *
249  * VarBind ::=
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  */
261 u_char *
262 snmp_var_EncodeVarBind(u_char * Buffer, int *BufLenP,
263  variable_list * VarList,
264  int Version)
265 {
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 
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:
307  /* case SMI_UNSIGNED32: */
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");
343  /* Fall through */
344 
345  default:
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);
362 
363  }
364 
365  /* or the end of the entire thing */
366  return (bufp);
367 }
368 
369 /* Parse all Vars from the buffer */
370 u_char *
371 snmp_var_DecodeVarBind(u_char * Buffer, int *BufLen,
372  struct variable_list ** VarP,
373  int Version)
374 {
375  struct variable_list *Var = NULL, **VarLastP;
376  u_char *bufp, *tmp;
377  u_char VarBindType;
378  u_char *DataPtr;
379  int DataLen;
380  oid TmpBuf[MAX_NAME_LEN];
381  memset(TmpBuf, 0, MAX_NAME_LEN * sizeof(*TmpBuf));
382 
383  int AllVarLen = *BufLen;
384  int ThisVarLen = 0;
385 
386  VarLastP = VarP;
387 #if DEBUG_VARS_DECODE
388  printf("VARS: Decoding buffer of length %d\n", *BufLen);
389 #endif
390 
391  /* Now parse the variables */
392  bufp = asn_parse_header(Buffer, &AllVarLen, &VarBindType);
393  if (bufp == NULL)
394  return (NULL);
395 
396  if (VarBindType != (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
398  return (NULL);
399  }
400 #if DEBUG_VARS_DECODE
401  printf("VARS: All Variable length %d\n", AllVarLen);
402 #endif
403 
404 #define PARSE_ERROR { snmp_var_free(Var); return(NULL); }
405 
406  /* We know how long the variable list is. Parse it. */
407  while ((int) AllVarLen > 0) {
408 
409  /* Create a new variable */
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)) {
429  PARSE_ERROR;
430  }
431 #if DEBUG_VARS_DECODE
432  printf("VARS: Header type 0x%x (%d bytes left)\n", VarBindType, ThisVarLen);
433 #endif
434 
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;
440 
441  if (VarBindType != (u_char) (ASN_UNIVERSAL |
442  ASN_PRIMITIVE |
443  ASN_OBJECT_ID)) {
445  PARSE_ERROR;
446  }
447 #if DEBUG_VARS_DECODE
448  printf("VARS: Decoded OBJID (%d bytes). (%d bytes left)\n",
449  Var->name_length, ThisVarLen);
450 #endif
451 
452  /* Keep a pointer to this object */
453  DataPtr = bufp;
454  DataLen = ThisVarLen;
455 
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;
461 
462 #if DEBUG_VARS_DECODE
463  printf("VARS: Data type %d\n", Var->type);
464 #endif
465 
466  /* Parse the type */
467 
468  switch ((short) Var->type) {
469 
470  case ASN_INTEGER:
471  Var->val.integer = (int *) xmalloc(sizeof(int));
472  if (Var->val.integer == NULL) {
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);
480 #if DEBUG_VARS_DECODE
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:
488  /* case SMI_UNSIGNED32: */
489  case SMI_TIMETICKS:
490  Var->val.integer = (int *) xmalloc(sizeof(u_int));
491  if (Var->val.integer == NULL) {
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);
499 #if DEBUG_VARS_DECODE
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:
508  Var->val_len = *&ThisVarLen; /* String is this at most */
509  Var->val.string = (u_char *) xmalloc((unsigned) Var->val_len);
510  if (Var->val.string == NULL) {
512  PARSE_ERROR;
513  }
514  bufp = asn_parse_string(DataPtr, &ThisVarLen,
515  &Var->type, Var->val.string,
516  &Var->val_len);
517 #if DEBUG_VARS_DECODE
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) {
531  PARSE_ERROR;
532  }
533  /* Only copy if we successfully decoded something */
534  if (bufp) {
535  memcpy((char *) Var->val.objid, (char *) TmpBuf, Var->val_len);
536  }
537 #if DEBUG_VARS_DECODE
538  printf("VARS: Decoded OBJID (length %d) (%d bytes left)\n",
539  Var->val_len, ThisVarLen);
540 #endif
541  break;
542 
543  case ASN_NULL:
544  case SMI_NOSUCHINSTANCE:
545  case SMI_NOSUCHOBJECT:
546  case SMI_ENDOFMIBVIEW:
547  break;
548 
549  case SMI_COUNTER64:
550  snmplib_debug(2, "Unable to parse type SMI_COUNTER64!\n");
552  PARSE_ERROR;
553 
554  default:
555  snmplib_debug(2, "bad type returned (%x)\n", Var->type);
557  PARSE_ERROR;
558  } /* End of var type switch */
559 
560  if (bufp == NULL)
561  PARSE_ERROR;
562 
563 #if DEBUG_VARS_DECODE
564  printf("VARS: Adding to list.\n");
565 #endif
566  /* Add variable to the list */
567  *VarLastP = Var;
568  VarLastP = &(Var->next_variable);
569  }
570 #undef PARSE_ERROR
571 
572  return (bufp);
573 }
574 
struct variable_list * snmp_var_new_integer(oid *Name, int Len, int ival, unsigned char type)
Definition: snmp_vars.c:154
#define ASN_PRIMITIVE
Definition: asn1.h:65
oid * objid
Definition: snmp_vars.h:52
#define SMI_NOSUCHINSTANCE
Definition: snmp_vars.h:119
struct variable_list * snmp_var_clone(struct variable_list *Src)
Definition: snmp_vars.c:169
#define ASN_NULL
Definition: asn1.h:55
#define SMI_IPADDRESS
Definition: snmp_vars.h:75
u_char * asn_build_int(u_char *, int *, u_char, int *, int)
Definition: asn1.c:245
#define ASN_OCTET_STR
Definition: asn1.h:54
SQUIDCEXTERN void snmplib_debug(int, const char *,...) PRINTF_FORMAT_ARG2
Definition: snmplib_debug.c:21
void snmp_set_api_error(int)
int type
Definition: errorpage.cc:79
u_char * asn_parse_string(u_char *, int *, u_char *, u_char *, int *)
Definition: asn1.c:387
int name_length
Definition: snmp_vars.h:47
#define SMI_OPAQUE
Definition: snmp_vars.h:80
u_char * asn_build_null(u_char *, int *, u_char)
Definition: asn1.c:876
struct variable_list * snmp_var_new(oid *Name, int Len)
Definition: snmp_vars.c:112
u_char * snmp_var_DecodeVarBind(u_char *Buffer, int *BufLen, struct variable_list **VarP, int Version)
Definition: snmp_vars.c:371
u_char * asn_build_objid(u_char *, int *, u_char, oid *, int)
Definition: asn1.c:759
u_char * asn_parse_objid(u_char *, int *, u_char *, oid *, int *)
Definition: asn1.c:674
u_char * asn_build_header(u_char *, int *, u_char, int)
Definition: asn1.c:93
u_char type
Definition: snmp_vars.h:48
u_char * snmp_var_EncodeVarBind(u_char *Buffer, int *BufLenP, variable_list *VarList, int Version)
Definition: snmp_vars.c:262
#define SNMPERR_OS_ERR
union variable_list::@20 val
#define ASN_INTEGER
Definition: asn1.h:52
#define SNMP_VERSION_1
Definition: snmp_msg.h:40
#define SMI_COUNTER64
Definition: snmp_vars.h:81
#define ASN_SEQUENCE
Definition: asn1.h:57
struct variable_list * next_variable
Definition: snmp_vars.h:45
u_char * asn_build_unsigned_int(u_char *, int *, u_char, u_int *, int)
Definition: asn1.c:311
u_char * asn_parse_unsigned_int(u_char *, int *, u_char *, u_int *, int)
Definition: asn1.c:179
u_char * asn_build_string(u_char *, int *, u_char, u_char *, int)
Definition: asn1.c:433
#define ASN_UNIVERSAL
Definition: asn1.h:60
int * integer
Definition: snmp_vars.h:50
u_char * asn_parse_int(u_char *, int *, u_char *, int *, int)
Definition: asn1.c:114
oid * name
Definition: snmp_vars.h:46
#define ASN_OBJECT_ID
Definition: asn1.h:56
u_int oid
Definition: asn1.h:42
#define SMI_TIMETICKS
Definition: snmp_vars.h:79
bool SIGHDLR int STUB void int
Definition: stub_tools.cc:68
void snmp_var_free(struct variable_list *Ptr)
Definition: snmp_vars.c:230
#define SMI_ENDOFMIBVIEW
Definition: snmp_vars.h:120
#define xmalloc
#define SMI_COUNTER32
Definition: snmp_vars.h:76
#define SNMPERR_PDU_PARSE
u_char * asn_build_exception(u_char *, int *, u_char)
Definition: asn1.c:1008
#define SMI_NOSUCHOBJECT
Definition: snmp_vars.h:118
#define SNMPERR_UNSUPPORTED_TYPE
u_char * asn_parse_header(u_char *, int *, u_char *)
Definition: asn1.c:470
#define xfree
#define MAX_NAME_LEN
Definition: snmp_vars.h:65
#define SMI_GAUGE32
Definition: snmp_vars.h:77
#define NULL
Definition: types.h:166
u_char * string
Definition: snmp_vars.h:51
#define PARSE_ERROR
#define ASN_CONSTRUCTOR
Definition: asn1.h:66

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors