extend.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:50k
- #include <net-snmp/net-snmp-config.h>
- #include <net-snmp/net-snmp-includes.h>
- #include <net-snmp/agent/net-snmp-agent-includes.h>
- #include <net-snmp/agent/watcher.h>
- #include "agent/extend.h"
- #include "utilities/execute.h"
- #include "struct.h"
- #ifndef USING_UCD_SNMP_EXTENSIBLE_MODULE
- #include "util_funcs.h"
- #include "mibdefs.h"
- #define SHELLCOMMAND 3
- #endif
- oid ns_extend_oid[] = { 1, 3, 6, 1, 4, 1, 8072, 1, 3, 2 };
- oid extend_count_oid[] = { 1, 3, 6, 1, 4, 1, 8072, 1, 3, 2, 1 };
- oid extend_config_oid[] = { 1, 3, 6, 1, 4, 1, 8072, 1, 3, 2, 2 };
- oid extend_out1_oid[] = { 1, 3, 6, 1, 4, 1, 8072, 1, 3, 2, 3 };
- oid extend_out2_oid[] = { 1, 3, 6, 1, 4, 1, 8072, 1, 3, 2, 4 };
- typedef struct extend_registration_block_s {
- netsnmp_table_data *dinfo;
- oid *root_oid;
- size_t oid_len;
- long num_entries;
- netsnmp_extend *ehead;
- struct extend_registration_block_s *next;
- } extend_registration_block;
- extend_registration_block *ereg_head = NULL;
- #ifndef USING_UCD_SNMP_EXTENSIBLE_MODULE
- typedef struct netsnmp_old_extend_s {
- int idx;
- netsnmp_extend *exec_entry;
- netsnmp_extend *efix_entry;
- } netsnmp_old_extend;
- int num_compatability_entries = 0;
- int max_compatability_entries = 50;
- netsnmp_old_extend *compatability_entries;
- WriteMethod fixExec2Error;
- FindVarMethod var_extensible_old;
- oid old_extensible_variables_oid[] = { UCDAVIS_MIB, SHELLMIBNUM, 1 };
- struct variable2 old_extensible_variables[] = {
- {MIBINDEX, ASN_INTEGER, RONLY, var_extensible_old, 1, {MIBINDEX}},
- {ERRORNAME, ASN_OCTET_STR, RONLY, var_extensible_old, 1, {ERRORNAME}},
- {SHELLCOMMAND, ASN_OCTET_STR, RONLY, var_extensible_old, 1, {SHELLCOMMAND}},
- {ERRORFLAG, ASN_INTEGER, RONLY, var_extensible_old, 1, {ERRORFLAG}},
- {ERRORMSG, ASN_OCTET_STR, RONLY, var_extensible_old, 1, {ERRORMSG}},
- {ERRORFIX, ASN_INTEGER, RWRITE, var_extensible_old, 1, {ERRORFIX}},
- {ERRORFIXCMD, ASN_OCTET_STR, RONLY, var_extensible_old, 1, {ERRORFIXCMD}}
- };
- #endif
- /*************************
- *
- * Main initialisation routine
- *
- *************************/
- extend_registration_block *
- _find_extension_block( oid *name, size_t name_len )
- {
- extend_registration_block *eptr;
- size_t len;
- for ( eptr=ereg_head; eptr; eptr=eptr->next ) {
- len = SNMP_MIN(name_len, eptr->oid_len);
- if (!snmp_oid_compare( name, len, eptr->root_oid, eptr->oid_len))
- return eptr;
- }
- return NULL;
- }
- extend_registration_block *
- _register_extend( oid *base, size_t len )
- {
- extend_registration_block *eptr;
- oid oid_buf[MAX_OID_LEN];
- netsnmp_table_data *dinfo;
- netsnmp_table_registration_info *tinfo;
- netsnmp_watcher_info *winfo;
- netsnmp_handler_registration *reg;
- for ( eptr=ereg_head; eptr; eptr=eptr->next ) {
- if (!snmp_oid_compare( base, len, eptr->root_oid, eptr->oid_len))
- return eptr;
- }
- if (!eptr) {
- eptr = SNMP_MALLOC_TYPEDEF( extend_registration_block );
- eptr->root_oid = snmp_duplicate_objid( base, len );
- eptr->oid_len = len;
- eptr->num_entries = 0;
- eptr->ehead = NULL;
- eptr->dinfo = netsnmp_create_table_data( "nsExtendTable" );
- eptr->next = ereg_head;
- ereg_head = eptr;
- }
- dinfo = eptr->dinfo;
- memcpy( oid_buf, base, len*sizeof(oid) );
- /*
- * Register the configuration table
- */
- tinfo = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info );
- netsnmp_table_helper_add_indexes( tinfo, ASN_OCTET_STR, 0 );
- tinfo->min_column = COLUMN_EXTCFG_FIRST_COLUMN;
- tinfo->max_column = COLUMN_EXTCFG_LAST_COLUMN;
- oid_buf[len] = 2;
- reg = netsnmp_create_handler_registration(
- "nsExtendConfigTable", handle_nsExtendConfigTable,
- oid_buf, len+1, HANDLER_CAN_RWRITE);
- netsnmp_register_table_data( reg, dinfo, tinfo );
- /*
- * Register the main output table
- * using the same table_data handle.
- * This is sufficient to link the two tables,
- * and implement the AUGMENTS behaviour
- */
- tinfo = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info );
- netsnmp_table_helper_add_indexes( tinfo, ASN_OCTET_STR, 0 );
- tinfo->min_column = COLUMN_EXTOUT1_FIRST_COLUMN;
- tinfo->max_column = COLUMN_EXTOUT1_LAST_COLUMN;
- oid_buf[len] = 3;
- reg = netsnmp_create_handler_registration(
- "nsExtendOut1Table", handle_nsExtendOutput1Table,
- oid_buf, len+1, HANDLER_CAN_RONLY);
- netsnmp_register_table_data( reg, dinfo, tinfo );
- /*
- * Register the multi-line output table
- * using a simple table helper.
- * This handles extracting the indexes from
- * the request OID, but leaves most of
- * the work to our handler routine.
- * Still, it was nice while it lasted...
- */
- tinfo = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info );
- netsnmp_table_helper_add_indexes( tinfo, ASN_OCTET_STR, ASN_INTEGER, 0 );
- tinfo->min_column = COLUMN_EXTOUT2_FIRST_COLUMN;
- tinfo->max_column = COLUMN_EXTOUT2_LAST_COLUMN;
- oid_buf[len] = 4;
- reg = netsnmp_create_handler_registration(
- "nsExtendOut2Table", handle_nsExtendOutput2Table,
- oid_buf, len+1, HANDLER_CAN_RONLY);
- netsnmp_register_table( reg, tinfo );
- /*
- * Register a watched scalar to keep track of the number of entries
- */
- oid_buf[len] = 1;
- reg = netsnmp_create_handler_registration(
- "nsExtendNumEntries", NULL,
- oid_buf, len+1, HANDLER_CAN_RONLY);
- winfo = netsnmp_create_watcher_info(
- &(eptr->num_entries), sizeof(eptr->num_entries),
- ASN_INTEGER, WATCHER_FIXED_SIZE);
- netsnmp_register_watched_scalar( reg, winfo );
- return eptr;
- }
- void init_extend( void )
- {
- snmpd_register_config_handler("extend", extend_parse_config, NULL, NULL);
- snmpd_register_config_handler("extend-sh", extend_parse_config, NULL, NULL);
- snmpd_register_config_handler("extendfix", extend_parse_config, NULL, NULL);
- snmpd_register_config_handler("exec2", extend_parse_config, NULL, NULL);
- snmpd_register_config_handler("sh2", extend_parse_config, NULL, NULL);
- snmpd_register_config_handler("execFix2", extend_parse_config, NULL, NULL);
- (void)_register_extend( ns_extend_oid, OID_LENGTH(ns_extend_oid));
- #ifndef USING_UCD_SNMP_EXTENSIBLE_MODULE
- snmpd_register_config_handler("exec", extend_parse_config, NULL, NULL);
- snmpd_register_config_handler("sh", extend_parse_config, NULL, NULL);
- snmpd_register_config_handler("execFix", extend_parse_config, NULL, NULL);
- compatability_entries = calloc( max_compatability_entries,
- sizeof(netsnmp_old_extend));
- REGISTER_MIB("ucd-extensible", old_extensible_variables,
- variable2, old_extensible_variables_oid);
- #endif
- }
- /*************************
- *
- * Cached-data hooks
- * see 'cache_handler' helper
- *
- *************************/
- int
- extend_load_cache(netsnmp_cache *cache, void *magic)
- {
- int out_len = 1024*100;
- char out_buf[ 1024*100 ];
- int cmd_len = 255*2 + 2; /* 2 * DisplayStrings */
- char cmd_buf[ 255*2 + 2 ];
- int ret;
- char *cp;
- char *line_buf[ 1024 ];
- netsnmp_extend *extension = (netsnmp_extend *)magic;
- if (!magic)
- return -1;
- DEBUGMSGTL(( "nsExtendTable:cache", "load %s", extension->token ));
- if ( extension->args )
- snprintf( cmd_buf, cmd_len, "%s %s", extension->command, extension->args );
- else
- snprintf( cmd_buf, cmd_len, "%s", extension->command );
- if ( extension->flags & NS_EXTEND_FLAGS_SHELL )
- ret = run_shell_command( cmd_buf, extension->input, out_buf, &out_len);
- else
- ret = run_exec_command( cmd_buf, extension->input, out_buf, &out_len);
- DEBUGMSG(( "nsExtendTable:cache", ": %s : %dn", cmd_buf, ret));
- if (ret >= 0) {
- if (out_buf[ out_len-1 ] == 'n')
- out_buf[ --out_len ] = ' '; /* Stomp on trailing newline */
- extension->output = strdup( out_buf );
- extension->out_len = out_len;
- /*
- * Now we need to pick the output apart into separate lines.
- * Start by counting how many lines we've got, and keeping
- * track of where each line starts in a static buffer
- */
- extension->numlines = 1;
- line_buf[ 0 ] = extension->output;
- for (cp=extension->output; *cp; cp++) {
- if (*cp == 'n') {
- line_buf[ extension->numlines++ ] = cp+1;
- }
- }
- if ( extension->numlines > 1 ) {
- extension->lines = calloc( sizeof(char *), extension->numlines );
- memcpy( extension->lines, line_buf,
- sizeof(char *) * extension->numlines );
- }
- }
- extension->result = ret;
- return ret;
- }
- void
- extend_free_cache(netsnmp_cache *cache, void *magic)
- {
- netsnmp_extend *extension = (netsnmp_extend *)magic;
- if (!magic)
- return;
- DEBUGMSGTL(( "nsExtendTable:cache", "free %sn", extension->token ));
- if (extension->output) {
- SNMP_FREE(extension->output);
- extension->output = NULL;
- }
- if (extension->lines) {
- SNMP_FREE(extension->lines);
- extension->lines = NULL;
- }
- extension->out_len = 0;
- extension->numlines = 0;
- }
- /*************************
- *
- * Utility routines for setting up a new entry
- * (either via SET requests, or the config file)
- *
- *************************/
- void
- _free_extension( netsnmp_extend *extension, extend_registration_block *ereg )
- {
- netsnmp_extend *eptr = NULL;
- netsnmp_extend *eprev = NULL;
- if (!extension)
- return;
- if (ereg) {
- /* Unlink from 'ehead' list */
- for (eptr=ereg->ehead; eptr; eptr=eptr->next) {
- if (eptr == extension)
- break;
- eprev = eptr;
- }
- if (eprev)
- eprev->next = eptr->next;
- else
- ereg->ehead = eptr->next;
- }
- netsnmp_table_data_remove_and_delete_row( ereg->dinfo, extension->row);
- SNMP_FREE( extension->token );
- SNMP_FREE( extension->cache );
- SNMP_FREE( extension->command );
- SNMP_FREE( extension->args );
- SNMP_FREE( extension->input );
- SNMP_FREE( extension );
- return;
- }
- netsnmp_extend *
- _new_extension( char *exec_name, int exec_flags, extend_registration_block *ereg )
- {
- netsnmp_extend *extension;
- netsnmp_table_row *row;
- netsnmp_extend *eptr1, *eptr2;
- netsnmp_table_data *dinfo = ereg->dinfo;
- if (!exec_name)
- return NULL;
- extension = SNMP_MALLOC_TYPEDEF( netsnmp_extend );
- if (!extension)
- return NULL;
- extension->token = strdup( exec_name );
- extension->flags = exec_flags;
- extension->cache = netsnmp_cache_create( 0, extend_load_cache,
- extend_free_cache, NULL, 0 );
- if (extension->cache)
- extension->cache->magic = extension;
- row = netsnmp_create_table_data_row();
- if (!row || !extension->cache) {
- _free_extension( extension, ereg );
- SNMP_FREE( row );
- return NULL;
- }
- row->data = (void *)extension;
- extension->row = row;
- netsnmp_table_row_add_index( row, ASN_OCTET_STR,
- exec_name, strlen(exec_name));
- netsnmp_table_data_add_row( dinfo, row);
- ereg->num_entries++;
- /*
- * Now add this structure to a private linked list.
- * We don't need this for the main tables - the
- * 'table_data' helper will take care of those.
- * But it's probably easier to handle the multi-line
- * output table ourselves, for which we need access
- * to the underlying data.
- * So we'll keep a list internally as well.
- */
- for ( eptr1 = ereg->ehead, eptr2 = NULL;
- eptr1;
- eptr2 = eptr1, eptr1 = eptr1->next ) {
- if (strlen( eptr1->token ) > strlen( exec_name ))
- break;
- if (strlen( eptr1->token ) == strlen( exec_name ) &&
- strcmp( eptr1->token, exec_name ) > 0 )
- break;
- }
- if ( eptr2 )
- eptr2->next = extension;
- else
- ereg->ehead = extension;
- extension->next = eptr1;
- return extension;
- }
- void
- extend_parse_config(const char *token, char *cptr)
- {
- netsnmp_extend *extension;
- char exec_name[STRMAX];
- char exec_command[STRMAX];
- oid oid_buf[MAX_OID_LEN];
- size_t oid_len;
- extend_registration_block *eptr;
- int flags;
- cptr = copy_nword(cptr, exec_name, sizeof(exec_name));
- if ( *exec_name == '.' ) {
- oid_len = MAX_OID_LEN;
- read_objid( exec_name, oid_buf, &oid_len );
- cptr = copy_nword(cptr, exec_name, sizeof(exec_name));
- } else {
- memcpy( oid_buf, ns_extend_oid, sizeof(ns_extend_oid));
- oid_len = OID_LENGTH(ns_extend_oid);
- }
- cptr = copy_nword(cptr, exec_command, sizeof(exec_command));
- /* XXX - check 'exec_command' exists & is executable */
- flags = (NS_EXTEND_FLAGS_ACTIVE | NS_EXTEND_FLAGS_CONFIG);
- if (!strcmp( token, "sh" ) ||
- !strcmp( token, "extend-sh" ) ||
- !strcmp( token, "sh2" ))
- flags |= NS_EXTEND_FLAGS_SHELL;
- if (!strcmp( token, "execFix" ) ||
- !strcmp( token, "extendfix" ) ||
- !strcmp( token, "execFix2" )) {
- strcat( exec_name, "Fix" );
- flags |= NS_EXTEND_FLAGS_WRITEABLE;
- /* XXX - Check for shell... */
- }
- eptr = _register_extend( oid_buf, oid_len );
- extension = _new_extension( exec_name, flags, eptr );
- if (extension) {
- extension->command = strdup( exec_command );
- if (cptr)
- extension->args = strdup( cptr );
- }
- #ifndef USING_UCD_SNMP_EXTENSIBLE_MODULE
- /*
- * Compatability with the UCD extTable
- */
- if (!strcmp( token, "execFix" )) {
- int i;
- for ( i=0; i < num_compatability_entries; i++ ) {
- if (!strcmp( exec_name,
- compatability_entries[i].exec_entry->token))
- break;
- }
- if ( i == num_compatability_entries )
- config_perror("No matching exec entry" );
- else
- compatability_entries[ i ].efix_entry = extension;
-
- } else if (!strcmp( token, "sh" ) ||
- !strcmp( token, "exec" )) {
- if ( num_compatability_entries == max_compatability_entries )
- /* XXX - should really use dynamic allocation */
- config_perror("No further UCD-compatible entries" );
- else
- compatability_entries[
- num_compatability_entries++ ].exec_entry = extension;
- }
- #endif
- }
- /*************************
- *
- * Main table handlers
- * Most of the work is handled
- * by the 'table_data' helper.
- *
- *************************/
- int
- handle_nsExtendConfigTable(netsnmp_mib_handler *handler,
- netsnmp_handler_registration *reginfo,
- netsnmp_agent_request_info *reqinfo,
- netsnmp_request_info *requests)
- {
- netsnmp_request_info *request;
- netsnmp_table_request_info *table_info;
- netsnmp_extend *extension;
- extend_registration_block *eptr;
- int i;
- int need_to_validate = 0;
- for ( request=requests; request; request=request->next ) {
- if (request->processed)
- continue;
- table_info = netsnmp_extract_table_info( request );
- extension = (netsnmp_extend*)netsnmp_extract_table_row_data( request );
- DEBUGMSGTL(( "nsExtendTable:config", "varbind: "));
- DEBUGMSGOID(("nsExtendTable:config", request->requestvb->name,
- request->requestvb->name_length));
- DEBUGMSG(( "nsExtendTable:config", " (%s)n",
- se_find_label_in_slist("agent_mode", reqinfo->mode)));
- switch (reqinfo->mode) {
- case MODE_GET:
- switch (table_info->colnum) {
- case COLUMN_EXTCFG_COMMAND:
- snmp_set_var_typed_value(
- request->requestvb, ASN_OCTET_STR,
- extension->command,
- (extension->command)?strlen(extension->command):0);
- break;
- case COLUMN_EXTCFG_ARGS:
- snmp_set_var_typed_value(
- request->requestvb, ASN_OCTET_STR,
- extension->args,
- (extension->args)?strlen(extension->args):0);
- break;
- case COLUMN_EXTCFG_INPUT:
- snmp_set_var_typed_value(
- request->requestvb, ASN_OCTET_STR,
- extension->input,
- (extension->input)?strlen(extension->input):0);
- break;
- case COLUMN_EXTCFG_CACHETIME:
- snmp_set_var_typed_value(
- request->requestvb, ASN_INTEGER,
- (u_char*)&extension->cache->timeout, sizeof(int));
- break;
- case COLUMN_EXTCFG_EXECTYPE:
- i = ((extension->flags & NS_EXTEND_FLAGS_SHELL) ?
- NS_EXTEND_ETYPE_SHELL :
- NS_EXTEND_ETYPE_EXEC);
- snmp_set_var_typed_value(
- request->requestvb, ASN_INTEGER,
- (u_char*)&i, sizeof(i));
- break;
- case COLUMN_EXTCFG_RUNTYPE:
- i = ((extension->flags & NS_EXTEND_FLAGS_WRITEABLE) ?
- NS_EXTEND_RTYPE_RWRITE :
- NS_EXTEND_RTYPE_RONLY);
- snmp_set_var_typed_value(
- request->requestvb, ASN_INTEGER,
- (u_char*)&i, sizeof(i));
- break;
- case COLUMN_EXTCFG_STORAGE:
- i = ((extension->flags & NS_EXTEND_FLAGS_CONFIG) ?
- ST_PERMANENT : ST_VOLATILE);
- snmp_set_var_typed_value(
- request->requestvb, ASN_INTEGER,
- (u_char*)&i, sizeof(i));
- break;
- case COLUMN_EXTCFG_STATUS:
- i = ((extension->flags & NS_EXTEND_FLAGS_ACTIVE) ?
- RS_ACTIVE :
- RS_NOTINSERVICE);
- snmp_set_var_typed_value(
- request->requestvb, ASN_INTEGER,
- (u_char*)&i, sizeof(i));
- break;
- default:
- netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT);
- continue;
- }
- break;
- /**********
- *
- * Start of SET handling
- *
- * All config objects are potentially writable except
- * nsExtendStorage which is fixed as either 'permanent'
- * (if read from a config file) or 'volatile' (if set via SNMP)
- * The string-based settings of a 'permanent' entry cannot
- * be changed - neither can the execution or run type.
- * Such entries can be (temporarily) marked as inactive,
- * and the cache timeout adjusted, but these changes are
- * not persistent.
- *
- **********/
- case MODE_SET_RESERVE1:
- /*
- * Validate the new assignments
- */
- switch (table_info->colnum) {
- case COLUMN_EXTCFG_COMMAND:
- if (request->requestvb->type != ASN_OCTET_STR) {
- netsnmp_set_request_error(reqinfo, request,
- SNMP_ERR_WRONGTYPE);
- return SNMP_ERR_WRONGTYPE;
- }
- /*
- * Must have a full path to the command
- * XXX - Assumes Unix-style paths
- */
- if (request->requestvb->val_len == 0 ||
- request->requestvb->val.string[0] != '/') {
- netsnmp_set_request_error(reqinfo, request,
- SNMP_ERR_WRONGVALUE);
- return SNMP_ERR_WRONGVALUE;
- }
- /*
- * XXX - need to check this file exists
- * (and is executable)
- */
- if (extension && extension->flags & NS_EXTEND_FLAGS_CONFIG) {
- /*
- * config entries are "permanent" so can't be changed
- */
- netsnmp_set_request_error(reqinfo, request,
- SNMP_ERR_NOTWRITABLE);
- return SNMP_ERR_NOTWRITABLE;
- }
- break;
- case COLUMN_EXTCFG_ARGS:
- case COLUMN_EXTCFG_INPUT:
- if (request->requestvb->type != ASN_OCTET_STR) {
- netsnmp_set_request_error(reqinfo, request,
- SNMP_ERR_WRONGTYPE);
- return SNMP_ERR_WRONGTYPE;
- }
- if (extension && extension->flags & NS_EXTEND_FLAGS_CONFIG) {
- /*
- * config entries are "permanent" so can't be changed
- */
- netsnmp_set_request_error(reqinfo, request,
- SNMP_ERR_NOTWRITABLE);
- return SNMP_ERR_NOTWRITABLE;
- }
- break;
- case COLUMN_EXTCFG_CACHETIME:
- if (request->requestvb->type != ASN_INTEGER) {
- netsnmp_set_request_error(reqinfo, request,
- SNMP_ERR_WRONGTYPE);
- return SNMP_ERR_WRONGTYPE;
- }
- i = *request->requestvb->val.integer;
- /*
- * -1 is a special value indicating "don't cache"
- * [[ XXX - should this be 0 ?? ]]
- * Otherwise, cache times must be non-negative
- */
- if (i < -1 ) {
- netsnmp_set_request_error(reqinfo, request,
- SNMP_ERR_WRONGVALUE);
- return SNMP_ERR_WRONGVALUE;
- }
- break;
- case COLUMN_EXTCFG_EXECTYPE:
- if (request->requestvb->type != ASN_INTEGER) {
- netsnmp_set_request_error(reqinfo, request,
- SNMP_ERR_WRONGTYPE);
- return SNMP_ERR_WRONGTYPE;
- }
- i = *request->requestvb->val.integer;
- if (i<1 || i>2) { /* 'exec(1)' or 'shell(2)' only */
- netsnmp_set_request_error(reqinfo, request,
- SNMP_ERR_WRONGVALUE);
- return SNMP_ERR_WRONGVALUE;
- }
- if (extension && extension->flags & NS_EXTEND_FLAGS_CONFIG) {
- /*
- * config entries are "permanent" so can't be changed
- */
- netsnmp_set_request_error(reqinfo, request,
- SNMP_ERR_NOTWRITABLE);
- return SNMP_ERR_NOTWRITABLE;
- }
- break;
- case COLUMN_EXTCFG_RUNTYPE:
- if (request->requestvb->type != ASN_INTEGER) {
- netsnmp_set_request_error(reqinfo, request,
- SNMP_ERR_WRONGTYPE);
- return SNMP_ERR_WRONGTYPE;
- }
- /*
- * 'run-on-read(1)', 'run-on-set(2)'
- * or 'run-command(3)' only
- */
- i = *request->requestvb->val.integer;
- if (i<1 || i>3) {
- netsnmp_set_request_error(reqinfo, request,
- SNMP_ERR_WRONGVALUE);
- return SNMP_ERR_WRONGVALUE;
- }
- /*
- * 'run-command(3)' can only be used with
- * a pre-existing 'run-on-set(2)' entry.
- */
- if (i==3 && !(extension && (extension->flags & NS_EXTEND_FLAGS_WRITEABLE))) {
- netsnmp_set_request_error(reqinfo, request,
- SNMP_ERR_INCONSISTENTVALUE);
- return SNMP_ERR_INCONSISTENTVALUE;
- }
- /*
- * 'run-command(3)' is the only valid assignment
- * for permanent (i.e. config) entries
- */
- if ((extension && extension->flags & NS_EXTEND_FLAGS_CONFIG)
- && i!=3 ) {
- netsnmp_set_request_error(reqinfo, request,
- SNMP_ERR_INCONSISTENTVALUE);
- return SNMP_ERR_INCONSISTENTVALUE;
- }
- break;
- case COLUMN_EXTCFG_STATUS:
- if (request->requestvb->type != ASN_INTEGER) {
- netsnmp_set_request_error(reqinfo, request,
- SNMP_ERR_WRONGTYPE);
- return SNMP_ERR_WRONGTYPE;
- }
- i = *request->requestvb->val.integer;
- switch (i) {
- case RS_ACTIVE:
- case RS_NOTINSERVICE:
- if (!extension) {
- /* Must be used with existing rows */
- netsnmp_set_request_error(reqinfo, request,
- SNMP_ERR_INCONSISTENTVALUE);
- return SNMP_ERR_INCONSISTENTVALUE;
- }
- break; /* OK */
- case RS_CREATEANDGO:
- case RS_CREATEANDWAIT:
- if (extension) {
- /* Can only be used to create new rows */
- netsnmp_set_request_error(reqinfo, request,
- SNMP_ERR_INCONSISTENTVALUE);
- return SNMP_ERR_INCONSISTENTVALUE;
- }
- break;
- case RS_DESTROY:
- break;
- default:
- netsnmp_set_request_error(reqinfo, request,
- SNMP_ERR_WRONGVALUE);
- return SNMP_ERR_WRONGVALUE;
- }
- break;
- default:
- netsnmp_set_request_error(reqinfo, request,
- SNMP_ERR_NOTWRITABLE);
- return SNMP_ERR_NOTWRITABLE;
- }
- break;
- case MODE_SET_RESERVE2:
- switch (table_info->colnum) {
- case COLUMN_EXTCFG_STATUS:
- i = *request->requestvb->val.integer;
- switch (i) {
- case RS_CREATEANDGO:
- case RS_CREATEANDWAIT:
- eptr = _find_extension_block( request->requestvb->name,
- request->requestvb->name_length );
- extension = _new_extension( table_info->indexes->val.string,
- 0, eptr );
- if (!extension) { /* failed */
- netsnmp_set_request_error(reqinfo, request,
- SNMP_ERR_RESOURCEUNAVAILABLE);
- return SNMP_ERR_RESOURCEUNAVAILABLE;
- }
- netsnmp_insert_table_row( request, extension->row );
- }
- }
- break;
- case MODE_SET_FREE:
- switch (table_info->colnum) {
- case COLUMN_EXTCFG_STATUS:
- i = *request->requestvb->val.integer;
- switch (i) {
- case RS_CREATEANDGO:
- case RS_CREATEANDWAIT:
- eptr = _find_extension_block( request->requestvb->name,
- request->requestvb->name_length );
- _free_extension( extension, eptr );
- }
- }
- break;
- case MODE_SET_ACTION:
- switch (table_info->colnum) {
- case COLUMN_EXTCFG_COMMAND:
- extension->old_command = extension->command;
- extension->command = netsnmp_strdup_and_null(
- request->requestvb->val.string,
- request->requestvb->val_len);
- break;
- case COLUMN_EXTCFG_ARGS:
- extension->old_args = extension->args;
- extension->args = netsnmp_strdup_and_null(
- request->requestvb->val.string,
- request->requestvb->val_len);
- break;
- case COLUMN_EXTCFG_INPUT:
- extension->old_input = extension->input;
- extension->input = netsnmp_strdup_and_null(
- request->requestvb->val.string,
- request->requestvb->val_len);
- break;
- case COLUMN_EXTCFG_STATUS:
- i = *request->requestvb->val.integer;
- switch (i) {
- case RS_ACTIVE:
- case RS_CREATEANDGO:
- need_to_validate = 1;
- }
- break;
- }
- break;
- case MODE_SET_UNDO:
- switch (table_info->colnum) {
- case COLUMN_EXTCFG_COMMAND:
- if ( extension && extension->old_command ) {
- SNMP_FREE(extension->command);
- extension->command = extension->old_command;
- extension->old_command = NULL;
- }
- break;
- case COLUMN_EXTCFG_ARGS:
- if ( extension && extension->old_args ) {
- SNMP_FREE(extension->args);
- extension->args = extension->old_args;
- extension->old_args = NULL;
- }
- break;
- case COLUMN_EXTCFG_INPUT:
- if ( extension && extension->old_input ) {
- SNMP_FREE(extension->input);
- extension->input = extension->old_input;
- extension->old_input = NULL;
- }
- break;
- case COLUMN_EXTCFG_STATUS:
- i = *request->requestvb->val.integer;
- switch (i) {
- case RS_CREATEANDGO:
- case RS_CREATEANDWAIT:
- eptr = _find_extension_block( request->requestvb->name,
- request->requestvb->name_length );
- _free_extension( extension, eptr );
- }
- break;
- }
- break;
- case MODE_SET_COMMIT:
- switch (table_info->colnum) {
- case COLUMN_EXTCFG_CACHETIME:
- i = *request->requestvb->val.integer;
- extension->cache->timeout = i;
- break;
- case COLUMN_EXTCFG_RUNTYPE:
- i = *request->requestvb->val.integer;
- switch (i) {
- case 1:
- extension->flags &= ~NS_EXTEND_FLAGS_WRITEABLE;
- break;
- case 2:
- extension->flags |= NS_EXTEND_FLAGS_WRITEABLE;
- break;
- case 3:
- (void)netsnmp_cache_check_and_reload( extension->cache );
- break;
- }
- break;
- case COLUMN_EXTCFG_EXECTYPE:
- i = *request->requestvb->val.integer;
- if ( i == NS_EXTEND_ETYPE_SHELL )
- extension->flags |= NS_EXTEND_FLAGS_SHELL;
- else
- extension->flags &= ~NS_EXTEND_FLAGS_SHELL;
- break;
- case COLUMN_EXTCFG_STATUS:
- i = *request->requestvb->val.integer;
- switch (i) {
- case RS_ACTIVE:
- case RS_CREATEANDGO:
- extension->flags |= NS_EXTEND_FLAGS_ACTIVE;
- break;
- case RS_NOTINSERVICE:
- case RS_CREATEANDWAIT:
- extension->flags &= ~NS_EXTEND_FLAGS_ACTIVE;
- break;
- case RS_DESTROY:
- eptr = _find_extension_block( request->requestvb->name,
- request->requestvb->name_length );
- _free_extension( extension, eptr );
- break;
- }
- }
- break;
- default:
- netsnmp_set_request_error(reqinfo, request, SNMP_ERR_GENERR);
- return SNMP_ERR_GENERR;
- }
- }
- /*
- * If we're marking a given row as active,
- * then we need to check that it's ready.
- */
- if (need_to_validate) {
- for ( request=requests; request; request=request->next ) {
- if (request->processed)
- continue;
- table_info = netsnmp_extract_table_info( request );
- extension = (netsnmp_extend*)netsnmp_extract_table_row_data( request );
- switch (table_info->colnum) {
- case COLUMN_EXTCFG_STATUS:
- i = *request->requestvb->val.integer;
- if (( i == RS_ACTIVE || i == RS_CREATEANDGO ) &&
- !(extension && extension->command &&
- extension->command[0] == '/' /* &&
- is_executable(extension->command) */)) {
- netsnmp_set_request_error(reqinfo, request,
- SNMP_ERR_INCONSISTENTVALUE);
- return SNMP_ERR_INCONSISTENTVALUE;
- }
- }
- }
- }
- return SNMP_ERR_NOERROR;
- }
- int
- handle_nsExtendOutput1Table(netsnmp_mib_handler *handler,
- netsnmp_handler_registration *reginfo,
- netsnmp_agent_request_info *reqinfo,
- netsnmp_request_info *requests)
- {
- netsnmp_request_info *request;
- netsnmp_table_request_info *table_info;
- netsnmp_extend *extension;
- int len;
- for ( request=requests; request; request=request->next ) {
- if (request->processed)
- continue;
- table_info = netsnmp_extract_table_info( request );
- extension = (netsnmp_extend*)netsnmp_extract_table_row_data( request );
- DEBUGMSGTL(( "nsExtendTable:output1", "varbind: "));
- DEBUGMSGOID(("nsExtendTable:output1", request->requestvb->name,
- request->requestvb->name_length));
- DEBUGMSG(( "nsExtendTable:output1", "n"));
- switch (reqinfo->mode) {
- case MODE_GET:
- if (!extension || !(extension->flags & NS_EXTEND_FLAGS_ACTIVE)) {
- /*
- * If this row is inactive, then skip it.
- */
- netsnmp_set_request_error(reqinfo, request,
- SNMP_NOSUCHINSTANCE);
- continue;
- }
- if (!(extension->flags & NS_EXTEND_FLAGS_WRITEABLE) &&
- (netsnmp_cache_check_and_reload( extension->cache ) < 0 )) {
- /*
- * If reloading the output cache of a 'run-on-read'
- * entry fails, then skip it.
- */
- netsnmp_set_request_error(reqinfo, request,
- SNMP_NOSUCHINSTANCE);
- continue;
- }
- if ((extension->flags & NS_EXTEND_FLAGS_WRITEABLE) &&
- (netsnmp_cache_check_expired( extension->cache ) == 1 )) {
- /*
- * If the output cache of a 'run-on-write'
- * entry has expired, then skip it.
- */
- netsnmp_set_request_error(reqinfo, request,
- SNMP_NOSUCHINSTANCE);
- continue;
- }
- switch (table_info->colnum) {
- case COLUMN_EXTOUT1_OUTLEN:
- snmp_set_var_typed_value(
- request->requestvb, ASN_INTEGER,
- (u_char*)&extension->out_len, sizeof(int));
- break;
- case COLUMN_EXTOUT1_OUTPUT1:
- /*
- * If we've got more than one line,
- * find the length of the first one.
- * Otherwise find the length of the whole string.
- */
- if (extension->lines) {
- len = (extension->lines[1])-(extension->output) -1;
- } else if (extension->output) {
- len = strlen(extension->output);
- } else {
- len = 0;
- }
- snmp_set_var_typed_value(
- request->requestvb, ASN_OCTET_STR,
- extension->output, len);
- break;
- case COLUMN_EXTOUT1_OUTPUT2:
- snmp_set_var_typed_value(
- request->requestvb, ASN_OCTET_STR,
- extension->output,
- (extension->output)?strlen(extension->output):0);
- break;
- case COLUMN_EXTOUT1_NUMLINES:
- snmp_set_var_typed_value(
- request->requestvb, ASN_INTEGER,
- (u_char*)&extension->numlines, sizeof(int));
- break;
- case COLUMN_EXTOUT1_RESULT:
- snmp_set_var_typed_value(
- request->requestvb, ASN_INTEGER,
- (u_char*)&extension->result, sizeof(int));
- break;
- default:
- netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT);
- continue;
- }
- break;
- default:
- netsnmp_set_request_error(reqinfo, request, SNMP_ERR_GENERR);
- return SNMP_ERR_GENERR;
- }
- }
- return SNMP_ERR_NOERROR;
- }
- /*************************
- *
- * Multi-line output table handler
- * Most of the work is handled here.
- *
- *************************/
- /*
- * Locate the appropriate entry for a given request
- */
- netsnmp_extend *
- _extend_find_entry( netsnmp_request_info *request,
- netsnmp_table_request_info *table_info,
- int mode )
- {
- netsnmp_extend *eptr;
- extend_registration_block *ereg;
- int line_idx;
- oid oid_buf[MAX_OID_LEN];
- int oid_len;
- int i;
- char *token;
- if (!request || !table_info || !table_info->indexes
- || !table_info->indexes->next_variable) {
- DEBUGMSGTL(( "nsExtendTable:output2", "invalid invocationn"));
- return NULL;
- }
- ereg = _find_extension_block( request->requestvb->name,
- request->requestvb->name_length );
- /***
- * GET handling - find the exact entry being requested
- ***/
- if ( mode == MODE_GET ) {
- DEBUGMSGTL(( "nsExtendTable:output2", "GET: %s / %dn ",
- table_info->indexes->val.string,
- *table_info->indexes->next_variable->val.integer));
- for ( eptr = ereg->ehead; eptr; eptr = eptr->next ) {
- if ( !strcmp( eptr->token, table_info->indexes->val.string ))
- break;
- }
- if ( eptr ) {
- /*
- * Ensure the output is available...
- */
- if (!(eptr->flags & NS_EXTEND_FLAGS_ACTIVE) ||
- (netsnmp_cache_check_and_reload( eptr->cache ) < 0 ))
- return NULL;
- /*
- * ...and check the line requested is valid
- */
- line_idx = *table_info->indexes->next_variable->val.integer;
- if (eptr->numlines < line_idx)
- return NULL;
- }
- return eptr;
- }
- /***
- * GETNEXT handling - find the first suitable entry
- ***/
- else {
- if (!table_info->indexes->val_len ) {
- DEBUGMSGTL(( "nsExtendTable:output2", "GETNEXT: first entryn"));
- /*
- * Beginning of the table - find the first active
- * (and successful) entry, and use the first line of it
- */
- for (eptr = ereg->ehead; eptr; eptr = eptr->next ) {
- if ((eptr->flags & NS_EXTEND_FLAGS_ACTIVE) &&
- (netsnmp_cache_check_and_reload( eptr->cache ) >= 0 )) {
- line_idx = 1;
- break;
- }
- }
- } else {
- token = table_info->indexes->val.string,
- line_idx = *table_info->indexes->next_variable->val.integer;
- DEBUGMSGTL(( "nsExtendTable:output2", "GETNEXT: %s / %dn ",
- token, line_idx ));
- /*
- * Otherwise, find the first entry not earlier
- * than the requested token...
- */
- for (eptr = ereg->ehead; eptr; eptr = eptr->next ) {
- if ( strlen(eptr->token) > strlen( token ))
- break;
- if ( strlen(eptr->token) == strlen( token ) &&
- strcmp(eptr->token, token) >= 0 )
- break;
- }
- if (!eptr)
- return NULL; /* (assuming there is one) */
- /*
- * ... and make sure it's active & the output is available
- * (or use the first following entry that is)
- */
- for ( ; eptr; eptr = eptr->next ) {
- if ((eptr->flags & NS_EXTEND_FLAGS_ACTIVE) &&
- (netsnmp_cache_check_and_reload( eptr->cache ) >= 0 )) {
- break;
- }
- line_idx = 1;
- }
- /*
- * If we're working with the same entry that was requested,
- * see whether we've reached the end of the output...
- */
- if (!strcmp( eptr->token, token )) {
- if ( eptr->numlines <= line_idx ) {
- /*
- * ... and if so, move on to the first line
- * of the next (active and successful) entry.
- */
- line_idx = 1;
- for (eptr = eptr->next ; eptr; eptr = eptr->next ) {
- if ((eptr->flags & NS_EXTEND_FLAGS_ACTIVE) &&
- (netsnmp_cache_check_and_reload( eptr->cache ) >= 0 )) {
- break;
- }
- }
- } else {
- /*
- * Otherwise just use the next line of this entry.
- */
- line_idx++;
- }
- }
- }
- if (eptr) {
- DEBUGMSGTL(( "nsExtendTable:output2", "GETNEXT -> %s / %dn ",
- eptr->token, line_idx));
- /*
- * Since we're processing a GETNEXT request,
- * now we've found the appropriate entry (and line),
- * we need to update the varbind OID ...
- */
- memcpy( oid_buf, extend_out2_oid, sizeof(extend_out2_oid));
- oid_len = OID_LENGTH(extend_out2_oid);
- oid_buf[ oid_len++ ] = 1; /* nsExtendOutput2Entry */
- oid_buf[ oid_len++ ] = COLUMN_EXTOUT2_OUTLINE;
- /* string token index */
- oid_buf[ oid_len++ ] = strlen(eptr->token);
- for ( i=0; i < (int)strlen(eptr->token); i++ )
- oid_buf[ oid_len+i ] = eptr->token[i];
- oid_len += strlen( eptr->token );
- /* plus line number */
- oid_buf[ oid_len++ ] = line_idx;
- snmp_set_var_objid( request->requestvb, oid_buf, oid_len );
- /*
- * ... and index values to match.
- */
- snmp_set_var_value( table_info->indexes,
- eptr->token, strlen(eptr->token));
- *table_info->indexes->next_variable->val.integer = line_idx;
- }
- return eptr; /* Finally, signal success */
- }
- return NULL;
- }
- /*
- * Multi-line output handler
- * Locate the appropriate entry (using _extend_find_entry)
- * and return the appropriate output line
- */
- int
- handle_nsExtendOutput2Table(netsnmp_mib_handler *handler,
- netsnmp_handler_registration *reginfo,
- netsnmp_agent_request_info *reqinfo,
- netsnmp_request_info *requests)
- {
- netsnmp_request_info *request;
- netsnmp_table_request_info *table_info;
- netsnmp_extend *extension;
- char *cp;
- int line_idx;
- int len;
- for ( request=requests; request; request=request->next ) {
- if (request->processed)
- continue;
- table_info = netsnmp_extract_table_info( request );
- extension = _extend_find_entry( request, table_info, reqinfo->mode );
- DEBUGMSGTL(( "nsExtendTable:output2", "varbind: "));
- DEBUGMSGOID(("nsExtendTable:output2", request->requestvb->name,
- request->requestvb->name_length));
- DEBUGMSG(( "nsExtendTable:output2", " (%s)n",
- (extension) ? extension->token : "[none]"));
- if (!extension) {
- if (reqinfo->mode == MODE_GET)
- netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE);
- else
- netsnmp_set_request_error(reqinfo, request, SNMP_ENDOFMIBVIEW);
- continue;
- }
- switch (reqinfo->mode) {
- case MODE_GET:
- case MODE_GETNEXT:
- switch (table_info->colnum) {
- case COLUMN_EXTOUT2_OUTLINE:
- /*
- * Determine which line we've been asked for....
- */
- line_idx = *table_info->indexes->next_variable->val.integer;
- if (extension->lines)
- cp = extension->lines[line_idx-1];
- else
- cp = extension->output;
- /*
- * ... and how long it is.
- */
- if ( extension->numlines > line_idx )
- len = (extension->lines[line_idx])-cp -1;
- else if (cp)
- len = strlen(cp);
- else
- len = 0;
- snmp_set_var_typed_value( request->requestvb,
- ASN_OCTET_STR, cp, len );
- break;
- default:
- netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT);
- continue;
- }
- break;
- default:
- netsnmp_set_request_error(reqinfo, request, SNMP_ERR_GENERR);
- return SNMP_ERR_GENERR;
- }
- }
- return SNMP_ERR_NOERROR;
- }
- #ifndef USING_UCD_SNMP_EXTENSIBLE_MODULE
- /*************************
- *
- * Compatability with the UCD extTable
- *
- *************************/
- u_char *
- var_extensible_old(struct variable * vp,
- oid * name,
- size_t * length,
- int exact,
- size_t * var_len, WriteMethod ** write_method)
- {
- netsnmp_old_extend *exten = NULL;
- static long long_ret;
- int idx;
- if (header_simple_table
- (vp, name, length, exact, var_len, write_method, num_compatability_entries))
- return (NULL);
- idx = name[*length-1] -1;
- exten = &compatability_entries[ idx ];
- if (exten) {
- switch (vp->magic) {
- case MIBINDEX:
- long_ret = name[*length - 1];
- return ((u_char *) (&long_ret));
- case ERRORNAME: /* name defined in config file */
- *var_len = strlen(exten->exec_entry->token);
- return ((u_char *) (exten->exec_entry->token));
- case SHELLCOMMAND:
- *var_len = strlen(exten->exec_entry->command);
- return ((u_char *) (exten->exec_entry->command));
- case ERRORFLAG: /* return code from the process */
- netsnmp_cache_check_and_reload( exten->exec_entry->cache );
- long_ret = exten->exec_entry->result;
- return ((u_char *) (&long_ret));
- case ERRORMSG: /* first line of text returned from the process */
- netsnmp_cache_check_and_reload( exten->exec_entry->cache );
- if (exten->exec_entry->lines) {
- *var_len = (exten->exec_entry->lines[1])-
- (exten->exec_entry->output) -1;
- } else if (exten->exec_entry->output) {
- *var_len = strlen(exten->exec_entry->output);
- } else {
- *var_len = 0;
- }
- return ((u_char *) (exten->exec_entry->output));
- case ERRORFIX:
- *write_method = fixExec2Error;
- long_return = 0;
- return ((u_char *) &long_return);
- case ERRORFIXCMD:
- if (exten->efix_entry) {
- *var_len = strlen(exten->efix_entry->command);
- return ((u_char *) exten->efix_entry->command);
- } else {
- *var_len = 0;
- return ((u_char *) &long_return); /* Just needs to be non-null! */
- }
- }
- return NULL;
- }
- return NULL;
- }
- int
- fixExec2Error(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)
- {
- netsnmp_old_extend *exten = NULL;
- int idx;
- idx = name[name_len-1] -1;
- exten = &compatability_entries[ idx ];
- switch (action) {
- case MODE_SET_RESERVE1:
- if (var_val_type != ASN_INTEGER) {
- snmp_log(LOG_ERR, "Wrong type != intn");
- return SNMP_ERR_WRONGTYPE;
- }
- idx = *((long *) var_val);
- if (idx != 1) {
- snmp_log(LOG_ERR, "Wrong value != 1n");
- return SNMP_ERR_WRONGVALUE;
- }
- if (!exten || !exten->efix_entry) {
- snmp_log(LOG_ERR, "No command to runn");
- return SNMP_ERR_GENERR;
- }
- return SNMP_ERR_NOERROR;
- case MODE_SET_COMMIT:
- netsnmp_cache_check_and_reload( exten->efix_entry->cache );
- }
- return SNMP_ERR_NOERROR;
- }
- #endif