Ejemplo n.º 1
0
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;
}