int proxy_got_response(int operation, netsnmp_session * sess, int reqid, netsnmp_pdu *pdu, void *cb_data) { netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *) cb_data; netsnmp_request_info *requests, *request = NULL; netsnmp_variable_list *vars, *var = NULL; struct simple_proxy *sp; oid myname[MAX_OID_LEN]; size_t myname_len = MAX_OID_LEN; cache = netsnmp_handler_check_cache(cache); if (!cache) { DEBUGMSGTL(("proxy", "a proxy request was no longer valid.\n")); return SNMP_ERR_NOERROR; } requests = cache->requests; sp = (struct simple_proxy *) cache->localinfo; if (!sp) { DEBUGMSGTL(("proxy", "a proxy request was no longer valid.\n")); return SNMP_ERR_NOERROR; } switch (operation) { case NETSNMP_CALLBACK_OP_TIMED_OUT: /* * WWWXXX: don't leave requests delayed if operation is * something like TIMEOUT */ DEBUGMSGTL(("proxy", "got timed out... requests = %08p\n", requests)); netsnmp_handler_mark_requests_as_delegated(requests, REQUEST_IS_NOT_DELEGATED); if(cache->reqinfo->mode != MODE_GETNEXT) { DEBUGMSGTL(("proxy", " ignoring timeout\n")); netsnmp_set_request_error(cache->reqinfo, requests, /* XXXWWW: should be index = 0 */ SNMP_ERR_GENERR); } netsnmp_free_delegated_cache(cache); return 0; case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE: vars = pdu->variables; if (pdu->errstat != SNMP_ERR_NOERROR) { /* * If we receive an error from the proxy agent, pass it on up. * The higher-level processing seems to Do The Right Thing. * * 2005/06 rks: actually, it doesn't do the right thing for * a get-next request that returns NOSUCHNAME. If we do nothing, * it passes that error back to the comman initiator. What it should * do is ignore the error and move on to the next tree. To * accomplish that, all we need to do is clear the delegated flag. * Not sure if any other error codes need the same treatment. Left * as an exercise to the reader... */ DEBUGMSGTL(("proxy", "got error response (%d)\n", pdu->errstat)); if((cache->reqinfo->mode == MODE_GETNEXT) && (SNMP_ERR_NOSUCHNAME == pdu->errstat)) { DEBUGMSGTL(("proxy", " ignoring error response\n")); netsnmp_handler_mark_requests_as_delegated(requests, REQUEST_IS_NOT_DELEGATED); } else netsnmp_set_request_error(cache->reqinfo, requests, pdu->errstat); /* * update the original request varbinds with the results */ } else for (var = vars, request = requests; request && var; request = request->next, var = var->next_variable) { /* * XXX - should this be done here? * Or wait until we know it's OK? */ snmp_set_var_typed_value(request->requestvb, var->type, var->val.string, var->val_len); DEBUGMSGTL(("proxy", "got response... ")); DEBUGMSGOID(("proxy", var->name, var->name_length)); DEBUGMSG(("proxy", "\n")); request->delegated = 0; /* * Check the response oid is legitimate, * and discard the value if not. * * XXX - what's the difference between these cases? */ if (sp->base_len && (var->name_length < sp->base_len || snmp_oid_compare(var->name, sp->base_len, sp->base, sp->base_len) != 0)) { DEBUGMSGTL(( "proxy", "out of registered range... ")); DEBUGMSGOID(("proxy", var->name, sp->base_len)); DEBUGMSG(( "proxy", " (%d) != ", sp->base_len)); DEBUGMSGOID(("proxy", sp->base, sp->base_len)); DEBUGMSG(( "proxy", "\n")); snmp_set_var_typed_value(request->requestvb, ASN_NULL, NULL, 0); continue; } else if (!sp->base_len && (var->name_length < sp->name_len || snmp_oid_compare(var->name, sp->name_len, sp->name, sp->name_len) != 0)) { DEBUGMSGTL(( "proxy", "out of registered base range... ")); DEBUGMSGOID(("proxy", var->name, sp->name_len)); DEBUGMSG(( "proxy", " (%d) != ", sp->name_len)); DEBUGMSGOID(("proxy", sp->name, sp->name_len)); DEBUGMSG(( "proxy", "\n")); snmp_set_var_typed_value(request->requestvb, ASN_NULL, NULL, 0); continue; } else { /* * If the returned OID is legitimate, then update * the original request varbind accordingly. */ if (sp->base_len) { /* * XXX: oid size maxed? */ memcpy(myname, sp->name, sizeof(oid) * sp->name_len); myname_len = sp->name_len + var->name_length - sp->base_len; if (myname_len > MAX_OID_LEN) { snmp_log(LOG_WARNING, "proxy OID return length too long.\n"); netsnmp_set_request_error(cache->reqinfo, requests, SNMP_ERR_GENERR); if (pdu) snmp_free_pdu(pdu); netsnmp_free_delegated_cache(cache); return 1; } if (var->name_length > sp->base_len) memcpy(&myname[sp->name_len], &var->name[sp->base_len], sizeof(oid) * (var->name_length - sp->base_len)); snmp_set_var_objid(request->requestvb, myname, myname_len); } else { snmp_set_var_objid(request->requestvb, var->name, var->name_length); } } } if (request || var) { /* * ack, this is bad. The # of varbinds don't match and * there is no way to fix the problem */ if (pdu) snmp_free_pdu(pdu); snmp_log(LOG_ERR, "response to proxy request illegal. We're screwed.\n"); netsnmp_set_request_error(cache->reqinfo, requests, SNMP_ERR_GENERR); } /* fix bulk_to_next operations */ if (cache->reqinfo->mode == MODE_GETBULK) netsnmp_bulk_to_next_fix_requests(requests); /* * free the response */ if (pdu && 0) snmp_free_pdu(pdu); break; default: DEBUGMSGTL(("proxy", "no response received: op = %d\n", operation)); break; } netsnmp_free_delegated_cache(cache); return 1; }
/* * Handle the response from an AgentX subagent, * merging the answers back into the original query */ int agentx_got_response(int operation, netsnmp_session * session, int reqid, netsnmp_pdu *pdu, void *magic) { netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *) magic; int i, ret; netsnmp_request_info *requests, *request; netsnmp_variable_list *var; netsnmp_session *ax_session; cache = netsnmp_handler_check_cache(cache); if (!cache) { DEBUGMSGTL(("agentx/master", "response too late on session %8p\n", session)); return 0; } requests = cache->requests; switch (operation) { case NETSNMP_CALLBACK_OP_TIMED_OUT:{ void *s = snmp_sess_pointer(session); DEBUGMSGTL(("agentx/master", "timeout on session %8p\n", session)); netsnmp_handler_mark_requests_as_delegated(requests, REQUEST_IS_NOT_DELEGATED); netsnmp_set_request_error(cache->reqinfo, requests, /* XXXWWW: should be index=0 */ SNMP_ERR_GENERR); /* * This is a bit sledgehammer because the other sessions on this * transport may be okay (e.g. some thread in the subagent has * wedged, but the others are alright). OTOH the overwhelming * probability is that the whole agent has died somehow. */ if (s != NULL) { netsnmp_transport *t = snmp_sess_transport(s); close_agentx_session(session, -1); if (t != NULL) { DEBUGMSGTL(("agentx/master", "close transport\n")); t->f_close(t); } else { DEBUGMSGTL(("agentx/master", "NULL transport??\n")); } } else { DEBUGMSGTL(("agentx/master", "NULL sess_pointer??\n")); } ax_session = (netsnmp_session *) cache->localinfo; netsnmp_free_agent_snmp_session_by_session(ax_session, NULL); netsnmp_free_delegated_cache(cache); return 0; } case NETSNMP_CALLBACK_OP_DISCONNECT: case NETSNMP_CALLBACK_OP_SEND_FAILED: if (operation == NETSNMP_CALLBACK_OP_DISCONNECT) { DEBUGMSGTL(("agentx/master", "disconnect on session %8p\n", session)); } else { DEBUGMSGTL(("agentx/master", "send failed on session %8p\n", session)); } close_agentx_session(session, -1); netsnmp_handler_mark_requests_as_delegated(requests, REQUEST_IS_NOT_DELEGATED); netsnmp_set_request_error(cache->reqinfo, requests, /* XXXWWW: should be index=0 */ SNMP_ERR_GENERR); netsnmp_free_delegated_cache(cache); return 0; case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE: /* * This session is alive */ CLEAR_SNMP_STRIKE_FLAGS(session->flags); break; default: snmp_log(LOG_ERR, "Unknown operation %d in agentx_got_response\n", operation); netsnmp_free_delegated_cache(cache); return 0; } DEBUGMSGTL(("agentx/master", "got response errstat=%ld, (req=0x%x,trans=" "0x%x,sess=0x%x)\n", pdu->errstat, (unsigned)pdu->reqid, (unsigned)pdu->transid, (unsigned)pdu->sessid)); if (pdu->errstat != AGENTX_ERR_NOERROR) { /* [RFC 2471 - 7.2.5.2.] * * 1) For any received AgentX response PDU, if res.error is * not `noError', the SNMP response PDU's error code is * set to this value. If res.error contains an AgentX * specific value (e.g. `parseError'), the SNMP response * PDU's error code is set to a value of genErr instead. * Also, the SNMP response PDU's error index is set to * the index of the variable binding corresponding to the * failed VarBind in the subagent's AgentX response PDU. * * All other AgentX response PDUs received due to * processing this SNMP request are ignored. Processing * is complete; the SNMP Response PDU is ready to be sent * (see section 7.2.6, "Sending the SNMP Response-PDU"). */ int err; DEBUGMSGTL(("agentx/master", "agentx_got_response() error branch\n")); switch (pdu->errstat) { case AGENTX_ERR_PARSE_FAILED: case AGENTX_ERR_REQUEST_DENIED: case AGENTX_ERR_PROCESSING_ERROR: err = SNMP_ERR_GENERR; break; default: err = pdu->errstat; } ret = 0; for (request = requests, i = 1; request; request = request->next, i++) { if (i == pdu->errindex) { /* * Mark this varbind as the one generating the error. * Note that the AgentX errindex may not match the * position in the original SNMP PDU (request->index) */ netsnmp_set_request_error(cache->reqinfo, request, err); ret = 1; } request->delegated = REQUEST_IS_NOT_DELEGATED; } if (!ret) { /* * ack, unknown, mark the first one */ netsnmp_set_request_error(cache->reqinfo, requests, SNMP_ERR_GENERR); } netsnmp_free_delegated_cache(cache); DEBUGMSGTL(("agentx/master", "end error branch\n")); return 1; } else if (cache->reqinfo->mode == MODE_GET || cache->reqinfo->mode == MODE_GETNEXT || cache->reqinfo->mode == MODE_GETBULK) { /* * Replace varbinds for data request types, but not SETs. */ DEBUGMSGTL(("agentx/master", "agentx_got_response() beginning...\n")); for (var = pdu->variables, request = requests; request && var; request = request->next, var = var->next_variable) { /* * Otherwise, process successful requests */ DEBUGMSGTL(("agentx/master", " handle_agentx_response: processing: ")); DEBUGMSGOID(("agentx/master", var->name, var->name_length)); DEBUGMSG(("agentx/master", "\n")); if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_VERBOSE)) { DEBUGMSGTL(("snmp_agent", " >> ")); DEBUGMSGVAR(("snmp_agent", var)); DEBUGMSG(("snmp_agent", "\n")); } /* * update the oid in the original request */ if (var->type != SNMP_ENDOFMIBVIEW) { snmp_set_var_typed_value(request->requestvb, var->type, var->val.string, var->val_len); snmp_set_var_objid(request->requestvb, var->name, var->name_length); } request->delegated = REQUEST_IS_NOT_DELEGATED; } if (request || var) { /* * ack, this is bad. The # of varbinds don't match and * there is no way to fix the problem */ snmp_log(LOG_ERR, "response to agentx request illegal. bailing out.\n"); netsnmp_set_request_error(cache->reqinfo, requests, SNMP_ERR_GENERR); } if (cache->reqinfo->mode == MODE_GETBULK) netsnmp_bulk_to_next_fix_requests(requests); } else { /* * mark set requests as handled */ for (request = requests; request; request = request->next) { request->delegated = REQUEST_IS_NOT_DELEGATED; } } DEBUGMSGTL(("agentx/master", "handle_agentx_response() finishing...\n")); netsnmp_free_delegated_cache(cache); return 1; }
int proxy_got_response(int operation, netsnmp_session * sess, int reqid, netsnmp_pdu *pdu, void *cb_data) { netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *) cb_data; netsnmp_request_info *requests, *request; netsnmp_variable_list *vars, *var; struct simple_proxy *sp; oid myname[MAX_OID_LEN]; size_t myname_len = MAX_OID_LEN; cache = netsnmp_handler_check_cache(cache); if (!cache) { DEBUGMSGTL(("proxy", "a proxy request was no longer valid.\n")); return SNMP_ERR_NOERROR; } requests = cache->requests; sp = (struct simple_proxy *) cache->localinfo; if (!sp) { DEBUGMSGTL(("proxy", "a proxy request was no longer valid.\n")); return SNMP_ERR_NOERROR; } switch (operation) { case NETSNMP_CALLBACK_OP_TIMED_OUT: /* * WWWXXX: don't leave requests delayed if operation is * something like TIMEOUT */ DEBUGMSGTL(("proxy", "got timed out... requests = %08p\n", requests)); netsnmp_handler_mark_requests_as_delegated(requests, REQUEST_IS_NOT_DELEGATED); netsnmp_set_request_error(cache->reqinfo, requests, /* XXXWWW: should be index = 0 */ SNMP_ERR_GENERR); netsnmp_free_delegated_cache(cache); return 0; case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE: vars = pdu->variables; /* * update the original request varbinds with the results */ for (var = vars, request = requests; request && var; request = request->next, var = var->next_variable) { snmp_set_var_typed_value(request->requestvb, var->type, var->val.string, var->val_len); DEBUGMSGTL(("proxy", "got response... ")); DEBUGMSGOID(("proxy", var->name, var->name_length)); DEBUGMSG(("proxy", "\n")); request->delegated = 0; /* * copy the oid it belongs to */ if (sp->base_len && (var->name_length < sp->base_len || snmp_oid_compare(var->name, sp->base_len, sp->base, sp->base_len) != 0)) { DEBUGMSGTL(("proxy", "out of registered range... ")); DEBUGMSGOID(("proxy", var->name, sp->base_len)); DEBUGMSG(("proxy", " (%d) != ", sp->base_len)); DEBUGMSGOID(("proxy", sp->base, sp->base_len)); DEBUGMSG(("proxy", "\n")); continue; } else if (!sp->base_len && (var->name_length < sp->name_len || snmp_oid_compare(var->name, sp->name_len, sp->name, sp->name_len) != 0)) { DEBUGMSGTL(("proxy", "out of registered base range...\n")); /* * or not if its out of our search range */ continue; } else { if (sp->base_len) { /* * XXX: oid size maxed? */ memcpy(myname, sp->name, sizeof(oid) * sp->name_len); myname_len = sp->name_len + var->name_length - sp->base_len; if (myname_len > MAX_OID_LEN) { snmp_log(LOG_WARNING, "proxy OID return length too long.\n"); netsnmp_set_request_error(cache->reqinfo, requests, SNMP_ERR_GENERR); if (pdu) snmp_free_pdu(pdu); netsnmp_free_delegated_cache(cache); return 1; } if (var->name_length > sp->base_len) memcpy(&myname[sp->name_len], &var->name[sp->base_len], sizeof(oid) * (var->name_length - sp->base_len)); snmp_set_var_objid(request->requestvb, myname, myname_len); } else { snmp_set_var_objid(request->requestvb, var->name, var->name_length); } } } if (request || var) { /* * ack, this is bad. The # of varbinds don't match and * there is no way to fix the problem */ if (pdu) snmp_free_pdu(pdu); snmp_log(LOG_ERR, "response to proxy request illegal. We're screwed.\n"); netsnmp_set_request_error(cache->reqinfo, requests, SNMP_ERR_GENERR); } /* fix bulk_to_next operations */ if (cache->reqinfo->mode == MODE_GETBULK) netsnmp_bulk_to_next_fix_requests(requests); /* * free the response */ if (pdu && 0) snmp_free_pdu(pdu); break; default: DEBUGMSGTL(("proxy", "no response received: op = %d\n", operation)); break; } netsnmp_free_delegated_cache(cache); return 1; }