| /** allows overriding of a given oid with a new type and value */ |
| |
| /* Portions of this file are subject to the following copyright(s). See |
| * the Net-SNMP's COPYING file for more details and other copyrights |
| * that may apply: |
| */ |
| /* |
| * Portions of this file are copyrighted by: |
| * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. |
| * Use is subject to license terms specified in the COPYING file |
| * distributed with the Net-SNMP package. |
| */ |
| |
| #include <net-snmp/net-snmp-config.h> |
| #include <net-snmp/net-snmp-includes.h> |
| #include <net-snmp/agent/net-snmp-agent-includes.h> |
| |
| typedef struct override_data_s { |
| int type; |
| void *value; |
| size_t value_len; |
| void *set_space; |
| size_t set_len; |
| } override_data; |
| |
| /** @todo: (optionally) save values persistently when configured for |
| * read-write */ |
| int |
| override_handler(netsnmp_mib_handler *handler, |
| netsnmp_handler_registration *reginfo, |
| netsnmp_agent_request_info *reqinfo, |
| netsnmp_request_info *requests) |
| { |
| |
| override_data *data = (override_data*)handler->myvoid; |
| void *tmpptr; |
| |
| if (!data) { |
| netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_GENERR); |
| return SNMP_ERR_NOERROR; |
| } |
| |
| switch (reqinfo->mode) { |
| case MODE_GET: |
| DEBUGMSGTL(("override", "overriding oid ")); |
| DEBUGMSGOID(("override", requests->requestvb->name, |
| requests->requestvb->name_length)); |
| DEBUGMSG(("override", "\n")); |
| snmp_set_var_typed_value(requests->requestvb, (u_char)data->type, |
| (u_char *) data->value, data->value_len); |
| break; |
| |
| #ifndef NETSNMP_NO_WRITE_SUPPORT |
| case MODE_SET_RESERVE1: |
| if (requests->requestvb->type != data->type) |
| netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_WRONGTYPE); |
| break; |
| |
| case MODE_SET_RESERVE2: |
| data->set_space = netsnmp_memdup(requests->requestvb->val.string, |
| requests->requestvb->val_len); |
| if (!data->set_space) |
| netsnmp_set_request_error(reqinfo, requests, |
| SNMP_ERR_RESOURCEUNAVAILABLE); |
| break; |
| |
| case MODE_SET_FREE: |
| SNMP_FREE(data->set_space); |
| break; |
| |
| case MODE_SET_ACTION: |
| /* swap the values in */ |
| tmpptr = data->value; |
| data->value = data->set_space; |
| data->set_space = tmpptr; |
| |
| /* set the lengths */ |
| data->set_len = data->value_len; |
| data->value_len = requests->requestvb->val_len; |
| break; |
| |
| case MODE_SET_UNDO: |
| SNMP_FREE(data->value); |
| data->value = data->set_space; |
| data->value_len = data->set_len; |
| break; |
| |
| case MODE_SET_COMMIT: |
| SNMP_FREE(data->set_space); |
| break; |
| #endif /* !NETSNMP_NO_WRITE_SUPPORT */ |
| |
| default: |
| snmp_log(LOG_ERR, "unsupported mode in override handler\n"); |
| netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_GENERR); |
| return SNMP_ERR_GENERR; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| #define MALLOC_OR_DIE(x) \ |
| thedata->value = malloc(x); \ |
| thedata->value_len = x; \ |
| if (!thedata->value) { \ |
| free(thedata); \ |
| config_perror("memory allocation failure"); \ |
| return; \ |
| } |
| |
| void |
| netsnmp_parse_override(const char *token, char *line) |
| { |
| char *cp; |
| char buf[SNMP_MAXBUF], namebuf[SNMP_MAXBUF]; |
| int readwrite = 0; |
| oid oidbuf[MAX_OID_LEN]; |
| size_t oidbuf_len = MAX_OID_LEN; |
| int type; |
| override_data *thedata; |
| netsnmp_handler_registration *the_reg; |
| |
| cp = copy_nword(line, namebuf, sizeof(namebuf) - 1); |
| if (strcmp(namebuf, "-rw") == 0) { |
| readwrite = 1; |
| cp = copy_nword(cp, namebuf, sizeof(namebuf) - 1); |
| } |
| |
| if (!cp) { |
| config_perror("no oid specified"); |
| return; |
| } |
| |
| if (!snmp_parse_oid(namebuf, oidbuf, &oidbuf_len)) { |
| config_perror("illegal oid"); |
| return; |
| } |
| cp = copy_nword(cp, buf, sizeof(buf) - 1); |
| |
| if (!cp && strcmp(buf, "null") != 0) { |
| config_perror("no variable value specified"); |
| return; |
| } |
| |
| { |
| struct { const char* key; int value; } const strings[] = { |
| { "counter", ASN_COUNTER }, |
| { "counter64", ASN_COUNTER64 }, |
| { "integer", ASN_INTEGER }, |
| { "ipaddress", ASN_IPADDRESS }, |
| { "nsap", ASN_NSAP }, |
| { "null", ASN_NULL }, |
| { "object_id", ASN_OBJECT_ID }, |
| { "octet_str", ASN_OCTET_STR }, |
| { "opaque", ASN_OPAQUE }, |
| #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES |
| { "opaque_counter64", ASN_OPAQUE_COUNTER64 }, |
| { "opaque_double", ASN_OPAQUE_DOUBLE }, |
| { "opaque_float", ASN_OPAQUE_FLOAT }, |
| { "opaque_i64", ASN_OPAQUE_I64 }, |
| { "opaque_u64", ASN_OPAQUE_U64 }, |
| #endif |
| { "timeticks", ASN_TIMETICKS }, |
| { "uinteger", ASN_GAUGE }, |
| { "unsigned", ASN_UNSIGNED }, |
| { NULL, 0 } |
| }, * run; |
| for(run = strings; run->key && strcasecmp(run->key, buf) < 0; ++run); |
| if(run->key && strcasecmp(run->key, buf) == 0) |
| type = run->value; |
| else { |
| config_perror("unknown type specified"); |
| return; |
| } |
| } |
| |
| if (cp) |
| copy_nword(cp, buf, sizeof(buf) - 1); |
| else |
| buf[0] = 0; |
| |
| thedata = SNMP_MALLOC_TYPEDEF(override_data); |
| if (!thedata) { |
| config_perror("memory allocation failure"); |
| return; |
| } |
| thedata->type = type; |
| |
| switch (type) { |
| case ASN_INTEGER: |
| MALLOC_OR_DIE(sizeof(long)); |
| *((long *) thedata->value) = strtol(buf, NULL, 0); |
| break; |
| |
| case ASN_COUNTER: |
| case ASN_TIMETICKS: |
| case ASN_UNSIGNED: |
| MALLOC_OR_DIE(sizeof(u_long)); |
| *((u_long *) thedata->value) = strtoul(buf, NULL, 0); |
| break; |
| |
| case ASN_OCTET_STR: |
| case ASN_BIT_STR: |
| if (buf[0] == '0' && buf[1] == 'x') { |
| /* |
| * hex |
| */ |
| thedata->value_len = |
| hex_to_binary2((u_char *)(buf + 2), strlen(buf) - 2, |
| (char **) &thedata->value); |
| } else { |
| thedata->value = strdup(buf); |
| thedata->value_len = strlen(buf); |
| } |
| break; |
| |
| case ASN_OBJECT_ID: |
| read_config_read_objid(buf, (oid **) & thedata->value, |
| &thedata->value_len); |
| /* We need the size of the value in bytes, not in oids */ |
| thedata->value_len *= sizeof(oid); |
| break; |
| |
| case ASN_NULL: |
| thedata->value_len = 0; |
| break; |
| |
| default: |
| SNMP_FREE(thedata); |
| config_perror("illegal/unsupported type specified"); |
| return; |
| } |
| |
| if (!thedata->value && thedata->type != ASN_NULL) { |
| config_perror("memory allocation failure"); |
| free(thedata); |
| return; |
| } |
| |
| the_reg = SNMP_MALLOC_TYPEDEF(netsnmp_handler_registration); |
| if (!the_reg) { |
| config_perror("memory allocation failure"); |
| free(thedata); |
| return; |
| } |
| |
| the_reg->handlerName = strdup(namebuf); |
| the_reg->priority = 255; |
| the_reg->modes = (readwrite) ? HANDLER_CAN_RWRITE : HANDLER_CAN_RONLY; |
| the_reg->handler = |
| netsnmp_create_handler("override", override_handler); |
| the_reg->rootoid = snmp_duplicate_objid(oidbuf, oidbuf_len); |
| the_reg->rootoid_len = oidbuf_len; |
| if (!the_reg->rootoid || !the_reg->handler || !the_reg->handlerName) { |
| if (the_reg->handler) |
| SNMP_FREE(the_reg->handler->handler_name); |
| SNMP_FREE(the_reg->handler); |
| SNMP_FREE(the_reg->handlerName); |
| SNMP_FREE(the_reg); |
| config_perror("memory allocation failure"); |
| free(thedata); |
| return; |
| } |
| the_reg->handler->myvoid = thedata; |
| |
| if (netsnmp_register_instance(the_reg)) { |
| config_perror("oid registration failed within the agent"); |
| SNMP_FREE(thedata->value); |
| free(thedata); |
| return; |
| } |
| } |
| |
| |
| void |
| init_override(void) |
| { |
| |
| snmpd_register_config_handler("override", netsnmp_parse_override, NULL, /* XXX: free func */ |
| "[-rw] mibnode type value"); |
| } |