blob: 24192a651e450e41caf0aad7e583dbda7b16de5c [file] [log] [blame]
/*
* DisMan Event MIB:
* Implementation of the event table configure handling
*/
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-features.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include <net-snmp/agent/agent_callbacks.h>
#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;
}