]> git.ipfire.org Git - thirdparty/squid.git/blob - lib/snmplib/snmp_vars.c
SourceFormat Enforcement
[thirdparty/squid.git] / lib / snmplib / snmp_vars.c
1 /*
2 * Copyright (C) 1996-2015 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) {
122 snmp_set_api_error(SNMPERR_OS_ERR);
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);
139 snmp_set_api_error(SNMPERR_OS_ERR);
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 *
169 snmp_var_clone(struct variable_list *Src) {
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) {
178 snmp_set_api_error(SNMPERR_OS_ERR);
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) {
191 snmp_set_api_error(SNMPERR_OS_ERR);
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) {
206 snmp_set_api_error(SNMPERR_OS_ERR);
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
230 snmp_var_free(struct variable_list *Ptr)
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:
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);
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)) {
397 snmp_set_api_error(SNMPERR_PDU_PARSE);
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 */
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 }
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)) {
444 snmp_set_api_error(SNMPERR_PDU_PARSE);
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) {
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);
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) {
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);
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) {
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);
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) {
530 snmp_set_api_error(SNMPERR_OS_ERR);
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");
551 snmp_set_api_error(SNMPERR_UNSUPPORTED_TYPE);
552 PARSE_ERROR;
553
554 default:
555 snmplib_debug(2, "bad type returned (%x)\n", Var->type);
556 snmp_set_api_error(SNMPERR_PDU_PARSE);
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