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