]> The Tcpdump Group git mirrors - tcpdump/blob - print-snmp.c
Get rid of libsmiV1 API compatibility. The configure script already
[tcpdump] / print-snmp.c
1 /*
2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by John Robert LoVerso.
11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
12 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
13 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
14 *
15 * This implementation has been influenced by the CMU SNMP release,
16 * by Steve Waldbusser. However, this shares no code with that system.
17 * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_.
18 * Earlier forms of this implementation were derived and/or inspired by an
19 * awk script originally written by C. Philip Wood of LANL (but later
20 * heavily modified by John Robert LoVerso). The copyright notice for
21 * that work is preserved below, even though it may not rightly apply
22 * to this file.
23 *
24 * Support for SNMPv2c/SNMPv3 and the ability to link the module against
25 * the libsmi was added by J. Schoenwaelder, Copyright (c) 1999.
26 *
27 * This started out as a very simple program, but the incremental decoding
28 * (into the BE structure) complicated things.
29 *
30 # Los Alamos National Laboratory
31 #
32 # Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
33 # This software was produced under a U.S. Government contract
34 # (W-7405-ENG-36) by Los Alamos National Laboratory, which is
35 # operated by the University of California for the U.S. Department
36 # of Energy. The U.S. Government is licensed to use, reproduce,
37 # and distribute this software. Permission is granted to the
38 # public to copy and use this software without charge, provided
39 # that this Notice and any statement of authorship are reproduced
40 # on all copies. Neither the Government nor the University makes
41 # any warranty, express or implied, or assumes any liability or
42 # responsibility for the use of this software.
43 # @(#)snmp.awk.x 1.1 (LANL) 1/15/90
44 */
45
46 #ifndef lint
47 static const char rcsid[] =
48 "@(#) $Header: /tcpdump/master/tcpdump/print-snmp.c,v 1.45 2001-01-24 21:50:58 fenner Exp $ (LBL)";
49 #endif
50
51 #ifdef HAVE_CONFIG_H
52 #include "config.h"
53 #endif
54
55 #include <sys/param.h>
56 #include <sys/time.h>
57
58 #include <ctype.h>
59 #include <stdio.h>
60 #include <string.h>
61
62 #ifdef HAVE_SMI_H
63 #include <smi.h>
64 #endif
65
66 #include "interface.h"
67 #include "addrtoname.h"
68
69 /*
70 * Universal ASN.1 types
71 * (we only care about the tag values for those allowed in the Internet SMI)
72 */
73 char *Universal[] = {
74 "U-0",
75 "Boolean",
76 "Integer",
77 #define INTEGER 2
78 "Bitstring",
79 "String",
80 #define STRING 4
81 "Null",
82 #define ASN_NULL 5
83 "ObjID",
84 #define OBJECTID 6
85 "ObjectDes",
86 "U-8","U-9","U-10","U-11", /* 8-11 */
87 "U-12","U-13","U-14","U-15", /* 12-15 */
88 "Sequence",
89 #define SEQUENCE 16
90 "Set"
91 };
92
93 /*
94 * Application-wide ASN.1 types from the Internet SMI and their tags
95 */
96 char *Application[] = {
97 "IpAddress",
98 #define IPADDR 0
99 "Counter",
100 #define COUNTER 1
101 "Gauge",
102 #define GAUGE 2
103 "TimeTicks",
104 #define TIMETICKS 3
105 "Opaque",
106 #define OPAQUE 4
107 "C-5",
108 "Counter64"
109 #define COUNTER64 6
110 };
111
112 /*
113 * Context-specific ASN.1 types for the SNMP PDUs and their tags
114 */
115 char *Context[] = {
116 "GetRequest",
117 #define GETREQ 0
118 "GetNextRequest",
119 #define GETNEXTREQ 1
120 "GetResponse",
121 #define GETRESP 2
122 "SetRequest",
123 #define SETREQ 3
124 "Trap",
125 #define TRAP 4
126 "GetBulk",
127 #define GETBULKREQ 5
128 "Inform",
129 #define INFORMREQ 6
130 "V2Trap",
131 #define V2TRAP 7
132 "Report"
133 #define REPORT 8
134 };
135
136 #define NOTIFY_CLASS(x) (x == TRAP || x == V2TRAP || x == INFORMREQ)
137 #define READ_CLASS(x) (x == GETREQ || x == GETNEXTREQ || x == GETBULKREQ)
138 #define WRITE_CLASS(x) (x == SETREQ)
139 #define RESPONSE_CLASS(x) (x == GETRESP)
140 #define INTERNAL_CLASS(x) (x == REPORT)
141
142 /*
143 * Context-specific ASN.1 types for the SNMP Exceptions and their tags
144 */
145 char *Exceptions[] = {
146 "noSuchObject",
147 #define NOSUCHOBJECT 0
148 "noSuchInstance",
149 #define NOSUCHINSTANCE 1
150 "endOfMibView",
151 #define ENDOFMIBVIEW 2
152 };
153
154 /*
155 * Private ASN.1 types
156 * The Internet SMI does not specify any
157 */
158 char *Private[] = {
159 "P-0"
160 };
161
162 /*
163 * error-status values for any SNMP PDU
164 */
165 char *ErrorStatus[] = {
166 "noError",
167 "tooBig",
168 "noSuchName",
169 "badValue",
170 "readOnly",
171 "genErr",
172 "noAccess",
173 "wrongType",
174 "wrongLength",
175 "wrongEncoding",
176 "wrongValue",
177 "noCreation",
178 "inconsistentValue",
179 "resourceUnavailable",
180 "commitFailed",
181 "undoFailed",
182 "authorizationError",
183 "notWritable",
184 "inconsistentName"
185 };
186 #define DECODE_ErrorStatus(e) \
187 ( e >= 0 && e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
188 ? ErrorStatus[e] \
189 : (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf))
190
191 /*
192 * generic-trap values in the SNMP Trap-PDU
193 */
194 char *GenericTrap[] = {
195 "coldStart",
196 "warmStart",
197 "linkDown",
198 "linkUp",
199 "authenticationFailure",
200 "egpNeighborLoss",
201 "enterpriseSpecific"
202 #define GT_ENTERPRISE 7
203 };
204 #define DECODE_GenericTrap(t) \
205 ( t >= 0 && t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
206 ? GenericTrap[t] \
207 : (snprintf(buf, sizeof(buf), "gt=%d", t), buf))
208
209 /*
210 * ASN.1 type class table
211 * Ties together the preceding Universal, Application, Context, and Private
212 * type definitions.
213 */
214 #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
215 struct {
216 char *name;
217 char **Id;
218 int numIDs;
219 } Class[] = {
220 defineCLASS(Universal),
221 #define UNIVERSAL 0
222 defineCLASS(Application),
223 #define APPLICATION 1
224 defineCLASS(Context),
225 #define CONTEXT 2
226 defineCLASS(Private),
227 #define PRIVATE 3
228 defineCLASS(Exceptions),
229 #define EXCEPTIONS 4
230 };
231
232 /*
233 * defined forms for ASN.1 types
234 */
235 char *Form[] = {
236 "Primitive",
237 #define PRIMITIVE 0
238 "Constructed",
239 #define CONSTRUCTED 1
240 };
241
242 /*
243 * A structure for the OID tree for the compiled-in MIB.
244 * This is stored as a general-order tree.
245 */
246 struct obj {
247 char *desc; /* name of object */
248 u_char oid; /* sub-id following parent */
249 u_char type; /* object type (unused) */
250 struct obj *child, *next; /* child and next sibling pointers */
251 } *objp = NULL;
252
253 /*
254 * Include the compiled in SNMP MIB. "mib.h" is produced by feeding
255 * RFC-1156 format files into "makemib". "mib.h" MUST define at least
256 * a value for `mibroot'.
257 *
258 * In particular, this is gross, as this is including initialized structures,
259 * and by right shouldn't be an "include" file.
260 */
261 #include "mib.h"
262
263 /*
264 * This defines a list of OIDs which will be abbreviated on output.
265 * Currently, this includes the prefixes for the Internet MIB, the
266 * private enterprises tree, and the experimental tree.
267 */
268 struct obj_abrev {
269 char *prefix; /* prefix for this abrev */
270 struct obj *node; /* pointer into object table */
271 char *oid; /* ASN.1 encoded OID */
272 } obj_abrev_list[] = {
273 #ifndef NO_ABREV_MIB
274 /* .iso.org.dod.internet.mgmt.mib */
275 { "", &_mib_obj, "\53\6\1\2\1" },
276 #endif
277 #ifndef NO_ABREV_ENTER
278 /* .iso.org.dod.internet.private.enterprises */
279 { "E:", &_enterprises_obj, "\53\6\1\4\1" },
280 #endif
281 #ifndef NO_ABREV_EXPERI
282 /* .iso.org.dod.internet.experimental */
283 { "X:", &_experimental_obj, "\53\6\1\3" },
284 #endif
285 #ifndef NO_ABBREV_SNMPMODS
286 /* .iso.org.dod.internet.snmpV2.snmpModules */
287 { "S:", &_snmpModules_obj, "\53\6\1\6\3" },
288 #endif
289 { 0,0,0 }
290 };
291
292 /*
293 * This is used in the OID print routine to walk down the object tree
294 * rooted at `mibroot'.
295 */
296 #define OBJ_PRINT(o, suppressdot) \
297 { \
298 if (objp) { \
299 do { \
300 if ((o) == objp->oid) \
301 break; \
302 } while ((objp = objp->next) != NULL); \
303 } \
304 if (objp) { \
305 printf(suppressdot?"%s":".%s", objp->desc); \
306 objp = objp->child; \
307 } else \
308 printf(suppressdot?"%u":".%u", (o)); \
309 }
310
311 /*
312 * This is the definition for the Any-Data-Type storage used purely for
313 * temporary internal representation while decoding an ASN.1 data stream.
314 */
315 struct be {
316 u_int32_t asnlen;
317 union {
318 caddr_t raw;
319 int32_t integer;
320 u_int32_t uns;
321 const u_char *str;
322 struct {
323 u_int32_t high;
324 u_int32_t low;
325 } uns64;
326 } data;
327 u_short id;
328 u_char form, class; /* tag info */
329 u_char type;
330 #define BE_ANY 255
331 #define BE_NONE 0
332 #define BE_NULL 1
333 #define BE_OCTET 2
334 #define BE_OID 3
335 #define BE_INT 4
336 #define BE_UNS 5
337 #define BE_STR 6
338 #define BE_SEQ 7
339 #define BE_INETADDR 8
340 #define BE_PDU 9
341 #define BE_UNS64 10
342 #define BE_NOSUCHOBJECT 128
343 #define BE_NOSUCHINST 129
344 #define BE_ENDOFMIBVIEW 130
345 };
346
347 /*
348 * SNMP versions recognized by this module
349 */
350 char *SnmpVersion[] = {
351 "SNMPv1",
352 #define SNMP_VERSION_1 0
353 "SNMPv2c",
354 #define SNMP_VERSION_2 1
355 "SNMPv2u",
356 #define SNMP_VERSION_2U 2
357 "SNMPv3"
358 #define SNMP_VERSION_3 3
359 };
360
361 /*
362 * Defaults for SNMP PDU components
363 */
364 #define DEF_COMMUNITY "public"
365
366 /*
367 * constants for ASN.1 decoding
368 */
369 #define OIDMUX 40
370 #define ASNLEN_INETADDR 4
371 #define ASN_SHIFT7 7
372 #define ASN_SHIFT8 8
373 #define ASN_BIT8 0x80
374 #define ASN_LONGLEN 0x80
375
376 #define ASN_ID_BITS 0x1f
377 #define ASN_FORM_BITS 0x20
378 #define ASN_FORM_SHIFT 5
379 #define ASN_CLASS_BITS 0xc0
380 #define ASN_CLASS_SHIFT 6
381
382 #define ASN_ID_EXT 0x1f /* extension ID in tag field */
383
384 /*
385 * truncated==1 means the packet was complete, but we don't have all of
386 * it to decode.
387 */
388 static int truncated;
389 #define ifNotTruncated if (truncated) fputs("[|snmp]", stdout); else
390
391 /*
392 * This decodes the next ASN.1 object in the stream pointed to by "p"
393 * (and of real-length "len") and stores the intermediate data in the
394 * provided BE object.
395 *
396 * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
397 * O/w, this returns the number of bytes parsed from "p".
398 */
399 static int
400 asn1_parse(register const u_char *p, u_int len, struct be *elem)
401 {
402 u_char form, class, id;
403 int i, hdr;
404
405 elem->asnlen = 0;
406 elem->type = BE_ANY;
407 if (len < 1) {
408 ifNotTruncated fputs("[nothing to parse]", stdout);
409 return -1;
410 }
411
412 /*
413 * it would be nice to use a bit field, but you can't depend on them.
414 * +---+---+---+---+---+---+---+---+
415 * + class |frm| id |
416 * +---+---+---+---+---+---+---+---+
417 * 7 6 5 4 3 2 1 0
418 */
419 id = *p & ASN_ID_BITS; /* lower 5 bits, range 00-1f */
420 #ifdef notdef
421 form = (*p & 0xe0) >> 5; /* move upper 3 bits to lower 3 */
422 class = form >> 1; /* bits 7&6 -> bits 1&0, range 0-3 */
423 form &= 0x1; /* bit 5 -> bit 0, range 0-1 */
424 #else
425 form = (u_char)(*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
426 class = (u_char)(*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
427 #endif
428 elem->form = form;
429 elem->class = class;
430 elem->id = id;
431 if (vflag > 1)
432 printf("|%.2x", *p);
433 p++; len--; hdr = 1;
434 /* extended tag field */
435 if (id == ASN_ID_EXT) {
436 for (id = 0; *p & ASN_BIT8 && len > 0; len--, hdr++, p++) {
437 if (vflag > 1)
438 printf("|%.2x", *p);
439 id = (id << 7) | (*p & ~ASN_BIT8);
440 }
441 if (len == 0 && *p & ASN_BIT8) {
442 ifNotTruncated fputs("[Xtagfield?]", stdout);
443 return -1;
444 }
445 elem->id = id = (id << 7) | *p;
446 --len;
447 ++hdr;
448 ++p;
449 }
450 if (len < 1) {
451 ifNotTruncated fputs("[no asnlen]", stdout);
452 return -1;
453 }
454 elem->asnlen = *p;
455 if (vflag > 1)
456 printf("|%.2x", *p);
457 p++; len--; hdr++;
458 if (elem->asnlen & ASN_BIT8) {
459 int noct = elem->asnlen % ASN_BIT8;
460 elem->asnlen = 0;
461 if (len < noct) {
462 ifNotTruncated printf("[asnlen? %d<%d]", len, noct);
463 return -1;
464 }
465 for (; noct-- > 0; len--, hdr++) {
466 if (vflag > 1)
467 printf("|%.2x", *p);
468 elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++;
469 }
470 }
471 if (len < elem->asnlen) {
472 if (!truncated) {
473 printf("[len%d<asnlen%u]", len, elem->asnlen);
474 return -1;
475 }
476 /* maybe should check at least 4? */
477 elem->asnlen = len;
478 }
479 if (form >= sizeof(Form)/sizeof(Form[0])) {
480 ifNotTruncated printf("[form?%d]", form);
481 return -1;
482 }
483 if (class >= sizeof(Class)/sizeof(Class[0])) {
484 ifNotTruncated printf("[class?%c/%d]", *Form[form], class);
485 return -1;
486 }
487 if ((int)id >= Class[class].numIDs) {
488 ifNotTruncated printf("[id?%c/%s/%d]", *Form[form],
489 Class[class].name, id);
490 return -1;
491 }
492
493 switch (form) {
494 case PRIMITIVE:
495 switch (class) {
496 case UNIVERSAL:
497 switch (id) {
498 case STRING:
499 elem->type = BE_STR;
500 elem->data.str = p;
501 break;
502
503 case INTEGER: {
504 register int32_t data;
505 elem->type = BE_INT;
506 data = 0;
507
508 if (*p & ASN_BIT8) /* negative */
509 data = -1;
510 for (i = elem->asnlen; i-- > 0; p++)
511 data = (data << ASN_SHIFT8) | *p;
512 elem->data.integer = data;
513 break;
514 }
515
516 case OBJECTID:
517 elem->type = BE_OID;
518 elem->data.raw = (caddr_t)p;
519 break;
520
521 case ASN_NULL:
522 elem->type = BE_NULL;
523 elem->data.raw = NULL;
524 break;
525
526 default:
527 elem->type = BE_OCTET;
528 elem->data.raw = (caddr_t)p;
529 printf("[P/U/%s]",
530 Class[class].Id[id]);
531 break;
532 }
533 break;
534
535 case APPLICATION:
536 switch (id) {
537 case IPADDR:
538 elem->type = BE_INETADDR;
539 elem->data.raw = (caddr_t)p;
540 break;
541
542 case COUNTER:
543 case GAUGE:
544 case TIMETICKS: {
545 register u_int32_t data;
546 elem->type = BE_UNS;
547 data = 0;
548 for (i = elem->asnlen; i-- > 0; p++)
549 data = (data << 8) + *p;
550 elem->data.uns = data;
551 break;
552 }
553
554 case COUNTER64: {
555 register u_int32_t high, low;
556 elem->type = BE_UNS64;
557 high = 0, low = 0;
558 for (i = elem->asnlen; i-- > 0; p++) {
559 high = (high << 8) |
560 ((low & 0xFF000000) >> 24);
561 low = (low << 8) | *p;
562 }
563 elem->data.uns64.high = high;
564 elem->data.uns64.low = low;
565 break;
566 }
567
568 default:
569 elem->type = BE_OCTET;
570 elem->data.raw = (caddr_t)p;
571 printf("[P/A/%s]",
572 Class[class].Id[id]);
573 break;
574 }
575 break;
576
577 case CONTEXT:
578 switch (id) {
579 case NOSUCHOBJECT:
580 elem->type = BE_NOSUCHOBJECT;
581 elem->data.raw = NULL;
582 break;
583
584 case NOSUCHINSTANCE:
585 elem->type = BE_NOSUCHINST;
586 elem->data.raw = NULL;
587 break;
588
589 case ENDOFMIBVIEW:
590 elem->type = BE_ENDOFMIBVIEW;
591 elem->data.raw = NULL;
592 break;
593 }
594 break;
595
596 default:
597 elem->type = BE_OCTET;
598 elem->data.raw = (caddr_t)p;
599 printf("[P/%s/%s]",
600 Class[class].name, Class[class].Id[id]);
601 break;
602 }
603 break;
604
605 case CONSTRUCTED:
606 switch (class) {
607 case UNIVERSAL:
608 switch (id) {
609 case SEQUENCE:
610 elem->type = BE_SEQ;
611 elem->data.raw = (caddr_t)p;
612 break;
613
614 default:
615 elem->type = BE_OCTET;
616 elem->data.raw = (caddr_t)p;
617 printf("C/U/%s", Class[class].Id[id]);
618 break;
619 }
620 break;
621
622 case CONTEXT:
623 elem->type = BE_PDU;
624 elem->data.raw = (caddr_t)p;
625 break;
626
627 default:
628 elem->type = BE_OCTET;
629 elem->data.raw = (caddr_t)p;
630 printf("C/%s/%s",
631 Class[class].name, Class[class].Id[id]);
632 break;
633 }
634 break;
635 }
636 p += elem->asnlen;
637 len -= elem->asnlen;
638 return elem->asnlen + hdr;
639 }
640
641 /*
642 * Display the ASN.1 object represented by the BE object.
643 * This used to be an integral part of asn1_parse() before the intermediate
644 * BE form was added.
645 */
646 static void
647 asn1_print(struct be *elem)
648 {
649 u_char *p = (u_char *)elem->data.raw;
650 u_int32_t asnlen = elem->asnlen;
651 int i;
652
653 switch (elem->type) {
654
655 case BE_OCTET:
656 for (i = asnlen; i-- > 0; p++)
657 printf("_%.2x", *p);
658 break;
659
660 case BE_NULL:
661 break;
662
663 case BE_OID: {
664 int o = 0, first = -1, i = asnlen;
665
666 if (!sflag && !nflag && asnlen > 2) {
667 struct obj_abrev *a = &obj_abrev_list[0];
668 for (; a->node; a++) {
669 if (!memcmp(a->oid, (char *)p,
670 strlen(a->oid))) {
671 objp = a->node->child;
672 i -= strlen(a->oid);
673 p += strlen(a->oid);
674 fputs(a->prefix, stdout);
675 first = 1;
676 break;
677 }
678 }
679 }
680
681 for (; !sflag && i-- > 0; p++) {
682 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
683 if (*p & ASN_LONGLEN)
684 continue;
685
686 /*
687 * first subitem encodes two items with 1st*OIDMUX+2nd
688 */
689 if (first < 0) {
690 if (!nflag)
691 objp = mibroot;
692 first = 0;
693 OBJ_PRINT(o/OIDMUX, first);
694 o %= OIDMUX;
695 }
696 OBJ_PRINT(o, first);
697 if (--first < 0)
698 first = 0;
699 o = 0;
700 }
701 break;
702 }
703
704 case BE_INT:
705 printf("%d", elem->data.integer);
706 break;
707
708 case BE_UNS:
709 printf("%u", elem->data.uns);
710 break;
711
712 case BE_UNS64: { /* idea borrowed from by Marshall Rose */
713 double d;
714 int j, carry;
715 char *cpf, *cpl, last[6], first[30];
716 if (elem->data.uns64.high == 0) {
717 printf("%u", elem->data.uns64.low);
718 break;
719 }
720 d = elem->data.uns64.high * 4294967296.0; /* 2^32 */
721 if (elem->data.uns64.high <= 0x1fffff) {
722 d += elem->data.uns64.low;
723 #if 0 /*is looks illegal, but what is the intention???*/
724 printf("%.f", d);
725 #else
726 printf("%f", d);
727 #endif
728 break;
729 }
730 d += (elem->data.uns64.low & 0xfffff000);
731 #if 0 /*is looks illegal, but what is the intention???*/
732 snprintf(first, sizeof(first), "%.f", d);
733 #else
734 snprintf(first, sizeof(first), "%f", d);
735 #endif
736 snprintf(last, sizeof(last), "%5.5d",
737 elem->data.uns64.low & 0xfff);
738 for (carry = 0, cpf = first+strlen(first)-1, cpl = last+4;
739 cpl >= last;
740 cpf--, cpl--) {
741 j = carry + (*cpf - '0') + (*cpl - '0');
742 if (j > 9) {
743 j -= 10;
744 carry = 1;
745 } else {
746 carry = 0;
747 }
748 *cpf = j + '0';
749 }
750 fputs(first, stdout);
751 break;
752 }
753
754 case BE_STR: {
755 register int printable = 1, first = 1;
756 const u_char *p = elem->data.str;
757 for (i = asnlen; printable && i-- > 0; p++)
758 printable = isprint(*p) || isspace(*p);
759 p = elem->data.str;
760 if (printable) {
761 putchar('"');
762 (void)fn_print(p, p + asnlen);
763 putchar('"');
764 } else
765 for (i = asnlen; i-- > 0; p++) {
766 printf(first ? "%.2x" : "_%.2x", *p);
767 first = 0;
768 }
769 break;
770 }
771
772 case BE_SEQ:
773 printf("Seq(%u)", elem->asnlen);
774 break;
775
776 case BE_INETADDR:
777 if (asnlen != ASNLEN_INETADDR)
778 printf("[inetaddr len!=%d]", ASNLEN_INETADDR);
779 for (i = asnlen; i-- > 0; p++) {
780 printf((i == asnlen-1) ? "%u" : ".%u", *p);
781 }
782 break;
783
784 case BE_NOSUCHOBJECT:
785 case BE_NOSUCHINST:
786 case BE_ENDOFMIBVIEW:
787 printf("[%s]", Class[EXCEPTIONS].Id[elem->id]);
788 break;
789
790 case BE_PDU:
791 printf("%s(%u)",
792 Class[CONTEXT].Id[elem->id], elem->asnlen);
793 break;
794
795 case BE_ANY:
796 fputs("[BE_ANY!?]", stdout);
797 break;
798
799 default:
800 fputs("[be!?]", stdout);
801 break;
802 }
803 }
804
805 #ifdef notdef
806 /*
807 * This is a brute force ASN.1 printer: recurses to dump an entire structure.
808 * This will work for any ASN.1 stream, not just an SNMP PDU.
809 *
810 * By adding newlines and spaces at the correct places, this would print in
811 * Rose-Normal-Form.
812 *
813 * This is not currently used.
814 */
815 static void
816 asn1_decode(u_char *p, u_int length)
817 {
818 struct be elem;
819 int i = 0;
820
821 while (i >= 0 && length > 0) {
822 i = asn1_parse(p, length, &elem);
823 if (i >= 0) {
824 fputs(" ", stdout);
825 asn1_print(&elem);
826 if (elem.type == BE_SEQ || elem.type == BE_PDU) {
827 fputs(" {", stdout);
828 asn1_decode(elem.data.raw, elem.asnlen);
829 fputs(" }", stdout);
830 }
831 length -= i;
832 p += i;
833 }
834 }
835 }
836 #endif
837
838 #ifdef LIBSMI
839
840 struct smi2be {
841 SmiBasetype basetype;
842 int be;
843 };
844
845 static struct smi2be smi2betab[] = {
846 { SMI_BASETYPE_INTEGER32, BE_INT },
847 { SMI_BASETYPE_OCTETSTRING, BE_STR },
848 { SMI_BASETYPE_OCTETSTRING, BE_INETADDR },
849 { SMI_BASETYPE_OBJECTIDENTIFIER, BE_OID },
850 { SMI_BASETYPE_UNSIGNED32, BE_UNS },
851 { SMI_BASETYPE_INTEGER64, BE_NONE },
852 { SMI_BASETYPE_UNSIGNED64, BE_UNS64 },
853 { SMI_BASETYPE_FLOAT32, BE_NONE },
854 { SMI_BASETYPE_FLOAT64, BE_NONE },
855 { SMI_BASETYPE_FLOAT128, BE_NONE },
856 { SMI_BASETYPE_ENUM, BE_INT },
857 { SMI_BASETYPE_BITS, BE_STR },
858 { SMI_BASETYPE_UNKNOWN, BE_NONE }
859 };
860
861 static void smi_decode_oid(struct be *elem, unsigned int *oid,
862 unsigned int *oidlen)
863 {
864 u_char *p = (u_char *)elem->data.raw;
865 u_int32_t asnlen = elem->asnlen;
866 int o = 0, first = -1, i = asnlen;
867
868 for (*oidlen = 0; sflag && i-- > 0; p++) {
869 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
870 if (*p & ASN_LONGLEN)
871 continue;
872
873 /*
874 * first subitem encodes two items with 1st*OIDMUX+2nd
875 */
876 if (first < 0) {
877 first = 0;
878 oid[(*oidlen)++] = o/OIDMUX;
879 o %= OIDMUX;
880 }
881 oid[(*oidlen)++] = o;
882 o = 0;
883 }
884 }
885
886 static int smi_check_type(SmiBasetype basetype, int be)
887 {
888 int i;
889
890 for (i = 0; smi2betab[i].basetype != SMI_BASETYPE_UNKNOWN; i++) {
891 if (smi2betab[i].basetype == basetype && smi2betab[i].be == be) {
892 return 1;
893 }
894 }
895
896 return 0;
897 }
898
899 static int smi_check_a_range(SmiType *smiType, SmiRange *smiRange,
900 struct be *elem)
901 {
902 int ok = 1;
903
904 switch (smiType->basetype) {
905 case SMI_BASETYPE_OBJECTIDENTIFIER:
906 case SMI_BASETYPE_OCTETSTRING:
907 if (smiRange->minValue.value.unsigned32
908 == smiRange->maxValue.value.unsigned32) {
909 ok = (elem->asnlen == smiRange->minValue.value.unsigned32);
910 } else {
911 ok = (elem->asnlen >= smiRange->minValue.value.unsigned32
912 && elem->asnlen <= smiRange->maxValue.value.unsigned32);
913 }
914 break;
915
916 case SMI_BASETYPE_INTEGER32:
917 ok = (elem->data.integer >= smiRange->minValue.value.integer32
918 && elem->data.integer <= smiRange->maxValue.value.integer32);
919 break;
920
921 case SMI_BASETYPE_UNSIGNED32:
922 ok = (elem->data.uns >= smiRange->minValue.value.unsigned32
923 && elem->data.uns <= smiRange->maxValue.value.unsigned32);
924 break;
925
926 case SMI_BASETYPE_UNSIGNED64:
927 /* XXX */
928 break;
929
930 /* case SMI_BASETYPE_INTEGER64: SMIng */
931 /* case SMI_BASETYPE_FLOAT32: SMIng */
932 /* case SMI_BASETYPE_FLOAT64: SMIng */
933 /* case SMI_BASETYPE_FLOAT128: SMIng */
934
935 case SMI_BASETYPE_ENUM:
936 case SMI_BASETYPE_BITS:
937 case SMI_BASETYPE_UNKNOWN:
938 ok = 1;
939 break;
940 }
941
942 return ok;
943 }
944
945 static int smi_check_range(SmiType *smiType, struct be *elem)
946 {
947 SmiRange *smiRange;
948 int ok = 1;
949
950 for (smiRange = smiGetFirstRange(smiType);
951 smiRange;
952 smiRange = smiGetNextRange(smiRange)) {
953
954 ok = smi_check_a_range(smiType, smiRange, elem);
955
956 if (ok) {
957 break;
958 }
959 }
960
961 if (ok) {
962 SmiType *parentType;
963 parentType = smiGetParentType(smiType);
964 if (parentType) {
965 ok = smi_check_range(parentType, elem);
966 }
967 }
968
969 return ok;
970 }
971
972 static SmiNode *smi_print_variable(struct be *elem)
973 {
974 unsigned int oid[128], oidlen;
975 SmiNode *smiNode = NULL;
976 int i;
977
978 smi_decode_oid(elem, oid, &oidlen);
979 smiNode = smiGetNodeByOID(oidlen, oid);
980 if (! smiNode) {
981 asn1_print(elem);
982 return NULL;
983 }
984 if (vflag) {
985 fputs(smiGetNodeModule(smiNode)->name, stdout);
986 fputs("::", stdout);
987 }
988 fputs(smiNode->name, stdout);
989 if (smiNode->oidlen < oidlen) {
990 for (i = smiNode->oidlen; i < oidlen; i++) {
991 printf(".%u", oid[i]);
992 }
993 }
994 return smiNode;
995 }
996
997 static void smi_print_value(SmiNode *smiNode, u_char pduid, struct be *elem)
998 {
999 unsigned int oid[128], oidlen;
1000 SmiType *smiType;
1001 SmiNamedNumber *nn;
1002 int i, done = 0;
1003
1004 if (! smiNode || ! (smiNode->nodekind
1005 & (SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN))) {
1006 asn1_print(elem);
1007 return;
1008 }
1009
1010 if (elem->type == BE_NOSUCHOBJECT
1011 || elem->type == BE_NOSUCHINST
1012 || elem->type == BE_ENDOFMIBVIEW) {
1013 asn1_print(elem);
1014 return;
1015 }
1016
1017 if (NOTIFY_CLASS(pduid) && smiNode->access < SMI_ACCESS_NOTIFY) {
1018 fputs("[notNotifyable]", stdout);
1019 }
1020
1021 if (READ_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_ONLY) {
1022 fputs("[notReadable]", stdout);
1023 }
1024
1025 if (WRITE_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_WRITE) {
1026 fputs("[notWritable]", stdout);
1027 }
1028
1029 if (RESPONSE_CLASS(pduid)
1030 && smiNode->access == SMI_ACCESS_NOT_ACCESSIBLE) {
1031 fputs("[noAccess]", stdout);
1032 }
1033
1034 smiType = smiGetNodeType(smiNode);
1035 if (! smiType) {
1036 asn1_print(elem);
1037 return;
1038 }
1039
1040 if (! smi_check_type(smiType->basetype, elem->type)) {
1041 fputs("[wrongType]", stdout);
1042 }
1043
1044 if (! smi_check_range(smiType, elem)) {
1045 fputs("[wrongLength]", stdout);
1046 }
1047
1048 /* resolve bits to named bits */
1049
1050 /* check whether instance identifier is valid */
1051
1052 /* apply display hints (integer, octetstring) */
1053
1054 /* convert instance identifier to index type values */
1055
1056 switch (elem->type) {
1057 case BE_OID:
1058 if (smiType->basetype == SMI_BASETYPE_BITS) {
1059 /* print bit labels */
1060 } else {
1061 smi_decode_oid(elem, oid, &oidlen);
1062 smiNode = smiGetNodeByOID(oidlen, oid);
1063 if (smiNode) {
1064 if (vflag) {
1065 fputs(smiGetNodeModule(smiNode)->name, stdout);
1066 fputs("::", stdout);
1067 }
1068 fputs(smiNode->name, stdout);
1069 if (smiNode->oidlen < oidlen) {
1070 for (i = smiNode->oidlen;
1071 i < oidlen; i++) {
1072 printf(".%u", oid[i]);
1073 }
1074 }
1075 done++;
1076 }
1077 }
1078 break;
1079
1080 case BE_INT:
1081 if (smiType->basetype == SMI_BASETYPE_ENUM) {
1082 for (nn = smiGetFirstNamedNumber(smiType);
1083 nn;
1084 nn = smiGetNextNamedNumber(nn)) {
1085 if (nn->value.value.integer32
1086 == elem->data.integer) {
1087 fputs(nn->name, stdout);
1088 printf("(%d)", elem->data.integer);
1089 done++;
1090 break;
1091 }
1092 }
1093 }
1094 break;
1095 }
1096
1097 if (! done) {
1098 asn1_print(elem);
1099 }
1100 }
1101 #endif
1102
1103 /*
1104 * General SNMP header
1105 * SEQUENCE {
1106 * version INTEGER {version-1(0)},
1107 * community OCTET STRING,
1108 * data ANY -- PDUs
1109 * }
1110 * PDUs for all but Trap: (see rfc1157 from page 15 on)
1111 * SEQUENCE {
1112 * request-id INTEGER,
1113 * error-status INTEGER,
1114 * error-index INTEGER,
1115 * varbindlist SEQUENCE OF
1116 * SEQUENCE {
1117 * name ObjectName,
1118 * value ObjectValue
1119 * }
1120 * }
1121 * PDU for Trap:
1122 * SEQUENCE {
1123 * enterprise OBJECT IDENTIFIER,
1124 * agent-addr NetworkAddress,
1125 * generic-trap INTEGER,
1126 * specific-trap INTEGER,
1127 * time-stamp TimeTicks,
1128 * varbindlist SEQUENCE OF
1129 * SEQUENCE {
1130 * name ObjectName,
1131 * value ObjectValue
1132 * }
1133 * }
1134 */
1135
1136 /*
1137 * Decode SNMP varBind
1138 */
1139 static void
1140 varbind_print(u_char pduid, const u_char *np, u_int length)
1141 {
1142 struct be elem;
1143 int count = 0, ind;
1144 #ifdef LIBSMI
1145 SmiNode *smiNode = NULL;
1146 #endif
1147
1148 /* Sequence of varBind */
1149 if ((count = asn1_parse(np, length, &elem)) < 0)
1150 return;
1151 if (elem.type != BE_SEQ) {
1152 fputs("[!SEQ of varbind]", stdout);
1153 asn1_print(&elem);
1154 return;
1155 }
1156 if (count < length)
1157 printf("[%d extra after SEQ of varbind]", length - count);
1158 /* descend */
1159 length = elem.asnlen;
1160 np = (u_char *)elem.data.raw;
1161
1162 for (ind = 1; length > 0; ind++) {
1163 const u_char *vbend;
1164 u_int vblength;
1165
1166 fputs(" ", stdout);
1167
1168 /* Sequence */
1169 if ((count = asn1_parse(np, length, &elem)) < 0)
1170 return;
1171 if (elem.type != BE_SEQ) {
1172 fputs("[!varbind]", stdout);
1173 asn1_print(&elem);
1174 return;
1175 }
1176 vbend = np + count;
1177 vblength = length - count;
1178 /* descend */
1179 length = elem.asnlen;
1180 np = (u_char *)elem.data.raw;
1181
1182 /* objName (OID) */
1183 if ((count = asn1_parse(np, length, &elem)) < 0)
1184 return;
1185 if (elem.type != BE_OID) {
1186 fputs("[objName!=OID]", stdout);
1187 asn1_print(&elem);
1188 return;
1189 }
1190 #ifdef LIBSMI
1191 smiNode = smi_print_variable(&elem);
1192 #else
1193 asn1_print(&elem);
1194 #endif
1195 length -= count;
1196 np += count;
1197
1198 if (pduid != GETREQ && pduid != GETNEXTREQ
1199 && pduid != GETBULKREQ)
1200 fputs("=", stdout);
1201
1202 /* objVal (ANY) */
1203 if ((count = asn1_parse(np, length, &elem)) < 0)
1204 return;
1205 if (pduid == GETREQ || pduid == GETNEXTREQ
1206 || pduid == GETBULKREQ) {
1207 if (elem.type != BE_NULL) {
1208 fputs("[objVal!=NULL]", stdout);
1209 asn1_print(&elem);
1210 }
1211 } else {
1212 if (elem.type != BE_NULL) {
1213 #ifdef LIBSMI
1214 smi_print_value(smiNode, pduid, &elem);
1215 #else
1216 asn1_print(&elem);
1217 #endif
1218 }
1219 }
1220 length = vblength;
1221 np = vbend;
1222 }
1223 }
1224
1225 /*
1226 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
1227 * GetBulk, Inform, V2Trap, and Report
1228 */
1229 static void
1230 snmppdu_print(u_char pduid, const u_char *np, u_int length)
1231 {
1232 struct be elem;
1233 int count = 0, error;
1234
1235 /* reqId (Integer) */
1236 if ((count = asn1_parse(np, length, &elem)) < 0)
1237 return;
1238 if (elem.type != BE_INT) {
1239 fputs("[reqId!=INT]", stdout);
1240 asn1_print(&elem);
1241 return;
1242 }
1243 if (vflag)
1244 printf("R=%d ", elem.data.integer);
1245 length -= count;
1246 np += count;
1247
1248 /* errorStatus (Integer) */
1249 if ((count = asn1_parse(np, length, &elem)) < 0)
1250 return;
1251 if (elem.type != BE_INT) {
1252 fputs("[errorStatus!=INT]", stdout);
1253 asn1_print(&elem);
1254 return;
1255 }
1256 error = 0;
1257 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1258 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1259 && elem.data.integer != 0) {
1260 char errbuf[10];
1261 printf("[errorStatus(%s)!=0]",
1262 DECODE_ErrorStatus(elem.data.integer));
1263 } else if (pduid == GETBULKREQ) {
1264 printf(" N=%d", elem.data.integer);
1265 } else if (elem.data.integer != 0) {
1266 char errbuf[10];
1267 printf(" %s", DECODE_ErrorStatus(elem.data.integer));
1268 error = elem.data.integer;
1269 }
1270 length -= count;
1271 np += count;
1272
1273 /* errorIndex (Integer) */
1274 if ((count = asn1_parse(np, length, &elem)) < 0)
1275 return;
1276 if (elem.type != BE_INT) {
1277 fputs("[errorIndex!=INT]", stdout);
1278 asn1_print(&elem);
1279 return;
1280 }
1281 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1282 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1283 && elem.data.integer != 0)
1284 printf("[errorIndex(%d)!=0]", elem.data.integer);
1285 else if (pduid == GETBULKREQ)
1286 printf(" M=%d", elem.data.integer);
1287 else if (elem.data.integer != 0) {
1288 if (!error)
1289 printf("[errorIndex(%d) w/o errorStatus]",
1290 elem.data.integer);
1291 else {
1292 printf("@%d", elem.data.integer);
1293 error = elem.data.integer;
1294 }
1295 } else if (error) {
1296 fputs("[errorIndex==0]", stdout);
1297 error = 0;
1298 }
1299 length -= count;
1300 np += count;
1301
1302 varbind_print(pduid, np, length);
1303 return;
1304 }
1305
1306 /*
1307 * Decode SNMP Trap PDU
1308 */
1309 static void
1310 trappdu_print(const u_char *np, u_int length)
1311 {
1312 struct be elem;
1313 int count = 0, generic;
1314
1315 putchar(' ');
1316
1317 /* enterprise (oid) */
1318 if ((count = asn1_parse(np, length, &elem)) < 0)
1319 return;
1320 if (elem.type != BE_OID) {
1321 fputs("[enterprise!=OID]", stdout);
1322 asn1_print(&elem);
1323 return;
1324 }
1325 asn1_print(&elem);
1326 length -= count;
1327 np += count;
1328
1329 putchar(' ');
1330
1331 /* agent-addr (inetaddr) */
1332 if ((count = asn1_parse(np, length, &elem)) < 0)
1333 return;
1334 if (elem.type != BE_INETADDR) {
1335 fputs("[agent-addr!=INETADDR]", stdout);
1336 asn1_print(&elem);
1337 return;
1338 }
1339 asn1_print(&elem);
1340 length -= count;
1341 np += count;
1342
1343 /* generic-trap (Integer) */
1344 if ((count = asn1_parse(np, length, &elem)) < 0)
1345 return;
1346 if (elem.type != BE_INT) {
1347 fputs("[generic-trap!=INT]", stdout);
1348 asn1_print(&elem);
1349 return;
1350 }
1351 generic = elem.data.integer;
1352 {
1353 char buf[10];
1354 printf(" %s", DECODE_GenericTrap(generic));
1355 }
1356 length -= count;
1357 np += count;
1358
1359 /* specific-trap (Integer) */
1360 if ((count = asn1_parse(np, length, &elem)) < 0)
1361 return;
1362 if (elem.type != BE_INT) {
1363 fputs("[specific-trap!=INT]", stdout);
1364 asn1_print(&elem);
1365 return;
1366 }
1367 if (generic != GT_ENTERPRISE) {
1368 if (elem.data.integer != 0)
1369 printf("[specific-trap(%d)!=0]", elem.data.integer);
1370 } else
1371 printf(" s=%d", elem.data.integer);
1372 length -= count;
1373 np += count;
1374
1375 putchar(' ');
1376
1377 /* time-stamp (TimeTicks) */
1378 if ((count = asn1_parse(np, length, &elem)) < 0)
1379 return;
1380 if (elem.type != BE_UNS) { /* XXX */
1381 fputs("[time-stamp!=TIMETICKS]", stdout);
1382 asn1_print(&elem);
1383 return;
1384 }
1385 asn1_print(&elem);
1386 length -= count;
1387 np += count;
1388
1389 varbind_print (TRAP, np, length);
1390 return;
1391 }
1392
1393 /*
1394 * Decode arbitrary SNMP PDUs.
1395 */
1396 static void
1397 pdu_print(const u_char *np, u_int length, int version)
1398 {
1399 struct be pdu;
1400 int count = 0;
1401
1402 /* PDU (Context) */
1403 if ((count = asn1_parse(np, length, &pdu)) < 0)
1404 return;
1405 if (pdu.type != BE_PDU) {
1406 fputs("[no PDU]", stdout);
1407 return;
1408 }
1409 if (count < length)
1410 printf("[%d extra after PDU]", length - count);
1411 if (vflag) {
1412 fputs("{ ", stdout);
1413 }
1414 asn1_print(&pdu);
1415 fputs(" ", stdout);
1416 /* descend into PDU */
1417 length = pdu.asnlen;
1418 np = (u_char *)pdu.data.raw;
1419
1420 if (version == SNMP_VERSION_1 &&
1421 (pdu.id == GETBULKREQ || pdu.id == INFORMREQ ||
1422 pdu.id == V2TRAP || pdu.id == REPORT)) {
1423 printf("[v2 PDU in v1 message]");
1424 return;
1425 }
1426
1427 if (version == SNMP_VERSION_2 && pdu.id == TRAP) {
1428 printf("[v1 PDU in v2 message]");
1429 return;
1430 }
1431
1432 switch (pdu.id) {
1433 case TRAP:
1434 trappdu_print(np, length);
1435 break;
1436 case GETREQ:
1437 case GETNEXTREQ:
1438 case GETRESP:
1439 case SETREQ:
1440 case GETBULKREQ:
1441 case INFORMREQ:
1442 case V2TRAP:
1443 case REPORT:
1444 snmppdu_print(pdu.id, np, length);
1445 break;
1446 }
1447
1448 if (vflag) {
1449 fputs("} ", stdout);
1450 }
1451 }
1452
1453 /*
1454 * Decode a scoped SNMP PDU.
1455 */
1456 static void
1457 scopedpdu_print(const u_char *np, u_int length, int version)
1458 {
1459 struct be elem;
1460 int i, count = 0;
1461
1462 /* Sequence */
1463 if ((count = asn1_parse(np, length, &elem)) < 0)
1464 return;
1465 if (elem.type != BE_SEQ) {
1466 fputs("[!scoped PDU]", stdout);
1467 asn1_print(&elem);
1468 return;
1469 }
1470 length = elem.asnlen;
1471 np = (u_char *)elem.data.raw;
1472
1473 /* contextEngineID (OCTET STRING) */
1474 if ((count = asn1_parse(np, length, &elem)) < 0)
1475 return;
1476 if (elem.type != BE_STR) {
1477 fputs("[contextEngineID!=STR]", stdout);
1478 asn1_print(&elem);
1479 return;
1480 }
1481 length -= count;
1482 np += count;
1483
1484 fputs("E= ", stdout);
1485 for (i = 0; i < (int)elem.asnlen; i++) {
1486 printf("0x%02X", elem.data.str[i]);
1487 }
1488 fputs(" ", stdout);
1489
1490 /* contextName (OCTET STRING) */
1491 if ((count = asn1_parse(np, length, &elem)) < 0)
1492 return;
1493 if (elem.type != BE_STR) {
1494 fputs("[contextName!=STR]", stdout);
1495 asn1_print(&elem);
1496 return;
1497 }
1498 length -= count;
1499 np += count;
1500
1501 printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
1502
1503 pdu_print(np, length, version);
1504 }
1505
1506 /*
1507 * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
1508 */
1509 static void
1510 community_print(const u_char *np, u_int length, int version)
1511 {
1512 struct be elem;
1513 int count = 0;
1514
1515 /* Community (String) */
1516 if ((count = asn1_parse(np, length, &elem)) < 0)
1517 return;
1518 if (elem.type != BE_STR) {
1519 fputs("[comm!=STR]", stdout);
1520 asn1_print(&elem);
1521 return;
1522 }
1523 /* default community */
1524 if (strncmp((char *)elem.data.str, DEF_COMMUNITY,
1525 sizeof(DEF_COMMUNITY) - 1))
1526 /* ! "public" */
1527 printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
1528 length -= count;
1529 np += count;
1530
1531 pdu_print(np, length, version);
1532 }
1533
1534 /*
1535 * Decode SNMPv3 User-based Security Message Header (SNMPv3)
1536 */
1537 static void
1538 usm_print(const u_char *np, u_int length)
1539 {
1540 struct be elem;
1541 int count = 0;
1542
1543 /* Sequence */
1544 if ((count = asn1_parse(np, length, &elem)) < 0)
1545 return;
1546 if (elem.type != BE_SEQ) {
1547 fputs("[!usm]", stdout);
1548 asn1_print(&elem);
1549 return;
1550 }
1551 length = elem.asnlen;
1552 np = (u_char *)elem.data.raw;
1553
1554 /* msgAuthoritativeEngineID (OCTET STRING) */
1555 if ((count = asn1_parse(np, length, &elem)) < 0)
1556 return;
1557 if (elem.type != BE_STR) {
1558 fputs("[msgAuthoritativeEngineID!=STR]", stdout);
1559 asn1_print(&elem);
1560 return;
1561 }
1562 length -= count;
1563 np += count;
1564
1565 /* msgAuthoritativeEngineBoots (INTEGER) */
1566 if ((count = asn1_parse(np, length, &elem)) < 0)
1567 return;
1568 if (elem.type != BE_INT) {
1569 fputs("[msgAuthoritativeEngineBoots!=INT]", stdout);
1570 asn1_print(&elem);
1571 return;
1572 }
1573 if (vflag)
1574 printf("B=%d ", elem.data.integer);
1575 length -= count;
1576 np += count;
1577
1578 /* msgAuthoritativeEngineTime (INTEGER) */
1579 if ((count = asn1_parse(np, length, &elem)) < 0)
1580 return;
1581 if (elem.type != BE_INT) {
1582 fputs("[msgAuthoritativeEngineTime!=INT]", stdout);
1583 asn1_print(&elem);
1584 return;
1585 }
1586 if (vflag)
1587 printf("T=%d ", elem.data.integer);
1588 length -= count;
1589 np += count;
1590
1591 /* msgUserName (OCTET STRING) */
1592 if ((count = asn1_parse(np, length, &elem)) < 0)
1593 return;
1594 if (elem.type != BE_STR) {
1595 fputs("[msgUserName!=STR]", stdout);
1596 asn1_print(&elem);
1597 return;
1598 }
1599 length -= count;
1600 np += count;
1601
1602 printf("U=%.*s ", (int)elem.asnlen, elem.data.str);
1603
1604 /* msgAuthenticationParameters (OCTET STRING) */
1605 if ((count = asn1_parse(np, length, &elem)) < 0)
1606 return;
1607 if (elem.type != BE_STR) {
1608 fputs("[msgAuthenticationParameters!=STR]", stdout);
1609 asn1_print(&elem);
1610 return;
1611 }
1612 length -= count;
1613 np += count;
1614
1615 /* msgPrivacyParameters (OCTET STRING) */
1616 if ((count = asn1_parse(np, length, &elem)) < 0)
1617 return;
1618 if (elem.type != BE_STR) {
1619 fputs("[msgPrivacyParameters!=STR]", stdout);
1620 asn1_print(&elem);
1621 return;
1622 }
1623 length -= count;
1624 np += count;
1625
1626 if (count < length)
1627 printf("[%d extra after usm SEQ]", length - count);
1628 }
1629
1630 /*
1631 * Decode SNMPv3 Message Header (SNMPv3)
1632 */
1633 static void
1634 v3msg_print(const u_char *np, u_int length)
1635 {
1636 struct be elem;
1637 int count = 0;
1638 u_char flags;
1639 int model;
1640 const u_char *xnp = np;
1641 int xlength = length;
1642
1643 /* Sequence */
1644 if ((count = asn1_parse(np, length, &elem)) < 0)
1645 return;
1646 if (elem.type != BE_SEQ) {
1647 fputs("[!message]", stdout);
1648 asn1_print(&elem);
1649 return;
1650 }
1651 length = elem.asnlen;
1652 np = (u_char *)elem.data.raw;
1653
1654 if (vflag) {
1655 fputs("{ ", stdout);
1656 }
1657
1658 /* msgID (INTEGER) */
1659 if ((count = asn1_parse(np, length, &elem)) < 0)
1660 return;
1661 if (elem.type != BE_INT) {
1662 fputs("[msgID!=INT]", stdout);
1663 asn1_print(&elem);
1664 return;
1665 }
1666 length -= count;
1667 np += count;
1668
1669 /* msgMaxSize (INTEGER) */
1670 if ((count = asn1_parse(np, length, &elem)) < 0)
1671 return;
1672 if (elem.type != BE_INT) {
1673 fputs("[msgMaxSize!=INT]", stdout);
1674 asn1_print(&elem);
1675 return;
1676 }
1677 length -= count;
1678 np += count;
1679
1680 /* msgFlags (OCTET STRING) */
1681 if ((count = asn1_parse(np, length, &elem)) < 0)
1682 return;
1683 if (elem.type != BE_STR) {
1684 fputs("[msgFlags!=STR]", stdout);
1685 asn1_print(&elem);
1686 return;
1687 }
1688 if (elem.asnlen != 1) {
1689 printf("[msgFlags size %d]", elem.asnlen);
1690 return;
1691 }
1692 flags = elem.data.str[0];
1693 if (flags != 0x00 && flags != 0x01 && flags != 0x03
1694 && flags != 0x04 && flags != 0x05 && flags != 0x07) {
1695 printf("[msgFlags=0x%02X]", flags);
1696 return;
1697 }
1698 length -= count;
1699 np += count;
1700
1701 fputs("F=", stdout);
1702 if (flags & 0x01) fputs("a", stdout);
1703 if (flags & 0x02) fputs("p", stdout);
1704 if (flags & 0x04) fputs("r", stdout);
1705 fputs(" ", stdout);
1706
1707 /* msgSecurityModel (INTEGER) */
1708 if ((count = asn1_parse(np, length, &elem)) < 0)
1709 return;
1710 if (elem.type != BE_INT) {
1711 fputs("[msgSecurityModel!=INT]", stdout);
1712 asn1_print(&elem);
1713 return;
1714 }
1715 model = elem.data.integer;
1716 length -= count;
1717 np += count;
1718
1719 if (count < length)
1720 printf("[%d extra after message SEQ]", length - count);
1721
1722 if (vflag) {
1723 fputs("} ", stdout);
1724 }
1725
1726 if (model == 3) {
1727 if (vflag) {
1728 fputs("{ USM ", stdout);
1729 }
1730 } else {
1731 printf("[security model %d]", model);
1732 return;
1733 }
1734
1735 np = xnp + (np - xnp);
1736 length = xlength - (np - xnp);
1737
1738 /* msgSecurityParameters (OCTET STRING) */
1739 if ((count = asn1_parse(np, length, &elem)) < 0)
1740 return;
1741 if (elem.type != BE_STR) {
1742 fputs("[msgSecurityParameters!=STR]", stdout);
1743 asn1_print(&elem);
1744 return;
1745 }
1746 length -= count;
1747 np += count;
1748
1749 if (model == 3) {
1750 usm_print(elem.data.str, elem.asnlen);
1751 if (vflag) {
1752 fputs("} ", stdout);
1753 }
1754 }
1755
1756 if (vflag) {
1757 fputs("{ ScopedPDU ", stdout);
1758 }
1759
1760 scopedpdu_print(np, length, 3);
1761
1762 if (vflag) {
1763 fputs("} ", stdout);
1764 }
1765 }
1766
1767 /*
1768 * Decode SNMP header and pass on to PDU printing routines
1769 */
1770 void
1771 snmp_print(const u_char *np, u_int length)
1772 {
1773 struct be elem;
1774 int count = 0;
1775 int version = 0;
1776
1777 truncated = 0;
1778
1779 /* truncated packet? */
1780 if (np + length > snapend) {
1781 truncated = 1;
1782 length = snapend - np;
1783 }
1784
1785 putchar(' ');
1786
1787 /* initial Sequence */
1788 if ((count = asn1_parse(np, length, &elem)) < 0)
1789 return;
1790 if (elem.type != BE_SEQ) {
1791 fputs("[!init SEQ]", stdout);
1792 asn1_print(&elem);
1793 return;
1794 }
1795 if (count < length)
1796 printf("[%d extra after iSEQ]", length - count);
1797 /* descend */
1798 length = elem.asnlen;
1799 np = (u_char *)elem.data.raw;
1800
1801 /* Version (INTEGER) */
1802 if ((count = asn1_parse(np, length, &elem)) < 0)
1803 return;
1804 if (elem.type != BE_INT) {
1805 fputs("[version!=INT]", stdout);
1806 asn1_print(&elem);
1807 return;
1808 }
1809
1810 switch (elem.data.integer) {
1811 case SNMP_VERSION_1:
1812 case SNMP_VERSION_2:
1813 case SNMP_VERSION_3:
1814 if (vflag)
1815 printf("{ %s ", SnmpVersion[elem.data.integer]);
1816 break;
1817 default:
1818 printf("[version = %d]", elem.data.integer);
1819 return;
1820 }
1821 version = elem.data.integer;
1822 length -= count;
1823 np += count;
1824
1825 switch (version) {
1826 case SNMP_VERSION_1:
1827 case SNMP_VERSION_2:
1828 community_print(np, length, version);
1829 break;
1830 case SNMP_VERSION_3:
1831 v3msg_print(np, length);
1832 break;
1833 default:
1834 printf("[version = %d]", elem.data.integer);
1835 break;
1836 }
1837
1838 if (vflag) {
1839 fputs("} ", stdout);
1840 }
1841 }