Anyone willing to look into this one?
Or someone objecting to me committing this?

On 9/26/19 2:33 PM, Martijn van Duren wrote:
> 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