I'm not quite sure yet where I want to move with snmpe_parsevarbinds, 
but the current implementation just gives me a headache every time I 
read it. There's still of plenty of issues in here, like not fully
complient gathering of statistics, relying on synchronous handling of
varbinds (required for proper AgentX support) and not taking RFC3584
into acount. But my goal for now is a small step to making things
more readable and see where we can go from there.

Regress still passes and except for some minor changes in the handling
of snmp_intotal{req,set}vars no functional changes intended.

For people who wonder what happened to the 1 return value: this value
was only used when agentx was called, which is currently no more.

OK?

martijn@

Index: snmpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/snmpd/snmpd.h,v
retrieving revision 1.87
diff -u -p -r1.87 snmpd.h
--- snmpd.h     30 Jun 2020 17:11:49 -0000      1.87
+++ snmpd.h     19 Jul 2020 12:08:04 -0000
@@ -394,19 +394,10 @@ struct snmp_message {
        struct ber_element      *sm_req;
        struct ber_element      *sm_resp;
 
-       int                      sm_i;
-       struct ber_element      *sm_a;
-       struct ber_element      *sm_b;
-       struct ber_element      *sm_c;
-       struct ber_element      *sm_next;
-       struct ber_element      *sm_last;
-       struct ber_element      *sm_end;
-
        u_int8_t                 sm_data[READ_BUF_SIZE];
        size_t                   sm_datalen;
 
        u_int                    sm_version;
-       u_int                    sm_state;
 
        /* V1, V2c */
        char                     sm_community[SNMPD_MAXCOMMUNITYLEN];
Index: snmpe.c
===================================================================
RCS file: /cvs/src/usr.sbin/snmpd/snmpe.c,v
retrieving revision 1.62
diff -u -p -r1.62 snmpe.c
--- snmpe.c     2 May 2020 14:22:31 -0000       1.62
+++ snmpe.c     19 Jul 2020 12:08:04 -0000
@@ -400,124 +400,112 @@ int
 snmpe_parsevarbinds(struct snmp_message *msg)
 {
        struct snmp_stats       *stats = &snmpd_env->sc_stats;
+       struct ber_element      *varbind, *value, *rvarbind = NULL;
+       struct ber_element      *pvarbind = NULL, *end;
        char                     buf[BUFSIZ];
        struct ber_oid           o;
-       int                      ret = 0;
+       int                      i;
 
        msg->sm_errstr = "invalid varbind element";
 
-       if (msg->sm_i == 0) {
-               msg->sm_i = 1;
-               msg->sm_a = msg->sm_varbind;
-               msg->sm_last = NULL;
-       }
-
-        for (; msg->sm_a != NULL && msg->sm_i < SNMPD_MAXVARBIND;
-           msg->sm_a = msg->sm_next, msg->sm_i++) {
-               msg->sm_next = msg->sm_a->be_next;
-
-               if (msg->sm_a->be_class != BER_CLASS_UNIVERSAL ||
-                   msg->sm_a->be_type != BER_TYPE_SEQUENCE)
-                       continue;
-               if ((msg->sm_b = msg->sm_a->be_sub) == NULL)
-                       continue;
-
-               for (msg->sm_state = 0; msg->sm_state < 2 && msg->sm_b != NULL;
-                   msg->sm_b = msg->sm_b->be_next) {
-                       switch (msg->sm_state++) {
-                       case 0:
-                               if (ober_get_oid(msg->sm_b, &o) != 0)
-                                       goto varfail;
-                               if (o.bo_n < BER_MIN_OID_LEN ||
-                                   o.bo_n > BER_MAX_OID_LEN)
-                                       goto varfail;
-                               if (msg->sm_context == SNMP_C_SETREQ)
-                                       stats->snmp_intotalsetvars++;
-                               else
-                                       stats->snmp_intotalreqvars++;
-                               log_debug("%s: %s: oid %s",
-                                   __func__, msg->sm_host,
-                                   smi_oid2string(&o, buf, sizeof(buf), 0));
-                               break;
-                       case 1:
-                               msg->sm_c = NULL;
-                               msg->sm_end = NULL;
-
-                               switch (msg->sm_context) {
-
-                               case SNMP_C_GETNEXTREQ:
-                                       msg->sm_c = ober_add_sequence(NULL);
-                                       ret = mps_getnextreq(msg, msg->sm_c,
-                                           &o);
-                                       if (ret == 0 || ret == 1)
-                                               break;
-                                       ober_free_elements(msg->sm_c);
-                                       msg->sm_error = SNMP_ERROR_NOSUCHNAME;
-                                       goto varfail;
-
-                               case SNMP_C_GETREQ:
-                                       msg->sm_c = ober_add_sequence(NULL);
-                                       ret = mps_getreq(msg, msg->sm_c, &o,
-                                           msg->sm_version);
-                                       if (ret == 0 || ret == 1)
-                                               break;
-                                       msg->sm_error = SNMP_ERROR_NOSUCHNAME;
-                                       ober_free_elements(msg->sm_c);
-                                       goto varfail;
-
-                               case SNMP_C_SETREQ:
-                                       if (snmpd_env->sc_readonly == 0) {
-                                               ret = mps_setreq(msg,
-                                                   msg->sm_b, &o);
-                                               if (ret == 0)
-                                                       break;
-                                       }
-                                       msg->sm_error = SNMP_ERROR_READONLY;
-                                       goto varfail;
-
-                               case SNMP_C_GETBULKREQ:
-                                       ret = mps_getbulkreq(msg, &msg->sm_c,
-                                           &msg->sm_end, &o,
-                                           (msg->sm_i <= msg->sm_nonrepeaters)
-                                           ? 1 : msg->sm_maxrepetitions);
-                                       if (ret == 0 || ret == 1)
-                                               break;
-                                       msg->sm_error = SNMP_ERROR_NOSUCHNAME;
-                                       goto varfail;
+       varbind = msg->sm_varbind;
+       msg->sm_varbindresp = NULL;
+       end = NULL;
+
+       for (i = 1; varbind != NULL && i < SNMPD_MAXVARBIND;
+           varbind = varbind->be_next, i++) {
+               if (ober_scanf_elements(varbind, "{oe}", &o, &value) == -1) {
+                       stats->snmp_inasnparseerrs++;
+                       msg->sm_errstr = "invalid varbind";
+                       goto varfail;
+               }
+               if (o.bo_n < BER_MIN_OID_LEN || o.bo_n > BER_MAX_OID_LEN)
+                       goto varfail;
 
-                               default:
-                                       goto varfail;
-                               }
-                               if (msg->sm_c == NULL)
+               log_debug("%s: %s: oid %s", __func__, msg->sm_host,
+                   smi_oid2string(&o, buf, sizeof(buf), 0));
+
+               /*
+                * XXX intotalreqvars should only be incremented after all are
+                * succeeded
+                */
+               switch (msg->sm_context) {
+               case SNMP_C_GETNEXTREQ:
+                       if ((rvarbind = ober_add_sequence(NULL)) == NULL)
+                               goto varfail;
+                       if (mps_getnextreq(msg, rvarbind, &o) == 0) {
+                               stats->snmp_intotalreqvars++;
+                               break;
+                       }
+                       msg->sm_error = SNMP_ERROR_NOSUCHNAME;
+                       ober_free_elements(rvarbind);
+                       goto varfail;
+               case SNMP_C_GETREQ:
+                       if ((rvarbind = ober_add_sequence(NULL)) == NULL)
+                               goto varfail;
+                       if (mps_getreq(msg, rvarbind, &o,
+                           msg->sm_version) == 0) {
+                               stats->snmp_intotalreqvars++;
+                               break;
+                       }
+                       msg->sm_error = SNMP_ERROR_NOSUCHNAME;
+                       ober_free_elements(rvarbind);
+                       goto varfail;
+               case SNMP_C_SETREQ:
+                       if (snmpd_env->sc_readonly == 0) {
+                               /*
+                                * XXX A set varbind should only be committed if
+                                * all variables are staged
+                                */
+                               if (mps_setreq(msg, value, &o) == 0) {
+                                       /* XXX Adjust after fixing staging */
+                                       stats->snmp_intotalsetvars++;
                                        break;
-                               if (msg->sm_end == NULL)
-                                       msg->sm_end = msg->sm_c;
-                               if (msg->sm_last == NULL)
-                                       msg->sm_varbindresp = msg->sm_c;
-                               else
-                                       ober_link_elements(msg->sm_last, 
msg->sm_c);
-                               msg->sm_last = msg->sm_end;
+                               }
+                       }
+                       msg->sm_error = SNMP_ERROR_READONLY;
+                       goto varfail;
+               case SNMP_C_GETBULKREQ:
+                       if ((rvarbind = ober_add_sequence(NULL)) == NULL)
+                               goto varfail;
+                       if (mps_getbulkreq(msg, &rvarbind, &end, &o,
+                           (i <= msg->sm_nonrepeaters)
+                           ? 1 : msg->sm_maxrepetitions) == 0) {
+                               /*
+                                * XXX This should be the amount of returned
+                                * vars
+                                */
+                               stats->snmp_intotalreqvars++;
                                break;
                        }
-               }
-               if (msg->sm_state < 2)  {
-                       log_debug("%s: state %d", __func__, msg->sm_state);
+                       msg->sm_error = SNMP_ERROR_NOSUCHNAME;
+                       goto varfail;
+
+               default:
                        goto varfail;
                }
+               if (rvarbind == NULL)
+                       break;
+               if (pvarbind == NULL)
+                       msg->sm_varbindresp = rvarbind;
+               else
+                       ober_link_elements(pvarbind, rvarbind);
+               pvarbind = end == NULL ? rvarbind : end;
+               break;
        }
 
        msg->sm_errstr = "none";
        msg->sm_error = 0;
        msg->sm_errorindex = 0;
 
-       return (ret);
+       return 0;
  varfail:
        log_debug("%s: %s: %s, error index %d", __func__,
-           msg->sm_host, msg->sm_errstr, msg->sm_i);
+           msg->sm_host, msg->sm_errstr, i);
        if (msg->sm_error == 0)
                msg->sm_error = SNMP_ERROR_GENERR;
-       msg->sm_errorindex = msg->sm_i;
-       return (-1);
+       msg->sm_errorindex = i;
+       return -1;
 }
 
 void
@@ -749,8 +737,8 @@ void
 snmpe_dispatchmsg(struct snmp_message *msg)
 {
        /* dispatched to subagent */
-       if (snmpe_parsevarbinds(msg) == 1)
-               return;
+       /* XXX Do proper error handling */
+       (void) snmpe_parsevarbinds(msg);
 
        /* respond directly */
        msg->sm_context = SNMP_C_GETRESP;

Reply via email to