home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / tcpdumpb.zip / print-snmp.c < prev    next >
C/C++ Source or Header  |  1996-07-23  |  23KB  |  1,040 lines

  1. /*
  2.  * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996
  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.  * This started out as a very simple program, but the incremental decoding
  25.  * (into the BE structure) complicated things.
  26.  *
  27.  #            Los Alamos National Laboratory
  28.  #
  29.  #    Copyright, 1990.  The Regents of the University of California.
  30.  #    This software was produced under a U.S. Government contract
  31.  #    (W-7405-ENG-36) by Los Alamos National Laboratory, which is
  32.  #    operated by the    University of California for the U.S. Department
  33.  #    of Energy.  The U.S. Government is licensed to use, reproduce,
  34.  #    and distribute this software.  Permission is granted to the
  35.  #    public to copy and use this software without charge, provided
  36.  #    that this Notice and any statement of authorship are reproduced
  37.  #    on all copies.  Neither the Government nor the University makes
  38.  #    any warranty, express or implied, or assumes any liability or
  39.  #    responsibility for the use of this software.
  40.  #    @(#)snmp.awk.x    1.1 (LANL) 1/15/90
  41.  */
  42. #ifndef lint
  43. static char rcsid[] =
  44.     "@(#) $Id: print-snmp.c,v 3.10 91/01/17 01:18:13 loverso Exp Locker: loverso $ (jlv)";
  45. #endif
  46.  
  47. #include <sys/param.h>
  48. #include <sys/time.h>
  49.  
  50. #include <stdio.h>
  51. #include <ctype.h>
  52. #include <string.h>
  53.  
  54. #include "interface.h"
  55. #include "addrtoname.h"
  56.  
  57. /*
  58.  * Universal ASN.1 types
  59.  * (we only care about the tag values for those allowed in the Internet SMI)
  60.  */
  61. char *Universal[] = {
  62.     "U-0",
  63.     "Boolean",
  64.     "Integer",
  65. #define INTEGER 2
  66.     "Bitstring",
  67.     "String",
  68. #define STRING 4
  69.     "Null",
  70. #define ASN_NULL 5
  71.     "ObjID",
  72. #define OBJECTID 6
  73.     "ObjectDes",
  74.     "U-8","U-9","U-10","U-11",    /* 8-11 */
  75.     "U-12","U-13","U-14","U-15",    /* 12-15 */
  76.     "Sequence",
  77. #define SEQUENCE 16
  78.     "Set"
  79. };
  80.  
  81. /*
  82.  * Application-wide ASN.1 types from the Internet SMI and their tags
  83.  */
  84. char *Application[] = {
  85.     "IpAddress",
  86. #define IPADDR 0
  87.     "Counter",
  88. #define COUNTER 1
  89.     "Gauge",
  90. #define GAUGE 2
  91.     "TimeTicks",
  92. #define TIMETICKS 3
  93.     "Opaque"
  94. };
  95.  
  96. /*
  97.  * Context-specific ASN.1 types for the SNMP PDUs and their tags
  98.  */
  99. char *Context[] = {
  100.     "GetRequest",
  101. #define GETREQ 0
  102.     "GetNextRequest",
  103. #define GETNEXTREQ 1
  104.     "GetResponse",
  105. #define GETRESP 2
  106.     "SetRequest",
  107. #define SETREQ 3
  108.     "Trap"
  109. #define TRAP 4
  110. };
  111.  
  112. /*
  113.  * Private ASN.1 types
  114.  * The Internet SMI does not specify any
  115.  */
  116. char *Private[] = {
  117.     "P-0"
  118. };
  119.  
  120. /*
  121.  * error-status values for any SNMP PDU
  122.  */
  123. char *ErrorStatus[] = {
  124.     "noError",
  125.     "tooBig",
  126.     "noSuchName",
  127.     "badValue",
  128.     "readOnly",
  129.     "genErr"
  130. };
  131. #define DECODE_ErrorStatus(e) \
  132.     ( e >= 0 && e <= sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
  133.     ? ErrorStatus[e] : (sprintf(errbuf, "err=%u", e), errbuf))
  134.  
  135. /*
  136.  * generic-trap values in the SNMP Trap-PDU
  137.  */
  138. char *GenericTrap[] = {
  139.     "coldStart",
  140.     "warmStart",
  141.     "linkDown",
  142.     "linkUp",
  143.     "authenticationFailure",
  144.     "egpNeighborLoss",
  145.     "enterpriseSpecific"
  146. #define GT_ENTERPRISE 7
  147. };
  148. #define DECODE_GenericTrap(t) \
  149.     ( t >= 0 && t <= sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
  150.     ? GenericTrap[t] : (sprintf(buf, "gt=%d", t), buf))
  151.  
  152. /*
  153.  * ASN.1 type class table
  154.  * Ties together the preceding Universal, Application, Context, and Private
  155.  * type definitions.
  156.  */
  157. #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
  158. struct {
  159.     char    *name;
  160.     char    **Id;
  161.         int    numIDs;
  162.     } Class[] = {
  163.     defineCLASS(Universal),
  164. #define    UNIVERSAL    0
  165.     defineCLASS(Application),
  166. #define    APPLICATION    1
  167.     defineCLASS(Context),
  168. #define    CONTEXT        2
  169.     defineCLASS(Private),
  170. #define    PRIVATE        3
  171. };
  172.  
  173. /*
  174.  * defined forms for ASN.1 types
  175.  */
  176. char *Form[] = {
  177.     "Primitive",
  178. #define PRIMITIVE    0
  179.     "Constructed",
  180. #define CONSTRUCTED    1
  181. };
  182.  
  183. /*
  184.  * A structure for the OID tree for the compiled-in MIB.
  185.  * This is stored as a general-order tree.
  186.  */
  187. struct obj {
  188.     char    *desc;            /* name of object */
  189.     u_char    oid;            /* sub-id following parent */
  190.     u_char    type;            /* object type (unused) */
  191.     struct obj *child, *next;    /* child and next sibling pointers */
  192. } *objp = NULL;
  193.  
  194. /*
  195.  * Include the compiled in SNMP MIB.  "mib.h" is produced by feeding
  196.  * RFC-1156 format files into "makemib".  "mib.h" MUST define at least
  197.  * a value for `mibroot'.
  198.  *
  199.  * In particular, this is gross, as this is including initialized structures,
  200.  * and by right shouldn't be an "include" file.
  201.  */
  202. #include "mib.h"
  203.  
  204. /*
  205.  * This defines a list of OIDs which will be abbreviated on output.
  206.  * Currently, this includes the prefixes for the Internet MIB, the
  207.  * private enterprises tree, and the experimental tree.
  208.  */
  209. struct obj_abrev {
  210.     char *prefix;            /* prefix for this abrev */
  211.     struct obj *node;        /* pointer into object table */
  212.     char *oid;            /* ASN.1 encoded OID */
  213. } obj_abrev_list[] = {
  214. #ifndef NO_ABREV_MIB
  215.     /* .iso.org.dod.internet.mgmt.mib */
  216.     { "",    &_mib_obj,        "\53\6\1\2\1" },
  217. #endif
  218. #ifndef NO_ABREV_ENTER
  219.     /* .iso.org.dod.internet.private.enterprises */
  220.     { "E:",    &_enterprises_obj,    "\53\6\1\4\1" },
  221. #endif
  222. #ifndef NO_ABREV_EXPERI
  223.     /* .iso.org.dod.internet.experimental */
  224.     { "X:",    &_experimental_obj,    "\53\6\1\3" },
  225. #endif
  226.     { 0,0,0 }
  227. };
  228.  
  229. /*
  230.  * This is used in the OID print routine to walk down the object tree
  231.  * rooted at `mibroot'.
  232.  */
  233. #define OBJ_PRINT(o, suppressdot) \
  234. { \
  235.     if (objp) { \
  236.         do { \
  237.             if ((o) == objp->oid) \
  238.                 break; \
  239.         } while ((objp = objp->next) != NULL); \
  240.     } \
  241.     if (objp) { \
  242.         printf(suppressdot?"%s":".%s", objp->desc); \
  243.         objp = objp->child; \
  244.     } else \
  245.         printf(suppressdot?"%u":".%u", (o)); \
  246. }
  247.  
  248. /*
  249.  * This is the definition for the Any-Data-Type storage used purely for
  250.  * temporary internal representation while decoding an ASN.1 data stream.
  251.  */
  252. struct be {
  253.     u_int32_t asnlen;
  254.     union {
  255.         caddr_t raw;
  256.         int32_t integer;
  257.         u_int32_t uns;
  258.         const u_char *str;
  259.     } data;
  260.     u_short id;
  261.     u_char form, class;        /* tag info */
  262.     u_char type;
  263. #define BE_ANY        255
  264. #define BE_NONE        0
  265. #define BE_NULL        1
  266. #define BE_OCTET    2
  267. #define BE_OID        3
  268. #define BE_INT        4
  269. #define BE_UNS        5
  270. #define BE_STR        6
  271. #define BE_SEQ        7
  272. #define BE_INETADDR    8
  273. #define BE_PDU        9
  274. };
  275.  
  276. /*
  277.  * Defaults for SNMP PDU components
  278.  */
  279. #define DEF_COMMUNITY "public"
  280. #define DEF_VERSION 0
  281.  
  282. /*
  283.  * constants for ASN.1 decoding
  284.  */
  285. #define OIDMUX 40
  286. #define ASNLEN_INETADDR 4
  287. #define ASN_SHIFT7 7
  288. #define ASN_SHIFT8 8
  289. #define ASN_BIT8 0x80
  290. #define ASN_LONGLEN 0x80
  291.  
  292. #define ASN_ID_BITS 0x1f
  293. #define ASN_FORM_BITS 0x20
  294. #define ASN_FORM_SHIFT 5
  295. #define ASN_CLASS_BITS 0xc0
  296. #define ASN_CLASS_SHIFT 6
  297.  
  298. #define ASN_ID_EXT 0x1f        /* extension ID in tag field */
  299.  
  300. /*
  301.  * truncated==1 means the packet was complete, but we don't have all of
  302.  * it to decode.
  303.  */
  304. static int truncated;
  305. #define ifNotTruncated if (truncated) fputs("[|snmp]", stdout); else
  306.  
  307. /*
  308.  * This decodes the next ASN.1 object in the stream pointed to by "p"
  309.  * (and of real-length "len") and stores the intermediate data in the
  310.  * provided BE object.
  311.  *
  312.  * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
  313.  * O/w, this returns the number of bytes parsed from "p".
  314.  */
  315. static int
  316. asn1_parse(register const u_char *p, u_int len, struct be *elem)
  317. {
  318.     u_char form, class, id;
  319.     int i, hdr;
  320.  
  321.     elem->asnlen = 0;
  322.     elem->type = BE_ANY;
  323.     if (len < 1) {
  324.         ifNotTruncated puts("[nothing to parse], stdout");
  325.         return -1;
  326.     }
  327.  
  328.     /*
  329.      * it would be nice to use a bit field, but you can't depend on them.
  330.      *  +---+---+---+---+---+---+---+---+
  331.      *  + class |frm|        id         |
  332.      *  +---+---+---+---+---+---+---+---+
  333.      *    7   6   5   4   3   2   1   0
  334.      */
  335.     id = *p & ASN_ID_BITS;        /* lower 5 bits, range 00-1f */
  336. #ifdef notdef
  337.     form = (*p & 0xe0) >> 5;    /* move upper 3 bits to lower 3 */
  338.     class = form >> 1;        /* bits 7&6 -> bits 1&0, range 0-3 */
  339.     form &= 0x1;            /* bit 5 -> bit 0, range 0-1 */
  340. #else
  341.     form = (*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
  342.     class = (*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
  343. #endif
  344.     elem->form = form;
  345.     elem->class = class;
  346.     elem->id = id;
  347.     if (vflag)
  348.         printf("|%.2x", *p);
  349.     p++; len--; hdr = 1;
  350.     /* extended tag field */
  351.     if (id == ASN_ID_EXT) {
  352.         for (id = 0; *p & ASN_BIT8 && len > 0; len--, hdr++, p++) {
  353.             if (vflag)
  354.                 printf("|%.2x", *p);
  355.             id = (id << 7) | (*p & ~ASN_BIT8);
  356.         }
  357.         if (len == 0 && *p & ASN_BIT8) {
  358.             ifNotTruncated fputs("[Xtagfield?]", stdout);
  359.             return -1;
  360.         }
  361.         elem->id = id = (id << 7) | *p;
  362.         --len;
  363.         ++hdr;
  364.         ++p;
  365.     }
  366.     if (len < 1) {
  367.         ifNotTruncated fputs("[no asnlen]", stdout);
  368.         return -1;
  369.     }
  370.     elem->asnlen = *p;
  371.     if (vflag)
  372.         printf("|%.2x", *p);
  373.     p++; len--; hdr++;
  374.     if (elem->asnlen & ASN_BIT8) {
  375.         int noct = elem->asnlen % ASN_BIT8;
  376.         elem->asnlen = 0;
  377.         if (len < noct) {
  378.             ifNotTruncated printf("[asnlen? %d<%d]", len, noct);
  379.             return -1;
  380.         }
  381.         for (; noct-- > 0; len--, hdr++) {
  382.             if (vflag)
  383.                 printf("|%.2x", *p);
  384.             elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++;
  385.         }
  386.     }
  387.     if (len < elem->asnlen) {
  388.         if (!truncated) {
  389.             printf("[len%d<asnlen%u]", len, elem->asnlen);
  390.             return -1;
  391.         }
  392.         /* maybe should check at least 4? */
  393.         elem->asnlen = len;
  394.     }
  395.     if (form >= sizeof(Form)/sizeof(Form[0])) {
  396.         ifNotTruncated printf("[form?%d]", form);
  397.         return -1;
  398.     }
  399.     if (class >= sizeof(Class)/sizeof(Class[0])) {
  400.         ifNotTruncated printf("[class?%c/%d]", *Form[form], class);
  401.         return -1;
  402.     }
  403.     if (id >= Class[class].numIDs) {
  404.         ifNotTruncated printf("[id?%c/%s/%d]", *Form[form],
  405.             Class[class].name, id);
  406.         return -1;
  407.     }
  408.  
  409.     switch (form) {
  410.     case PRIMITIVE:
  411.         switch (class) {
  412.         case UNIVERSAL:
  413.             switch (id) {
  414.             case STRING:
  415.                 elem->type = BE_STR;
  416.                 elem->data.str = p;
  417.                 break;
  418.  
  419.             case INTEGER: {
  420.                 register int32_t data;
  421.                 elem->type = BE_INT;
  422.                 data = 0;
  423.  
  424.                 if (*p & ASN_BIT8)    /* negative */
  425.                     data = -1;
  426.                 for (i = elem->asnlen; i-- > 0; p++)
  427.                     data = (data << ASN_SHIFT8) | *p;
  428.                 elem->data.integer = data;
  429.                 break;
  430.             }
  431.  
  432.             case OBJECTID:
  433.                 elem->type = BE_OID;
  434.                 elem->data.raw = (caddr_t)p;
  435.                 break;
  436.  
  437.             case ASN_NULL:
  438.                 elem->type = BE_NULL;
  439.                 elem->data.raw = NULL;
  440.                 break;
  441.  
  442.             default:
  443.                 elem->type = BE_OCTET;
  444.                 elem->data.raw = (caddr_t)p;
  445.                 printf("[P/U/%s]",
  446.                     Class[class].Id[id]);
  447.                 break;
  448.             }
  449.             break;
  450.  
  451.         case APPLICATION:
  452.             switch (id) {
  453.             case IPADDR:
  454.                 elem->type = BE_INETADDR;
  455.                 elem->data.raw = (caddr_t)p;
  456.                 break;
  457.  
  458.             case COUNTER:
  459.             case GAUGE:
  460.             case TIMETICKS: {
  461.                 register u_int32_t data;
  462.                 elem->type = BE_UNS;
  463.                 data = 0;
  464.                 for (i = elem->asnlen; i-- > 0; p++)
  465.                     data = (data << 8) + *p;
  466.                 elem->data.uns = data;
  467.                 break;
  468.             }
  469.  
  470.             default:
  471.                 elem->type = BE_OCTET;
  472.                 elem->data.raw = (caddr_t)p;
  473.                 printf("[P/A/%s]",
  474.                     Class[class].Id[id]);
  475.                 break;
  476.             }
  477.             break;
  478.  
  479.         default:
  480.             elem->type = BE_OCTET;
  481.             elem->data.raw = (caddr_t)p;
  482.             printf("[P/%s/%s]",
  483.                 Class[class].name, Class[class].Id[id]);
  484.             break;
  485.         }
  486.         break;
  487.  
  488.     case CONSTRUCTED:
  489.         switch (class) {
  490.         case UNIVERSAL:
  491.             switch (id) {
  492.             case SEQUENCE:
  493.                 elem->type = BE_SEQ;
  494.                 elem->data.raw = (caddr_t)p;
  495.                 break;
  496.  
  497.             default:
  498.                 elem->type = BE_OCTET;
  499.                 elem->data.raw = (caddr_t)p;
  500.                 printf("C/U/%s", Class[class].Id[id]);
  501.                 break;
  502.             }
  503.             break;
  504.  
  505.         case CONTEXT:
  506.             elem->type = BE_PDU;
  507.             elem->data.raw = (caddr_t)p;
  508.             break;
  509.  
  510.         default:
  511.             elem->type = BE_OCTET;
  512.             elem->data.raw = (caddr_t)p;
  513.             printf("C/%s/%s",
  514.                 Class[class].name, Class[class].Id[id]);
  515.             break;
  516.         }
  517.         break;
  518.     }
  519.     p += elem->asnlen;
  520.     len -= elem->asnlen;
  521.     return elem->asnlen + hdr;
  522. }
  523.  
  524. /*
  525.  * Display the ASN.1 object represented by the BE object.
  526.  * This used to be an integral part of asn1_parse() before the intermediate
  527.  * BE form was added.
  528.  */
  529. static void
  530. asn1_print(struct be *elem)
  531. {
  532.     u_char *p = (u_char *)elem->data.raw;
  533.     u_int32_t asnlen = elem->asnlen;
  534.     int i;
  535.  
  536.     switch (elem->type) {
  537.  
  538.     case BE_OCTET:
  539.         for (i = asnlen; i-- > 0; p++);
  540.             printf("_%.2x", *p);
  541.         break;
  542.  
  543.     case BE_NULL:
  544.         break;
  545.  
  546.     case BE_OID: {
  547.     int o = 0, first = -1, i = asnlen;
  548.  
  549.         if (!nflag && asnlen > 2) {
  550.             struct obj_abrev *a = &obj_abrev_list[0];
  551.             for (; a->node; a++) {
  552.                 if (!memcmp(a->oid, (char *)p,
  553.                     strlen(a->oid))) {
  554.                     objp = a->node->child;
  555.                     i -= strlen(a->oid);
  556.                     p += strlen(a->oid);
  557.                     fputs(a->prefix, stdout);
  558.                     first = 1;
  559.                     break;
  560.                 }
  561.             }
  562.         }
  563.         for (; i-- > 0; p++) {
  564.             o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
  565.             if (*p & ASN_LONGLEN)
  566.                 continue;
  567.  
  568.             /*
  569.              * first subitem encodes two items with 1st*OIDMUX+2nd
  570.              */
  571.             if (first < 0) {
  572.                 if (!nflag)
  573.                     objp = mibroot;
  574.                 first = 0;
  575.                 OBJ_PRINT(o/OIDMUX, first);
  576.                 o %= OIDMUX;
  577.             }
  578.             OBJ_PRINT(o, first);
  579.             if (--first < 0)
  580.                 first = 0;
  581.             o = 0;
  582.         }
  583.         break;
  584.     }
  585.  
  586.     case BE_INT:
  587.         printf("%d", elem->data.integer);
  588.         break;
  589.  
  590.     case BE_UNS:
  591.         printf("%d", elem->data.uns);
  592.         break;
  593.  
  594.     case BE_STR: {
  595.         register int printable = 1, first = 1;
  596.         const u_char *p = elem->data.str;
  597.         for (i = asnlen; printable && i-- > 0; p++)
  598.             printable = isprint(*p) || isspace(*p);
  599.         p = elem->data.str;
  600.         if (printable) {
  601.             putchar('"');
  602.             (void)fn_print(p, p + asnlen);
  603.             putchar('"');
  604.         } else
  605.             for (i = asnlen; i-- > 0; p++) {
  606.                 printf(first ? "%.2x" : "_%.2x", *p);
  607.                 first = 0;
  608.             }
  609.         break;
  610.     }
  611.  
  612.     case BE_SEQ:
  613.         printf("Seq(%u)", elem->asnlen);
  614.         break;
  615.  
  616.     case BE_INETADDR: {
  617.         char sep;
  618.         if (asnlen != ASNLEN_INETADDR)
  619.             printf("[inetaddr len!=%d]", ASNLEN_INETADDR);
  620.         sep='[';
  621.         for (i = asnlen; i-- > 0; p++) {
  622.             printf("%c%u", sep, *p);
  623.             sep='.';
  624.         }
  625.         putchar(']');
  626.         break;
  627.     }
  628.  
  629.     case BE_PDU:
  630.         printf("%s(%u)",
  631.             Class[CONTEXT].Id[elem->id], elem->asnlen);
  632.         break;
  633.  
  634.     case BE_ANY:
  635.         fputs("[BE_ANY!?]", stdout);
  636.         break;
  637.  
  638.     default:
  639.         fputs("[be!?]", stdout);
  640.         break;
  641.     }
  642. }
  643.  
  644. #ifdef notdef
  645. /*
  646.  * This is a brute force ASN.1 printer: recurses to dump an entire structure.
  647.  * This will work for any ASN.1 stream, not just an SNMP PDU.
  648.  *
  649.  * By adding newlines and spaces at the correct places, this would print in
  650.  * Rose-Normal-Form.
  651.  *
  652.  * This is not currently used.
  653.  */
  654. static void
  655. asn1_decode(u_char *p, u_int length)
  656. {
  657.     struct be elem;
  658.     int i = 0;
  659.  
  660.     while (i >= 0 && length > 0) {
  661.         i = asn1_parse(p, length, &elem);
  662.         if (i >= 0) {
  663.             fputs(" ", stdout);
  664.             asn1_print(&elem);
  665.             if (elem.type == BE_SEQ || elem.type == BE_PDU) {
  666.                 fputs(" {", stdout);
  667.                 asn1_decode(elem.data.raw, elem.asnlen);
  668.                 fputs(" }", stdout);
  669.             }
  670.             length -= i;
  671.             p += i;
  672.         }
  673.     }
  674. }
  675. #endif
  676.  
  677. /*
  678.  * General SNMP header
  679.  *    SEQUENCE {
  680.  *        version INTEGER {version-1(0)},
  681.  *        community OCTET STRING,
  682.  *        data ANY    -- PDUs
  683.  *    }
  684.  * PDUs for all but Trap: (see rfc1157 from page 15 on)
  685.  *    SEQUENCE {
  686.  *        request-id INTEGER,
  687.  *        error-status INTEGER,
  688.  *        error-index INTEGER,
  689.  *        varbindlist SEQUENCE OF
  690.  *            SEQUENCE {
  691.  *                name ObjectName,
  692.  *                value ObjectValue
  693.  *            }
  694.  *    }
  695.  * PDU for Trap:
  696.  *    SEQUENCE {
  697.  *        enterprise OBJECT IDENTIFIER,
  698.  *        agent-addr NetworkAddress,
  699.  *        generic-trap INTEGER,
  700.  *        specific-trap INTEGER,
  701.  *        time-stamp TimeTicks,
  702.  *        varbindlist SEQUENCE OF
  703.  *            SEQUENCE {
  704.  *                name ObjectName,
  705.  *                value ObjectValue
  706.  *            }
  707.  *    }
  708.  */
  709.  
  710. /*
  711.  * Decode SNMP varBind
  712.  */
  713. static void
  714. varbind_print(u_char pduid, const u_char *np, u_int length, int error)
  715. {
  716.     struct be elem;
  717.     int count = 0, ind;
  718.  
  719.     /* Sequence of varBind */
  720.     if ((count = asn1_parse(np, length, &elem)) < 0)
  721.         return;
  722.     if (elem.type != BE_SEQ) {
  723.         fputs("[!SEQ of varbind]", stdout);
  724.         asn1_print(&elem);
  725.         return;
  726.     }
  727.     if (count < length)
  728.         printf("[%d extra after SEQ of varbind]", length - count);
  729.     /* descend */
  730.     length = elem.asnlen;
  731.     np = (u_char *)elem.data.raw;
  732.  
  733.     for (ind = 1; length > 0; ind++) {
  734.         const u_char *vbend;
  735.         u_int vblength;
  736.  
  737.         if (!error || ind == error)
  738.             fputs(" ", stdout);
  739.  
  740.         /* Sequence */
  741.         if ((count = asn1_parse(np, length, &elem)) < 0)
  742.             return;
  743.         if (elem.type != BE_SEQ) {
  744.             fputs("[!varbind]", stdout);
  745.             asn1_print(&elem);
  746.             return;
  747.         }
  748.         vbend = np + count;
  749.         vblength = length - count;
  750.         /* descend */
  751.         length = elem.asnlen;
  752.         np = (u_char *)elem.data.raw;
  753.  
  754.         /* objName (OID) */
  755.         if ((count = asn1_parse(np, length, &elem)) < 0)
  756.             return;
  757.         if (elem.type != BE_OID) {
  758.             fputs("[objName!=OID]", stdout);
  759.             asn1_print(&elem);
  760.             return;
  761.         }
  762.         if (!error || ind == error)
  763.             asn1_print(&elem);
  764.         length -= count;
  765.         np += count;
  766.  
  767.         if (pduid != GETREQ && pduid != GETNEXTREQ && !error)
  768.                 fputs("=", stdout);
  769.  
  770.         /* objVal (ANY) */
  771.         if ((count = asn1_parse(np, length, &elem)) < 0)
  772.             return;
  773.         if (pduid == GETREQ || pduid == GETNEXTREQ) {
  774.             if (elem.type != BE_NULL) {
  775.                 fputs("[objVal!=NULL]", stdout);
  776.                 asn1_print(&elem);
  777.             }
  778.         } else
  779.             if (error && ind == error && elem.type != BE_NULL)
  780.                 fputs("[err objVal!=NULL]", stdout);
  781.             if (!error || ind == error)
  782.                 asn1_print(&elem);
  783.  
  784.         length = vblength;
  785.         np = vbend;
  786.     }
  787. }
  788.  
  789. /*
  790.  * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, and SetRequest
  791.  */
  792. static void
  793. snmppdu_print(u_char pduid, const u_char *np, u_int length)
  794. {
  795.     struct be elem;
  796.     int count = 0, error;
  797.  
  798.     /* reqId (Integer) */
  799.     if ((count = asn1_parse(np, length, &elem)) < 0)
  800.         return;
  801.     if (elem.type != BE_INT) {
  802.         fputs("[reqId!=INT]", stdout);
  803.         asn1_print(&elem);
  804.         return;
  805.     }
  806.     /* ignore the reqId */
  807.     length -= count;
  808.     np += count;
  809.  
  810.     /* errorStatus (Integer) */
  811.     if ((count = asn1_parse(np, length, &elem)) < 0)
  812.         return;
  813.     if (elem.type != BE_INT) {
  814.         fputs("[errorStatus!=INT]", stdout);
  815.         asn1_print(&elem);
  816.         return;
  817.     }
  818.     error = 0;
  819.     if ((pduid == GETREQ || pduid == GETNEXTREQ)
  820.         && elem.data.integer != 0) {
  821.         char errbuf[10];
  822.         printf("[errorStatus(%s)!=0]",
  823.             DECODE_ErrorStatus(elem.data.integer));
  824.     } else if (elem.data.integer != 0) {
  825.         char errbuf[10];
  826.         printf(" %s", DECODE_ErrorStatus(elem.data.integer));
  827.         error = elem.data.integer;
  828.     }
  829.     length -= count;
  830.     np += count;
  831.  
  832.     /* errorIndex (Integer) */
  833.     if ((count = asn1_parse(np, length, &elem)) < 0)
  834.         return;
  835.     if (elem.type != BE_INT) {
  836.         fputs("[errorIndex!=INT]", stdout);
  837.         asn1_print(&elem);
  838.         return;
  839.     }
  840.     if ((pduid == GETREQ || pduid == GETNEXTREQ)
  841.         && elem.data.integer != 0)
  842.         printf("[errorIndex(%d)!=0]", elem.data.integer);
  843.     else if (elem.data.integer != 0) {
  844.         if (!error)
  845.             printf("[errorIndex(%d) w/o errorStatus]",
  846.                 elem.data.integer);
  847.         else {
  848.             printf("@%d", elem.data.integer);
  849.             error = elem.data.integer;
  850.         }
  851.     } else if (error) {
  852.         fputs("[errorIndex==0]", stdout);
  853.         error = 0;
  854.     }
  855.     length -= count;
  856.     np += count;
  857.  
  858.     varbind_print(pduid, np, length, error);
  859.     return;
  860. }
  861.  
  862. /*
  863.  * Decode SNMP Trap PDU
  864.  */
  865. static void
  866. trap_print(const u_char *np, u_int length)
  867. {
  868.     struct be elem;
  869.     int count = 0, generic;
  870.  
  871.     putchar(' ');
  872.  
  873.     /* enterprise (oid) */
  874.     if ((count = asn1_parse(np, length, &elem)) < 0)
  875.         return;
  876.     if (elem.type != BE_OID) {
  877.         fputs("[enterprise!=OID]", stdout);
  878.         asn1_print(&elem);
  879.         return;
  880.     }
  881.     asn1_print(&elem);
  882.     length -= count;
  883.     np += count;
  884.  
  885.     putchar(' ');
  886.  
  887.     /* agent-addr (inetaddr) */
  888.     if ((count = asn1_parse(np, length, &elem)) < 0)
  889.         return;
  890.     if (elem.type != BE_INETADDR) {
  891.         fputs("[agent-addr!=INETADDR]", stdout);
  892.         asn1_print(&elem);
  893.         return;
  894.     }
  895.     asn1_print(&elem);
  896.     length -= count;
  897.     np += count;
  898.  
  899.     /* generic-trap (Integer) */
  900.     if ((count = asn1_parse(np, length, &elem)) < 0)
  901.         return;
  902.     if (elem.type != BE_INT) {
  903.         fputs("[generic-trap!=INT]", stdout);
  904.         asn1_print(&elem);
  905.         return;
  906.     }
  907.     generic = elem.data.integer;
  908.     {
  909.         char buf[10];
  910.         printf(" %s", DECODE_GenericTrap(generic));
  911.     }
  912.     length -= count;
  913.     np += count;
  914.  
  915.     /* specific-trap (Integer) */
  916.     if ((count = asn1_parse(np, length, &elem)) < 0)
  917.         return;
  918.     if (elem.type != BE_INT) {
  919.         fputs("[specific-trap!=INT]", stdout);
  920.         asn1_print(&elem);
  921.         return;
  922.     }
  923.     if (generic != GT_ENTERPRISE) {
  924.         if (elem.data.integer != 0)
  925.             printf("[specific-trap(%d)!=0]", elem.data.integer);
  926.     } else
  927.         printf(" s=%d", elem.data.integer);
  928.     length -= count;
  929.     np += count;
  930.  
  931.     putchar(' ');
  932.  
  933.     /* time-stamp (TimeTicks) */
  934.     if ((count = asn1_parse(np, length, &elem)) < 0)
  935.         return;
  936.     if (elem.type != BE_UNS) {            /* XXX */
  937.         fputs("[time-stamp!=TIMETICKS]", stdout);
  938.         asn1_print(&elem);
  939.         return;
  940.     }
  941.     asn1_print(&elem);
  942.     length -= count;
  943.     np += count;
  944.  
  945.     varbind_print (TRAP, np, length, 0);
  946.     return;
  947. }
  948.  
  949. /*
  950.  * Decode SNMP header and pass on to PDU printing routines
  951.  */
  952. void
  953. snmp_print(const u_char *np, u_int length)
  954. {
  955.     struct be elem, pdu;
  956.     int count = 0;
  957.  
  958.     truncated = 0;
  959.  
  960.     /* truncated packet? */
  961.     if (np + length > snapend) {
  962.         truncated = 1;
  963.         length = snapend - np;
  964.     }
  965.  
  966.     putchar(' ');
  967.  
  968.     /* initial Sequence */
  969.     if ((count = asn1_parse(np, length, &elem)) < 0)
  970.         return;
  971.     if (elem.type != BE_SEQ) {
  972.         fputs("[!init SEQ]", stdout);
  973.         asn1_print(&elem);
  974.         return;
  975.     }
  976.     if (count < length)
  977.         printf("[%d extra after iSEQ]", length - count);
  978.     /* descend */
  979.     length = elem.asnlen;
  980.     np = (u_char *)elem.data.raw;
  981.     /* Version (Integer) */
  982.     if ((count = asn1_parse(np, length, &elem)) < 0)
  983.         return;
  984.     if (elem.type != BE_INT) {
  985.         fputs("[version!=INT]", stdout);
  986.         asn1_print(&elem);
  987.         return;
  988.     }
  989.     /* only handle version==0 */
  990.     if (elem.data.integer != DEF_VERSION) {
  991.         printf("[version(%d)!=0]", elem.data.integer);
  992.         return;
  993.     }
  994.     length -= count;
  995.     np += count;
  996.  
  997.     /* Community (String) */
  998.     if ((count = asn1_parse(np, length, &elem)) < 0)
  999.         return;
  1000.     if (elem.type != BE_STR) {
  1001.         fputs("[comm!=STR]", stdout);
  1002.         asn1_print(&elem);
  1003.         return;
  1004.     }
  1005.     /* default community */
  1006.     if (strncmp((char *)elem.data.str, DEF_COMMUNITY,
  1007.         sizeof(DEF_COMMUNITY) - 1))
  1008.         /* ! "public" */
  1009.         printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
  1010.     length -= count;
  1011.     np += count;
  1012.  
  1013.     /* PDU (Context) */
  1014.     if ((count = asn1_parse(np, length, &pdu)) < 0)
  1015.         return;
  1016.     if (pdu.type != BE_PDU) {
  1017.         fputs("[no PDU]", stdout);
  1018.         return;
  1019.     }
  1020.     if (count < length)
  1021.         printf("[%d extra after PDU]", length - count);
  1022.     asn1_print(&pdu);
  1023.     /* descend into PDU */
  1024.     length = pdu.asnlen;
  1025.     np = (u_char *)pdu.data.raw;
  1026.  
  1027.     switch (pdu.id) {
  1028.     case TRAP:
  1029.         trap_print(np, length);
  1030.         break;
  1031.     case GETREQ:
  1032.     case GETNEXTREQ:
  1033.     case GETRESP:
  1034.     case SETREQ:
  1035.         snmppdu_print(pdu.id, np, length);
  1036.         break;
  1037.     }
  1038.     return;
  1039. }
  1040.