Exemplo n.º 1
0
int
handle_snmp_packet(int operation, struct snmp_session *session, int reqid,
                   struct snmp_pdu *pdu, void *magic)
{
    struct agent_snmp_session  *asp;
    int status, allDone, i;
    struct variable_list *var_ptr, *var_ptr2;

    if ( magic == NULL ) {
	asp = init_agent_snmp_session( session, snmp_clone_pdu(pdu) );
	status = SNMP_ERR_NOERROR;
    }
    else {
	asp = (struct agent_snmp_session *)magic;
        status =   asp->status;
    }

    if (asp->outstanding_requests != NULL)
	return 1;

    if ( check_access(pdu) != 0) {
        /* access control setup is incorrect */
	send_easy_trap(SNMP_TRAP_AUTHFAIL, 0);
        if (asp->pdu->version != SNMP_VERSION_1 && asp->pdu->version != SNMP_VERSION_2c) {
            asp->pdu->errstat = SNMP_ERR_AUTHORIZATIONERROR;
            asp->pdu->command = SNMP_MSG_RESPONSE;
            snmp_increment_statistic(STAT_SNMPOUTPKTS);
            snmp_send( asp->session, asp->pdu );
            free( asp );
            return 1;
        } else {
            /* drop the request */
            free( asp );
            return 0;
        }
    }

    switch (pdu->command) {
    case SNMP_MSG_GET:
	if ( asp->mode != RESERVE1 )
	    break;			/* Single pass */
        snmp_increment_statistic(STAT_SNMPINGETREQUESTS);
	status = handle_next_pass( asp );
	asp->mode = RESERVE2;
	break;

    case SNMP_MSG_GETNEXT:
	if ( asp->mode != RESERVE1 )
	    break;			/* Single pass */
        snmp_increment_statistic(STAT_SNMPINGETNEXTS);
	asp->exact   = FALSE;
	status = handle_next_pass( asp );
	asp->mode = RESERVE2;
	break;

    case SNMP_MSG_GETBULK:
	    /*
	     * GETBULKS require multiple passes. The first pass handles the
	     * explicitly requested varbinds, and subsequent passes append
	     * to the existing var_op_list.  Each pass (after the first)
	     * uses the results of the preceeding pass as the input list
	     * (delimited by the start & end pointers.
	     * Processing is terminated if all entries in a pass are
	     * EndOfMib, or the maximum number of repetitions are made.
	     */
	if ( asp->mode == RESERVE1 ) {
            snmp_increment_statistic(STAT_SNMPINGETREQUESTS);
	    asp->exact   = FALSE;
		    /*
		     * Limit max repetitions to something reasonable
		     *	XXX: We should figure out what will fit somehow...
		     */
	    if ( asp->pdu->errindex > 100 )
	        asp->pdu->errindex = 100;
    
	    status = handle_next_pass( asp );	/* First pass */
	    asp->mode = RESERVE2;
	    if ( status != SNMP_ERR_NOERROR )
	        break;
    
	    while ( asp->pdu->errstat-- > 0 )	/* Skip non-repeaters */
	        asp->start = asp->start->next_variable;
	    asp->pdu->errindex--;           /* Handled first repetition */

	    if ( asp->outstanding_requests != NULL )
		return 1;
	}

	while ( asp->pdu->errindex-- > 0 ) {	/* Process repeaters */
		/*
		 * Add new variable structures for the
		 * repeating elements, ready for the next pass.
		 * Also check that these are not all EndOfMib
		 */
	    allDone = TRUE;		/* Check for some content */
	    for ( var_ptr = asp->start;
		  var_ptr != asp->end->next_variable;
		  var_ptr = var_ptr->next_variable ) {
				/* XXX: we don't know the size of the next
					OID, so assume the maximum length */
		if ( var_ptr->type != SNMP_ENDOFMIBVIEW )
		{
		var_ptr2 = snmp_add_null_var(asp->pdu, var_ptr->name, MAX_OID_LEN);
		for ( i=var_ptr->name_length ; i<MAX_OID_LEN ; i++)
		    var_ptr2->name[i] = 0;
		var_ptr2->name_length = var_ptr->name_length;

		    allDone = FALSE;
		}
	    }
	    if ( allDone )
		break;

	    asp->start = asp->end->next_variable;
	    while ( asp->end->next_variable != NULL )
		asp->end = asp->end->next_variable;
	    
	    status = handle_next_pass( asp );
	    if ( status != SNMP_ERR_NOERROR )
		break;
	    if ( asp->outstanding_requests != NULL )
		return 1;
	}
	break;

    case SNMP_MSG_SET:
    	    /*
	     * SETS require 3-4 passes through the var_op_list.  The first two
	     * passes verify that all types, lengths, and values are valid
	     * and may reserve resources and the third does the set and a
	     * fourth executes any actions.  Then the identical GET RESPONSE
	     * packet is returned.
	     * If either of the first two passes returns an error, another
	     * pass is made so that any reserved resources can be freed.
	     * If the third pass returns an error, another pass is made so that
	     * any changes can be reversed.
	     * If the fourth pass (or any of the error handling passes)
	     * return an error, we'd rather not know about it!
	     */
	if ( asp->mode == RESERVE1 ) {
            snmp_increment_statistic(STAT_SNMPINSETREQUESTS);
	    asp->rw      = WRITE;

	    status = handle_next_pass( asp );

	    if ( status != SNMP_ERR_NOERROR )
	        asp->mode = FREE;
	    else
	        asp->mode = RESERVE2;

	    if ( asp->outstanding_requests != NULL )
		return 1;
	}

	if ( asp->mode == RESERVE2 ) {
	    status = handle_next_pass( asp );

	    if ( status != SNMP_ERR_NOERROR )
	        asp->mode = FREE;
	    else
	        asp->mode = ACTION;

	    if ( asp->outstanding_requests != NULL )
		return 1;
	}

	if ( asp->mode == ACTION ) {
	    status = handle_next_pass( asp );

	    if ( status != SNMP_ERR_NOERROR )
	        asp->mode = UNDO;
	    else
	        asp->mode = COMMIT;

	    if ( asp->outstanding_requests != NULL )
		return 1;
	}

	if ( asp->mode == COMMIT ) {
	    status = handle_next_pass( asp );

	    if ( status != SNMP_ERR_NOERROR ) {
		status    = SNMP_ERR_COMMITFAILED;
	        asp->mode = FINISHED_FAILURE;
	    }
	    else
	        asp->mode = FINISHED_SUCCESS;

	    if ( asp->outstanding_requests != NULL )
		return 1;
	}

	if ( asp->mode == UNDO ) {
	    if (handle_next_pass( asp ) != SNMP_ERR_NOERROR )
		status = SNMP_ERR_UNDOFAILED;

	    asp->mode = FINISHED_FAILURE;
	    break;
	}

	if ( asp->mode == FREE ) {
	    (void) handle_next_pass( asp );
	    break;
	}

	break;

    case SNMP_MSG_RESPONSE:
        snmp_increment_statistic(STAT_SNMPINGETRESPONSES);
	free( asp );
	return 0;
    case SNMP_MSG_TRAP:
    case SNMP_MSG_TRAP2:
        snmp_increment_statistic(STAT_SNMPINTRAPS);
	free( asp );
	return 0;
    default:
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
	free( asp );
	return 0;
    }

