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; }
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; }