]> The Tcpdump Group git mirrors - tcpdump/blob - print-snmp.c
Mention the SourceForge site.
[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[] =
61 "@(#) $Header: /tcpdump/master/tcpdump/print-snmp.c,v 1.52 2002-05-07 18:27:40 fenner Exp $ (LBL)";
62 #endif
63
64 #ifdef HAVE_CONFIG_H
65 #include "config.h"
66 #endif
67
68 #include <sys/param.h>
69 #include <sys/time.h>
70
71 #include <ctype.h>
72 #include <stdio.h>
73 #include <string.h>
74
75 #ifdef HAVE_SMI_H
76 #include <smi.h>
77 #endif
78
79 #include "interface.h"
80 #include "addrtoname.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 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 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 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 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 char *Private[] = {
172 "P-0"
173 };
174
175 /*
176 * error-status values for any SNMP PDU
177 */
178 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 && 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 char *GenericTrap[] = {
208 "coldStart",
209 "warmStart",
210 "linkDown",
211 "linkUp",
212 "authenticationFailure",
213 "egpNeighborLoss",
214 "enterpriseSpecific"
215 #define GT_ENTERPRISE 7
216 };
217 #define DECODE_GenericTrap(t) \
218 ( t >= 0 && 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 char *name;
230 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 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 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 char *prefix; /* prefix for this abrev */
283 struct obj *node; /* pointer into object table */
284 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 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 int 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 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 * (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
956 return ok;
957 }
958
959 static int smi_check_range(SmiType *smiType, struct be *elem)
960 {
961 SmiRange *smiRange;
962 int ok = 1;
963
964 for (smiRange = smiGetFirstRange(smiType);
965 smiRange;
966 smiRange = smiGetNextRange(smiRange)) {
967
968 ok = smi_check_a_range(smiType, smiRange, elem);
969
970 if (ok) {
971 break;
972 }
973 }
974
975 if (ok) {
976 SmiType *parentType;
977 parentType = smiGetParentType(smiType);
978 if (parentType) {
979 ok = smi_check_range(parentType, elem);
980 }
981 }
982
983 return ok;
984 }
985
986 static SmiNode *smi_print_variable(struct be *elem)
987 {
988 unsigned int oid[128], oidlen;
989 SmiNode *smiNode = NULL;
990 int i;
991
992 smi_decode_oid(elem, oid, sizeof(oid)/sizeof(unsigned int), &oidlen);
993 smiNode = smiGetNodeByOID(oidlen, oid);
994 if (! smiNode) {
995 asn1_print(elem);
996 return NULL;
997 }
998 if (vflag) {
999 fputs(smiGetNodeModule(smiNode)->name, stdout);
1000 fputs("::", stdout);
1001 }
1002 fputs(smiNode->name, stdout);
1003 if (smiNode->oidlen < oidlen) {
1004 for (i = smiNode->oidlen; i < oidlen; i++) {
1005 printf(".%u", oid[i]);
1006 }
1007 }
1008 return smiNode;
1009 }
1010
1011 static void smi_print_value(SmiNode *smiNode, u_char pduid, struct be *elem)
1012 {
1013 unsigned int oid[128], oidlen;
1014 SmiType *smiType;
1015 SmiNamedNumber *nn;
1016 int i, done = 0;
1017
1018 if (! smiNode || ! (smiNode->nodekind
1019 & (SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN))) {
1020 asn1_print(elem);
1021 return;
1022 }
1023
1024 if (elem->type == BE_NOSUCHOBJECT
1025 || elem->type == BE_NOSUCHINST
1026 || elem->type == BE_ENDOFMIBVIEW) {
1027 asn1_print(elem);
1028 return;
1029 }
1030
1031 if (NOTIFY_CLASS(pduid) && smiNode->access < SMI_ACCESS_NOTIFY) {
1032 fputs("[notNotifyable]", stdout);
1033 }
1034
1035 if (READ_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_ONLY) {
1036 fputs("[notReadable]", stdout);
1037 }
1038
1039 if (WRITE_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_WRITE) {
1040 fputs("[notWritable]", stdout);
1041 }
1042
1043 if (RESPONSE_CLASS(pduid)
1044 && smiNode->access == SMI_ACCESS_NOT_ACCESSIBLE) {
1045 fputs("[noAccess]", stdout);
1046 }
1047
1048 smiType = smiGetNodeType(smiNode);
1049 if (! smiType) {
1050 asn1_print(elem);
1051 return;
1052 }
1053
1054 if (! smi_check_type(smiType->basetype, elem->type)) {
1055 fputs("[wrongType]", stdout);
1056 }
1057
1058 if (! smi_check_range(smiType, elem)) {
1059 fputs("[outOfRange]", stdout);
1060 }
1061
1062 /* resolve bits to named bits */
1063
1064 /* check whether instance identifier is valid */
1065
1066 /* apply display hints (integer, octetstring) */
1067
1068 /* convert instance identifier to index type values */
1069
1070 switch (elem->type) {
1071 case BE_OID:
1072 if (smiType->basetype == SMI_BASETYPE_BITS) {
1073 /* print bit labels */
1074 } else {
1075 smi_decode_oid(elem, oid,
1076 sizeof(oid)/sizeof(unsigned int),
1077 &oidlen);
1078 smiNode = smiGetNodeByOID(oidlen, oid);
1079 if (smiNode) {
1080 if (vflag) {
1081 fputs(smiGetNodeModule(smiNode)->name, stdout);
1082 fputs("::", stdout);
1083 }
1084 fputs(smiNode->name, stdout);
1085 if (smiNode->oidlen < oidlen) {
1086 for (i = smiNode->oidlen;
1087 i < oidlen; i++) {
1088 printf(".%u", oid[i]);
1089 }
1090 }
1091 done++;
1092 }
1093 }
1094 break;
1095
1096 case BE_INT:
1097 if (smiType->basetype == SMI_BASETYPE_ENUM) {
1098 for (nn = smiGetFirstNamedNumber(smiType);
1099 nn;
1100 nn = smiGetNextNamedNumber(nn)) {
1101 if (nn->value.value.integer32
1102 == elem->data.integer) {
1103 fputs(nn->name, stdout);
1104 printf("(%d)", elem->data.integer);
1105 done++;
1106 break;
1107 }
1108 }
1109 }
1110 break;
1111 }
1112
1113 if (! done) {
1114 asn1_print(elem);
1115 }
1116 }
1117 #endif
1118
1119 /*
1120 * General SNMP header
1121 * SEQUENCE {
1122 * version INTEGER {version-1(0)},
1123 * community OCTET STRING,
1124 * data ANY -- PDUs
1125 * }
1126 * PDUs for all but Trap: (see rfc1157 from page 15 on)
1127 * SEQUENCE {
1128 * request-id INTEGER,
1129 * error-status INTEGER,
1130 * error-index INTEGER,
1131 * varbindlist SEQUENCE OF
1132 * SEQUENCE {
1133 * name ObjectName,
1134 * value ObjectValue
1135 * }
1136 * }
1137 * PDU for Trap:
1138 * SEQUENCE {
1139 * enterprise OBJECT IDENTIFIER,
1140 * agent-addr NetworkAddress,
1141 * generic-trap INTEGER,
1142 * specific-trap INTEGER,
1143 * time-stamp TimeTicks,
1144 * varbindlist SEQUENCE OF
1145 * SEQUENCE {
1146 * name ObjectName,
1147 * value ObjectValue
1148 * }
1149 * }
1150 */
1151
1152 /*
1153 * Decode SNMP varBind
1154 */
1155 static void
1156 varbind_print(u_char pduid, const u_char *np, u_int length)
1157 {
1158 struct be elem;
1159 int count = 0, ind;
1160 #ifdef LIBSMI
1161 SmiNode *smiNode = NULL;
1162 #endif
1163
1164 /* Sequence of varBind */
1165 if ((count = asn1_parse(np, length, &elem)) < 0)
1166 return;
1167 if (elem.type != BE_SEQ) {
1168 fputs("[!SEQ of varbind]", stdout);
1169 asn1_print(&elem);
1170 return;
1171 }
1172 if (count < length)
1173 printf("[%d extra after SEQ of varbind]", length - count);
1174 /* descend */
1175 length = elem.asnlen;
1176 np = (u_char *)elem.data.raw;
1177
1178 for (ind = 1; length > 0; ind++) {
1179 const u_char *vbend;
1180 u_int vblength;
1181
1182 fputs(" ", stdout);
1183
1184 /* Sequence */
1185 if ((count = asn1_parse(np, length, &elem)) < 0)
1186 return;
1187 if (elem.type != BE_SEQ) {
1188 fputs("[!varbind]", stdout);
1189 asn1_print(&elem);
1190 return;
1191 }
1192 vbend = np + count;
1193 vblength = length - count;
1194 /* descend */
1195 length = elem.asnlen;
1196 np = (u_char *)elem.data.raw;
1197
1198 /* objName (OID) */
1199 if ((count = asn1_parse(np, length, &elem)) < 0)
1200 return;
1201 if (elem.type != BE_OID) {
1202 fputs("[objName!=OID]", stdout);
1203 asn1_print(&elem);
1204 return;
1205 }
1206 #ifdef LIBSMI
1207 smiNode = smi_print_variable(&elem);
1208 #else
1209 asn1_print(&elem);
1210 #endif
1211 length -= count;
1212 np += count;
1213
1214 if (pduid != GETREQ && pduid != GETNEXTREQ
1215 && pduid != GETBULKREQ)
1216 fputs("=", stdout);
1217
1218 /* objVal (ANY) */
1219 if ((count = asn1_parse(np, length, &elem)) < 0)
1220 return;
1221 if (pduid == GETREQ || pduid == GETNEXTREQ
1222 || pduid == GETBULKREQ) {
1223 if (elem.type != BE_NULL) {
1224 fputs("[objVal!=NULL]", stdout);
1225 asn1_print(&elem);
1226 }
1227 } else {
1228 if (elem.type != BE_NULL) {
1229 #ifdef LIBSMI
1230 smi_print_value(smiNode, pduid, &elem);
1231 #else
1232 asn1_print(&elem);
1233 #endif
1234 }
1235 }
1236 length = vblength;
1237 np = vbend;
1238 }
1239 }
1240
1241 /*
1242 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
1243 * GetBulk, Inform, V2Trap, and Report
1244 */
1245 static void
1246 snmppdu_print(u_char pduid, const u_char *np, u_int length)
1247 {
1248 struct be elem;
1249 int count = 0, error;
1250
1251 /* reqId (Integer) */
1252 if ((count = asn1_parse(np, length, &elem)) < 0)
1253 return;
1254 if (elem.type != BE_INT) {
1255 fputs("[reqId!=INT]", stdout);
1256 asn1_print(&elem);
1257 return;
1258 }
1259 if (vflag)
1260 printf("R=%d ", elem.data.integer);
1261 length -= count;
1262 np += count;
1263
1264 /* errorStatus (Integer) */
1265 if ((count = asn1_parse(np, length, &elem)) < 0)
1266 return;
1267 if (elem.type != BE_INT) {
1268 fputs("[errorStatus!=INT]", stdout);
1269 asn1_print(&elem);
1270 return;
1271 }
1272 error = 0;
1273 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1274 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1275 && elem.data.integer != 0) {
1276 char errbuf[10];
1277 printf("[errorStatus(%s)!=0]",
1278 DECODE_ErrorStatus(elem.data.integer));
1279 } else if (pduid == GETBULKREQ) {
1280 printf(" N=%d", elem.data.integer);
1281 } else if (elem.data.integer != 0) {
1282 char errbuf[10];
1283 printf(" %s", DECODE_ErrorStatus(elem.data.integer));
1284 error = elem.data.integer;
1285 }
1286 length -= count;
1287 np += count;
1288
1289 /* errorIndex (Integer) */
1290 if ((count = asn1_parse(np, length, &elem)) < 0)
1291 return;
1292 if (elem.type != BE_INT) {
1293 fputs("[errorIndex!=INT]", stdout);
1294 asn1_print(&elem);
1295 return;
1296 }
1297 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1298 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1299 && elem.data.integer != 0)
1300 printf("[errorIndex(%d)!=0]", elem.data.integer);
1301 else if (pduid == GETBULKREQ)
1302 printf(" M=%d", elem.data.integer);
1303 else if (elem.data.integer != 0) {
1304 if (!error)
1305 printf("[errorIndex(%d) w/o errorStatus]",
1306 elem.data.integer);
1307 else {
1308 printf("@%d", elem.data.integer);
1309 error = elem.data.integer;
1310 }
1311 } else if (error) {
1312 fputs("[errorIndex==0]", stdout);
1313 error = 0;
1314 }
1315 length -= count;
1316 np += count;
1317
1318 varbind_print(pduid, np, length);
1319 return;
1320 }
1321
1322 /*
1323 * Decode SNMP Trap PDU
1324 */
1325 static void
1326 trappdu_print(const u_char *np, u_int length)
1327 {
1328 struct be elem;
1329 int count = 0, generic;
1330
1331 putchar(' ');
1332
1333 /* enterprise (oid) */
1334 if ((count = asn1_parse(np, length, &elem)) < 0)
1335 return;
1336 if (elem.type != BE_OID) {
1337 fputs("[enterprise!=OID]", stdout);
1338 asn1_print(&elem);
1339 return;
1340 }
1341 asn1_print(&elem);
1342 length -= count;
1343 np += count;
1344
1345 putchar(' ');
1346
1347 /* agent-addr (inetaddr) */
1348 if ((count = asn1_parse(np, length, &elem)) < 0)
1349 return;
1350 if (elem.type != BE_INETADDR) {
1351 fputs("[agent-addr!=INETADDR]", stdout);
1352 asn1_print(&elem);
1353 return;
1354 }
1355 asn1_print(&elem);
1356 length -= count;
1357 np += count;
1358
1359 /* generic-trap (Integer) */
1360 if ((count = asn1_parse(np, length, &elem)) < 0)
1361 return;
1362 if (elem.type != BE_INT) {
1363 fputs("[generic-trap!=INT]", stdout);
1364 asn1_print(&elem);
1365 return;
1366 }
1367 generic = elem.data.integer;
1368 {
1369 char buf[10];
1370 printf(" %s", DECODE_GenericTrap(generic));
1371 }
1372 length -= count;
1373 np += count;
1374
1375 /* specific-trap (Integer) */
1376 if ((count = asn1_parse(np, length, &elem)) < 0)
1377 return;
1378 if (elem.type != BE_INT) {
1379 fputs("[specific-trap!=INT]", stdout);
1380 asn1_print(&elem);
1381 return;
1382 }
1383 if (generic != GT_ENTERPRISE) {
1384 if (elem.data.integer != 0)
1385 printf("[specific-trap(%d)!=0]", elem.data.integer);
1386 } else
1387 printf(" s=%d", elem.data.integer);
1388 length -= count;
1389 np += count;
1390
1391 putchar(' ');
1392
1393 /* time-stamp (TimeTicks) */
1394 if ((count = asn1_parse(np, length, &elem)) < 0)
1395 return;
1396 if (elem.type != BE_UNS) { /* XXX */
1397 fputs("[time-stamp!=TIMETICKS]", stdout);
1398 asn1_print(&elem);
1399 return;
1400 }
1401 asn1_print(&elem);
1402 length -= count;
1403 np += count;
1404
1405 varbind_print (TRAP, np, length);
1406 return;
1407 }
1408
1409 /*
1410 * Decode arbitrary SNMP PDUs.
1411 */
1412 static void
1413 pdu_print(const u_char *np, u_int length, int version)
1414 {
1415 struct be pdu;
1416 int count = 0;
1417
1418 /* PDU (Context) */
1419 if ((count = asn1_parse(np, length, &pdu)) < 0)
1420 return;
1421 if (pdu.type != BE_PDU) {
1422 fputs("[no PDU]", stdout);
1423 return;
1424 }
1425 if (count < length)
1426 printf("[%d extra after PDU]", length - count);
1427 if (vflag) {
1428 fputs("{ ", stdout);
1429 }
1430 asn1_print(&pdu);
1431 fputs(" ", stdout);
1432 /* descend into PDU */
1433 length = pdu.asnlen;
1434 np = (u_char *)pdu.data.raw;
1435
1436 if (version == SNMP_VERSION_1 &&
1437 (pdu.id == GETBULKREQ || pdu.id == INFORMREQ ||
1438 pdu.id == V2TRAP || pdu.id == REPORT)) {
1439 printf("[v2 PDU in v1 message]");
1440 return;
1441 }
1442
1443 if (version == SNMP_VERSION_2 && pdu.id == TRAP) {
1444 printf("[v1 PDU in v2 message]");
1445 return;
1446 }
1447
1448 switch (pdu.id) {
1449 case TRAP:
1450 trappdu_print(np, length);
1451 break;
1452 case GETREQ:
1453 case GETNEXTREQ:
1454 case GETRESP:
1455 case SETREQ:
1456 case GETBULKREQ:
1457 case INFORMREQ:
1458 case V2TRAP:
1459 case REPORT:
1460 snmppdu_print(pdu.id, np, length);
1461 break;
1462 }
1463
1464 if (vflag) {
1465 fputs(" } ", stdout);
1466 }
1467 }
1468
1469 /*
1470 * Decode a scoped SNMP PDU.
1471 */
1472 static void
1473 scopedpdu_print(const u_char *np, u_int length, int version)
1474 {
1475 struct be elem;
1476 int i, count = 0;
1477
1478 /* Sequence */
1479 if ((count = asn1_parse(np, length, &elem)) < 0)
1480 return;
1481 if (elem.type != BE_SEQ) {
1482 fputs("[!scoped PDU]", stdout);
1483 asn1_print(&elem);
1484 return;
1485 }
1486 length = elem.asnlen;
1487 np = (u_char *)elem.data.raw;
1488
1489 /* contextEngineID (OCTET STRING) */
1490 if ((count = asn1_parse(np, length, &elem)) < 0)
1491 return;
1492 if (elem.type != BE_STR) {
1493 fputs("[contextEngineID!=STR]", stdout);
1494 asn1_print(&elem);
1495 return;
1496 }
1497 length -= count;
1498 np += count;
1499
1500 fputs("E= ", stdout);
1501 for (i = 0; i < (int)elem.asnlen; i++) {
1502 printf("0x%02X", elem.data.str[i]);
1503 }
1504 fputs(" ", stdout);
1505
1506 /* contextName (OCTET STRING) */
1507 if ((count = asn1_parse(np, length, &elem)) < 0)
1508 return;
1509 if (elem.type != BE_STR) {
1510 fputs("[contextName!=STR]", stdout);
1511 asn1_print(&elem);
1512 return;
1513 }
1514 length -= count;
1515 np += count;
1516
1517 printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
1518
1519 pdu_print(np, length, version);
1520 }
1521
1522 /*
1523 * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
1524 */
1525 static void
1526 community_print(const u_char *np, u_int length, int version)
1527 {
1528 struct be elem;
1529 int count = 0;
1530
1531 /* Community (String) */
1532 if ((count = asn1_parse(np, length, &elem)) < 0)
1533 return;
1534 if (elem.type != BE_STR) {
1535 fputs("[comm!=STR]", stdout);
1536 asn1_print(&elem);
1537 return;
1538 }
1539 /* default community */
1540 if (strncmp((char *)elem.data.str, DEF_COMMUNITY,
1541 sizeof(DEF_COMMUNITY) - 1))
1542 /* ! "public" */
1543 printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
1544 length -= count;
1545 np += count;
1546
1547 pdu_print(np, length, version);
1548 }
1549
1550 /*
1551 * Decode SNMPv3 User-based Security Message Header (SNMPv3)
1552 */
1553 static void
1554 usm_print(const u_char *np, u_int length)
1555 {
1556 struct be elem;
1557 int count = 0;
1558
1559 /* Sequence */
1560 if ((count = asn1_parse(np, length, &elem)) < 0)
1561 return;
1562 if (elem.type != BE_SEQ) {
1563 fputs("[!usm]", stdout);
1564 asn1_print(&elem);
1565 return;
1566 }
1567 length = elem.asnlen;
1568 np = (u_char *)elem.data.raw;
1569
1570 /* msgAuthoritativeEngineID (OCTET STRING) */
1571 if ((count = asn1_parse(np, length, &elem)) < 0)
1572 return;
1573 if (elem.type != BE_STR) {
1574 fputs("[msgAuthoritativeEngineID!=STR]", stdout);
1575 asn1_print(&elem);
1576 return;
1577 }
1578 length -= count;
1579 np += count;
1580
1581 /* msgAuthoritativeEngineBoots (INTEGER) */
1582 if ((count = asn1_parse(np, length, &elem)) < 0)
1583 return;
1584 if (elem.type != BE_INT) {
1585 fputs("[msgAuthoritativeEngineBoots!=INT]", stdout);
1586 asn1_print(&elem);
1587 return;
1588 }
1589 if (vflag)
1590 printf("B=%d ", elem.data.integer);
1591 length -= count;
1592 np += count;
1593
1594 /* msgAuthoritativeEngineTime (INTEGER) */
1595 if ((count = asn1_parse(np, length, &elem)) < 0)
1596 return;
1597 if (elem.type != BE_INT) {
1598 fputs("[msgAuthoritativeEngineTime!=INT]", stdout);
1599 asn1_print(&elem);
1600 return;
1601 }
1602 if (vflag)
1603 printf("T=%d ", elem.data.integer);
1604 length -= count;
1605 np += count;
1606
1607 /* msgUserName (OCTET STRING) */
1608 if ((count = asn1_parse(np, length, &elem)) < 0)
1609 return;
1610 if (elem.type != BE_STR) {
1611 fputs("[msgUserName!=STR]", stdout);
1612 asn1_print(&elem);
1613 return;
1614 }
1615 length -= count;
1616 np += count;
1617
1618 printf("U=%.*s ", (int)elem.asnlen, elem.data.str);
1619
1620 /* msgAuthenticationParameters (OCTET STRING) */
1621 if ((count = asn1_parse(np, length, &elem)) < 0)
1622 return;
1623 if (elem.type != BE_STR) {
1624 fputs("[msgAuthenticationParameters!=STR]", stdout);
1625 asn1_print(&elem);
1626 return;
1627 }
1628 length -= count;
1629 np += count;
1630
1631 /* msgPrivacyParameters (OCTET STRING) */
1632 if ((count = asn1_parse(np, length, &elem)) < 0)
1633 return;
1634 if (elem.type != BE_STR) {
1635 fputs("[msgPrivacyParameters!=STR]", stdout);
1636 asn1_print(&elem);
1637 return;
1638 }
1639 length -= count;
1640 np += count;
1641
1642 if (count < length)
1643 printf("[%d extra after usm SEQ]", length - count);
1644 }
1645
1646 /*
1647 * Decode SNMPv3 Message Header (SNMPv3)
1648 */
1649 static void
1650 v3msg_print(const u_char *np, u_int length)
1651 {
1652 struct be elem;
1653 int count = 0;
1654 u_char flags;
1655 int model;
1656 const u_char *xnp = np;
1657 int xlength = length;
1658
1659 /* Sequence */
1660 if ((count = asn1_parse(np, length, &elem)) < 0)
1661 return;
1662 if (elem.type != BE_SEQ) {
1663 fputs("[!message]", stdout);
1664 asn1_print(&elem);
1665 return;
1666 }
1667 length = elem.asnlen;
1668 np = (u_char *)elem.data.raw;
1669
1670 if (vflag) {
1671 fputs("{ ", stdout);
1672 }
1673
1674 /* msgID (INTEGER) */
1675 if ((count = asn1_parse(np, length, &elem)) < 0)
1676 return;
1677 if (elem.type != BE_INT) {
1678 fputs("[msgID!=INT]", stdout);
1679 asn1_print(&elem);
1680 return;
1681 }
1682 length -= count;
1683 np += count;
1684
1685 /* msgMaxSize (INTEGER) */
1686 if ((count = asn1_parse(np, length, &elem)) < 0)
1687 return;
1688 if (elem.type != BE_INT) {
1689 fputs("[msgMaxSize!=INT]", stdout);
1690 asn1_print(&elem);
1691 return;
1692 }
1693 length -= count;
1694 np += count;
1695
1696 /* msgFlags (OCTET STRING) */
1697 if ((count = asn1_parse(np, length, &elem)) < 0)
1698 return;
1699 if (elem.type != BE_STR) {
1700 fputs("[msgFlags!=STR]", stdout);
1701 asn1_print(&elem);
1702 return;
1703 }
1704 if (elem.asnlen != 1) {
1705 printf("[msgFlags size %d]", elem.asnlen);
1706 return;
1707 }
1708 flags = elem.data.str[0];
1709 if (flags != 0x00 && flags != 0x01 && flags != 0x03
1710 && flags != 0x04 && flags != 0x05 && flags != 0x07) {
1711 printf("[msgFlags=0x%02X]", flags);
1712 return;
1713 }
1714 length -= count;
1715 np += count;
1716
1717 fputs("F=", stdout);
1718 if (flags & 0x01) fputs("a", stdout);
1719 if (flags & 0x02) fputs("p", stdout);
1720 if (flags & 0x04) fputs("r", stdout);
1721 fputs(" ", stdout);
1722
1723 /* msgSecurityModel (INTEGER) */
1724 if ((count = asn1_parse(np, length, &elem)) < 0)
1725 return;
1726 if (elem.type != BE_INT) {
1727 fputs("[msgSecurityModel!=INT]", stdout);
1728 asn1_print(&elem);
1729 return;
1730 }
1731 model = elem.data.integer;
1732 length -= count;
1733 np += count;
1734
1735 if (count < length)
1736 printf("[%d extra after message SEQ]", length - count);
1737
1738 if (vflag) {
1739 fputs("} ", stdout);
1740 }
1741
1742 if (model == 3) {
1743 if (vflag) {
1744 fputs("{ USM ", stdout);
1745 }
1746 } else {
1747 printf("[security model %d]", model);
1748 return;
1749 }
1750
1751 np = xnp + (np - xnp);
1752 length = xlength - (np - xnp);
1753
1754 /* msgSecurityParameters (OCTET STRING) */
1755 if ((count = asn1_parse(np, length, &elem)) < 0)
1756 return;
1757 if (elem.type != BE_STR) {
1758 fputs("[msgSecurityParameters!=STR]", stdout);
1759 asn1_print(&elem);
1760 return;
1761 }
1762 length -= count;
1763 np += count;
1764
1765 if (model == 3) {
1766 usm_print(elem.data.str, elem.asnlen);
1767 if (vflag) {
1768 fputs("} ", stdout);
1769 }
1770 }
1771
1772 if (vflag) {
1773 fputs("{ ScopedPDU ", stdout);
1774 }
1775
1776 scopedpdu_print(np, length, 3);
1777
1778 if (vflag) {
1779 fputs("} ", stdout);
1780 }
1781 }
1782
1783 /*
1784 * Decode SNMP header and pass on to PDU printing routines
1785 */
1786 void
1787 snmp_print(const u_char *np, u_int length)
1788 {
1789 struct be elem;
1790 int count = 0;
1791 int version = 0;
1792
1793 truncated = 0;
1794
1795 /* truncated packet? */
1796 if (np + length > snapend) {
1797 truncated = 1;
1798 length = snapend - np;
1799 }
1800
1801 putchar(' ');
1802
1803 /* initial Sequence */
1804 if ((count = asn1_parse(np, length, &elem)) < 0)
1805 return;
1806 if (elem.type != BE_SEQ) {
1807 fputs("[!init SEQ]", stdout);
1808 asn1_print(&elem);
1809 return;
1810 }
1811 if (count < length)
1812 printf("[%d extra after iSEQ]", length - count);
1813 /* descend */
1814 length = elem.asnlen;
1815 np = (u_char *)elem.data.raw;
1816
1817 /* Version (INTEGER) */
1818 if ((count = asn1_parse(np, length, &elem)) < 0)
1819 return;
1820 if (elem.type != BE_INT) {
1821 fputs("[version!=INT]", stdout);
1822 asn1_print(&elem);
1823 return;
1824 }
1825
1826 switch (elem.data.integer) {
1827 case SNMP_VERSION_1:
1828 case SNMP_VERSION_2:
1829 case SNMP_VERSION_3:
1830 if (vflag)
1831 printf("{ %s ", SnmpVersion[elem.data.integer]);
1832 break;
1833 default:
1834 printf("[version = %d]", elem.data.integer);
1835 return;
1836 }
1837 version = elem.data.integer;
1838 length -= count;
1839 np += count;
1840
1841 switch (version) {
1842 case SNMP_VERSION_1:
1843 case SNMP_VERSION_2:
1844 community_print(np, length, version);
1845 break;
1846 case SNMP_VERSION_3:
1847 v3msg_print(np, length);
1848 break;
1849 default:
1850 printf("[version = %d]", elem.data.integer);
1851 break;
1852 }
1853
1854 if (vflag) {
1855 fputs("} ", stdout);
1856 }
1857 }