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