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