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
108struct variable_list *
109snmp_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
150struct variable_list *
151snmp_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
165struct 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 */
226void
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 */
258u_char *
259snmp_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 |
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
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 */
367u_char *
368snmp_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)
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)) {
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)
437
438 if (VarBindType != (u_char) (ASN_UNIVERSAL |
440 ASN_OBJECT_ID)) {
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)
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) {
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) {
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) {
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) {
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:
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");
555
556 default:
557 snmplib_debug(2, "bad type returned (%x)\n", Var->type);
560 } /* End of var type switch */
561
562 if (bufp == NULL)
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
u_int oid
Definition: asn1.h:42
u_char * asn_build_header(u_char *, int *, u_char, int)
Definition: asn1.c:93
u_char * asn_build_unsigned_int(u_char *, int *, u_char, u_int *, int)
Definition: asn1.c:311
#define ASN_NULL
Definition: asn1.h:55
#define ASN_CONSTRUCTOR
Definition: asn1.h:66
u_char * asn_parse_unsigned_int(u_char *, int *, u_char *, u_int *, int)
Definition: asn1.c:179
#define ASN_SEQUENCE
Definition: asn1.h:57
#define ASN_OCTET_STR
Definition: asn1.h:54
#define ASN_OBJECT_ID
Definition: asn1.h:56
#define ASN_PRIMITIVE
Definition: asn1.h:65
u_char * asn_build_objid(u_char *, int *, u_char, oid *, int)
Definition: asn1.c:723
u_char * asn_build_null(u_char *, int *, u_char)
Definition: asn1.c:803
#define ASN_INTEGER
Definition: asn1.h:52
u_char * asn_parse_int(u_char *, int *, u_char *, int *, int)
Definition: asn1.c:114
#define ASN_UNIVERSAL
Definition: asn1.h:60
u_char * asn_parse_objid(u_char *, int *, u_char *, oid *, int *)
Definition: asn1.c:638
u_char * asn_parse_string(u_char *, int *, u_char *, u_char *, int *)
Definition: asn1.c:387
u_char * asn_build_int(u_char *, int *, u_char, int *, int)
Definition: asn1.c:245
u_char * asn_build_exception(u_char *, int *, u_char)
Definition: asn1.c:837
u_char * asn_parse_header(u_char *, int *, u_char *)
Definition: asn1.c:470
u_char * asn_build_string(u_char *, int *, u_char, u_char *, int)
Definition: asn1.c:433
#define xfree
#define xmalloc
#define SNMPERR_OS_ERR
void snmp_set_api_error(int)
#define SNMPERR_PDU_PARSE
#define SNMPERR_UNSUPPORTED_TYPE
SQUIDCEXTERN void snmplib_debug(int, const char *,...) PRINTF_FORMAT_ARG2
Definition: snmplib_debug.c:21
#define SNMP_VERSION_1
Definition: snmp_msg.h:40
struct variable_list * snmp_var_new(oid *Name, int Len)
Definition: snmp_vars.c:109
struct variable_list * snmp_var_clone(struct variable_list *Src)
Definition: snmp_vars.c:166
void snmp_var_free(struct variable_list *Ptr)
Definition: snmp_vars.c:227
struct variable_list * snmp_var_new_integer(oid *Name, int Len, int ival, unsigned char type)
Definition: snmp_vars.c:151
#define PARSE_ERROR
u_char * snmp_var_DecodeVarBind(u_char *Buffer, int *BufLen, struct variable_list **VarP, int Version)
Definition: snmp_vars.c:368
u_char * snmp_var_EncodeVarBind(u_char *Buffer, int *BufLenP, variable_list *VarList, int Version)
Definition: snmp_vars.c:259
#define SMI_GAUGE32
Definition: snmp_vars.h:77
#define SMI_NOSUCHOBJECT
Definition: snmp_vars.h:118
#define SMI_COUNTER32
Definition: snmp_vars.h:76
#define SMI_ENDOFMIBVIEW
Definition: snmp_vars.h:120
#define SMI_TIMETICKS
Definition: snmp_vars.h:79
#define SMI_OPAQUE
Definition: snmp_vars.h:80
#define SMI_COUNTER64
Definition: snmp_vars.h:81
#define SMI_IPADDRESS
Definition: snmp_vars.h:75
#define MAX_NAME_LEN
Definition: snmp_vars.h:65
#define SMI_NOSUCHINSTANCE
Definition: snmp_vars.h:119
struct variable_list * next_variable
Definition: snmp_vars.h:45
int name_length
Definition: snmp_vars.h:47
oid * objid
Definition: snmp_vars.h:52
int * integer
Definition: snmp_vars.h:50
oid * name
Definition: snmp_vars.h:46
u_char type
Definition: snmp_vars.h:48
u_char * string
Definition: snmp_vars.h:51
union variable_list::@19 val
int unsigned int
Definition: stub_fd.cc:19
#define NULL
Definition: types.h:145

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors