On 9/26/19 9:54 AM, Martijn van Duren wrote:
> Hello,
> 
> I reckon this will be on of the last major additions.
> Adding "snmp set" allows us to run snmpd's regress without installing
> netsnmp. :-)
> 
> Tested with snmpd's regress test.
> 
> Majority of diff is moving oid/value parsing from snmp trap to a
> separate function.
> 
> OK?
> 
> martijn@

Some manpage feedback from jmc.

Index: snmp.1
===================================================================
RCS file: /cvs/src/usr.bin/snmp/snmp.1,v
retrieving revision 1.6
diff -u -p -r1.6 snmp.1
--- snmp.1      18 Sep 2019 09:54:36 -0000      1.6
+++ snmp.1      26 Sep 2019 12:32:38 -0000
@@ -110,6 +110,28 @@
 .Ar agent
 .Op Ar oid
 .Nm
+.Cm set
+.Op Fl A Ar authpass
+.Op Fl a Ar digest
+.Op Fl c Ar community
+.Op Fl E Ar ctxengineid
+.Op Fl e Ar secengineid
+.Op Fl K Ar localpriv
+.Op Fl k Ar localauth
+.Op Fl l Ar seclevel
+.Op Fl n Ar ctxname
+.Op Fl O Cm afnQqSvx
+.Op Fl r Ar retries
+.Op Fl t Ar timeout
+.Op Fl u Ar user
+.Op Fl v Ar version
+.Op Fl X Ar privpass
+.Op Fl x Ar cipher
+.Op Fl Z Ar boots , Ns Ar time
+.Ar agent
+.Ar varoid type value
+.Oo Ar varoid type value Oc ...
+.Nm
 .Cm trap
 .Op Fl A Ar authpass
 .Op Fl a Ar digest
@@ -182,6 +204,12 @@ This uses the
 subcommand internally to retrieve multiple MIBs at a time.
 This command is not available for
 .Fl v Cm 1 .
+.It Cm set
+Set one or more OID to a new value.
+The triple
+.Ar varoid , type , value
+is described in
+.Sx Data types .
 .It Cm trap
 Send a trap message to the
 .Ar agent .
@@ -194,8 +222,8 @@ The
 .Ar trapoid
 is the identification OID used by the trap handler to determine its action.
 The triple
-.Op Ar varoid , type, value
-is described below
+.Op Ar varoid , type , value
+is described in
 .Sx Data types .
 This command is not available for
 .Fl v Cm 1 .
Index: snmp.c
===================================================================
RCS file: /cvs/src/usr.bin/snmp/snmp.c,v
retrieving revision 1.6
diff -u -p -r1.6 snmp.c
--- snmp.c      18 Sep 2019 09:54:36 -0000      1.6
+++ snmp.c      26 Sep 2019 12:32:38 -0000
@@ -249,6 +249,22 @@ fail:
        return NULL;
 }
 
+struct ber_element *
+snmp_set(struct snmp_agent *agent, struct ber_element *vblist)
+{
+       struct ber_element *pdu;
+
+       if ((pdu = ber_add_sequence(NULL)) == NULL)
+               return NULL;
+       if (ber_printf_elements(pdu, "tddd{e", BER_CLASS_CONTEXT,
+           SNMP_C_SETREQ, arc4random() & 0x7fffffff, 0, 0, vblist) == NULL) {
+               ber_free_elements(pdu);
+               return NULL;
+       }
+
+       return snmp_resolve(agent, pdu, 1);
+}
+
 static struct ber_element *
 snmp_resolve(struct snmp_agent *agent, struct ber_element *pdu, int reply)
 {
Index: snmp.h
===================================================================
RCS file: /cvs/src/usr.bin/snmp/snmp.h,v
retrieving revision 1.5
diff -u -p -r1.5 snmp.h
--- snmp.h      18 Sep 2019 09:54:36 -0000      1.5
+++ snmp.h      26 Sep 2019 12:32:38 -0000
@@ -164,6 +164,7 @@ struct ber_element *
 struct ber_element *snmp_getnext(struct snmp_agent *, struct ber_oid *, 
size_t);
 struct ber_element *
     snmp_getbulk(struct snmp_agent *, struct ber_oid *, size_t, int, int);
+struct ber_element *snmp_set(struct snmp_agent *, struct ber_element *);
 int snmp_trap(struct snmp_agent *, struct timespec *, struct ber_oid *,
     struct ber_element *);
 
Index: snmpc.c
===================================================================
RCS file: /cvs/src/usr.bin/snmp/snmpc.c,v
retrieving revision 1.11
diff -u -p -r1.11 snmpc.c
--- snmpc.c     18 Sep 2019 09:54:36 -0000      1.11
+++ snmpc.c     26 Sep 2019 12:32:38 -0000
@@ -46,6 +46,7 @@
 
 int snmpc_get(int, char *[]);
 int snmpc_walk(int, char *[]);
+int snmpc_set(int, char *[]);
 int snmpc_trap(int, char *[]);
 int snmpc_mibtree(int, char *[]);
 struct snmp_agent *snmpc_connect(char *, char *);
@@ -53,6 +54,7 @@ int snmpc_parseagent(char *, char *);
 int snmpc_print(struct ber_element *);
 __dead void snmpc_printerror(enum snmp_error, char *);
 char *snmpc_hex2bin(char *, size_t *);
+struct ber_element *snmpc_varbindparse(int, char *[]);
 void usage(void);
 
 struct snmp_app {
@@ -69,6 +71,7 @@ struct snmp_app snmp_apps[] = {
        { "walk", 1, "C:", "[-C cIipt] [-C E endoid] agent [oid]", snmpc_walk },
        { "bulkget", 1, "C:", "[-C n<nonrep>r<maxrep>] agent oid ...", 
snmpc_get },
        { "bulkwalk", 1, "C:", "[-C cipn<nonrep>r<maxrep>] agent [oid]", 
snmpc_walk },
+       { "set", 1, NULL, "agent oid type value [oid type value] ...", 
snmpc_set },
        { "trap", 1, NULL, "agent uptime oid [oid type value] ...", snmpc_trap 
},
        { "mibtree", 0, "O:", "[-O fnS]", snmpc_mibtree }
 };
@@ -666,19 +669,54 @@ snmpc_walk(int argc, char *argv[])
 }
 
 int
+snmpc_set(int argc, char *argv[])
+{
+       struct snmp_agent *agent;
+       struct ber_element *pdu, *varbind;
+       int errorstatus, errorindex;
+       int class;
+       unsigned type;
+
+       if (argc < 4)
+               usage();
+       if ((agent = snmpc_connect(argv[0], "161")) == NULL)
+               err(1, "%s", snmp_app->name);
+       argc--;
+       argv++;
+
+       if (argc < 3 || argc % 3 != 0)
+               usage();
+
+       if (pledge("stdio", NULL) == -1)
+               err(1, "pledge");
+
+       pdu = snmp_set(agent, snmpc_varbindparse(argc, argv));
+
+       (void) ber_scanf_elements(pdu, "t{Sdd{e", &class, &type, &errorstatus,
+           &errorindex, &varbind);
+       if (errorstatus != 0)
+               snmpc_printerror((enum snmp_error) errorstatus,
+                   argv[errorindex - 1]);
+
+       if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT)
+               printf("Received report:\n");
+       for (; varbind != NULL; varbind = varbind->be_next) {
+               if (!snmpc_print(varbind))
+                       err(1, "Can't print response");
+       }
+       ber_free_elements(pdu);
+       snmp_free_agent(agent);
+       return 0;
+}
+
+int
 snmpc_trap(int argc, char *argv[])
 {
        struct snmp_agent *agent;
        struct timespec ts;
-       struct ber_oid trapoid, oid, oidval;
-       struct in_addr addr4;
-       char *addr = (char *)&addr4;
-       char *str = NULL, *tmpstr, *endstr;
+       struct ber_oid trapoid;
        const char *errstr = NULL;
-       struct ber_element *varbind = NULL, *pdu = NULL;
        long long lval;
-       int i, ret;
-       size_t strl, byte;
 
        if (argc < 3 || argc % 3 != 0)
                usage();
@@ -706,164 +744,8 @@ snmpc_trap(int argc, char *argv[])
 
        argc -= 3;
        argv += 3;
-       for (i = 0; i < argc; i += 3) {
-               if (smi_string2oid(argv[i], &oid) == -1)
-                       errx(1, "Invalid oid: %s\n", argv[i]);
-               switch (argv[i + 1][0]) {
-               case 'a':
-                       ret = inet_pton(AF_INET, argv[i + 2], &addr4);
-                       if (ret == -1)
-                               err(1, "inet_pton");
-                       if (ret == 0)
-                               errx(1, "%s: Bad value notation (%s)", argv[i],
-                                   argv[i + 2]);
-                       if ((varbind = ber_printf_elements(varbind, "{Oxt}",
-                           &oid, addr, sizeof(addr4), BER_CLASS_APPLICATION,
-                           SNMP_T_IPADDR)) == NULL)
-                               err(1, "ber_printf_elements");
-                       break;
-               case 'b':
-                       tmpstr = argv[i + 2];
-                       strl = 0;
-                       do {
-                               lval = strtoll(tmpstr, &endstr, 10);
-                               if (endstr[0] != ' ' && endstr[0] != '\t' &&
-                                   endstr[0] != ',' && endstr[0] != '\0')
-                                       errx(1, "%s: Bad value notation (%s)",
-                                           argv[i], argv[i + 2]);
-                               if (tmpstr == endstr) {
-                                       tmpstr++;
-                                       continue;
-                               }
-                               if (lval < 0)
-                                       errx(1, "%s: Bad value notation (%s)",
-                                           argv[i], argv[i + 2]);
-                               byte = lval / 8;
-                               if (byte >= strl) {
-                                       if ((str = recallocarray(str, strl,
-                                           byte + 1, 1)) == NULL)
-                                               err(1, "malloc");
-                                       strl = byte + 1;
-                               }
-                               str[byte] |= 0x80 >> (lval % 8);
-                               tmpstr = endstr + 1;
-                       } while (endstr[0] != '\0');
-                       /*
-                        * RFC3416 Section 2.5
-                        * A BITS value is encoded as an OCTET STRING
-                        */
-                       goto pastestring;
-               case 'c':
-                       lval = strtonum(argv[i + 2], INT32_MIN, INT32_MAX,
-                           &errstr);
-                       if (errstr != NULL)
-                               errx(1, "%s: Bad value notation (%s)", argv[i],
-                                   argv[i + 2]);
-                       if ((varbind = ber_printf_elements(varbind, "{Oit}",
-                           &oid, lval, BER_CLASS_APPLICATION,
-                           SNMP_T_COUNTER32)) == NULL)
-                               err(1, "ber_printf_elements");
-                       break;
-               case 'd':
-                       /* String always shrinks */
-                       if ((str = malloc(strlen(argv[i + 2]))) == NULL)
-                               err(1, "malloc");
-                       tmpstr = argv[i + 2];
-                       strl = 0;
-                       do {
-                               lval = strtoll(tmpstr, &endstr, 10);
-                               if (endstr[0] != ' ' && endstr[0] != '\t' &&
-                                   endstr[0] != '\0')
-                                       errx(1, "%s: Bad value notation (%s)",
-                                           argv[i], argv[i + 2]);
-                               if (tmpstr == endstr) {
-                                       tmpstr++;
-                                       continue;
-                               }
-                               if (lval < 0 || lval > 0xff)
-                                       errx(1, "%s: Bad value notation (%s)",
-                                           argv[i], argv[i + 2]);
-                               str[strl++] = (unsigned char) lval;
-                               tmpstr = endstr + 1;
-                       } while (endstr[0] != '\0');
-                       goto pastestring;
-               case 'u':
-               case 'i':
-                       lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_MAX,
-                           &errstr);
-                       if (errstr != NULL)
-                               errx(1, "%s: Bad value notation (%s)", argv[i],
-                                   argv[i + 2]);
-                       if ((varbind = ber_printf_elements(varbind, "{Oi}",
-                           &oid, lval)) == NULL)
-                               err(1, "ber_printf_elements");
-                       break;
-               case 'n':
-                       if ((varbind = ber_printf_elements(varbind, "{O0}",
-                           &oid)) == NULL)
-                               err(1, "ber_printf_elements");
-                       break;
-               case 'o':
-                       if (smi_string2oid(argv[i + 2], &oidval) == -1)
-                               errx(1, "%s: Unknown Object Identifier (Sub-id "
-                                   "not found: (top) -> %s)", argv[i],
-                                   argv[i + 2]);
-                       if ((varbind = ber_printf_elements(varbind, "{OO}",
-                           &oid, &oidval)) == NULL)
-                               err(1, "ber_printf_elements");
-                       break;
-               case 's':
-                       if ((str = strdup(argv[i + 2])) == NULL)
-                               err(1, NULL);
-                       strl = strlen(argv[i + 2]);
-pastestring:
-                       if ((varbind = ber_printf_elements(varbind, "{Ox}",
-                           &oid, str, strl)) == NULL)
-                               err(1, "ber_printf_elements");
-                       free(str);
-                       break;
-               case 't':
-                       lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_MAX,
-                           &errstr);
-                       if (errstr != NULL)
-                               errx(1, "%s: Bad value notation (%s)", argv[i],
-                                   argv[i + 2]);
-                       if ((varbind = ber_printf_elements(varbind, "{Oit}",
-                           &oid, lval, BER_CLASS_APPLICATION,
-                           SNMP_T_TIMETICKS)) == NULL)
-                               err(1, "ber_printf_elements");
-                       break;
-               case 'x':
-                       /* String always shrinks */
-                       if ((str = malloc(strlen(argv[i + 2]))) == NULL)
-                               err(1, "malloc");
-                       tmpstr = argv[i + 2];
-                       strl = 0;
-                       do {
-                               lval = strtoll(tmpstr, &endstr, 16);
-                               if (endstr[0] != ' ' && endstr[0] != '\t' &&
-                                   endstr[0] != '\0')
-                                       errx(1, "%s: Bad value notation (%s)",
-                                           argv[i], argv[i + 2]);
-                               if (tmpstr == endstr) {
-                                       tmpstr++;
-                                       continue;
-                               }
-                               if (lval < 0 || lval > 0xff)
-                                       errx(1, "%s: Bad value notation (%s)",
-                                           argv[i], argv[i + 2]);
-                               str[strl++] = (unsigned char) lval;
-                               tmpstr = endstr + 1;
-                       } while (endstr[0] != '\0');
-                       goto pastestring;
-               default:
-                       usage();
-               }
-               if (pdu == NULL)
-                       pdu = varbind;
-       }
 
