On Thu, Sep 26, 2019 at 02:33:11PM +0200, 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@

few comments.

thanks.

> 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
> @@ -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]);

is "errorindex - 1" the right index ?

$ ./obj/snmp set 192.168.1.5 sysContact.0 s "test"
snmp: Can't parse oid 192.168.1.5: Not writable

Note that the same pattern is used in others commands.

> +
> +     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
> @@ -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();

if I don't mess myself, callers already checks that 'argc % 3 != 0'. So I think
the condition is more a defense for programmer error that user error, and I
would use an assert(argc % 3 == 0) or abort().

> +     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
> 

-- 
Sebastien Marie

Reply via email to