/* * DisMan Event MIB: * Implementation of the event table configure handling */ #include #include #include #include #include #include "disman/event/mteObjects.h" #include "disman/event/mteEvent.h" #include "disman/event/mteEventConf.h" netsnmp_feature_require(iquery) /** Initializes the mteEventsConf module */ void init_mteEventConf(void) { init_event_table_data(); /* * Register config handlers for user-level (fixed) events.... */ snmpd_register_config_handler("notificationEvent", parse_notificationEvent, NULL, "eventname notifyOID [-m] [-i OID|-o OID]*"); snmpd_register_config_handler("setEvent", parse_setEvent, NULL, "eventname [-I] OID = value"); netsnmp_ds_register_config(ASN_BOOLEAN, netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE), "strictDisman", NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_STRICT_DISMAN); /* * ... and for persistent storage of dynamic event table entries. * * (The previous implementation didn't store these entries, * so we don't need to worry about backwards compatability) */ snmpd_register_config_handler("_mteETable", parse_mteETable, NULL, NULL); snmpd_register_config_handler("_mteENotTable", parse_mteENotTable, NULL, NULL); snmpd_register_config_handler("_mteESetTable", parse_mteESetTable, NULL, NULL); /* * Register to save (non-fixed) entries when the agent shuts down */ snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, store_mteETable, NULL); snmp_register_callback(SNMP_CALLBACK_APPLICATION, SNMPD_CALLBACK_PRE_UPDATE_CONFIG, clear_mteETable, NULL); } /* ============================== * * utility routines * * ============================== */ /* * Find or create the specified event entry */ static struct mteEvent * _find_mteEvent_entry( const char *owner, const char *ename ) { netsnmp_variable_list owner_var, ename_var; netsnmp_tdata_row *row; /* * If there's already an existing entry, * then use that... */ memset(&owner_var, 0, sizeof(netsnmp_variable_list)); memset(&ename_var, 0, sizeof(netsnmp_variable_list)); snmp_set_var_typed_value(&owner_var, ASN_OCTET_STR, owner, strlen(owner)); snmp_set_var_typed_value(&ename_var, ASN_PRIV_IMPLIED_OCTET_STR, ename, strlen(ename)); owner_var.next_variable = &ename_var; row = netsnmp_tdata_row_get_byidx( event_table_data, &owner_var ); /* * ... otherwise, create a new one */ if (!row) row = mteEvent_createEntry( owner, ename, 0 ); if (!row) return NULL; /* return (struct mteEvent *)netsnmp_tdata_row_entry( row ); */ return (struct mteEvent *)row->data; } static struct mteEvent * _find_typed_mteEvent_entry( const char *owner, const char *ename, int type ) { struct mteEvent *entry = _find_mteEvent_entry( owner, ename ); if (!entry) return NULL; /* * If this is an existing (i.e. valid) entry of the * same type, then throw an error and discard it. * But allow combined Set/Notification events. */ if ( entry && (entry->flags & MTE_EVENT_FLAG_VALID) && (entry->mteEventActions & type )) { config_perror("error: duplicate event name"); return NULL; } return entry; } /* ============================== * * User-configured (static) events * * ============================== */ void parse_notificationEvent( const char *token, char *line ) { char ename[MTE_STR1_LEN+1]; char buf[SPRINT_MAX_LEN]; oid name_buf[MAX_OID_LEN]; size_t name_buf_len; struct mteEvent *entry; struct mteObject *object; int wild = 1; int idx = 0; char *cp; #ifndef NETSNMP_DISABLE_MIB_LOADING struct tree *tp; #endif struct varbind_list *var; DEBUGMSGTL(("disman:event:conf", "Parsing notificationEvent config\n")); /* * The event name could be used directly to index the mteObjectsTable. * But it's quite possible that the same name could also be used to * set up a mteTriggerTable entry (with trigger-specific objects). * * To avoid such a clash, we'll add a prefix ("_E"). */ memset(ename, 0, sizeof(ename)); ename[0] = '_'; ename[1] = 'E'; cp = copy_nword(line, ename+2, MTE_STR1_LEN-2); if (!cp || ename[2] == '\0') { config_perror("syntax error: no event name"); return; } /* * Parse the notification OID field ... */ cp = copy_nword(cp, buf, SPRINT_MAX_LEN); if ( buf[0] == '\0' ) { config_perror("syntax error: no notification OID"); return; } name_buf_len = MAX_OID_LEN; if (!snmp_parse_oid(buf, name_buf, &name_buf_len)) { snmp_log(LOG_ERR, "notificationEvent OID: %s\n", buf); config_perror("unknown notification OID"); return; } /* * ... and the relevant object/instances. */ if ( cp && *cp=='-' && *(cp+1)=='m' ) { #ifdef NETSNMP_DISABLE_MIB_LOADING config_perror("Can't use -m if MIB loading is disabled"); return; #else /* * Use the MIB definition to add the standard * notification payload to the mteObjectsTable. */ cp = skip_token( cp ); tp = get_tree( name_buf, name_buf_len, get_tree_head()); if (!tp) { config_perror("Can't locate notification payload info"); return; } for (var = tp->varbinds; var; var=var->next) { idx++; object = mteObjects_addOID( "snmpd.conf", ename, idx, var->vblabel, wild ); idx = object->mteOIndex; } #endif } while (cp) { if ( *cp == '-' ) { switch (*(cp+1)) { case 'm': config_perror("-m option must come first"); return; case 'i': /* exact instance */ case 'w': /* "not-wild" (backward compatability) */ wild = 0; break; case 'o': /* wildcarded object */ wild = 1; break; default: config_perror("unrecognised option"); return; } cp = skip_token( cp ); if (!cp) { config_perror("missing parameter"); return; } } idx++; cp = copy_nword(cp, buf, SPRINT_MAX_LEN); object = mteObjects_addOID( "snmpd.conf", ename, idx, buf, wild ); idx = object->mteOIndex; wild = 1; /* default to wildcarded objects */ } /* * If the entry has parsed successfully, then create, * populate and activate the new event entry. */ entry = _find_typed_mteEvent_entry("snmpd.conf", ename+2, MTE_EVENT_NOTIFICATION); if (!entry) { mteObjects_removeEntries( "snmpd.conf", ename ); return; } entry->mteNotification_len = name_buf_len; memcpy( entry->mteNotification, name_buf, name_buf_len*sizeof(oid)); memcpy( entry->mteNotifyOwner, "snmpd.conf", 10 ); memcpy( entry->mteNotifyObjects, ename, MTE_STR1_LEN ); entry->mteEventActions |= MTE_EVENT_NOTIFICATION; entry->flags |= MTE_EVENT_FLAG_ENABLED | MTE_EVENT_FLAG_ACTIVE | MTE_EVENT_FLAG_FIXED | MTE_EVENT_FLAG_VALID; return; } void parse_setEvent( const char *token, char *line ) { char ename[MTE_STR1_LEN+1]; char buf[SPRINT_MAX_LEN]; oid name_buf[MAX_OID_LEN]; size_t name_buf_len; long value; int wild = 1; struct mteEvent *entry; char *cp; DEBUGMSGTL(("disman:event:conf", "Parsing setEvent config... ")); memset( ename, 0, sizeof(ename)); cp = copy_nword(line, ename, MTE_STR1_LEN); if (!cp || ename[0] == '\0') { config_perror("syntax error: no event name"); return; } if (cp && *cp=='-' && *(cp+1)=='I') { wild = 0; /* an instance assignment */ cp = skip_token( cp ); } /* * Parse the SET assignment in the form "OID = value" */ cp = copy_nword(cp, buf, SPRINT_MAX_LEN); if ( buf[0] == '\0' ) { config_perror("syntax error: no set OID"); return; } name_buf_len = MAX_OID_LEN; if (!snmp_parse_oid(buf, name_buf, &name_buf_len)) { snmp_log(LOG_ERR, "setEvent OID: %s\n", buf); config_perror("unknown set OID"); return; } if (cp && *cp == '=') { cp = skip_token( cp ); /* skip the '=' assignment character */ } if (!cp) { config_perror("syntax error: missing set value"); return; } value = strtol( cp, NULL, 0); /* * If the entry has parsed successfully, then create, * populate and activate the new event entry. */ entry = _find_typed_mteEvent_entry("snmpd.conf", ename, MTE_EVENT_SET); if (!entry) { return; } memcpy( entry->mteSetOID, name_buf, name_buf_len*sizeof(oid)); entry->mteSetOID_len = name_buf_len; entry->mteSetValue = value; if (wild) entry->flags |= MTE_SET_FLAG_OBJWILD; entry->mteEventActions |= MTE_EVENT_SET; entry->flags |= MTE_EVENT_FLAG_ENABLED | MTE_EVENT_FLAG_ACTIVE | MTE_EVENT_FLAG_FIXED | MTE_EVENT_FLAG_VALID; return; } /* ============================== * * Persistent (dynamic) configuration * * ============================== */ void parse_mteETable(const char *token, char *line ) { char owner[MTE_STR1_LEN+1]; char ename[MTE_STR1_LEN+1]; void *vp; size_t tmp; size_t len; struct mteEvent *entry; DEBUGMSGTL(("disman:event:conf", "Parsing mteEventTable config... ")); /* * Read in the index information for this entry * and create a (non-fixed) data structure for it. */ memset( owner, 0, sizeof(owner)); memset( ename, 0, sizeof(ename)); len = MTE_STR1_LEN; vp = owner; line = read_config_read_data(ASN_OCTET_STR, line, &vp, &len); len = MTE_STR1_LEN; vp = ename; line = read_config_read_data(ASN_OCTET_STR, line, &vp, &len); entry = _find_mteEvent_entry( owner, ename ); DEBUGMSG(("disman:event:conf", "(%s, %s) ", owner, ename)); /* * Read in the accessible (event-independent) column values. */ len = MTE_STR2_LEN; vp = entry->mteEventComment; line = read_config_read_data(ASN_OCTET_STR, line, &vp, &len); /* * Skip the mteEventAction field, and note that the * boolean values are combined into a single field. */ line = read_config_read_data(ASN_UNSIGNED, line, &tmp, NULL); entry->flags |= (tmp & (MTE_EVENT_FLAG_ENABLED|MTE_EVENT_FLAG_ACTIVE)); /* * XXX - Will need to read in the 'iquery' access information */ entry->flags |= MTE_EVENT_FLAG_VALID; DEBUGMSG(("disman:event:conf", "\n")); } void parse_mteENotTable(const char *token, char *line) { char owner[MTE_STR1_LEN+1]; char ename[MTE_STR1_LEN+1]; void *vp; size_t len; struct mteEvent *entry; DEBUGMSGTL(("disman:event:conf", "Parsing mteENotifyTable config... ")); /* * Read in the index information for this entry * and create a (non-fixed) data structure for it. */ memset( owner, 0, sizeof(owner)); memset( ename, 0, sizeof(ename)); len = MTE_STR1_LEN; vp = owner; line = read_config_read_data(ASN_OCTET_STR, line, &vp, &len); len = MTE_STR1_LEN; vp = ename; line = read_config_read_data(ASN_OCTET_STR, line, &vp, &len); entry = _find_mteEvent_entry( owner, ename ); DEBUGMSG(("disman:event:conf", "(%s, %s) ", owner, ename)); /* * Read in the accessible column values. */ vp = entry->mteNotification; line = read_config_read_data(ASN_OBJECT_ID, line, &vp, &entry->mteNotification_len); len = MTE_STR1_LEN; vp = entry->mteNotifyOwner; line = read_config_read_data(ASN_OCTET_STR, line, &vp, &len); len = MTE_STR1_LEN; vp = entry->mteNotifyObjects; line = read_config_read_data(ASN_OCTET_STR, line, &vp, &len); entry->mteEventActions |= MTE_EVENT_NOTIFICATION; entry->flags |= MTE_EVENT_FLAG_VALID; DEBUGMSG(("disman:event:conf", "\n")); } void parse_mteESetTable(const char *token, char *line) { char owner[MTE_STR1_LEN+1]; char ename[MTE_STR1_LEN+1]; void *vp; size_t len; struct mteEvent *entry; DEBUGMSGTL(("disman:event:conf", "Parsing mteESetTable config... ")); /* * Read in the index information for this entry * and create a (non-fixed) data structure for it. */ memset( owner, 0, sizeof(owner)); memset( ename, 0, sizeof(ename)); len = MTE_STR1_LEN; vp = owner; line = read_config_read_data(ASN_OCTET_STR, line, &vp, &len); len = MTE_STR1_LEN; vp = ename; line = read_config_read_data(ASN_OCTET_STR, line, &vp, &len); entry = _find_mteEvent_entry( owner, ename ); DEBUGMSG(("disman:event:conf", "(%s, %s) ", owner, ename)); /* * Read in the accessible column values. */ vp = entry->mteSetOID; line = read_config_read_data(ASN_OBJECT_ID, line, &vp, &entry->mteSetOID_len); line = read_config_read_data(ASN_UNSIGNED, line, &entry->mteSetValue, &len); len = MTE_STR2_LEN; vp = entry->mteSetTarget; line = read_config_read_data(ASN_OCTET_STR, line, &vp, &len); len = MTE_STR2_LEN; vp = entry->mteSetContext; line = read_config_read_data(ASN_OCTET_STR, line, &vp, &len); entry->mteEventActions |= MTE_EVENT_SET; entry->flags |= MTE_EVENT_FLAG_VALID; DEBUGMSG(("disman:event:conf", "\n")); } int store_mteETable(int majorID, int minorID, void *serverarg, void *clientarg) { char line[SNMP_MAXBUF]; char *cptr, *cp; void *vp; size_t tint; netsnmp_tdata_row *row; struct mteEvent *entry; DEBUGMSGTL(("disman:event:conf", "Storing mteEventTable config:\n")); for (row = netsnmp_tdata_row_first( event_table_data ); row; row = netsnmp_tdata_row_next( event_table_data, row )) { /* * Skip entries that were set up via static config directives */ entry = (struct mteEvent *)netsnmp_tdata_row_entry( row ); if ( entry->flags & MTE_EVENT_FLAG_FIXED ) continue; DEBUGMSGTL(("disman:event:conf", " Storing (%s %s)\n", entry->mteOwner, entry->mteEName)); /* * Save the basic mteEventTable entry... */ memset(line, 0, sizeof(line)); strcat(line, "_mteETable "); cptr = line + strlen(line); cp = entry->mteOwner; tint = strlen( cp ); cptr = read_config_store_data( ASN_OCTET_STR, cptr, &cp, &tint ); cp = entry->mteEName; tint = strlen( cp ); cptr = read_config_store_data( ASN_OCTET_STR, cptr, &cp, &tint ); cp = entry->mteEventComment; tint = strlen( cp ); cptr = read_config_store_data( ASN_OCTET_STR, cptr, &cp, &tint ); /* ... (but skip the mteEventAction field)... */ tint = entry->flags & (MTE_EVENT_FLAG_ENABLED|MTE_EVENT_FLAG_ACTIVE); cptr = read_config_store_data( ASN_UNSIGNED, cptr, &tint, NULL ); /* XXX - Need to store the 'iquery' access information */ snmpd_store_config(line); /* * ... then save Notify and/or Set entries separately * (The mteEventAction bits will be set when these are read in). */ if ( entry->mteEventActions & MTE_EVENT_NOTIFICATION ) { memset(line, 0, sizeof(line)); strcat(line, "_mteENotTable "); cptr = line + strlen(line); cp = entry->mteOwner; tint = strlen( cp ); cptr = read_config_store_data(ASN_OCTET_STR, cptr, &cp, &tint ); cp = entry->mteEName; tint = strlen( cp ); cptr = read_config_store_data(ASN_OCTET_STR, cptr, &cp, &tint ); vp = entry->mteNotification; cptr = read_config_store_data(ASN_OBJECT_ID, cptr, &vp, &entry->mteNotification_len); cp = entry->mteNotifyOwner; tint = strlen( cp ); cptr = read_config_store_data(ASN_OCTET_STR, cptr, &cp, &tint ); cp = entry->mteNotifyObjects; tint = strlen( cp ); cptr = read_config_store_data(ASN_OCTET_STR, cptr, &cp, &tint ); snmpd_store_config(line); } if ( entry->mteEventActions & MTE_EVENT_SET ) { memset(line, 0, sizeof(line)); strcat(line, "_mteESetTable "); cptr = line + strlen(line); cp = entry->mteOwner; tint = strlen( cp ); cptr = read_config_store_data(ASN_OCTET_STR, cptr, &cp, &tint ); cp = entry->mteEName; tint = strlen( cp ); cptr = read_config_store_data(ASN_OCTET_STR, cptr, &cp, &tint ); vp = entry->mteSetOID; cptr = read_config_store_data(ASN_OBJECT_ID, cptr, &vp, &entry->mteSetOID_len); tint = entry->mteSetValue; cptr = read_config_store_data(ASN_INTEGER, cptr, &tint, NULL); cp = entry->mteSetTarget; tint = strlen( cp ); cptr = read_config_store_data(ASN_OCTET_STR, cptr, &cp, &tint ); cp = entry->mteSetContext; tint = strlen( cp ); cptr = read_config_store_data(ASN_OCTET_STR, cptr, &cp, &tint ); tint = entry->flags & (MTE_SET_FLAG_OBJWILD|MTE_SET_FLAG_CTXWILD); cptr = read_config_store_data(ASN_UNSIGNED, cptr, &tint, NULL); snmpd_store_config(line); } } DEBUGMSGTL(("disman:event:conf", " done.\n")); return SNMPERR_SUCCESS; } int clear_mteETable(int majorID, int minorID, void *serverarg, void *clientarg) { netsnmp_tdata_row *row; netsnmp_variable_list owner_var; /* * We're only interested in entries set up via the config files */ memset( &owner_var, 0, sizeof(netsnmp_variable_list)); snmp_set_var_typed_value( &owner_var, ASN_OCTET_STR, "snmpd.conf", strlen("snmpd.conf")); while (( row = netsnmp_tdata_row_next_byidx( event_table_data, &owner_var ))) { /* * XXX - check for owner of "snmpd.conf" * and break at the end of these */ netsnmp_tdata_remove_and_delete_row( event_table_data, row ); } return SNMPERR_SUCCESS; }