    if ( asp->outstanding_requests != NULL ) {
	asp->status = status;
	asp->next = agent_session_list;
	agent_session_list = asp;
    }
    else {
		/*
		 * May need to "dumb down" a SET error status for a
		 *  v1 query.  See RFC2576 - section 4.3
		 */
	if (( asp->pdu->command == SNMP_MSG_SET ) &&
	    ( asp->pdu->version == SNMP_VERSION_1 )) {
	    switch ( status ) {
		case SNMP_ERR_WRONGVALUE:
		case SNMP_ERR_WRONGENCODING:
		case SNMP_ERR_WRONGTYPE:
		case SNMP_ERR_WRONGLENGTH:
		case SNMP_ERR_INCONSISTENTVALUE:
			status = SNMP_ERR_BADVALUE;
			break;
		case SNMP_ERR_NOACCESS:
		case SNMP_ERR_NOTWRITABLE:
		case SNMP_ERR_NOCREATION:
		case SNMP_ERR_INCONSISTENTNAME:
		case SNMP_ERR_AUTHORIZATIONERROR:
			status = SNMP_ERR_NOSUCHNAME;
			break;
		case SNMP_ERR_RESOURCEUNAVAILABLE:
		case SNMP_ERR_COMMITFAILED:
		case SNMP_ERR_UNDOFAILED:
			status = SNMP_ERR_GENERR;
			break;
	    }
	}
		/*
		 * Similarly we may need to "dumb down" v2 exception
		 *  types to throw an error for a v1 query.
		 *  See RFC2576 - section 4.1.2.3
		 */
	if (( asp->pdu->command != SNMP_MSG_SET ) &&
	    ( asp->pdu->version == SNMP_VERSION_1 )) {
		for ( var_ptr = asp->pdu->variables, i=0 ;
			var_ptr != NULL ;
			var_ptr = var_ptr->next_variable, i++ ) {
		    switch ( var_ptr->type ) {
			case SNMP_NOSUCHOBJECT:
			case SNMP_NOSUCHINSTANCE:
			case SNMP_ENDOFMIBVIEW:
			case ASN_COUNTER64:
				status = SNMP_ERR_NOSUCHNAME;
				asp->pdu->errindex=i;
				break;
		    }
		}
	}
	if ( status == SNMP_ERR_NOERROR ) {
	    snmp_increment_statistic_by(
		(asp->pdu->command == SNMP_MSG_SET ?
			STAT_SNMPINTOTALSETVARS : STAT_SNMPINTOTALREQVARS ),
	    	count_varbinds( asp->pdu ));
	}
	else {
		/*
		 * Use a copy of the original request
		 *   to report failures.
		 */
	    i = asp->pdu->errindex;
	    snmp_free_pdu( asp->pdu );
	    asp->pdu = snmp_clone_pdu( pdu );
	    asp->pdu->errindex = i;
	}
	asp->pdu->command = SNMP_MSG_RESPONSE;
	asp->pdu->errstat = status;
	snmp_send( asp->session, asp->pdu );
	snmp_increment_statistic(STAT_SNMPOUTPKTS);
	snmp_increment_statistic(STAT_SNMPOUTGETRESPONSES);
	free( asp );
    }

