| /* |
| * This file was generated by mib2c and is intended for use as |
| * a mib module for the ucd-snmp snmpd agent. |
| */ |
| |
| |
| /* |
| * This should always be included first before anything else |
| */ |
| #include <net-snmp/net-snmp-config.h> |
| #include <net-snmp/net-snmp-features.h> |
| |
| #include <sys/types.h> |
| #if HAVE_STDLIB_H |
| #include <stdlib.h> |
| #endif |
| #if HAVE_STRING_H |
| #include <string.h> |
| #else |
| #include <strings.h> |
| #endif |
| |
| /* |
| * minimal include directives |
| */ |
| #include <net-snmp/net-snmp-includes.h> |
| #include <net-snmp/agent/net-snmp-agent-includes.h> |
| |
| #include "header_complex.h" |
| #include "snmpNotifyTable.h" |
| #include "snmpNotifyFilterProfileTable.h" |
| #include "target/snmpTargetParamsEntry.h" |
| #include "target/snmpTargetAddrEntry.h" |
| #include "target/target.h" |
| #include "snmp-notification-mib/snmpNotifyFilterTable/snmpNotifyFilterTable.h" |
| #include <net-snmp/agent/agent_callbacks.h> |
| #include <net-snmp/agent/agent_trap.h> |
| #include <net-snmp/agent/mib_module_config.h> |
| #include "net-snmp/agent/sysORTable.h" |
| |
| #ifdef USING_NOTIFICATION_LOG_MIB_NOTIFICATION_LOG_MODULE |
| # include "notification-log-mib/notification_log.h" |
| #endif |
| |
| #ifndef NETSNMP_NO_WRITE_SUPPORT |
| netsnmp_feature_require(header_complex_find_entry) |
| #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
| |
| SNMPCallback store_snmpNotifyTable; |
| |
| /* |
| * snmpNotifyTable_variables_oid: |
| * this is the top level oid that we want to register under. This |
| * is essentially a prefix, with the suffix appearing in the |
| * variable below. |
| */ |
| |
| |
| oid snmpNotifyTable_variables_oid[] = |
| { 1, 3, 6, 1, 6, 3, 13, 1, 1 }; |
| |
| static oid snmpNotifyFullCompliance[] = |
| { SNMP_OID_SNMPMODULES, 13, 3, 1, 3 }; /* SNMP-NOTIFICATION-MIB::snmpNotifyFullCompliance */ |
| |
| |
| /* |
| * variable2 snmpNotifyTable_variables: |
| * this variable defines function callbacks and type return information |
| * for the snmpNotifyTable mib section |
| */ |
| |
| |
| struct variable2 snmpNotifyTable_variables[] = { |
| /* |
| * magic number , variable type , ro/rw , callback fn , L, oidsuffix |
| */ |
| #define SNMPNOTIFYTAG 4 |
| {SNMPNOTIFYTAG, ASN_OCTET_STR, NETSNMP_OLDAPI_RWRITE, |
| var_snmpNotifyTable, 2, {1, 2}}, |
| #define SNMPNOTIFYTYPE 5 |
| {SNMPNOTIFYTYPE, ASN_INTEGER, NETSNMP_OLDAPI_RWRITE, |
| var_snmpNotifyTable, 2, {1, 3}}, |
| #define SNMPNOTIFYSTORAGETYPE 6 |
| {SNMPNOTIFYSTORAGETYPE, ASN_INTEGER, NETSNMP_OLDAPI_RWRITE, |
| var_snmpNotifyTable, 2, {1, 4}}, |
| #define SNMPNOTIFYROWSTATUS 7 |
| {SNMPNOTIFYROWSTATUS, ASN_INTEGER, NETSNMP_OLDAPI_RWRITE, |
| var_snmpNotifyTable, 2, {1, 5}}, |
| |
| }; |
| /* |
| * (L = length of the oidsuffix) |
| */ |
| |
| |
| /* |
| * global storage of our data, saved in and configured by header_complex() |
| */ |
| static struct header_complex_index *snmpNotifyTableStorage = NULL; |
| |
| static int |
| _checkFilter(const char* paramName, netsnmp_pdu *pdu) |
| { |
| /* |
| * find appropriate filterProfileEntry |
| */ |
| netsnmp_variable_list *var, *trap_var; |
| char *profileName; |
| size_t profileNameLen; |
| struct vacm_viewEntry *vp, *head; |
| int vb_oid_excluded = 0; |
| extern const oid snmptrap_oid[]; |
| extern const size_t snmptrap_oid_len; |
| |
| netsnmp_assert(NULL != paramName); |
| netsnmp_assert(NULL != pdu); |
| |
| DEBUGMSGTL(("send_notifications", "checking filters...\n")); |
| |
| /* |
| A notification originator uses the snmpNotifyFilterTable to filter |
| notifications. A notification filter profile may be associated with |
| a particular entry in the snmpTargetParamsTable. The associated |
| filter profile is identified by an entry in the |
| snmpNotifyFilterProfileTable whose index is equal to the index of the |
| entry in the snmpTargetParamsTable. If no such entry exists in the |
| snmpNotifyFilterProfileTable, no filtering is performed for that |
| management target. |
| */ |
| profileName = get_FilterProfileName(paramName, strlen(paramName), |
| &profileNameLen); |
| if (NULL == profileName) { |
| DEBUGMSGTL(("send_notifications", " no matching profile\n")); |
| return 0; |
| } |
| |
| /* |
| If such an entry does exist, the value of snmpNotifyFilterProfileName |
| of the entry is compared with the corresponding portion of the index |
| of all active entries in the snmpNotifyFilterTable. All such entries |
| for which this comparison results in an exact match are used for |
| filtering a notification generated using the associated |
| snmpTargetParamsEntry. If no such entries exist, no filtering is |
| performed, and a notification may be sent to the management target. |
| */ |
| head = snmpNotifyFilterTable_vacm_view_subtree(profileName); |
| if (NULL == head) { |
| DEBUGMSGTL(("send_notifications", " no matching filters\n")); |
| return 0; |
| } |
| |
| /* |
| Otherwise, if matching entries do exist, a notification may be sent |
| if the NOTIFICATION-TYPE OBJECT IDENTIFIER of the notification (this |
| is the value of the element of the variable bindings whose name is |
| snmpTrapOID.0, i.e., the second variable binding) is specifically |
| included, and none of the object instances to be included in the |
| variable-bindings of the notification are specifically excluded by |
| the matching entries. |
| */ |
| trap_var = find_varbind_in_list( pdu->variables, |
| snmptrap_oid, |
| snmptrap_oid_len); |
| if (NULL != trap_var) { |
| /* |
| For a notification name, if none match, |
| then the notification name is considered excluded, and the |
| notification should not be sent to this management target. |
| */ |
| vp = netsnmp_view_get(head, profileName, trap_var->val.objid, |
| trap_var->val_len / sizeof(oid), VACM_MODE_FIND); |
| if ((NULL == vp) || (SNMP_VIEW_INCLUDED != vp->viewType)) { |
| DEBUGMSGTL(("send_notifications", " filtered (snmpTrapOID.0 ")); |
| DEBUGMSGOID(("send_notifications",trap_var->val.objid, |
| trap_var->val_len / sizeof(oid))); |
| DEBUGMSG(("send_notifications", " not included)\n")); |
| free(head); |
| return 1; |
| } |
| } |
| |
| /* |
| * check varbinds |
| */ |
| for(var = pdu->variables; var; var = var->next_variable) { |
| /* |
| For an |
| object instance, if none match, the object instance is considered |
| included, and the notification may be sent to this management target. |
| */ |
| |
| if (var == trap_var) { |
| continue; |
| } |
| |
| vp = netsnmp_view_get(head, profileName, var->name, |
| var->name_length, VACM_MODE_FIND); |
| if ((NULL != vp) && (SNMP_VIEW_EXCLUDED == vp->viewType)) { |
| DEBUGMSGTL(("send_notifications"," filtered (varbind ")); |
| DEBUGMSGOID(("send_notifications",var->name, var->name_length)); |
| DEBUGMSG(("send_notifications", " excluded)\n")); |
| vb_oid_excluded = 1; |
| break; |
| } |
| } |
| |
| free(head); |
| |
| return vb_oid_excluded; |
| } |
| |
| int |
| send_notifications(int major, int minor, void *serverarg, void *clientarg) |
| { |
| struct header_complex_index *hptr; |
| struct snmpNotifyTable_data *nptr; |
| netsnmp_session *sess, *sptr; |
| netsnmp_pdu *template_pdu = (netsnmp_pdu *) serverarg; |
| int count = 0, send = 0; |
| |
| DEBUGMSGTL(("send_notifications", "starting: pdu=%p, vars=%p\n", |
| template_pdu, template_pdu->variables)); |
| |
| for (hptr = snmpNotifyTableStorage; hptr; hptr = hptr->next) { |
| nptr = (struct snmpNotifyTable_data *) hptr->data; |
| if (nptr->snmpNotifyRowStatus != RS_ACTIVE) |
| continue; |
| if (!nptr->snmpNotifyTag) |
| continue; |
| |
| sess = get_target_sessions(nptr->snmpNotifyTag, NULL, NULL); |
| |
| /* |
| * filter appropriately, per section 6 of RFC 3413 |
| */ |
| |
| for (sptr = sess; sptr; sptr = sptr->next) { |
| send = 0; |
| #ifndef NETSNMP_DISABLE_SNMPV1 |
| if (sptr->version == SNMP_VERSION_1 && |
| minor == SNMPD_CALLBACK_SEND_TRAP1) { |
| send = 1; |
| } else |
| #endif |
| if ((sptr->version == SNMP_VERSION_3 |
| #ifndef NETSNMP_DISABLE_SNMPV2C |
| || sptr->version == SNMP_VERSION_2c |
| #endif |
| ) && minor == SNMPD_CALLBACK_SEND_TRAP2) { |
| if (nptr->snmpNotifyType == SNMPNOTIFYTYPE_INFORM) { |
| template_pdu->command = SNMP_MSG_INFORM; |
| } else { |
| template_pdu->command = SNMP_MSG_TRAP2; |
| } |
| send = 1; |
| } |
| if (send && sess->paramName) { |
| int filter = _checkFilter(sess->paramName, template_pdu); |
| if (filter) |
| send = 0; |
| } |
| if (send) { |
| send_trap_to_sess(sptr, template_pdu); |
| ++count; |
| } /* session to send to */ |
| } /* for(sptr) */ |
| } /* for(hptr) */ |
| |
| DEBUGMSGTL(("send_notifications", "sent %d notifications\n", count)); |
| |
| #ifdef USING_NOTIFICATION_LOG_MIB_NOTIFICATION_LOG_MODULE |
| if (count) |
| log_notification(template_pdu, NULL); |
| #endif |
| |
| return 0; |
| } |
| |
| #define MAX_ENTRIES 1024 |
| |
| int |
| notifyTable_register_notifications(int major, int minor, |
| void *serverarg, void *clientarg) |
| { |
| struct targetAddrTable_struct *ptr; |
| struct targetParamTable_struct *pptr; |
| struct snmpNotifyTable_data *nptr; |
| int confirm, i, bufLen; |
| char buf[SNMP_MAXBUF_SMALL]; |
| netsnmp_transport *t = NULL; |
| struct agent_add_trap_args *args = |
| (struct agent_add_trap_args *) serverarg; |
| netsnmp_session *ss; |
| |
| if (!args || !(args->ss)) { |
| return (0); |
| } |
| confirm = args->confirm; |
| ss = args->ss; |
| |
| /* |
| * XXX: START move target creation to target code |
| */ |
| for (i = 0; i < MAX_ENTRIES; i++) { |
| bufLen = sprintf(buf, "internal%d", i); |
| if (get_addrForName2(buf, bufLen) == NULL && |
| get_paramEntry(buf) == NULL) |
| break; |
| } |
| if (i == MAX_ENTRIES) { |
| snmp_log(LOG_ERR, |
| "Can't register new trap destination: max limit reached: %d", |
| MAX_ENTRIES); |
| snmp_sess_close(ss); |
| return (0); |
| } |
| |
| /* |
| * address |
| */ |
| t = snmp_sess_transport(snmp_sess_pointer(ss)); |
| if (!t) { |
| snmp_log(LOG_ERR, |
| "Cannot add new trap destination, transport is closed."); |
| snmp_sess_close(ss); |
| return 0; |
| } |
| ptr = snmpTargetAddrTable_create(); |
| ptr->nameData = netsnmp_memdup(buf, bufLen); |
| ptr->nameLen = bufLen; |
| memcpy(ptr->tDomain, t->domain, t->domain_length * sizeof(oid)); |
| ptr->tDomainLen = t->domain_length; |
| ptr->tAddressLen = t->remote_length; |
| ptr->tAddress = t->remote; |
| |
| ptr->timeout = ss->timeout / 10000; |
| ptr->retryCount = ss->retries; |
| SNMP_FREE(ptr->tagList); |
| ptr->tagList = strdup(buf); /* strdup ok since buf contains 'internal%d' */ |
| ptr->params = strdup(buf); |
| ptr->storageType = ST_READONLY; |
| ptr->rowStatus = RS_ACTIVE; |
| ptr->sess = ss; |
| DEBUGMSGTL(("trapsess", "adding to trap table\n")); |
| snmpTargetAddrTable_add(ptr); |
| |
| /* |
| * param |
| */ |
| pptr = snmpTargetParamTable_create(); |
| pptr->paramName = strdup(buf); |
| pptr->mpModel = ss->version; |
| if (ss->version == SNMP_VERSION_3) { |
| pptr->secModel = ss->securityModel; |
| pptr->secLevel = ss->securityLevel; |
| pptr->secName = (char *) malloc(ss->securityNameLen + 1); |
| if (pptr->secName == NULL) { |
| snmpTargetParamTable_dispose(pptr); |
| return 0; |
| } |
| memcpy((void *) pptr->secName, (void *) ss->securityName, |
| ss->securityNameLen); |
| pptr->secName[ss->securityNameLen] = 0; |
| } |
| #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) |
| else { |
| pptr->secModel = |
| #ifndef NETSNMP_DISABLE_SNMPV1 |
| ss->version == SNMP_VERSION_1 ? SNMP_SEC_MODEL_SNMPv1 : |
| #endif |
| SNMP_SEC_MODEL_SNMPv2c; |
| pptr->secLevel = SNMP_SEC_LEVEL_NOAUTH; |
| pptr->secName = NULL; |
| if (ss->community && (ss->community_len > 0)) { |
| pptr->secName = (char *) malloc(ss->community_len + 1); |
| if (pptr->secName == NULL) { |
| snmpTargetParamTable_dispose(pptr); |
| return 0; |
| } |
| memcpy((void *) pptr->secName, (void *) ss->community, |
| ss->community_len); |
| pptr->secName[ss->community_len] = 0; |
| } |
| } |
| #endif |
| pptr->storageType = ST_READONLY; |
| pptr->rowStatus = RS_ACTIVE; |
| snmpTargetParamTable_add(pptr); |
| /* |
| * XXX: END move target creation to target code |
| */ |
| |
| /* |
| * notify table |
| */ |
| nptr = SNMP_MALLOC_STRUCT(snmpNotifyTable_data); |
| if (nptr == NULL) |
| return 0; |
| nptr->snmpNotifyName = strdup(buf); |
| nptr->snmpNotifyNameLen = strlen(buf); |
| nptr->snmpNotifyTag = strdup(buf); |
| nptr->snmpNotifyTagLen = strlen(buf); |
| nptr->snmpNotifyType = confirm ? |
| SNMPNOTIFYTYPE_INFORM : SNMPNOTIFYTYPE_TRAP; |
| nptr->snmpNotifyStorageType = ST_READONLY; |
| nptr->snmpNotifyRowStatus = RS_ACTIVE; |
| |
| snmpNotifyTable_add(nptr); |
| return 0; |
| } |
| |
| |
| /* |
| * XXX: this really needs to be done for the target mib entries too. |
| * But we can only trust that we've added stuff here and we don't want |
| * to destroy other valid entries in the target tables, so... Don't |
| * do too many kill -HUPs to your agent as re reading the config file |
| * will be a slow memory leak in the target mib. |
| */ |
| int |
| notifyTable_unregister_notifications(int major, int minor, |
| void *serverarg, void *clientarg) |
| { |
| struct header_complex_index *hptr, *nhptr; |
| |
| for (hptr = snmpNotifyTableStorage; hptr; hptr = nhptr) { |
| struct snmpNotifyTable_data *nptr = hptr->data; |
| nhptr = hptr->next; |
| if (nptr->snmpNotifyStorageType == ST_READONLY) { |
| header_complex_extract_entry(&snmpNotifyTableStorage, hptr); |
| free(nptr->snmpNotifyName); |
| free(nptr->snmpNotifyTag); |
| free(nptr); |
| } |
| } |
| snmpNotifyTableStorage = NULL; |
| return (0); |
| } |
| |
| /* |
| * init_snmpNotifyTable(): |
| * Initialization routine. This is called when the agent starts up. |
| * At a minimum, registration of your variables should take place here. |
| */ |
| void |
| init_snmpNotifyTable(void) |
| { |
| DEBUGMSGTL(("snmpNotifyTable", "initializing... ")); |
| |
| |
| /* |
| * register ourselves with the agent to handle our mib tree |
| */ |
| REGISTER_MIB("snmpNotifyTable", snmpNotifyTable_variables, variable2, |
| snmpNotifyTable_variables_oid); |
| |
| |
| /* |
| * register our config handler(s) to deal with registrations |
| */ |
| snmpd_register_config_handler("snmpNotifyTable", parse_snmpNotifyTable, |
| NULL, NULL); |
| |
| |
| /* |
| * we need to be called back later to store our data |
| */ |
| snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, |
| store_snmpNotifyTable, NULL); |
| |
| #ifndef DISABLE_SNMPV1 |
| snmp_register_callback(SNMP_CALLBACK_APPLICATION, |
| SNMPD_CALLBACK_SEND_TRAP1, send_notifications, |
| NULL); |
| #endif |
| snmp_register_callback(SNMP_CALLBACK_APPLICATION, |
| SNMPD_CALLBACK_SEND_TRAP2, send_notifications, |
| NULL); |
| snmp_register_callback(SNMP_CALLBACK_APPLICATION, |
| SNMPD_CALLBACK_REGISTER_NOTIFICATIONS, |
| notifyTable_register_notifications, NULL); |
| snmp_register_callback(SNMP_CALLBACK_APPLICATION, |
| SNMPD_CALLBACK_PRE_UPDATE_CONFIG, |
| notifyTable_unregister_notifications, NULL); |
| |
| /* |
| * place any other initialization junk you need here |
| */ |
| |
| REGISTER_SYSOR_ENTRY(snmpNotifyFullCompliance, |
| "The MIB modules for managing SNMP Notification, plus filtering."); |
| |
| DEBUGMSGTL(("snmpNotifyTable", "done.\n")); |
| } |
| |
| void |
| shutdown_snmpNotifyTable(void) |
| { |
| DEBUGMSGTL(("snmpNotifyTable", "shutting down ... ")); |
| |
| notifyTable_unregister_notifications(SNMP_CALLBACK_APPLICATION, |
| SNMPD_CALLBACK_PRE_UPDATE_CONFIG, |
| NULL, |
| NULL); |
| |
| snmp_unregister_callback(SNMP_CALLBACK_APPLICATION, |
| SNMPD_CALLBACK_PRE_UPDATE_CONFIG, |
| notifyTable_unregister_notifications, NULL, FALSE); |
| snmp_unregister_callback(SNMP_CALLBACK_APPLICATION, |
| SNMPD_CALLBACK_REGISTER_NOTIFICATIONS, |
| notifyTable_register_notifications, NULL, FALSE); |
| snmp_unregister_callback(SNMP_CALLBACK_APPLICATION, |
| SNMPD_CALLBACK_SEND_TRAP2, send_notifications, |
| NULL, FALSE); |
| #ifndef DISABLE_SNMPV1 |
| snmp_unregister_callback(SNMP_CALLBACK_APPLICATION, |
| SNMPD_CALLBACK_SEND_TRAP1, send_notifications, |
| NULL, FALSE); |
| #endif |
| snmp_unregister_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, |
| store_snmpNotifyTable, NULL, FALSE); |
| |
| UNREGISTER_SYSOR_ENTRY(snmpNotifyFullCompliance); |
| |
| DEBUGMSGTL(("snmpNotifyTable", "done.\n")); |
| } |
| |
| /* |
| * snmpNotifyTable_add(): adds a structure node to our data set |
| */ |
| int |
| snmpNotifyTable_add(struct snmpNotifyTable_data *thedata) |
| { |
| netsnmp_variable_list *vars = NULL; |
| int retVal; |
| |
| DEBUGMSGTL(("snmpNotifyTable", "adding data... ")); |
| /* |
| * add the index variables to the varbind list, which is |
| * used by header_complex to index the data |
| */ |
| |
| |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_PRIV_IMPLIED_OCTET_STR, (u_char *) thedata->snmpNotifyName, thedata->snmpNotifyNameLen); /* snmpNotifyName */ |
| |
| |
| |
| if (header_complex_maybe_add_data(&snmpNotifyTableStorage, vars, thedata, 1) |
| != NULL){ |
| DEBUGMSGTL(("snmpNotifyTable", "registered an entry\n")); |
| retVal = SNMPERR_SUCCESS; |
| }else{ |
| retVal = SNMPERR_GENERR; |
| } |
| |
| |
| DEBUGMSGTL(("snmpNotifyTable", "done.\n")); |
| return retVal; |
| } |
| |
| |
| /* |
| * parse_snmpNotifyTable(): |
| * parses .conf file entries needed to configure the mib. |
| */ |
| void |
| parse_snmpNotifyTable(const char *token, char *line) |
| { |
| size_t tmpint; |
| struct snmpNotifyTable_data *StorageTmp = |
| SNMP_MALLOC_STRUCT(snmpNotifyTable_data); |
| |
| |
| DEBUGMSGTL(("snmpNotifyTable", "parsing config... ")); |
| |
| |
| if (StorageTmp == NULL) { |
| config_perror("malloc failure"); |
| return; |
| } |
| |
| line = |
| read_config_read_data(ASN_OCTET_STR, line, |
| &StorageTmp->snmpNotifyName, |
| &StorageTmp->snmpNotifyNameLen); |
| if (StorageTmp->snmpNotifyName == NULL) { |
| config_perror("invalid specification for snmpNotifyName"); |
| SNMP_FREE(StorageTmp); |
| return; |
| } |
| |
| line = |
| read_config_read_data(ASN_OCTET_STR, line, |
| &StorageTmp->snmpNotifyTag, |
| &StorageTmp->snmpNotifyTagLen); |
| if (StorageTmp->snmpNotifyTag == NULL) { |
| config_perror("invalid specification for snmpNotifyTag"); |
| SNMP_FREE(StorageTmp); |
| return; |
| } |
| |
| line = |
| read_config_read_data(ASN_INTEGER, line, |
| &StorageTmp->snmpNotifyType, &tmpint); |
| |
| line = |
| read_config_read_data(ASN_INTEGER, line, |
| &StorageTmp->snmpNotifyStorageType, &tmpint); |
| if (!StorageTmp->snmpNotifyStorageType) |
| StorageTmp->snmpNotifyStorageType = ST_READONLY; |
| |
| line = |
| read_config_read_data(ASN_INTEGER, line, |
| &StorageTmp->snmpNotifyRowStatus, &tmpint); |
| if (!StorageTmp->snmpNotifyRowStatus) |
| StorageTmp->snmpNotifyRowStatus = RS_ACTIVE; |
| |
| |
| if (snmpNotifyTable_add(StorageTmp) != SNMPERR_SUCCESS){ |
| SNMP_FREE(StorageTmp->snmpNotifyName); |
| SNMP_FREE(StorageTmp->snmpNotifyTag); |
| SNMP_FREE(StorageTmp); |
| } |
| |
| |
| DEBUGMSGTL(("snmpNotifyTable", "done.\n")); |
| } |
| |
| |
| |
| |
| /* |
| * store_snmpNotifyTable(): |
| * stores .conf file entries needed to configure the mib. |
| */ |
| int |
| store_snmpNotifyTable(int majorID, int minorID, void *serverarg, |
| void *clientarg) |
| { |
| char line[SNMP_MAXBUF]; |
| char *cptr; |
| size_t tmpint; |
| struct snmpNotifyTable_data *StorageTmp; |
| struct header_complex_index *hcindex; |
| |
| |
| DEBUGMSGTL(("snmpNotifyTable", "storing data... ")); |
| |
| |
| for (hcindex = snmpNotifyTableStorage; hcindex != NULL; |
| hcindex = hcindex->next) { |
| StorageTmp = (struct snmpNotifyTable_data *) hcindex->data; |
| |
| /* |
| * store permanent and nonvolatile rows. |
| * XXX should there be a qualification on RowStatus?? |
| */ |
| if ((StorageTmp->snmpNotifyStorageType == ST_NONVOLATILE) || |
| (StorageTmp->snmpNotifyStorageType == ST_PERMANENT) ){ |
| |
| memset(line, 0, sizeof(line)); |
| strcat(line, "snmpNotifyTable "); |
| cptr = line + strlen(line); |
| |
| cptr = |
| read_config_store_data(ASN_OCTET_STR, cptr, |
| &StorageTmp->snmpNotifyName, |
| &StorageTmp->snmpNotifyNameLen); |
| cptr = |
| read_config_store_data(ASN_OCTET_STR, cptr, |
| &StorageTmp->snmpNotifyTag, |
| &StorageTmp->snmpNotifyTagLen); |
| cptr = |
| read_config_store_data(ASN_INTEGER, cptr, |
| &StorageTmp->snmpNotifyType, |
| &tmpint); |
| cptr = |
| read_config_store_data(ASN_INTEGER, cptr, |
| &StorageTmp->snmpNotifyStorageType, |
| &tmpint); |
| cptr = |
| read_config_store_data(ASN_INTEGER, cptr, |
| &StorageTmp->snmpNotifyRowStatus, |
| &tmpint); |
| |
| snmpd_store_config(line); |
| } |
| } |
| DEBUGMSGTL(("snmpNotifyTable", "done.\n")); |
| return 0; |
| } |
| |
| |
| |
| |
| /* |
| * var_snmpNotifyTable(): |
| * Handle this table separately from the scalar value case. |
| * The workings of this are basically the same as for var_snmpNotifyTable above. |
| */ |
| unsigned char * |
| var_snmpNotifyTable(struct variable *vp, |
| oid * name, |
| size_t * length, |
| int exact, |
| size_t * var_len, WriteMethod ** write_method) |
| { |
| struct snmpNotifyTable_data *StorageTmp = NULL; |
| int found = 1; |
| |
| DEBUGMSGTL(("snmpNotifyTable", |
| "var_snmpNotifyTable: Entering... \n")); |
| /* |
| * this assumes you have registered all your data properly |
| */ |
| if ((StorageTmp = (struct snmpNotifyTable_data *) |
| header_complex((struct header_complex_index *) |
| snmpNotifyTableStorage, vp, name, length, exact, |
| var_len, write_method)) == NULL) { |
| found = 0; |
| } |
| |
| switch (vp->magic) { |
| #ifndef NETSNMP_NO_WRITE_SUPPORT |
| case SNMPNOTIFYTAG: |
| *write_method = write_snmpNotifyTag; |
| break; |
| case SNMPNOTIFYTYPE: |
| *write_method = write_snmpNotifyType; |
| break; |
| case SNMPNOTIFYSTORAGETYPE: |
| *write_method = write_snmpNotifyStorageType; |
| break; |
| case SNMPNOTIFYROWSTATUS: |
| *write_method = write_snmpNotifyRowStatus; |
| break; |
| #endif /* !NETSNMP_NO_WRITE_SUPPORT */ |
| default: |
| *write_method = NULL; |
| } |
| |
| if (!found) { |
| return NULL; |
| } |
| |
| #ifndef NETSNMP_NO_READ_SUPPORT |
| switch (vp->magic) { |
| case SNMPNOTIFYTAG: |
| *var_len = StorageTmp->snmpNotifyTagLen; |
| return (u_char *) StorageTmp->snmpNotifyTag; |
| |
| case SNMPNOTIFYTYPE: |
| *var_len = sizeof(StorageTmp->snmpNotifyType); |
| return (u_char *) & StorageTmp->snmpNotifyType; |
| |
| case SNMPNOTIFYSTORAGETYPE: |
| *var_len = sizeof(StorageTmp->snmpNotifyStorageType); |
| return (u_char *) & StorageTmp->snmpNotifyStorageType; |
| |
| case SNMPNOTIFYROWSTATUS: |
| *var_len = sizeof(StorageTmp->snmpNotifyRowStatus); |
| return (u_char *) & StorageTmp->snmpNotifyRowStatus; |
| |
| default: |
| ERROR_MSG(""); |
| } |
| #endif /* !NETSNMP_NO_READ_SUPPORT */ |
| return NULL; |
| } |
| |
| static int |
| is_delim(const char c) |
| { |
| return (c == 0x020 || c == 0x09 || c == 0x0d || c == 0x0b); |
| } |
| |
| int |
| snmpTagValid(const char *tag, const size_t tagLen) |
| { |
| size_t i = 0; |
| |
| |
| for (i = 0; i < tagLen; i++) { |
| if (is_delim(tag[i])) { |
| /* |
| * Delimeters aren't allowed. |
| */ |
| return 0; |
| } |
| } |
| return 1; |
| } |
| |
| static struct snmpNotifyTable_data *StorageNew; |
| |
| #ifndef NETSNMP_NO_WRITE_SUPPORT |
| |
| int |
| write_snmpNotifyTag(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| static char *tmpvar; |
| struct snmpNotifyTable_data *StorageTmp = NULL; |
| static size_t tmplen; |
| size_t newlen = |
| name_len - (sizeof(snmpNotifyTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| |
| DEBUGMSGTL(("snmpNotifyTable", |
| "write_snmpNotifyTag entering action=%d... \n", action)); |
| if (action != RESERVE1 && |
| (StorageTmp = (struct snmpNotifyTable_data *) |
| header_complex((struct header_complex_index *) |
| snmpNotifyTableStorage, NULL, |
| &name[sizeof(snmpNotifyTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) { |
| if ((StorageTmp = StorageNew) == NULL) |
| return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ |
| } |
| |
| |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_OCTET_STR) { |
| return SNMP_ERR_WRONGTYPE; |
| } |
| if (var_val_len > 255) { |
| return SNMP_ERR_WRONGLENGTH; |
| } |
| if (!snmpTagValid((char *) var_val, var_val_len)) { |
| return SNMP_ERR_WRONGVALUE; |
| } |
| break; |
| |
| |
| case RESERVE2: |
| /* |
| * memory reseveration, final preparation... |
| */ |
| tmpvar = StorageTmp->snmpNotifyTag; |
| tmplen = StorageTmp->snmpNotifyTagLen; |
| StorageTmp->snmpNotifyTag = (char*)calloc(1, var_val_len + 1); |
| if (NULL == StorageTmp->snmpNotifyTag) |
| return SNMP_ERR_RESOURCEUNAVAILABLE; |
| break; |
| |
| |
| case FREE: |
| /* |
| * Release any resources that have been allocated |
| */ |
| break; |
| |
| |
| case ACTION: |
| memcpy(StorageTmp->snmpNotifyTag, var_val, var_val_len); |
| StorageTmp->snmpNotifyTagLen = var_val_len; |
| break; |
| |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| SNMP_FREE(StorageTmp->snmpNotifyTag); |
| StorageTmp->snmpNotifyTag = tmpvar; |
| StorageTmp->snmpNotifyTagLen = tmplen; |
| tmpvar = NULL; |
| break; |
| |
| |
| case COMMIT: |
| /* |
| * Things are working well, so it's now safe to make the change |
| * permanently. Make sure that anything done here can't fail! |
| */ |
| SNMP_FREE(tmpvar); |
| snmp_store_needed(NULL); |
| break; |
| } |
| |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| |
| int |
| write_snmpNotifyType(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| static int tmpvar; |
| struct snmpNotifyTable_data *StorageTmp = NULL; |
| long value = *((long *) var_val); |
| size_t newlen = |
| name_len - (sizeof(snmpNotifyTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| |
| DEBUGMSGTL(("snmpNotifyTable", |
| "write_snmpNotifyType entering action=%d... \n", action)); |
| if (action != RESERVE1 && |
| (StorageTmp = (struct snmpNotifyTable_data *) |
| header_complex((struct header_complex_index *) |
| snmpNotifyTableStorage, NULL, |
| &name[sizeof(snmpNotifyTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) { |
| if ((StorageTmp = StorageNew) == NULL) |
| return SNMP_ERR_NOSUCHNAME; |
| } |
| |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_INTEGER) { |
| return SNMP_ERR_WRONGTYPE; |
| } |
| if (var_val_len != sizeof(long)) { |
| return SNMP_ERR_WRONGLENGTH; |
| } |
| if (value < 1 || value > 2) { |
| return SNMP_ERR_WRONGVALUE; |
| } |
| break; |
| |
| case ACTION: |
| tmpvar = StorageTmp->snmpNotifyType; |
| StorageTmp->snmpNotifyType = value; |
| break; |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| StorageTmp->snmpNotifyType = tmpvar; |
| break; |
| } |
| |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| |
| int |
| write_snmpNotifyStorageType(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| static int tmpvar; |
| long value = *((long *) var_val); |
| struct snmpNotifyTable_data *StorageTmp = NULL; |
| size_t newlen = |
| name_len - (sizeof(snmpNotifyTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| |
| DEBUGMSGTL(("snmpNotifyTable", |
| "write_snmpNotifyStorageType entering action=%d... \n", |
| action)); |
| if (action != RESERVE1 && |
| (StorageTmp = (struct snmpNotifyTable_data *) |
| header_complex((struct header_complex_index *) |
| snmpNotifyTableStorage, NULL, |
| &name[sizeof(snmpNotifyTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) { |
| if ((StorageTmp = StorageNew) == NULL) |
| return SNMP_ERR_NOSUCHNAME; |
| } |
| |
| |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_INTEGER) { |
| return SNMP_ERR_WRONGTYPE; |
| } |
| if (var_val_len != sizeof(long)) { |
| return SNMP_ERR_WRONGLENGTH; |
| } |
| if (value != SNMP_STORAGE_OTHER && value != SNMP_STORAGE_VOLATILE |
| && value != SNMP_STORAGE_NONVOLATILE) { |
| return SNMP_ERR_WRONGVALUE; |
| } |
| break; |
| |
| case ACTION: |
| tmpvar = StorageTmp->snmpNotifyStorageType; |
| StorageTmp->snmpNotifyStorageType = value; |
| break; |
| |
| case UNDO: |
| StorageTmp->snmpNotifyStorageType = tmpvar; |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| |
| int |
| write_snmpNotifyRowStatus(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| struct snmpNotifyTable_data *StorageTmp = NULL; |
| static struct snmpNotifyTable_data *StorageDel; |
| size_t newlen = |
| name_len - (sizeof(snmpNotifyTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| static int old_value; |
| int set_value = *((long *) var_val); |
| static netsnmp_variable_list *vars, *vp; |
| struct header_complex_index *hciptr; |
| |
| |
| DEBUGMSGTL(("snmpNotifyTable", |
| "write_snmpNotifyRowStatus entering action=%d... \n", |
| action)); |
| StorageTmp = (struct snmpNotifyTable_data *) |
| header_complex((struct header_complex_index *) |
| snmpNotifyTableStorage, NULL, |
| &name[sizeof(snmpNotifyTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, NULL); |
| |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_INTEGER || var_val == NULL) { |
| return SNMP_ERR_WRONGTYPE; |
| } |
| if (var_val_len != sizeof(long)) { |
| return SNMP_ERR_WRONGLENGTH; |
| } |
| if (set_value < 1 || set_value > 6 || set_value == RS_NOTREADY) { |
| return SNMP_ERR_WRONGVALUE; |
| } |
| if (StorageTmp == NULL) { |
| /* |
| * create the row now? |
| */ |
| /* |
| * ditch illegal values now |
| */ |
| if (set_value == RS_ACTIVE || set_value == RS_NOTINSERVICE) { |
| return SNMP_ERR_INCONSISTENTVALUE; |
| } |
| } else { |
| /* |
| * row exists. Check for a valid state change |
| */ |
| if (set_value == RS_CREATEANDGO |
| || set_value == RS_CREATEANDWAIT) { |
| /* |
| * can't create a row that exists |
| */ |
| return SNMP_ERR_INCONSISTENTVALUE; |
| } |
| /* |
| * XXX: interaction with row storage type needed |
| */ |
| } |
| |
| /* |
| * memory reseveration, final preparation... |
| */ |
| if (StorageTmp == NULL && |
| (set_value == RS_CREATEANDGO |
| || set_value == RS_CREATEANDWAIT)) { |
| /* |
| * creation |
| */ |
| vars = NULL; |
| |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_PRIV_IMPLIED_OCTET_STR, NULL, 0); /* snmpNotifyName */ |
| |
| if (header_complex_parse_oid |
| (& |
| (name |
| [sizeof(snmpNotifyTable_variables_oid) / sizeof(oid) + |
| 2]), newlen, vars) != SNMPERR_SUCCESS) { |
| /* |
| * XXX: free, zero vars |
| */ |
| snmp_free_var(vars); |
| return SNMP_ERR_INCONSISTENTNAME; |
| } |
| vp = vars; |
| |
| |
| StorageNew = SNMP_MALLOC_STRUCT(snmpNotifyTable_data); |
| if (StorageNew == NULL) { |
| return SNMP_ERR_RESOURCEUNAVAILABLE; |
| } |
| StorageNew->snmpNotifyName = (char*)calloc( 1, vp->val_len + 1 ); |
| if (StorageNew->snmpNotifyName == NULL) { |
| return SNMP_ERR_RESOURCEUNAVAILABLE; |
| } |
| memcpy(StorageNew->snmpNotifyName, vp->val.string, vp->val_len); |
| StorageNew->snmpNotifyNameLen = vp->val_len; |
| vp = vp->next_variable; |
| |
| /* |
| * default values |
| */ |
| StorageNew->snmpNotifyStorageType = ST_NONVOLATILE; |
| StorageNew->snmpNotifyType = SNMPNOTIFYTYPE_TRAP; |
| StorageNew->snmpNotifyTagLen = 0; |
| StorageNew->snmpNotifyTag = (char *) calloc(sizeof(char), 1); |
| if (StorageNew->snmpNotifyTag == NULL) { |
| return SNMP_ERR_RESOURCEUNAVAILABLE; |
| } |
| |
| StorageNew->snmpNotifyRowStatus = set_value; |
| snmp_free_var(vars); |
| } |
| break; |
| |
| case RESERVE2: |
| break; |
| |
| case FREE: |
| if (StorageNew != NULL) { |
| SNMP_FREE(StorageNew->snmpNotifyTag); |
| SNMP_FREE(StorageNew->snmpNotifyName); |
| free(StorageNew); |
| StorageNew = NULL; |
| } |
| break; |
| |
| case ACTION: |
| if (StorageTmp == NULL && (set_value == RS_CREATEANDGO || |
| set_value == RS_CREATEANDWAIT)) { |
| /* |
| * row creation, so add it |
| */ |
| if (StorageNew != NULL) { |
| snmpNotifyTable_add(StorageNew); |
| } |
| } else if (set_value != RS_DESTROY) { |
| /* |
| * set the flag? |
| */ |
| if (StorageTmp == NULL) |
| return SNMP_ERR_GENERR; /* should never ever get here */ |
| |
| old_value = StorageTmp->snmpNotifyRowStatus; |
| StorageTmp->snmpNotifyRowStatus = *((long *) var_val); |
| } else { |
| /* |
| * destroy... extract it for now |
| */ |
| if (StorageTmp) { |
| hciptr = header_complex_find_entry(snmpNotifyTableStorage, |
| StorageTmp); |
| StorageDel = (struct snmpNotifyTable_data *) |
| header_complex_extract_entry((struct |
| header_complex_index **) |
| &snmpNotifyTableStorage, |
| hciptr); |
| } |
| } |
| break; |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| if (StorageTmp == NULL && (set_value == RS_CREATEANDGO || |
| set_value == RS_CREATEANDWAIT)) { |
| /* |
| * row creation, so remove it again |
| */ |
| hciptr = header_complex_find_entry(snmpNotifyTableStorage, |
| StorageNew); |
| StorageDel = (struct snmpNotifyTable_data *) |
| header_complex_extract_entry((struct header_complex_index |
| **) &snmpNotifyTableStorage, |
| hciptr); |
| /* |
| * XXX: free it |
| */ |
| } else if (StorageDel != NULL) { |
| /* |
| * row deletion, so add it again |
| */ |
| snmpNotifyTable_add(StorageDel); |
| } else if (set_value != RS_DESTROY) { |
| if (StorageTmp) |
| StorageTmp->snmpNotifyRowStatus = old_value; |
| } |
| break; |
| |
| case COMMIT: |
| if (StorageDel != NULL) { |
| SNMP_FREE(StorageDel->snmpNotifyTag); |
| SNMP_FREE(StorageDel->snmpNotifyName); |
| free(StorageDel); |
| StorageDel = NULL; |
| } |
| if (StorageTmp |
| && StorageTmp->snmpNotifyRowStatus == RS_CREATEANDGO) { |
| StorageTmp->snmpNotifyRowStatus = RS_ACTIVE; |
| StorageNew = NULL; |
| } else if (StorageTmp && |
| StorageTmp->snmpNotifyRowStatus == RS_CREATEANDWAIT) { |
| StorageTmp->snmpNotifyRowStatus = RS_NOTINSERVICE; |
| StorageNew = NULL; |
| } |
| snmp_store_needed(NULL); |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| #endif /* !NETSNMP_NO_WRITE_SUPPORT */ |