home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #16 / NN_1992_16.iso / spool / comp / lang / perl / 5041 < prev    next >
Encoding:
Internet Message Format  |  1992-07-30  |  41.3 KB

  1. Xref: sparky comp.lang.perl:5041 comp.protocols.snmp:523
  2. Newsgroups: comp.lang.perl,comp.protocols.snmp
  3. Path: sparky!uunet!infonode!ingr!b30!guy!guy
  4. From: guy@guy.b11.ingr.com (Guy Streeter)
  5. Subject: PERL interface to CMU-SNMP
  6. Message-ID: <guy.712515964@guy>
  7. Keywords: perl,snmp,CMU
  8. Sender: usenet@b30.ingr.com (Usenet Feed)
  9. Reply-To: guy@guy.b11.ingr.com
  10. Organization: evidently not
  11. Date: Thu, 30 Jul 1992 17:06:04 GMT
  12. Lines: 1636
  13.  
  14. I was planning to hold off releasing this in order to port it to the
  15. new CMU release.  But it looks like it may be a while before I can get
  16. to that, so here it is.
  17.  
  18. What is it?  It is snmperl, an interface from perl to the API of the
  19. CMU SNMP implementation.  See the README file for more information.
  20.  
  21. I'll be glad to hear feedback about problems with this package, and
  22. about how useful/useless it is, but I don't guarantee support for it
  23. and I don't warantee it at all.
  24.  
  25. I'll also be glad to hear from Mr. Wall or anyone else familiar with
  26. the user-supplied subroutine code about how well (or not) I did the
  27. implementation.
  28.  
  29. have fun,
  30. Guy Streeter
  31. guy@guy.b30.ingr.com
  32.  
  33. ---- Cut Here and feed the following to sh ----
  34. #!/bin/sh
  35. # This is a shell archive (produced by shar 3.49)
  36. # To extract the files from this archive, save it to a file, remove
  37. # everything above the "!/bin/sh" line above, and type "sh file_name".
  38. #
  39. # made 07/30/1992 17:03 UTC by guy@guy.b30.ingr.com
  40. # Source directory /usr2/perl/snmp
  41. #
  42. # existing files will NOT be overwritten unless -c is specified
  43. #
  44. # This shar contains:
  45. # length  mode       name
  46. # ------ ---------- ------------------------------------------
  47. #   3407 -rw-rw-r-- README
  48. #    495 -rw-r--r-- Makefile
  49. #   9601 -rw-rw-r-- snmp.c
  50. #  16738 -rw-r--r-- mib.c
  51. #   1754 -rw-rw-rw- snmp.pl
  52. #   4584 -rwxr-xr-x snmp-tracer
  53. #
  54. # ============= README ==============
  55. if test -f 'README' -a X"$1" != X"-c"; then
  56.     echo 'x - skipping README (File already exists)'
  57. else
  58. echo 'x - extracting README (Text)'
  59. sed 's/^X//' << 'SHAR_EOF' > 'README' &&
  60. XThis directory contains the source code to add callable C subroutines
  61. Xto perl.  The subroutines implement the SNMP functions "get",
  62. X"getnext", and "set".  They use the freely-distributable SNMP package
  63. X(version 1.1b) from CMU.
  64. X
  65. XThis file tells how to build and use this package.  The following
  66. Xfiles should be present:
  67. X
  68. XREADME     -- This file.
  69. X
  70. Xsnmp.c     -- The callable interface to perl.
  71. X
  72. Xmib.c     -- The only file from the CMU SNMP package which has been
  73. X     modified for use here.
  74. X
  75. XMakefile -- The Makefile (You'll need to edit this).
  76. X
  77. Xsnmp.pl     -- A small package of useful routines.
  78. X
  79. Xsnmp-tracer -- An incomplete attempt to implement trace-route.
  80. X        Supplied as an example of the interface.
  81. X
  82. XSETUP:
  83. X  These files should be in a subdirectory of the main perl source
  84. Xdirectory.  If not, you must change the SRC variable in the Makefile
  85. Xto point to the perl source directory.  Perl should be built.
  86. XSpecifically, "uperl.o" should be present in the perl directory.
  87. X
  88. X  You must have the CMU SNMP package.  This can be retrieved from
  89. Xlancaster.andrew.cmu.edu as pub/snmp1.1b.tar, via anonymous FTP.  You
  90. Xdon't have to build all the applications (some of them won't work
  91. Xunless you are a BSD system), you just need to build libsnmp.a.
  92. X
  93. XBUILD:
  94. X  Once you have perl and the CMU SNMP package:
  95. X1) Copy libsnmp.a from the CMU package to this directory (we will
  96. Xmodify it).
  97. X2) Edit "Makefile".  See especially the CC and INCS variables.
  98. X3) make.
  99. X
  100. XMake should compile mib.c and replace mib.o in libsnmp.a, compile
  101. Xsnmp.c, and create an executable called "snmperl".  Installation is
  102. Xleft to the user.
  103. X
  104. XUSE:
  105. X  There are four subroutines defined in the callable interface:
  106. Xsnmp_get, snmp_next, snmp_set, and snmp_error.
  107. X
  108. X  snmp_get and snmp_next implement the GET and GETNEXT operations,
  109. Xrespectively.  The first two calling arguments are the hostname and
  110. XCommunity string.  The IP address of the host, as a dotted-quad ASCII
  111. Xstring, may be used as the hostname.  The rest of the calling
  112. Xarguments are a list of variables.  See the CMU package documentation
  113. Xfor how variables may be specified.
  114. X  snmp_set also takes hostname and Community string as arguments.  The
  115. Xremaining arguments are a list of triples consisting of variable name,
  116. Xvariable type, and value.  The variable type is a string, such as
  117. X"INTEGER" or "IpAddress".
  118. X  snmp_get, snmp_next, and snmp_set return a list containing
  119. Xalternating variables and values.  snmp_get and snmp_next will simply
  120. Xomit non-existent variables on return.  snmp_set will fail completely
  121. Xif one of the specified variables does not exist (or is read-only).
  122. X  snmp_error will return a text string containing some error
  123. Xinformation about the most recent snmp_get|next|set call, if it had an
  124. Xerror.
  125. X
  126. XOTHER NOTES:
  127. X  I didn't find all the places where the CMU library writes to stderr
  128. Xor calls exit() directly.
  129. X  The changes I made to mib.c involve the formatting of variable values
  130. Xfor return to the caller.  I took out the descriptive prefix so the
  131. Xstring contains only the value.
  132. X  Enumerated types are returned as a string containing the symbolic
  133. Xrepresentation followed in parentheses by the numeric.
  134. X
  135. XDISTRIBUTION and OWNERSHIP
  136. X  perl and the CMU SNMP package have their own statements.  Read them.
  137. XThe work I've done is free and clear.  Just don't say you wrote it if
  138. Xyou didn't, and don't say I wrote it if you change it.
  139. X
  140. XGuy Streeter
  141. Xstreeter@ingr.com
  142. XApril 1, 1992 (not a joke!)
  143. SHAR_EOF
  144. chmod 0664 README ||
  145. echo 'restore of README failed'
  146. Wc_c="`wc -c < 'README'`"
  147. test 3407 -eq "$Wc_c" ||
  148.     echo 'README: original size 3407, current size' "$Wc_c"
  149. fi
  150. # ============= Makefile ==============
  151. if test -f 'Makefile' -a X"$1" != X"-c"; then
  152.     echo 'x - skipping Makefile (File already exists)'
  153. else
  154. echo 'x - extracting Makefile (Text)'
  155. sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
  156. X# define your C compiler command here
  157. XCC = gcc -mc300 -O -s -fwritable-strings -fstrength-reduce -fpcc-struct-return
  158. X
  159. X# point this to the "include" directory of the CMU SNMP source. 
  160. XINCS=-I/usr2/guy/src/cmu-snmp/include
  161. X
  162. XSRC = ..
  163. XLDLIBS = libsnmp.a `. $(SRC)/config.sh; echo $$libs`
  164. X
  165. Xsnmperl: $(SRC)/uperl.o snmp.o libsnmp.a
  166. X    $(CC) $(SRC)/uperl.o snmp.o $(LDLIBS) -o snmperl
  167. X
  168. Xsnmp.o : snmp.c
  169. X    $(CC) -c -I$(SRC) $(INCS) snmp.c
  170. X
  171. Xmib.o : mib.c
  172. X    $(CC) -c $(INCS) mib.c
  173. X
  174. Xlibsnmp.a: libsnmp.a(mib.o)
  175. SHAR_EOF
  176. chmod 0644 Makefile ||
  177. echo 'restore of Makefile failed'
  178. Wc_c="`wc -c < 'Makefile'`"
  179. test 495 -eq "$Wc_c" ||
  180.     echo 'Makefile: original size 495, current size' "$Wc_c"
  181. fi
  182. # ============= snmp.c ==============
  183. if test -f 'snmp.c' -a X"$1" != X"-c"; then
  184.     echo 'x - skipping snmp.c (File already exists)'
  185. else
  186. echo 'x - extracting snmp.c (Text)'
  187. sed 's/^X//' << 'SHAR_EOF' > 'snmp.c' &&
  188. X/*
  189. X * Guy Streeter, 31-mar-92
  190. X *
  191. X * 15-may-92 Fix the handling of Octet Strings, so they come out unmodified.
  192. X *
  193. X *  A lot of this code was derived by example from the CMU SNMP package,
  194. X * whose copyright notice follows:
  195. X */
  196. X/***********************************************************
  197. X    Copyright 1988, 1989 by Carnegie Mellon University
  198. X
  199. X                      All Rights Reserved
  200. X
  201. XPermission to use, copy, modify, and distribute this software and its 
  202. Xdocumentation for any purpose and without fee is hereby granted, 
  203. Xprovided that the above copyright notice appear in all copies and that
  204. Xboth that copyright notice and this permission notice appear in 
  205. Xsupporting documentation, and that the name of CMU not be
  206. Xused in advertising or publicity pertaining to distribution of the
  207. Xsoftware without specific, written prior permission.  
  208. X
  209. XCMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  210. XALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  211. XCMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  212. XANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  213. XWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  214. XARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  215. XSOFTWARE.
  216. X******************************************************************/
  217. X#include "EXTERN.h"
  218. X#include "perl.h"
  219. X
  220. X#include <sys/types.h>
  221. X#include <netinet/in.h>
  222. X#include <sys/time.h>
  223. X#include "snmp.h"
  224. X#include "snmp_impl.h"
  225. X#include "asn1.h"
  226. X#include "snmp_api.h"
  227. X#include "snmp_client.h"
  228. X
  229. Xextern int snmp_errno;
  230. Xextern struct tree *Mib;
  231. X
  232. Xint snmp_dump_packet = 0;
  233. X
  234. Xstatic int last_status;
  235. Xstatic int last_errstat;
  236. Xstatic char err_text[1024];
  237. X
  238. Xenum usersubs {
  239. X    US_snmp_get,
  240. X    US_snmp_next,
  241. X    US_snmp_set,
  242. X    US_snmp_error,
  243. X};
  244. X
  245. Xint
  246. Xuserinit()
  247. X{
  248. X    static void usersub();
  249. X    static char *filename = "snmp.c";
  250. X
  251. X    make_usub("snmp_get", US_snmp_get, usersub, filename);
  252. X    make_usub("snmp_next", US_snmp_next, usersub, filename);
  253. X    make_usub("snmp_set", US_snmp_set, usersub, filename);
  254. X    make_usub("snmp_error", US_snmp_error, usersub, filename);
  255. X    /* ../perl.h declares this routine as returning an int, but the
  256. X       documentation doesn't define the return value, and the code
  257. X       doesn't check it */
  258. X    return 0;
  259. X}
  260. X
  261. X
  262. Xstatic char *
  263. Xsnmp_error()
  264. X{
  265. X    if (err_text[0] != '\0') return err_text;
  266. X
  267. X    if (last_status == STAT_SUCCESS) return snmp_errstring(last_errstat);
  268. X
  269. X    if (last_status == STAT_TIMEOUT) return "Timeout ocurred";
  270. X
  271. X    return "A general error ocurred";
  272. X}
  273. X
  274. X
  275. Xstatic int
  276. Xusersub(ix, sp, items)
  277. X  int ix;
  278. X  register int sp;
  279. X  register int items;
  280. X{
  281. X    STR **st = stack->ary_array + sp;
  282. X    struct snmp_session session, *ss;
  283. X    struct snmp_pdu *pdu, *response = NULL;
  284. X    oid name[MAX_NAME_LEN];
  285. X    int name_length;
  286. X    char buf[1024];
  287. X    int i;
  288. X
  289. X    switch (ix)
  290. X    {
  291. X      case US_snmp_get:
  292. X      case US_snmp_next:
  293. X      case US_snmp_set:
  294. X      {
  295. X      char *host = (char *)str_get(st[1]);
  296. X      char *community = (char *)str_get(st[2]);
  297. X
  298. X      last_status = 0;
  299. X      err_text[0] = '\0';
  300. X
  301. X      if (Mib == (struct tree *)0) init_mib();
  302. X
  303. X      bzero((char *)&session, sizeof(struct snmp_session));
  304. X      session.peername = host;
  305. X      session.community = community;
  306. X      session.community_len = strlen(community);
  307. X      session.retries = SNMP_DEFAULT_RETRIES;
  308. X      session.timeout = SNMP_DEFAULT_TIMEOUT;
  309. X      session.authenticator = NULL;
  310. X
  311. X      snmp_synch_setup(&session);
  312. X      ss = snmp_open(&session);
  313. X      if (ss == NULL)
  314. X      {
  315. X          strcpy(err_text,"Couldn't open snmp");
  316. X          return NULL;
  317. X      }
  318. X
  319. X      if (ix == US_snmp_set) 
  320. X      {
  321. X          struct variable_list *vars = NULL;
  322. X
  323. X          if (items < 5)
  324. X        fatal(
  325. X       "Usage: &snmp_set($host, $community, $variable, $type, $value...)");
  326. X          pdu = snmp_pdu_create(SET_REQ_MSG);
  327. X
  328. X          for (i = 3; i <= items; )
  329. X          {
  330. X          struct variable_list *vp;
  331. X          char *type, *variable = (char *)str_get(st[i]);
  332. X
  333. X          name_length = MAX_NAME_LEN;
  334. X          if ( !read_objid(variable, name, &name_length))
  335. X          {
  336. X              sprintf(err_text,"Invalid object identifier: %s",
  337. X                  variable);
  338. X              snmp_free_pdu(pdu);
  339. X              snmp_close(ss);
  340. X              return NULL;
  341. X          }
  342. X
  343. X          if ((vp = (struct variable_list *)malloc(sizeof *vp))
  344. X              == NULL) fatal ("malloc() failed, line %d",__LINE__);
  345. X          if (vars == NULL)
  346. X            pdu->variables = vp;
  347. X          else
  348. X            vars->next_variable = vp;
  349. X          vars = vp;
  350. X
  351. X          vp->name_length = name_length;
  352. X          if ((vp->name = (oid *)malloc(vp->name_length * sizeof(oid)))
  353. X              == NULL) fatal("malloc() failed, line %d",__LINE__);
  354. X          bcopy((char *)name, (char *)vp->name,
  355. X            vp->name_length * sizeof(oid));
  356. X
  357. X          type = (char *)str_get(st[++i]);
  358. X          variable = (char *)str_get(st[++i]);
  359. X
  360. X          if (strcmp(type, "INTEGER") == 0)
  361. X          {
  362. X              vp->type = INTEGER;
  363. X              if ((vp->val.integer = (long *)malloc(sizeof(long)))
  364. X              == NULL) fatal("malloc() failed");
  365. X              vp->val_len = sizeof(long);
  366. X              *(vp->val.integer) = atoi(variable);
  367. X          }
  368. X          else if (strcmp(type, "DisplayString") == 0)
  369. X          {
  370. X              vp->type = STRING;
  371. X              if ((vp->val.string = strdup(variable)) == NULL)
  372. X            fatal("strdup() failed");
  373. X              vp->val_len = strlen(variable);
  374. X          }
  375. X          else if (strcmp(type, "OCTET STRING") == 0)
  376. X          {
  377. X              vp->type = STRING;
  378. X              vp->val_len = st[i]->str_cur;
  379. X              if ((vp->val.string = (char *)malloc(vp->val_len))
  380. X              == NULL) fatal("malloc() failed");
  381. X              bcopy(st[i]->str_ptr, vp->val.string, vp->val_len);
  382. X          }
  383. X          else if (strcmp(type, "NULL") == 0)
  384. X          {
  385. X              vp->type = NULLOBJ;
  386. X              vp->val_len = 0;
  387. X              vp->val.string = NULL;
  388. X          }
  389. X          else if (strcmp(type, "OBJECT IDENTIFIER") == 0)
  390. X          {
  391. X              vp->type = OBJID;
  392. X              vp->val_len = MAX_NAME_LEN;
  393. X              read_objid(variable, name, &vp->val_len);
  394. X              vp->val_len *= sizeof(oid);
  395. X              if ((vp->val.objid = (oid *)malloc(vp->val_len))
  396. X              == NULL) fatal("malloc() failed");
  397. X              bcopy((char *)name, (char *)vp->val.objid,
  398. X                vp->val_len);
  399. X          }
  400. X          else if (strcmp(type, "TimeTicks") == 0)
  401. X          {
  402. X              vp->type = TIMETICKS;
  403. X              if ((vp->val.integer = (long *)malloc(sizeof(long)))
  404. X              == NULL) fatal("malloc() failed");
  405. X              vp->val_len = sizeof(long);
  406. X              *(vp->val.integer) = atoi(variable);
  407. X          }
  408. X          else if (strcmp(type, "IpAddress") == 0)
  409. X          {
  410. X              vp->type = IPADDRESS;
  411. X              if ((vp->val.integer = (long *)malloc(sizeof(long)))
  412. X              == NULL) fatal("malloc() failed");
  413. X              vp->val_len = sizeof(long);
  414. X              *(vp->val.integer) = inet_addr(variable);
  415. X          }
  416. X          else if (strcmp(type, "Counter") == 0)
  417. X          {
  418. X              vp->type = COUNTER;
  419. X              if ((vp->val.integer = (long *)malloc(sizeof(long)))
  420. X              == NULL) fatal("malloc() failed");
  421. X              vp->val_len = sizeof(long);
  422. X              *(vp->val.integer) = atoi(variable);
  423. X          }
  424. X          else if (strcmp(type, "Gauge") == 0)
  425. X          {
  426. X              vp->type = GAUGE;
  427. X              if ((vp->val.integer = (long *)malloc(sizeof(long)))
  428. X              == NULL) fatal("malloc() failed");
  429. X              vp->val_len = sizeof(long);
  430. X              *(vp->val.integer) = atoi(variable);
  431. X          }
  432. X          else if (strcmp(type, "Opaque") == 0)
  433. X          {
  434. X              vp->type = OPAQUE;
  435. X              vp->val_len = st[i]->str_cur;
  436. X              if ((vp->val.string = (char *)malloc(vp->val_len))
  437. X              == NULL) fatal("malloc() failed");
  438. X              bcopy(st[i]->str_ptr, vp->val.string, vp->val_len);
  439. X          }
  440. X          else
  441. X            fatal(
  442. X             "snmp_set() bad type: use one of INTEGER, Counter, etc.");
  443. X
  444. X          i++;
  445. X          }
  446. X      }
  447. X      else 
  448. X      {
  449. X          if (items < 3)
  450. X        fatal("Usage: &snmp_%s($host, $community, $variable, ...)",
  451. X              ix == US_snmp_get ? "get" : "next");
  452. X          pdu = snmp_pdu_create(ix == US_snmp_get
  453. X                    ? GET_REQ_MSG : GETNEXT_REQ_MSG);
  454. X
  455. X          for (i = 3; i <= items; i++)
  456. X          {
  457. X          char *variable = (char *)str_get(st[i]);
  458. X
  459. X          name_length = MAX_NAME_LEN;
  460. X          if ( !read_objid(variable, name, &name_length))
  461. X          {
  462. X              sprintf(err_text,"Invalid object identifier: %s",
  463. X                  variable);
  464. X              snmp_free_pdu(pdu);
  465. X              snmp_close(ss);
  466. X              return NULL;
  467. X          }
  468. X
  469. X          snmp_add_null_var(pdu, name, name_length);
  470. X          }
  471. X      }
  472. X
  473. Xretry:        
  474. X      last_status = snmp_synch_response(ss, pdu, &response);
  475. X
  476. X      i = 0;
  477. X      if (last_status == STAT_SUCCESS)
  478. X      {
  479. X          last_errstat = response->errstat;
  480. X          if (response->errstat == SNMP_ERR_NOERROR)
  481. X          {
  482. X          struct variable_list *vars;
  483. X
  484. X          for (vars = response->variables;
  485. X               vars != NULL;
  486. X               vars = vars->next_variable)
  487. X          {
  488. X              i++;
  489. X              astore(stack, sp + i*2, Nullstr);
  490. X              st = stack->ary_array + sp + (i-1)*2;
  491. X              buf[0] = '.';
  492. X              get_symbol(vars->name,vars->name_length, Mib, buf+1);
  493. X              st[0] = str_2mortal(str_make(buf,strlen(buf)));
  494. X
  495. X              if (vars->type == ASN_OCTET_STR)
  496. X              {
  497. X              if (vars->val_len == 0)
  498. X                st[1] = str_2mortal(&str_undef);
  499. X              else
  500. X                st[1] = str_2mortal(str_make(vars->val.string,
  501. X                             vars->val_len));
  502. X              }
  503. X              else 
  504. X              {
  505. X              sprint_value(buf, vars->name, vars->name_length,
  506. X                       vars);
  507. X              if (buf[0] == '\0')
  508. X                st[1] = str_2mortal(&str_undef);
  509. X              else
  510. X                st[1] = str_2mortal(str_make(buf,strlen(buf)));
  511. X              }
  512. X          }
  513. X
  514. X          }
  515. X          else
  516. X        if (ix != US_snmp_set &&
  517. X            (pdu = snmp_fix_pdu(response, ix == US_snmp_get
  518. X                    ? GET_REQ_MSG : GETNEXT_REQ_MSG))
  519. X            != NULL)
  520. X          goto retry;
  521. X      }
  522. X
  523. X      if (response) snmp_free_pdu(response);
  524. X
  525. X      snmp_close(ss);
  526. X
  527. X      err_text[0] = '\0';
  528. X
  529. X      return sp + i*2 - 1;
  530. X      }
  531. X
  532. X      case US_snmp_error:
  533. X    if (items != 0)
  534. X      fatal("Usage: &snmp_error()");
  535. X    else
  536. X      str_set(st[0], (char*) snmp_error());
  537. X    return sp;
  538. X    }
  539. X    fatal("Can't happen");
  540. X}
  541. SHAR_EOF
  542. chmod 0664 snmp.c ||
  543. echo 'restore of snmp.c failed'
  544. Wc_c="`wc -c < 'snmp.c'`"
  545. test 9601 -eq "$Wc_c" ||
  546.     echo 'snmp.c: original size 9601, current size' "$Wc_c"
  547. fi
  548. # ============= mib.c ==============
  549. if test -f 'mib.c' -a X"$1" != X"-c"; then
  550.     echo 'x - skipping mib.c (File already exists)'
  551. else
  552. echo 'x - extracting mib.c (Text)'
  553. sed 's/^X//' << 'SHAR_EOF' > 'mib.c' &&
  554. X/*
  555. X * MODIFIED
  556. X *
  557. X * For use in callable subroutines in perl, I modified the sprint_<type>
  558. X * routines so the don't prepend "<type>: " to the strings they create.
  559. X *            Guy Streeter, 2-20-1992
  560. X */
  561. X/***********************************************************
  562. X    Copyright 1988, 1989 by Carnegie Mellon University
  563. X
  564. X                      All Rights Reserved
  565. X
  566. XPermission to use, copy, modify, and distribute this software and its 
  567. Xdocumentation for any purpose and without fee is hereby granted, 
  568. Xprovided that the above copyright notice appear in all copies and that
  569. Xboth that copyright notice and this permission notice appear in 
  570. Xsupporting documentation, and that the name of CMU not be
  571. Xused in advertising or publicity pertaining to distribution of the
  572. Xsoftware without specific, written prior permission.  
  573. X
  574. XCMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  575. XALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  576. XCMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  577. XANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  578. XWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  579. XARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  580. XSOFTWARE.
  581. X******************************************************************/
  582. X#include <stdio.h>
  583. X#include <ctype.h>
  584. X#include <sys/types.h>
  585. X#include <netinet/in.h>
  586. X#include <sys/time.h>
  587. X#include "asn1.h"
  588. X#include "snmp_impl.h"
  589. X#include "snmp_api.h"
  590. X#include "parse.h"
  591. X#include "snmp.h"
  592. X
  593. Xstatic void sprint_by_type();
  594. Xstatic set_functions(), parse_subtree(), lc_cmp();
  595. X
  596. Xoid RFC1066_MIB[] = { 1, 3, 6, 1, 2, 1 };
  597. Xunsigned char RFC1066_MIB_text[] = ".iso.org.dod.internet.mgmt.mib";
  598. Xstruct tree *Mib = 0;
  599. X
  600. X
  601. Xstatic char *uptimeString(timeticks, buf)
  602. X
  603. Xregister long timeticks;
  604. Xchar *buf;
  605. X
  606. X{
  607. X    int    seconds, minutes, hours, days;
  608. X
  609. X    timeticks /= 100;
  610. X    days = timeticks / (60 * 60 * 24);
  611. X    timeticks %= (60 * 60 * 24);
  612. X
  613. X    hours = timeticks / (60 * 60);
  614. X    timeticks %= (60 * 60);
  615. X
  616. X    minutes = timeticks / 60;
  617. X    seconds = timeticks % 60;
  618. X
  619. X    if (days == 0){
  620. X        sprintf(buf, "%d:%02d:%02d", hours, minutes, seconds);
  621. X    } else if (days == 1) {
  622. X        sprintf(buf, "%d day, %d:%02d:%02d", days, hours, minutes, seconds);
  623. X    } else {
  624. X        sprintf(buf, "%d days, %d:%02d:%02d", days, hours, minutes, seconds);
  625. X    }
  626. X    return buf;
  627. X}
  628. X
  629. X
  630. Xstatic sprint_hexstring(buf, cp, len)
  631. X
  632. Xchar *buf;
  633. Xu_char  *cp;
  634. Xint        len;
  635. X
  636. X{
  637. X
  638. X    for(; len >= 16; len -= 16){
  639. X        sprintf(buf, "%02X %02X %02X %02X %02X %02X %02X %02X ", 
  640. X                cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
  641. X        buf += strlen(buf);
  642. X        cp += 8;
  643. X        sprintf(buf, "%02X %02X %02X %02X %02X %02X %02X %02X\n", 
  644. X                cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
  645. X        buf += strlen(buf);
  646. X        cp += 8;
  647. X    }
  648. X
  649. X    for(; len > 0; len--){
  650. X        sprintf(buf, "%02X ", *cp++);
  651. X        buf += strlen(buf);
  652. X    }
  653. X    *buf = '\0';
  654. X}
  655. X
  656. X
  657. Xstatic sprint_asciistring(buf, cp, len)
  658. X
  659. Xchar *buf;
  660. Xu_char  *cp;
  661. Xint        len;
  662. X
  663. X{
  664. X    int    x;
  665. X
  666. X    for(x = 0; x < len; x++){
  667. X        if (*cp){
  668. X            *buf++ = *cp++;
  669. X        } else {
  670. X            *buf++ = '.';
  671. X            cp++;
  672. X        }
  673. X    }
  674. X    *buf = '\0';
  675. X}
  676. X
  677. X
  678. Xstatic void sprint_octet_string(buf, var)
  679. X
  680. Xchar *buf;
  681. Xstruct variable_list *var;
  682. X
  683. X{
  684. X    if (var->type != ASN_OCTET_STR){
  685. X        sprintf(buf, "Wrong Type (should be OCTET STRING): ");
  686. X        buf += strlen(buf);
  687. X        sprint_by_type(buf, var, (struct enum_list *)NULL);
  688. X        return;
  689. X    }
  690. X    sprint_asciistring(buf, var->val.string, var->val_len);
  691. X}
  692. X
  693. X
  694. Xstatic void sprint_ascii_string(buf, var)
  695. X
  696. Xchar *buf;
  697. Xstruct variable_list *var;
  698. X
  699. X{
  700. X
  701. X    if (var->type != ASN_OCTET_STR){
  702. X        sprintf(buf, "Wrong Type (should be OCTET STRING): ");
  703. X        buf += strlen(buf);
  704. X        sprint_by_type(buf, var, (struct enum_list *)NULL);
  705. X        return;
  706. X    }
  707. X    sprint_asciistring(buf, var->val.string, var->val_len);
  708. X}
  709. X
  710. X
  711. Xstatic void sprint_opaque(buf, var)
  712. X
  713. Xchar *buf;
  714. Xstruct variable_list *var;
  715. X
  716. X{
  717. X
  718. X    if (var->type != OPAQUE){
  719. X        sprintf(buf, "Wrong Type (should be Opaque): ");
  720. X        buf += strlen(buf);
  721. X        sprint_by_type(buf, var, (struct enum_list *)NULL);
  722. X        return;
  723. X    }
  724. X    sprint_hexstring(buf, var->val.string, var->val_len);
  725. X}
  726. X
  727. X
  728. Xstatic void sprint_object_identifier(buf, var)
  729. X
  730. Xchar *buf;
  731. Xstruct variable_list *var;
  732. X
  733. X{
  734. X    if (var->type != ASN_OBJECT_ID){
  735. X        sprintf(buf, "Wrong Type (should be OBJECT IDENTIFIER): ");
  736. X        buf += strlen(buf);
  737. X        sprint_by_type(buf, var, (struct enum_list *)NULL);
  738. X        return;
  739. X    }
  740. X    sprint_objid(buf, (oid *)(var->val.objid), var->val_len / sizeof(oid));
  741. X}
  742. X
  743. X
  744. Xstatic void sprint_timeticks(buf, var)
  745. X
  746. Xchar *buf;
  747. Xstruct variable_list *var;
  748. X
  749. X{
  750. X    char timebuf[32];
  751. X
  752. X    if (var->type != TIMETICKS){
  753. X        sprintf(buf, "Wrong Type (should be Timeticks): ");
  754. X        buf += strlen(buf);
  755. X        sprint_by_type(buf, var, (struct enum_list *)NULL);
  756. X        return;
  757. X    }
  758. X    sprintf(buf, "%d (%s)", 
  759. X            *(var->val.integer), uptimeString(*(var->val.integer), timebuf));
  760. X}
  761. X
  762. X
  763. Xstatic void sprint_integer(buf, var, enums)
  764. X
  765. Xchar *buf;
  766. Xstruct variable_list *var;
  767. Xstruct enum_list        *enums;
  768. X
  769. X{
  770. X    char    *enum_string = NULL;
  771. X
  772. X    if (var->type != ASN_INTEGER){
  773. X        sprintf(buf, "Wrong Type (should be INTEGER): ");
  774. X        buf += strlen(buf);
  775. X        sprint_by_type(buf, var, (struct enum_list *)NULL);
  776. X        return;
  777. X    }
  778. X    for (; enums; enums = enums->next) {
  779. X        if (enums->value == *var->val.integer){
  780. X            enum_string = enums->label;
  781. X            break;
  782. X        }
  783. X    }
  784. X
  785. X    if (enum_string == NULL) {
  786. X        sprintf(buf, "%d", *var->val.integer);
  787. X    } else {
  788. X        sprintf(buf, "%s(%d)", enum_string, *var->val.integer);
  789. X    }
  790. X}
  791. X
  792. X
  793. Xstatic void sprint_gauge(buf, var)
  794. X
  795. Xchar *buf;
  796. Xstruct variable_list *var;
  797. X
  798. X{
  799. X    if (var->type != GAUGE){
  800. X        sprintf(buf, "Wrong Type (should be Gauge): ");
  801. X        buf += strlen(buf);
  802. X        sprint_by_type(buf, var, (struct enum_list *)NULL);
  803. X        return;
  804. X    }
  805. X    sprintf(buf, "%lu", *var->val.integer);
  806. X}
  807. X
  808. X
  809. Xstatic void sprint_counter(buf, var)
  810. X
  811. Xchar *buf;
  812. Xstruct variable_list *var;
  813. X
  814. X{
  815. X    if (var->type != COUNTER){
  816. X        sprintf(buf, "Wrong Type (should be Counter): ");
  817. X        buf += strlen(buf);
  818. X        sprint_by_type(buf, var, (struct enum_list *)NULL);
  819. X        return;
  820. X    }
  821. X    sprintf(buf, "%lu", *var->val.integer);
  822. X}
  823. X
  824. X
  825. Xstatic void sprint_networkaddress(buf, var)
  826. X
  827. Xchar *buf;
  828. Xstruct variable_list *var;
  829. X
  830. X{
  831. X    int x, len;
  832. X    u_char *cp;
  833. X
  834. X    cp = var->val.string;    
  835. X    len = var->val_len;
  836. X    for(x = 0; x < len; x++){
  837. X        sprintf(buf, "%02X", *cp++);
  838. X        buf += strlen(buf);
  839. X        if (x < (len - 1)) {
  840. X            *buf++ = ':';
  841. X        }
  842. X    }
  843. X}
  844. X
  845. X
  846. Xstatic void sprint_ipaddress(buf, var)
  847. X
  848. Xchar *buf;
  849. Xstruct variable_list *var;
  850. X
  851. X{
  852. X    u_char *ip;
  853. X
  854. X    if (var->type != IPADDRESS){
  855. X        sprintf(buf, "Wrong Type (should be Ipaddress): ");
  856. X        buf += strlen(buf);
  857. X        sprint_by_type(buf, var, (struct enum_list *)NULL);
  858. X        return;
  859. X    }
  860. X    ip = var->val.string;
  861. X    sprintf(buf, "%d.%d.%d.%d",ip[0], ip[1], ip[2], ip[3]);
  862. X}
  863. X
  864. X
  865. Xstatic void sprint_unsigned_short(buf, var)
  866. X
  867. Xchar *buf;
  868. Xstruct variable_list *var;
  869. X
  870. X{
  871. X    if (var->type != ASN_INTEGER){
  872. X        sprintf(buf, "Wrong Type (should be INTEGER): ");
  873. X        buf += strlen(buf);
  874. X        sprint_by_type(buf, var, (struct enum_list *)NULL);
  875. X        return;
  876. X    }
  877. X    sprintf(buf, "%lu", *var->val.integer);
  878. X}
  879. X
  880. X
  881. Xstatic void sprint_null(buf, var)
  882. X
  883. Xchar *buf;
  884. Xstruct variable_list *var;
  885. X
  886. X{
  887. X    if (var->type != ASN_NULL){
  888. X        sprintf(buf, "Wrong Type (should be NULL): ");
  889. X        buf += strlen(buf);
  890. X        sprint_by_type(buf, var, (struct enum_list *)NULL);
  891. X        return;
  892. X    }
  893. X    sprintf(buf, "NULL");
  894. X}
  895. X
  896. X
  897. Xstatic void sprint_unknowntype(buf, var)
  898. X
  899. Xchar *buf;
  900. Xstruct variable_list *var;
  901. X
  902. X{
  903. X    /*    sprintf(buf, "Variable has bad type"); */
  904. X    sprint_by_type(buf, var, NULL);
  905. X}
  906. X
  907. X
  908. Xstatic void sprint_badtype(buf)
  909. X
  910. Xchar *buf;
  911. X
  912. X{
  913. X    sprintf(buf, "Variable has bad type");
  914. X}
  915. X
  916. X
  917. Xstatic void sprint_by_type(buf, var, enums)
  918. X
  919. Xchar *buf;
  920. Xstruct variable_list *var;
  921. Xstruct enum_list        *enums;
  922. X
  923. X{
  924. X    switch (var->type){
  925. X        case ASN_INTEGER:
  926. X            sprint_integer(buf, var, enums);
  927. X        break;
  928. X        case ASN_OCTET_STR:
  929. X            sprint_octet_string(buf, var);
  930. X        break;
  931. X        case OPAQUE:
  932. X            sprint_opaque(buf, var);
  933. X        break;
  934. X        case ASN_OBJECT_ID:
  935. X            sprint_object_identifier(buf, var);
  936. X        break;
  937. X        case TIMETICKS:
  938. X            sprint_timeticks(buf, var);
  939. X        break;
  940. X        case GAUGE:
  941. X            sprint_gauge(buf, var);
  942. X        break;
  943. X        case COUNTER:
  944. X            sprint_counter(buf, var);
  945. X        break;
  946. X        case IPADDRESS:
  947. X            sprint_ipaddress(buf, var);
  948. X        break;
  949. X        case ASN_NULL:
  950. X            sprint_null(buf, var);
  951. X        break;
  952. X        default:
  953. X            sprint_badtype(buf);
  954. X        break;
  955. X    }
  956. X}
  957. X
  958. X
  959. Xinit_mib()
  960. X{
  961. X    char *file, *getenv();
  962. X
  963. X    file = getenv("MIBFILE");
  964. X    if (file) {
  965. X        Mib = read_mib(file);
  966. X    }
  967. X    if (!Mib) {
  968. X        Mib = read_mib("mib.txt");
  969. X    }
  970. X    if (!Mib) {
  971. X        Mib = read_mib("/etc/mib.txt");
  972. X    }
  973. X    if (!Mib){
  974. X        fprintf(stderr, "Couldn't find mib file\n");
  975. X        exit(2);
  976. X    }
  977. X    set_functions(Mib);
  978. X}
  979. X
  980. X
  981. Xstatic set_functions(subtree)
  982. X
  983. Xstruct tree *subtree;
  984. X
  985. X{
  986. X    for(; subtree; subtree = subtree->next_peer){
  987. X
  988. X        switch(subtree->type){
  989. X            case TYPE_OBJID:
  990. X                subtree->printer = sprint_object_identifier;
  991. X            break;
  992. X            case TYPE_OCTETSTR:
  993. X                subtree->printer = sprint_octet_string;
  994. X            break;
  995. X            case TYPE_INTEGER:
  996. X                subtree->printer = sprint_integer;
  997. X            break;
  998. X            case TYPE_NETADDR:
  999. X                subtree->printer = sprint_networkaddress;
  1000. X            break;
  1001. X            case TYPE_IPADDR:
  1002. X                subtree->printer = sprint_ipaddress;
  1003. X            break;
  1004. X            case TYPE_COUNTER:
  1005. X                subtree->printer = sprint_counter;
  1006. X            break;
  1007. X            case TYPE_GAUGE:
  1008. X                subtree->printer = sprint_gauge;
  1009. X            break;
  1010. X            case TYPE_TIMETICKS:
  1011. X                subtree->printer = sprint_timeticks;
  1012. X            break;
  1013. X            case TYPE_OPAQUE:
  1014. X                subtree->printer = sprint_opaque;
  1015. X            break;
  1016. X            case TYPE_NULL:
  1017. X                subtree->printer = sprint_null;
  1018. X            break;
  1019. X            case TYPE_DISPLAYSTR:
  1020. X                subtree->printer = sprint_ascii_string;
  1021. X            break;
  1022. X            case TYPE_OTHER:
  1023. X            default:
  1024. X                subtree->printer = sprint_unknowntype;
  1025. X            break;
  1026. X        }
  1027. X    set_functions(subtree->child_list);
  1028. X    }
  1029. X}
  1030. X
  1031. X
  1032. Xstatic struct tree *find_rfc1066_mib(root)
  1033. X
  1034. Xstruct tree *root;
  1035. X
  1036. X{
  1037. X    oid *op = RFC1066_MIB;
  1038. X    struct tree *tp;
  1039. X    int len;
  1040. X
  1041. X    for(len = sizeof(RFC1066_MIB)/sizeof(oid); len; len--, op++){
  1042. X        for(tp = root; tp; tp = tp->next_peer){
  1043. X            if (tp->subid == *op){
  1044. X                root = tp->child_list;
  1045. X                break;
  1046. X            }
  1047. X        }
  1048. X        if (tp == NULL) {
  1049. X            return NULL;
  1050. X        }
  1051. X    }
  1052. X    return root;
  1053. X}
  1054. X
  1055. X
  1056. Xint read_objid(input, output, out_len)
  1057. X
  1058. Xchar *input;
  1059. Xoid *output;
  1060. Xint    *out_len;   /* number of subid's in "output" */
  1061. X
  1062. X{
  1063. X    struct tree *root = Mib;
  1064. X    oid *op = output;
  1065. X    int i;
  1066. X
  1067. X    if (*input == '.') {
  1068. X        input++;
  1069. X    } else {
  1070. X        root = find_rfc1066_mib(root);
  1071. X        for (i = 0; i < sizeof (RFC1066_MIB)/sizeof(oid); i++) {
  1072. X            if ((*out_len)-- > 0) {
  1073. X                *output++ = RFC1066_MIB[i];
  1074. X            } else {
  1075. X                fprintf(stderr, "object identifier too long\n");
  1076. X                return (0);
  1077. X            }
  1078. X        }
  1079. X    }
  1080. X
  1081. X    if (root == NULL){
  1082. X        fprintf(stderr, "Mib not initialized.  Exiting.\n");
  1083. X        exit(1);
  1084. X    }
  1085. X    if ((*out_len =     parse_subtree(root, input, output, out_len)) == 0) {
  1086. X        return (0);
  1087. X    }
  1088. X    
  1089. X    *out_len += output - op;
  1090. X
  1091. X    return (1);
  1092. X}
  1093. X
  1094. X
  1095. Xstatic parse_subtree(subtree, input, output, out_len)
  1096. X
  1097. Xstruct tree *subtree;
  1098. Xchar *input;
  1099. Xoid    *output;
  1100. Xint    *out_len;   /* number of subid's */
  1101. X
  1102. X{
  1103. X    char buf[128], *to = buf;
  1104. X    u_long subid = 0;
  1105. X    struct tree *tp;
  1106. X
  1107. X    /*
  1108. X     * No empty strings.  Can happen if there is a trailing '.' or two '.'s
  1109. X     * in a row, i.e. "..".
  1110. X     */
  1111. X
  1112. X    if ((*input == '\0') || (*input == '.')) {
  1113. X        return (0);
  1114. X    }
  1115. X    
  1116. X    if (isdigit(*input)) {
  1117. X        /*
  1118. X         * Read the number, then try to find it in the subtree.
  1119. X         */
  1120. X        while (isdigit(*input)) {
  1121. X            subid *= 10;
  1122. X            subid += *input++ - '0';
  1123. X        }
  1124. X        for (tp = subtree; tp; tp = tp->next_peer) {
  1125. X            if (tp->subid == subid)
  1126. X            goto found;
  1127. X        }
  1128. X        tp = NULL;
  1129. X    } else {
  1130. X        /*
  1131. X         * Read the name into a buffer.
  1132. X         */
  1133. X        while ((*input != '\0') && (*input != '.')) {
  1134. X            *to++ = *input++;
  1135. X        }
  1136. X        *to = '\0';
  1137. X
  1138. X        /*
  1139. X         * Find the name in the subtree;
  1140. X         */
  1141. X        for (tp = subtree; tp; tp = tp->next_peer) {
  1142. X            if (lc_cmp(tp->label, buf) == 0) {
  1143. X                subid = tp->subid;
  1144. X                goto found;
  1145. X            }
  1146. X        }
  1147. X
  1148. X        /*
  1149. X         * If we didn't find the entry, punt...
  1150. X         */
  1151. X        if (tp == NULL) {
  1152. X            fprintf(stderr, "sub-identifier not found: %s\n", buf);
  1153. X            return (0);
  1154. X        }
  1155. X    }
  1156. X
  1157. Xfound:
  1158. X    if(subid > (u_long)MAX_SUBID){
  1159. X        fprintf(stderr, "sub-identifier too large: %s\n", buf);
  1160. X        return (0);
  1161. X    }
  1162. X
  1163. X    if ((*out_len)-- <= 0){
  1164. X        fprintf(stderr, "object identifier too long\n");
  1165. X        return (0);
  1166. X    }
  1167. X    *output++ = subid;
  1168. X
  1169. X    if (*input != '.') {
  1170. X        return (1);
  1171. X    }
  1172. X    if ((*out_len = parse_subtree(tp ? tp->child_list : NULL, 
  1173. X                                  ++input, output, out_len)) == 0) {
  1174. X        return (0);
  1175. X    }
  1176. X    return (++*out_len);
  1177. X}
  1178. X
  1179. X
  1180. Xstruct tree * get_symbol(objid, objidlen, subtree, buf)
  1181. X
  1182. Xoid        *objid;
  1183. Xint        objidlen;
  1184. Xstruct tree    *subtree;
  1185. Xchar    *buf;
  1186. X
  1187. X{
  1188. X    struct tree    *return_tree = NULL;
  1189. X
  1190. X    for(; subtree; subtree = subtree->next_peer){
  1191. X        if (*objid == subtree->subid){
  1192. X            strcpy(buf, subtree->label);
  1193. X            goto found;
  1194. X        }
  1195. X    }
  1196. X
  1197. X    /* subtree not found */
  1198. X    while(objidlen--){    /* output rest of name, uninterpreted */
  1199. X        sprintf(buf, "%u.", *objid++);
  1200. X        while(*buf) {
  1201. X            buf++;
  1202. X        }
  1203. X    }
  1204. X    *(buf - 1) = '\0'; /* remove trailing dot */
  1205. X    return NULL;
  1206. X
  1207. Xfound:
  1208. X    if (objidlen > 1){
  1209. X        while(*buf) {
  1210. X            buf++;
  1211. X        }
  1212. X        *buf++ = '.';
  1213. X        *buf = '\0';
  1214. X        return_tree = get_symbol(objid + 1, objidlen - 1, 
  1215. X                                 subtree->child_list, buf);
  1216. X    } 
  1217. X    if (return_tree != NULL) {
  1218. X        return return_tree;
  1219. X    } else {
  1220. X        return subtree;
  1221. X    }
  1222. X}
  1223. X
  1224. X
  1225. Xprint_objid(objid, objidlen)
  1226. X
  1227. Xoid        *objid;
  1228. Xint        objidlen;    /* number of subidentifiers */
  1229. X
  1230. X{
  1231. X    char    buf[256];
  1232. X    struct tree    *subtree = Mib;
  1233. X
  1234. X    *buf = '.';    /* this is a fully qualified name */
  1235. X    get_symbol(objid, objidlen, subtree, buf + 1);
  1236. X    printf("%s\n", buf);
  1237. X        
  1238. X}
  1239. X
  1240. X
  1241. Xsprint_objid(buf, objid, objidlen)
  1242. X
  1243. Xchar *buf;
  1244. Xoid        *objid;
  1245. Xint        objidlen;    /* number of subidentifiers */
  1246. X
  1247. X{
  1248. X    struct tree    *subtree = Mib;
  1249. X
  1250. X    *buf = '.';    /* this is a fully qualified name */
  1251. X    get_symbol(objid, objidlen, subtree, buf + 1);
  1252. X}
  1253. X
  1254. X
  1255. Xprint_variable(objid, objidlen, variable)
  1256. X
  1257. Xoid     *objid;
  1258. Xint        objidlen;
  1259. Xstruct  variable_list *variable;
  1260. X
  1261. X{
  1262. X    char    buf[512], *cp;
  1263. X    struct tree    *subtree = Mib;
  1264. X
  1265. X    *buf = '.';    /* this is a fully qualified name */
  1266. X    subtree = get_symbol(objid, objidlen, subtree, buf + 1);
  1267. X    cp = buf;
  1268. X    if ( (strlen(buf) >= strlen((char *)RFC1066_MIB_text)) && 
  1269. X         ! bcmp( buf, (char *)RFC1066_MIB_text,
  1270. X                 strlen((char *)RFC1066_MIB_text))){
  1271. X        cp += sizeof(RFC1066_MIB_text);
  1272. X    }
  1273. X    printf("Name: %s\n", cp);
  1274. X    *buf = '\0';
  1275. X    if (subtree->printer) {
  1276. X        (*subtree->printer)(buf, variable, subtree->enums);
  1277. X    } else {
  1278. X        sprint_by_type(buf, variable, subtree->enums);
  1279. X    }
  1280. X    printf("%s\n", buf);
  1281. X}
  1282. X
  1283. X
  1284. Xsprint_variable(buf, objid, objidlen, variable)
  1285. X
  1286. Xchar *buf;
  1287. Xoid     *objid;
  1288. Xint        objidlen;
  1289. Xstruct  variable_list *variable;
  1290. X
  1291. X{
  1292. X    char    tempbuf[512], *cp;
  1293. X    struct tree    *subtree = Mib;
  1294. X
  1295. X    *tempbuf = '.';    /* this is a fully qualified name */
  1296. X    subtree = get_symbol(objid, objidlen, subtree, tempbuf + 1);
  1297. X    cp = tempbuf;
  1298. X    if ( (strlen(tempbuf) >= strlen((char *)RFC1066_MIB_text)) && 
  1299. X         ! bcmp(tempbuf, (char *)RFC1066_MIB_text,
  1300. X                strlen((char *)RFC1066_MIB_text))){
  1301. X        cp += sizeof(RFC1066_MIB_text);
  1302. X    }
  1303. X    sprintf(buf, "Name: %s\n", cp);
  1304. X    buf += strlen(buf);
  1305. X    if (subtree->printer) {
  1306. X        (*subtree->printer)(buf, variable, subtree->enums);
  1307. X     } else {
  1308. X        sprint_by_type(buf, variable, subtree->enums);
  1309. X    }
  1310. X    strcat(buf, "\n");
  1311. X}
  1312. X
  1313. X
  1314. Xsprint_value(buf, objid, objidlen, variable)
  1315. X
  1316. Xchar *buf;
  1317. Xoid     *objid;
  1318. Xint        objidlen;
  1319. Xstruct  variable_list *variable;
  1320. X
  1321. X{
  1322. X    char    tempbuf[512];
  1323. X    struct tree    *subtree = Mib;
  1324. X
  1325. X    subtree = get_symbol(objid, objidlen, subtree, tempbuf);
  1326. X    if (subtree->printer) {
  1327. X        (*subtree->printer)(buf, variable, subtree->enums);
  1328. X    } else {
  1329. X        sprint_by_type(buf, variable, subtree->enums);
  1330. X    }
  1331. X}
  1332. X
  1333. X
  1334. Xprint_value(objid, objidlen, variable)
  1335. X
  1336. Xoid     *objid;
  1337. Xint        objidlen;
  1338. Xstruct  variable_list *variable;
  1339. X
  1340. X{
  1341. X    char    tempbuf[512];
  1342. X    struct tree    *subtree = Mib;
  1343. X
  1344. X    subtree = get_symbol(objid, objidlen, subtree, tempbuf);
  1345. X    if (subtree->printer) {
  1346. X        (*subtree->printer)(tempbuf, variable, subtree->enums);
  1347. X    } else {
  1348. X        sprint_by_type(tempbuf, variable, subtree->enums);
  1349. X    }
  1350. X    printf("%s\n", tempbuf);
  1351. X}
  1352. X
  1353. X
  1354. Xstatic int lc_cmp(s1, s2)
  1355. Xchar *s1, *s2;
  1356. X
  1357. X{
  1358. X    char c1, c2;
  1359. X
  1360. X    while(*s1 && *s2){
  1361. X        if (isupper(*s1)) {
  1362. X            c1 = tolower(*s1);
  1363. X        } else {
  1364. X            c1 = *s1;
  1365. X        }
  1366. X        if (isupper(*s2)) {
  1367. X            c2 = tolower(*s2);
  1368. X        } else {
  1369. X            c2 = *s2;
  1370. X        }
  1371. X        
  1372. X        if (c1 != c2) {
  1373. X            return ((c1 - c2) > 0 ? 1 : -1);
  1374. X        }
  1375. X
  1376. X        s1++;
  1377. X        s2++;
  1378. X    }
  1379. X
  1380. X    if (*s1) {
  1381. X        return -1;
  1382. X    }
  1383. X    if (*s2) {
  1384. X        return 1;
  1385. X    }
  1386. X    return 0;
  1387. X}
  1388. X
  1389. SHAR_EOF
  1390. chmod 0644 mib.c ||
  1391. echo 'restore of mib.c failed'
  1392. Wc_c="`wc -c < 'mib.c'`"
  1393. test 16738 -eq "$Wc_c" ||
  1394.     echo 'mib.c: original size 16738, current size' "$Wc_c"
  1395. fi
  1396. # ============= snmp.pl ==============
  1397. if test -f 'snmp.pl' -a X"$1" != X"-c"; then
  1398.     echo 'x - skipping snmp.pl (File already exists)'
  1399. else
  1400. echo 'x - extracting snmp.pl (Text)'
  1401. sed 's/^X//' << 'SHAR_EOF' > 'snmp.pl' &&
  1402. X#
  1403. X# a few useful routines.    Guy Streeter, 3/31/92
  1404. X#
  1405. Xpackage SNMP;
  1406. X
  1407. X# not much debug output here, but it can be turned on by setting
  1408. X# $SNMP'debug to a positive value.
  1409. X
  1410. X$debug = 0;
  1411. X
  1412. X# &inet_addr takes an IP address in ASCII dotted quad form (0.0.0.0) and
  1413. X# returns an integer in network byte-order.
  1414. X
  1415. Xsub main'inet_addr {            # @_ = (dotted quad)
  1416. X    return unpack("N",pack("C4",split(/\./,$_[0])));
  1417. X}
  1418. X
  1419. X# &inet_ntoa takes an integer IP address in network byte-order and returns
  1420. X# an ASCII string in dotted decimal notation.
  1421. X
  1422. Xsub main'inet_ntoa {            # @_ = (integer)
  1423. X    return join('.',unpack('C4',pack('N',$_[0])));
  1424. X}
  1425. X
  1426. X# &dottedquad takes a hostname or dotted-quad IP address and returns
  1427. X# a dotted-quad address.
  1428. X
  1429. Xsub main'dottedquad {        # @_ = (hostname or dotted quad)
  1430. X    if ($_[0] =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/) {
  1431. X    return $_[0];
  1432. X    } else {
  1433. X    $saddr = (gethostbyname($_[0]))[4] || return undef;
  1434. X    return join('.',unpack("C4",$saddr));
  1435. X    }
  1436. X}
  1437. X
  1438. X# $SNMP'communityFile specifies the location of a DBM file that associates
  1439. X# a host with a Community string.
  1440. X
  1441. X$communityFile = "/etc/mib.commun";
  1442. X
  1443. X# &communityString returns the Community string associated with a given
  1444. X# key.  For simplicity the key should be the dotted-decimal ASCII form
  1445. X# of the address of the host, but the routine doesn't care what the key
  1446. X# is.  "public" is returned if the key or the file doesn't exist.
  1447. X
  1448. Xsub main'communityString {        # @_ = (dotted quad)
  1449. X    if (undef %communityArray) {
  1450. X    warn "opening $communityFile for reading\n" if $debug;
  1451. X    dbmopen(%communityArray,$communityFile,undef)
  1452. X        || warn "somebody stole $communityFile!\n" if $debug;
  1453. X    }
  1454. X    warn "using default community\n" if $debug > 1
  1455. X    && ! $communityArray{@_[0]};
  1456. X    return "$communityArray{@_[0]}" || "public";
  1457. X}
  1458. SHAR_EOF
  1459. chmod 0666 snmp.pl ||
  1460. echo 'restore of snmp.pl failed'
  1461. Wc_c="`wc -c < 'snmp.pl'`"
  1462. test 1754 -eq "$Wc_c" ||
  1463.     echo 'snmp.pl: original size 1754, current size' "$Wc_c"
  1464. fi
  1465. # ============= snmp-tracer ==============
  1466. if test -f 'snmp-tracer' -a X"$1" != X"-c"; then
  1467.     echo 'x - skipping snmp-tracer (File already exists)'
  1468. else
  1469. echo 'x - extracting snmp-tracer (Text)'
  1470. sed 's/^X//' << 'SHAR_EOF' > 'snmp-tracer' &&
  1471. X#!/usr/local/bin/snmperl
  1472. X
  1473. Xrequire 'snmp.pl';
  1474. X
  1475. Xsub subnet {            # @_ = (dotted quad)
  1476. X    split(/\./,$destination);
  1477. X
  1478. X    if ($_[1] < 128) {
  1479. X    return "255.0.0.0";
  1480. X    } else {
  1481. X    if ($_[1] < 192) {
  1482. X        return "255.255.0.0";
  1483. X    } else {
  1484. X        return "255.255.255.0";
  1485. X    }
  1486. X    }
  1487. X}
  1488. X
  1489. Xsub findMask {
  1490. X    return $netmask{$start} if $netmask{$start};
  1491. X    local($dnum) = &inet_addr($destination);
  1492. X    local($ipAdEntAddr) = "ip.ipAddrTable.ipAddrEntry.ipAdEntAddr";
  1493. X    local($ipAdEntNetMask) = "ip.ipAddrTable.ipAddrEntry.ipAdEntNetMask";
  1494. X    local($nextAddr) = $ipAdEntAddr;
  1495. X    local($nextMask) = $ipAdEntNetMask;
  1496. X    local($addrValue,$maskValue,$mnum);
  1497. X    while ($nextMask) {
  1498. X    ($nextAddr,$addrValue,$nextMask,$maskValue) =
  1499. X        &snmp_next($start,&communityString($start),$nextAddr,$nextMask);
  1500. X    last unless $nextMask =~ /$ipAdEntNetMask/;
  1501. X    $mnum = &inet_addr($maskValue);
  1502. X    if (($dnum & $mnum) == (&inet_addr($addrValue) & $mnum)) {
  1503. X        return $netmask{$start} = $maskValue;
  1504. X    }
  1505. X    }
  1506. X    return $netmask{$start} = &subnet($destination);
  1507. X}
  1508. X
  1509. Xwhile ($a=shift(ARGV)) {
  1510. X    $debug++, next if $a eq "-d";
  1511. X    die "Usage: $0 [-d] destination [start]\n" if $a =~ /-.*/;
  1512. X    $destination = $a, next unless $destination;
  1513. X    $start = $a, next unless $start;
  1514. X    die "Usage: $0 [-d] destination [start]\n";
  1515. X}
  1516. X
  1517. X$SNMP'debug = $debug;
  1518. X
  1519. Xdie "Usage: $0 [-d] destination [start]\n" unless $destination;
  1520. X
  1521. Xchop($start = `uname -n`) unless $start;
  1522. X
  1523. Xprint "from $start to $destination:\n";
  1524. X
  1525. X$start = &dottedquad($start) || die "Address lookup failed for $start\n";
  1526. X$destination = &dottedquad($destination)
  1527. X    || die "Address lookup failed for $destination\n";
  1528. X
  1529. X$dest_num = &inet_addr($destination);
  1530. X
  1531. X$ipRouteDest = "ip.ipRoutingTable.ipRouteEntry.ipRouteDest";
  1532. X$ipRouteNextHop = "ip.ipRoutingTable.ipRouteEntry.ipRouteNextHop";
  1533. X$ipRouteType = "ip.ipRoutingTable.ipRouteEntry.ipRouteType";
  1534. X$ipRouteMask = "ip.ipRoutingTable.ipRouteEntry.ipRouteMask";
  1535. X
  1536. X$| = 1;                # unbuffered stdout
  1537. X$indent = " ";
  1538. X%netmask = ();
  1539. X
  1540. Xwhile ($start && $start ne $destination) {
  1541. X    print $indent, "from $start";
  1542. X    $indent .= " ";
  1543. X
  1544. X    $nextDest = $ipRouteDest;
  1545. X    $nextNextHop = $ipRouteNextHop;
  1546. X    $nextType = $ipRouteType;
  1547. X    $nextMask = $ipRouteMask;
  1548. X    undef $hop;
  1549. X
  1550. X    $tryDest = &inet_ntoa(&inet_addr($destination) & &inet_addr(&findMask));
  1551. X    if (@result = &snmp_get($start,&communityString($start),
  1552. X                "$nextDest.$tryDest","$nextNextHop.$tryDest",
  1553. X                "$nextType.$tryDest")) {
  1554. X    undef $valueOfNextHop;
  1555. X    if ($result[0] =~ /$ipRouteDest/) {
  1556. X        shift(result);
  1557. X        shift(result);
  1558. X    }
  1559. X    if ($result[0] =~ /$ipRouteNextHop/) {
  1560. X        shift(result);
  1561. X        $valueOfNextHop = shift(result);
  1562. X    }
  1563. X    if ($result[0] =~ /$ipRouteType/) {
  1564. X        shift(result);
  1565. X        $valueOfType = shift(result);
  1566. X    }
  1567. X    if ($valueOfType &&
  1568. X        !($valueOfType =~ /invalid/ || $valueOfType == 2))
  1569. X    {
  1570. X        $hop = $valueOfNextHop;
  1571. X        undef $nextDest if $valueOfType;
  1572. X    }
  1573. X    }
  1574. X
  1575. X    undef $default;
  1576. X
  1577. X    while ($nextDest) {
  1578. X    @questions = ($nextDest,$nextNextHop,$nextType);
  1579. X    push(questions,$nextMask) if $nextMask;
  1580. X    if ($debug > 2) {
  1581. X        warn "asking @questions\nof $start ",
  1582. X        &communityString($start),"\n";
  1583. X    }
  1584. X    @result = &snmp_next($start,&communityString($start),@questions);
  1585. X    die "Something is foobar" unless @result;
  1586. X
  1587. X    undef $nextDest;
  1588. X    undef $nextMask;
  1589. X
  1590. X    if ($result[0] =~ /$ipRouteDest/) {
  1591. X        $nextDest = shift(result);
  1592. X        $valueOfDest = shift(result);
  1593. X    }
  1594. X    if ($result[0] =~ /$ipRouteNextHop/) {
  1595. X        $nextNextHop = shift(result);
  1596. X        $valueOfNextHop = shift(result);
  1597. X    }
  1598. X    if ($result[0] =~ /$ipRouteType/) {
  1599. X        $nextType = shift(result);
  1600. X        $valueOfType = shift(result);
  1601. X    }
  1602. X    if ($result[0] =~ /$ipRouteMask/) {
  1603. X        $nextMask = shift(result);
  1604. X        $valueOfMask = shift(result);
  1605. X    }
  1606. X
  1607. X    last unless $nextDest;
  1608. X
  1609. X    next if $valueOfType =~ /invalid/ || $valueOfType == 2;
  1610. X
  1611. X    $valueOfMask = &findMask unless $nextMask;
  1612. X
  1613. X    if ($debug) {
  1614. X        warn "mask is $valueOfMask\n";
  1615. X        warn "mask is from default\n" unless $nextMask;
  1616. X    }
  1617. X
  1618. X    $thisdest = &inet_addr($valueOfDest);
  1619. X    if ($thisdest == 0) {
  1620. X        warn "default route discovered: $valueOfNextHop\n" if $debug;
  1621. X        $default = $valueOfNextHop;
  1622. X        next;
  1623. X    }
  1624. X    $thismask = &inet_addr($valueOfMask);
  1625. X
  1626. X    printf(STDERR "comparing %lx and %lx, mask %lx\n", $dest_num,
  1627. X           $thisdest, $thismask) if $debug > 1;
  1628. X    if (($dest_num & $thismask) == ($thisdest & $thismask))
  1629. X    {
  1630. X        $hop = $valueOfNextHop;
  1631. X        last;
  1632. X    }
  1633. X    }
  1634. X
  1635. X    $start = $hop ? $hop : $default;
  1636. X    print " to $start, type = $valueOfType\n";
  1637. X
  1638. X    exit 0 if (($dest_num & $thismask) == ($thismask & &inet_addr($start)));
  1639. X}
  1640. X
  1641. Xdie "I got to here somehow";
  1642. SHAR_EOF
  1643. chmod 0755 snmp-tracer ||
  1644. echo 'restore of snmp-tracer failed'
  1645. Wc_c="`wc -c < 'snmp-tracer'`"
  1646. test 4584 -eq "$Wc_c" ||
  1647.     echo 'snmp-tracer: original size 4584, current size' "$Wc_c"
  1648. fi
  1649. exit 0
  1650.