    return 1;
}
Exemplo n.º 2
0
int
handle_master_agentx_packet(int operation,
                            netsnmp_session * session,
                            int reqid, netsnmp_pdu *pdu, void *magic)
{
    netsnmp_agent_session *asp;

    if (operation == NETSNMP_CALLBACK_OP_DISCONNECT) {
        DEBUGMSGTL(("agentx/master",
                    "transport disconnect on session %8p\n", session));
        /*
         * Shut this session down gracefully.  
         */
        close_agentx_session(session, -1);
        return 1;
    } else if (operation == NETSNMP_CALLBACK_OP_CONNECT) {
        DEBUGMSGTL(("agentx/master",
                    "transport connect on session %8p\n", session));
        return 1;
    } else if (operation != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
        DEBUGMSGTL(("agentx/master", "unexpected callback op %d\n",
                    operation));
        return 1;
    }

    /*
     * Okay, it's a NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE op.  
     */

    if (magic) {
        asp = (netsnmp_agent_session *) magic;
    } else {
        asp = init_agent_snmp_session(session, pdu);
    }

    DEBUGMSGTL(("agentx/master", "handle pdu (req=0x%lx,trans=0x%lx,sess=0x%lx)\n",
                (unsigned long)pdu->reqid, (unsigned long)pdu->transid,
		(unsigned long)pdu->sessid));
    
    switch (pdu->command) {
    case AGENTX_MSG_OPEN:
        asp->pdu->sessid = open_agentx_session(session, pdu);
        if (asp->pdu->sessid == -1)
            asp->status = session->s_snmp_errno;
        break;

    case AGENTX_MSG_CLOSE:
        asp->status = close_agentx_session(session, pdu->sessid);
        break;

    case AGENTX_MSG_REGISTER:
        asp->status = register_agentx_list(session, pdu);
        break;

    case AGENTX_MSG_UNREGISTER:
        asp->status = unregister_agentx_list(session, pdu);
        break;

    case AGENTX_MSG_INDEX_ALLOCATE:
        asp->status = allocate_idx_list(session, asp->pdu);
        if (asp->status != AGENTX_ERR_NOERROR) {
            snmp_free_pdu(asp->pdu);
            asp->pdu = snmp_clone_pdu(pdu);
        }
        break;

    case AGENTX_MSG_INDEX_DEALLOCATE:
        asp->status = release_idx_list(session, pdu);
        break;

    case AGENTX_MSG_ADD_AGENT_CAPS:
        asp->status = add_agent_caps_list(session, pdu);
        break;

    case AGENTX_MSG_REMOVE_AGENT_CAPS:
        asp->status = remove_agent_caps_list(session, pdu);
        break;

    case AGENTX_MSG_NOTIFY:
        asp->status = agentx_notify(session, pdu);
        break;

    case AGENTX_MSG_PING:
        asp->status = agentx_ping_response(session, pdu);
        break;

        /*
         * TODO: Other admin packets 
         */

    case AGENTX_MSG_GET:
    case AGENTX_MSG_GETNEXT:
    case AGENTX_MSG_GETBULK:
    case AGENTX_MSG_TESTSET:
    case AGENTX_MSG_COMMITSET:
    case AGENTX_MSG_UNDOSET:
    case AGENTX_MSG_CLEANUPSET:
    case AGENTX_MSG_RESPONSE:
        /*
         * Shouldn't be handled here 
         */
        break;

    default:
        asp->status = AGENTX_ERR_PARSE_FAILED;
        break;
    }

    asp->pdu->time = netsnmp_get_agent_uptime();
    asp->pdu->command = AGENTX_MSG_RESPONSE;
    asp->pdu->errstat = asp->status;
    DEBUGMSGTL(("agentx/master", "send response, stat %d (req=0x%lx,trans="
                "0x%lx,sess=0x%lx)\n",
                asp->status, (unsigned long)pdu->reqid,
		(unsigned long)pdu->transid, (unsigned long)pdu->sessid));
    if (!snmp_send(asp->session, asp->pdu)) {
        char           *eb = NULL;
        int             pe, pse;
        snmp_error(asp->session, &pe, &pse, &eb);
        snmp_free_pdu(asp->pdu);
        DEBUGMSGTL(("agentx/master", "FAILED %d %d %s\n", pe, pse, eb));
        free(eb);
    }
    asp->pdu = NULL;
    free_agent_snmp_session(asp);

    return 1;
}