-       snmp_trap(agent, &ts, &trapoid, pdu);
+       snmp_trap(agent, &ts, &trapoid, snmpc_varbindparse(argc, argv));
 
        return 0;
 }
@@ -1116,6 +998,181 @@ fail:
        errno = EINVAL;
        free(decstr);
        return NULL;
+}
+
+struct ber_element *
+snmpc_varbindparse(int argc, char *argv[])
+{
+       struct ber_oid oid, oidval;
+       struct in_addr addr4;
+       char *addr = (char *)&addr4;
+       char *str = NULL, *tmpstr, *endstr;
+       const char *errstr = NULL;
+       struct ber_element *varbind = NULL, *vblist = NULL;
+       int i, ret;
+       size_t strl, byte;
+       long long lval;
+
+       if (argc % 3 != 0)
+               usage();
+       for (i = 0; i < argc; i += 3) {
+               if (smi_string2oid(argv[i], &oid) == -1)
+                       errx(1, "Invalid oid: %s\n", argv[i]);
+               switch (argv[i + 1][0]) {
+               case 'a':
+                       ret = inet_pton(AF_INET, argv[i + 2], &addr4);
+                       if (ret == -1)
+                               err(1, "inet_pton");
+                       if (ret == 0)
+                               errx(1, "%s: Bad value notation (%s)", argv[i],
+                                   argv[i + 2]);
+                       if ((varbind = ber_printf_elements(varbind, "{Oxt}",
+                           &oid, addr, sizeof(addr4), BER_CLASS_APPLICATION,
+                           SNMP_T_IPADDR)) == NULL)
+                               err(1, "ber_printf_elements");
+                       break;
+               case 'b':
+                       tmpstr = argv[i + 2];
+                       strl = 0;
+                       do {
+                               lval = strtoll(tmpstr, &endstr, 10);
+                               if (endstr[0] != ' ' && endstr[0] != '\t' &&
+                                   endstr[0] != ',' && endstr[0] != '\0')
+                                       errx(1, "%s: Bad value notation (%s)",
+                                           argv[i], argv[i + 2]);
+                               if (tmpstr == endstr) {
+                                       tmpstr++;
+                                       continue;
+                               }
+                               if (lval < 0)
+                                       errx(1, "%s: Bad value notation (%s)",
+                                           argv[i], argv[i + 2]);
+                               byte = lval / 8;
+                               if (byte >= strl) {
+                                       if ((str = recallocarray(str, strl,
+                                           byte + 1, 1)) == NULL)
+                                               err(1, "malloc");
+                                       strl = byte + 1;
+                               }
+                               str[byte] |= 0x80 >> (lval % 8);
+                               tmpstr = endstr + 1;
+                       } while (endstr[0] != '\0');
+                       /*
+                        * RFC3416 Section 2.5
+                        * A BITS value is encoded as an OCTET STRING
+                        */
+                       goto pastestring;
+               case 'c':
+                       lval = strtonum(argv[i + 2], INT32_MIN, INT32_MAX,
+                           &errstr);
+                       if (errstr != NULL)
+                               errx(1, "%s: Bad value notation (%s)", argv[i],
+                                   argv[i + 2]);
+                       if ((varbind = ber_printf_elements(varbind, "{Oit}",
+                           &oid, lval, BER_CLASS_APPLICATION,
+                           SNMP_T_COUNTER32)) == NULL)
+                               err(1, "ber_printf_elements");
+                       break;
+               case 'd':
+                       /* String always shrinks */
+                       if ((str = malloc(strlen(argv[i + 2]))) == NULL)
+                               err(1, "malloc");
+                       tmpstr = argv[i + 2];
+                       strl = 0;
+                       do {
+                               lval = strtoll(tmpstr, &endstr, 10);
+                               if (endstr[0] != ' ' && endstr[0] != '\t' &&
+                                   endstr[0] != '\0')
+                                       errx(1, "%s: Bad value notation (%s)",
+                                           argv[i], argv[i + 2]);
+                               if (tmpstr == endstr) {
+                                       tmpstr++;
+                                       continue;
+                               }
+                               if (lval < 0 || lval > 0xff)
+                                       errx(1, "%s: Bad value notation (%s)",
+                                           argv[i], argv[i + 2]);
+                               str[strl++] = (unsigned char) lval;
+                               tmpstr = endstr + 1;
+                       } while (endstr[0] != '\0');
+                       goto pastestring;
+               case 'u':
+               case 'i':
+                       lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_MAX,
+                           &errstr);
+                       if (errstr != NULL)
+                               errx(1, "%s: Bad value notation (%s)", argv[i],
+                                   argv[i + 2]);
+                       if ((varbind = ber_printf_elements(varbind, "{Oi}",
+                           &oid, lval)) == NULL)
+                               err(1, "ber_printf_elements");
+                       break;
+               case 'n':
+                       if ((varbind = ber_printf_elements(varbind, "{O0}",
+                           &oid)) == NULL)
+                               err(1, "ber_printf_elements");
+                       break;
+               case 'o':
+                       if (smi_string2oid(argv[i + 2], &oidval) == -1)
+                               errx(1, "%s: Unknown Object Identifier (Sub-id "
+                                   "not found: (top) -> %s)", argv[i],
+                                   argv[i + 2]);
+                       if ((varbind = ber_printf_elements(varbind, "{OO}",
+                           &oid, &oidval)) == NULL)
+                               err(1, "ber_printf_elements");
+                       break;
+               case 's':
+                       if ((str = strdup(argv[i + 2])) == NULL)
+                               err(1, NULL);
+                       strl = strlen(argv[i + 2]);
+pastestring:
+                       if ((varbind = ber_printf_elements(varbind, "{Ox}",
+                           &oid, str, strl)) == NULL)
+                               err(1, "ber_printf_elements");
+                       free(str);
+                       break;
+               case 't':
+                       lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_MAX,
+                           &errstr);
+                       if (errstr != NULL)
+                               errx(1, "%s: Bad value notation (%s)", argv[i],
+                                   argv[i + 2]);
+                       if ((varbind = ber_printf_elements(varbind, "{Oit}",
+                           &oid, lval, BER_CLASS_APPLICATION,
+                           SNMP_T_TIMETICKS)) == NULL)
+                               err(1, "ber_printf_elements");
+                       break;
+               case 'x':
+                       /* String always shrinks */
+                       if ((str = malloc(strlen(argv[i + 2]))) == NULL)
+                               err(1, "malloc");
+                       tmpstr = argv[i + 2];
+                       strl = 0;
+                       do {
+                               lval = strtoll(tmpstr, &endstr, 16);
+                               if (endstr[0] != ' ' && endstr[0] != '\t' &&
+                                   endstr[0] != '\0')
+                                       errx(1, "%s: Bad value notation (%s)",
+                                           argv[i], argv[i + 2]);
+                               if (tmpstr == endstr) {
+                                       tmpstr++;
+                                       continue;
+                               }
+                               if (lval < 0 || lval > 0xff)
+                                       errx(1, "%s: Bad value notation (%s)",
+                                           argv[i], argv[i + 2]);
+                               str[strl++] = (unsigned char) lval;
+                               tmpstr = endstr + 1;
+                       } while (endstr[0] != '\0');
+                       goto pastestring;
+               default:
+                       usage();
+               }
+               if (vblist == NULL)
+                       vblist = varbind;
+       }
+
+       return vblist;
 }
 
 __dead void

Reply via email to