int handle_var_list(struct agent_snmp_session *asp) { struct variable_list *varbind_ptr; u_char statType; u_char *statP; size_t statLen; u_short acl; WriteMethod *write_method; AddVarMethod *add_method; int noSuchObject = TRUE; int count, view; count = 0; varbind_ptr = asp->start; if ( !varbind_ptr ) { return SNMP_ERR_NOERROR; } while (1) { count++; statp_loop: statP = getStatPtr( varbind_ptr->name, &varbind_ptr->name_length, &statType, &statLen, &acl, asp->exact, &write_method, asp->pdu, &noSuchObject); if (statP == NULL && (asp->rw != WRITE || write_method == NULL)) { /* Careful -- if the varbind was lengthy, it will have allocated some memory. */ snmp_set_var_value(varbind_ptr, NULL, 0); varbind_ptr->val.integer = NULL; varbind_ptr->val_len = 0; if ( asp->exact ) { if ( noSuchObject == TRUE ){ statType = SNMP_NOSUCHOBJECT; } else { statType = SNMP_NOSUCHINSTANCE; } } else { statType = SNMP_ENDOFMIBVIEW; } if (asp->pdu->version == SNMP_VERSION_1) { asp->pdu->errstat = SNMP_ERR_NOSUCHNAME; asp->pdu->errindex = count; return SNMP_ERR_NOSUCHNAME; } else if (asp->rw == WRITE) { asp->pdu->errstat = ( noSuchObject ? SNMP_ERR_NOTWRITABLE : SNMP_ERR_NOCREATION ); asp->pdu->errindex = count; return asp->pdu->errstat; } else varbind_ptr->type = statType; } /* Delegated variables should be added to the relevant outgoing request */ else if ( IS_DELEGATED(statType)) { add_method = (AddVarMethod*)statP; statType = (*add_method)( asp, varbind_ptr ); } /* GETNEXT/GETBULK should just skip inaccessible entries */ else if ((view = in_a_view(varbind_ptr->name, &varbind_ptr->name_length, asp->pdu, varbind_ptr->type)) && !asp->exact) { if (view != 5) send_easy_trap(SNMP_TRAP_AUTHFAIL, 0); goto statp_loop; } /* Other access problems are permanent */ else if (( asp->rw == WRITE && !(acl & 2)) || view) { if (asp->pdu->version == SNMP_VERSION_1 || asp->rw != WRITE) { if (ds_get_boolean(DS_APPLICATION_ID, DS_AGENT_VERBOSE)) DEBUGMSGTL(("snmp_agent", " >> noSuchName (read-only)\n")); ERROR_MSG("read-only"); statType = SNMP_ERR_NOSUCHNAME; } else { if (ds_get_boolean(DS_APPLICATION_ID, DS_AGENT_VERBOSE)) DEBUGMSGTL(("snmp_agent", " >> notWritable\n")); ERROR_MSG("Not Writable"); statType = SNMP_ERR_NOTWRITABLE; } asp->pdu->errstat = statType; asp->pdu->errindex = count; send_easy_trap(SNMP_TRAP_AUTHFAIL, 0); return statType; } else { /* dump verbose info */ if (ds_get_boolean(DS_APPLICATION_ID, DS_AGENT_VERBOSE) && statP) dump_var(varbind_ptr->name, varbind_ptr->name_length, statType, statP, statLen); /* FINALLY we can act on SET requests ....*/ if ( asp->rw == WRITE ) { if ( write_method != NULL ) { statType = (*write_method)(asp->mode, varbind_ptr->val.string, varbind_ptr->type, varbind_ptr->val_len, statP, varbind_ptr->name, varbind_ptr->name_length); if (statType != SNMP_ERR_NOERROR) { asp->pdu->errstat = statType; asp->pdu->errindex = count; return statType; } } else { if (!goodValue(varbind_ptr->type, varbind_ptr->val_len, statType, statLen)){ if (asp->pdu->version == SNMP_VERSION_1) statType = SNMP_ERR_BADVALUE; else statType = SNMP_ERR_WRONGTYPE; /* poor approximation */ asp->pdu->errstat = statType; asp->pdu->errindex = count; return statType; } /* actually do the set if necessary */ if (asp->mode == COMMIT) setVariable(varbind_ptr->val.string, varbind_ptr->type, varbind_ptr->val_len, statP, statLen); } } /* ... or save the results from assorted GETs */ else { snmp_set_var_value(varbind_ptr, statP, statLen); varbind_ptr->type = statType; } } if ( varbind_ptr == asp->end ) return SNMP_ERR_NOERROR; varbind_ptr = varbind_ptr->next_variable; if ( asp->mode == RESERVE1 ) snmp_vars_inc++; } }
//* //* Parse_var_op_list goes through the list of variables and retrieves each one, //* placing it's value in the output packet. In the case of a set request, //* if action is RESERVE, the value is just checked for correct type and //* value, and resources may need to be reserved. If the action is COMMIT, //* the variable is set. If the action is FREE, an error was discovered //* somewhere in the previous RESERVE pass, so any reserved resources //* should be FREE'd. //* If any error occurs, an error code is returned. //* int parse_var_op_list( snmp_session *session, uint8 *data, //point to variable-binding of in-packet data int length, //in packet data length uint8 *out_data, //point to variable-binding of out-packet data int out_length, //out packet buffer length long *index, //error-index (output) int msgtype, //message type int action //??? ) { uint8 type; oid var_name[SNMP_MAX_NAME_LEN]; int var_name_len, var_val_len; uint8 var_val_type, *var_val, statType; uint8 *statP; int statLen; uint16 acl; int (*write_method)(); uint8 *headerP, *var_list_start; int dummyLen; #ifdef WEBADMIN int dummyLen1; // add -- By arius 5/17/2000 uint8 *newpacket_end; // add -- By arius 5/17/2000 #endif WEBADMIN int noSuchObject; int (*WriteMethod)(int,uint8 *,uint8,int,uint8 *,oid *,int); int err, exact; // if (msgtype== SET_REQ_MSG) rw = SNMP_WRITE; // else rw = SNMP_READ; if (msgtype == GETNEXT_REQ_MSG) exact = FALSE; else exact = TRUE; //Parse variable-binging header data = asn_parse_header(data, &length, &type); if (data == NULL){ ERROR("not enough space for varlist"); return PARSE_ERROR; } if (type != (uint8)(ASN_SEQUENCE | ASN_CONSTRUCTOR)){ ERROR("wrong type"); return PARSE_ERROR; } headerP = out_data; //Set Resp variable-binging header out_data = asn_build_sequence(out_data, &out_length, (uint8)(ASN_SEQUENCE | ASN_CONSTRUCTOR), 0); if (out_data == NULL){ ERROR("not enough space in output packet"); return BUILD_ERROR; } var_list_start = out_data; *index = 1; while((int)length > 0){ // parse the name, value pair var_name_len = SNMP_MAX_NAME_LEN; data = snmp_parse_var_op(data, var_name, &var_name_len, &var_val_type, &var_val_len, &var_val, (int *)&length); if (data == NULL) return PARSE_ERROR; // now attempt to retrieve the variable on the local entity statP = getStatPtr(var_name, &var_name_len, &statType, &statLen, &acl, exact, &write_method, SNMP_VERSION_1, &noSuchObject, (msgtype==SET_REQ_MSG? (session->access & SNMP_ACCESS_WRITE): (session->access & SNMP_ACCESS_READ) ) ); if (/* session->version == SNMP_VERSION_1 &&*/ statP == NULL && (msgtype != SET_REQ_MSG || !write_method)) { //** XXX: happens when running // XXX: snmpwalk localhost public .1 // XXX: fix me some day. //** //** ERROR("warning: internal v1_error"); ** return SNMP_ERR_NOSUCHNAME; } // check if this variable is read-write (in the MIB sense). if( msgtype == SET_REQ_MSG && acl != RWRITE ) return SNMP_ERR_READONLY; // return session->version == SNMP_VERSION_1 ? SNMP_ERR_NOSUCHNAME : SNMP_ERR_NOTWRITABLE; //* Its bogus to check here on getnexts - the whole packet shouldn't // be dumped - this should should be the loop in getStatPtr // luckily no objects are set unreadable. This can still be // useful for sets to determine which are intrinsically writable if (msgtype== SET_REQ_MSG){ if (write_method == NULL){ if (statP != NULL){ // see if the type and value is consistent with this entity's variable if (!goodValue(var_val_type, var_val_len, statType,statLen)) { // if (session->version != SNMP_VERSION_1) // return SNMP_ERR_WRONGTYPE; // poor approximation // else { snmp_inbadvalues++; return SNMP_ERR_BADVALUE; } } // actually do the set if necessary if (action == COMMIT) setVariable(var_val, var_val_type, var_val_len,statP, statLen); } else { // if (session->version != SNMP_VERSION_1) // return SNMP_ERR_NOCREATION; // else return SNMP_ERR_NOSUCHNAME; } } else { WriteMethod = (int (*)(int,uint8 *,uint8,int,uint8 *,oid *,int)) write_method; err = (*WriteMethod)(action, var_val, var_val_type, var_val_len, statP, var_name, var_name_len); //* //* Map the SNMPv2 error codes to SNMPv1 error codes (RFC 2089). //* // if (session->version == SNMP_VERSION_1) { switch (err) { case SNMP_ERR_NOERROR: // keep the no-error error: break; case SNMP_ERR_WRONGVALUE: case SNMP_ERR_WRONGENCODING: case SNMP_ERR_WRONGTYPE: case SNMP_ERR_WRONGLENGTH: case SNMP_ERR_INCONSISTENTVALUE: err = SNMP_ERR_BADVALUE; break; case SNMP_ERR_NOACCESS: case SNMP_ERR_NOTWRITABLE: case SNMP_ERR_NOCREATION: case SNMP_ERR_INCONSISTENTNAME: case SNMP_ERR_AUTHORIZATIONERROR: err = SNMP_ERR_NOSUCHNAME; break; default: err = SNMP_ERR_GENERR; break; // } }//if(session->version == SNMP_VERSION_1) .... if (err != SNMP_ERR_NOERROR){ // if (session->version == SNMP_VERSION_1) { snmp_inbadvalues++; // } return err; } } } else { //* retrieve the value of the variable and place it into the //* outgoing packet if (statP == NULL){ statLen = 0; if (exact){ if (noSuchObject == TRUE){ statType = SNMP_NOSUCHOBJECT; } else { statType = SNMP_NOSUCHINSTANCE; } } else { statType = SNMP_ENDOFMIBVIEW; } } //if (statP == NULL) ... out_data = snmp_build_var_op(out_data, var_name, &var_name_len, statType, statLen, statP, &out_length); if (out_data == NULL){ return SNMP_ERR_TOOBIG; } } //if (msgtype== SET_REQ_MSG) ... (*index)++; } //while((int)length > 0) .... if(msgtype!= SET_REQ_MSG){ // save a pointer to the end of the packet packet_end = out_data; // Now rebuild header with the actual lengths dummyLen = packet_end - var_list_start; // modified by ---- Arius 5/17/2000 #ifdef WEBADMIN dummyLen1 = packet_end - headerP; newpacket_end = asn_build_sequence(headerP, &dummyLen1, (uint8)(ASN_SEQUENCE | ASN_CONSTRUCTOR), dummyLen); var_list_start -= (packet_end - newpacket_end); out_length += (packet_end - newpacket_end); // save new pointer to the end of the packet when the sapces will be adjust packet_end = newpacket_end; if (headerP == NULL) #else if (asn_build_sequence(headerP, &dummyLen, (uint8)(ASN_SEQUENCE | ASN_CONSTRUCTOR), dummyLen) == NULL) #endif WEBADMIN // end of here { return SNMP_ERR_TOOBIG; // bogus error ???? } } *index = 0; return SNMP_ERR_NOERROR; }