blob: cd54452deb3293973ef355d3c2a96f65c9ec4885 [file] [log] [blame]
/*
* Note: this file originally auto-generated by mib2c using
* $
*/
#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 <openssl/ssl.h>
#include <openssl/x509.h>
#include <net-snmp/library/cert_util.h>
#include "tlstm-mib.h"
#include "snmpTlstmParamsTable.h"
netsnmp_feature_require(table_tdata)
netsnmp_feature_require(tlstmparams_find)
netsnmp_feature_require(tlstmparams_external)
netsnmp_feature_require(cert_fingerprints)
netsnmp_feature_require(table_tdata_delete_table)
netsnmp_feature_require(table_tdata_extract_table)
netsnmp_feature_require(table_tdata_remove_row)
#ifndef NETSNMP_NO_WRITE_SUPPORT
netsnmp_feature_require(check_vb_storagetype)
netsnmp_feature_require(check_vb_type_and_max_size)
netsnmp_feature_require(check_vb_rowstatus_with_storagetype)
netsnmp_feature_require(table_tdata_insert_row)
#endif /* NETSNMP_NO_WRITE_SUPPORT */
/** XXX - move these to table_data header? */
#define FATE_NEWLY_CREATED 1
#define FATE_NO_CHANGE 0
#define FATE_DELETE_ME -1
/** **************************************************************************
*
* table structures
*
*/
/*
* structure for undo storage and other vars for set processing
*/
typedef struct snmpTlstmParamsTable_undo_s {
char fate;
char copied;
char is_consistent;
netsnmp_request_info *req[SNMPTLSTMPARAMSTABLE_MAX_COLUMN + 1];
/* undo Column space */
char snmpTlstmParamsClientFingerprint[SNMPTLSTMPARAMSCLIENTFINGERPRINT_MAX_SIZE];
size_t snmpTlstmParamsClientFingerprint_len;
char snmpTlstmParamsStorageType;
char snmpTlstmParamsRowStatus;
} snmpTlstmParamsTable_undo;
/*
* Typical data structure for a row entry
*/
typedef struct snmpTlstmParamsTable_entry_s {
/* Index values */
char snmpTargetParamsName[SNMPTARGETPARAMSNAME_MAX_SIZE];
size_t snmpTargetParamsName_len;
/* Column values */
char snmpTlstmParamsClientFingerprint[SNMPTLSTMPARAMSCLIENTFINGERPRINT_MAX_SIZE];
size_t snmpTlstmParamsClientFingerprint_len;
char snmpTlstmParamsStorageType;
char snmpTlstmParamsRowStatus;
char hashType;
char params_flags;
/* used during set processing */
snmpTlstmParamsTable_undo *undo;
} snmpTlstmParamsTable_entry;
static Netsnmp_Node_Handler snmpTlstmParamsTable_handler;
static NetsnmpCacheLoad snmpTlstmParamsTable_load;
static NetsnmpCacheFree snmpTlstmParamsTable_free;
static int _count_handler(netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests);
static void _tlstmParams_init_persistence(void);
static void _params_add(snmpTlstmParamsTable_entry *entry);
static void _params_remove(snmpTlstmParamsTable_entry *entry);
static void _params_tweak_storage(snmpTlstmParamsTable_entry *entry);
static uint32_t _last_changed = 0;
static netsnmp_tdata *_table_data = NULL;
/*
* Initialize the snmpTlstmParamsTable table by defining its contents
* and how it's structured
*/
void
init_snmpTlstmParamsTable(void)
{
oid reg_oid[] = {SNMP_TLS_TM_BASE,2,2,1,6};
const size_t reg_oid_len = OID_LENGTH(reg_oid);
netsnmp_handler_registration *reg;
netsnmp_table_registration_info *table_info;
netsnmp_cache *cache;
netsnmp_watcher_info *watcher;
DEBUGMSGTL(("tlstmParamsTable:init", "initializing table snmpTlstmParamsTable\n"));
reg = netsnmp_create_handler_registration
("snmpTlstmParamsTable", snmpTlstmParamsTable_handler, reg_oid,
reg_oid_len, HANDLER_CAN_RWRITE);
_table_data = netsnmp_tdata_create_table( "snmpTlstmParamsTable", 0 );
if (NULL == _table_data) {
snmp_log(LOG_ERR,"error creating tdata table for snmpTlstmParamsTable\n");
return;
}
cache = netsnmp_cache_create(SNMPTLSTMPARAMSTABLE_TIMEOUT,
snmpTlstmParamsTable_load,
snmpTlstmParamsTable_free,
reg_oid, reg_oid_len);
if (NULL == cache) {
snmp_log(LOG_ERR,"error creating cache for snmpTlstmParamsTable\n");
netsnmp_tdata_delete_table(_table_data);
_table_data = NULL;
return;
}
cache->magic = (void *)_table_data;
cache->flags = NETSNMP_CACHE_DONT_INVALIDATE_ON_SET;
table_info = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info );
if (NULL == table_info) {
snmp_log(LOG_ERR,"error creating table info for snmpTlstmParamsTable\n");
netsnmp_tdata_delete_table(_table_data);
_table_data = NULL;
netsnmp_cache_free(cache);
return;
}
/*
* populate index types
*/
netsnmp_table_helper_add_indexes(table_info,
/* index: snmpTargetParamsName */
ASN_PRIV_IMPLIED_OCTET_STR, 0);
table_info->min_column = SNMPTLSTMPARAMSTABLE_MIN_COLUMN;
table_info->max_column = SNMPTLSTMPARAMSTABLE_MAX_COLUMN;
netsnmp_tdata_register( reg, _table_data, table_info );
netsnmp_inject_handler_before( reg, netsnmp_cache_handler_get(cache),
"table_container");
/*
* register scalars
*/
reg_oid[10] = 4;
reg = netsnmp_create_handler_registration("snmpTlstmParamsCount",
_count_handler, reg_oid,
OID_LENGTH(reg_oid),
HANDLER_CAN_RONLY);
if (NULL == reg)
snmp_log(LOG_ERR,
"could not create handler for snmpTlstmParamsCount\n");
else {
netsnmp_register_scalar(reg);
if (cache)
netsnmp_inject_handler_before(reg,
netsnmp_cache_handler_get(cache),
"snmpTlstmParamsCount");
}
reg_oid[10] = 5;
reg = netsnmp_create_handler_registration(
"snmpTlstmParamsTableLastChanged", NULL, reg_oid,
OID_LENGTH(reg_oid), HANDLER_CAN_RONLY);
watcher = netsnmp_create_watcher_info((void*)&_last_changed,
sizeof(_last_changed),
ASN_TIMETICKS,
WATCHER_FIXED_SIZE);
if ((NULL == reg) || (NULL == watcher))
snmp_log(LOG_ERR,
"could not create handler for snmpTlstmParamsTableLastChanged\n");
else
netsnmp_register_watched_scalar2(reg, watcher);
/*
* Initialise the contents of the table here
*/
_tlstmParams_init_persistence();
}
/** **************************************************************************
*
* utility functions for table structures
*
*/
/* create a new row in the table */
netsnmp_tdata_row *
snmpTlstmParamsTable_createEntry(netsnmp_tdata *table_data,
char* snmpTargetParamsName,
size_t snmpTargetParamsName_len ) {
snmpTlstmParamsTable_entry *entry;
netsnmp_tdata_row *row;
if ((NULL == snmpTargetParamsName) || (snmpTargetParamsName_len >
sizeof(entry->snmpTargetParamsName)))
return NULL;
entry = SNMP_MALLOC_TYPEDEF(snmpTlstmParamsTable_entry);
if (!entry)
return NULL;
row = netsnmp_tdata_create_row();
if (!row) {
SNMP_FREE(entry);
return NULL;
}
row->data = entry;
DEBUGMSGT(("tlstmParamsTable:entry:create", "entry %p / row %p\n",
entry, row));
DEBUGIF("snmpTlstmParamTable:entry:create") {
char name[sizeof(entry->snmpTargetParamsName)+1];
snprintf(name, sizeof(name), "%s", snmpTargetParamsName);
DEBUGMSGT(("tlstmParamsTable:entry:create",
"entry %s %p / row %p\n",
name, entry, row));
}
/*
* populate index
*/
memcpy(entry->snmpTargetParamsName, snmpTargetParamsName,
snmpTargetParamsName_len);
entry->snmpTargetParamsName_len = snmpTargetParamsName_len;
netsnmp_tdata_row_add_index( row, ASN_PRIV_IMPLIED_OCTET_STR,
entry->snmpTargetParamsName,
snmpTargetParamsName_len);
entry->snmpTlstmParamsClientFingerprint[0] = '\0';
entry->snmpTlstmParamsClientFingerprint_len = 0;
entry->snmpTlstmParamsRowStatus = RS_NOTREADY;
entry->snmpTlstmParamsStorageType = ST_NONVOLATILE;
if (table_data) {
DEBUGMSGTL(("tlstmParamsTable:row:insert", "row %p\n",
row));
netsnmp_tdata_add_row( table_data, row );
}
return row;
}
/* allocate undo resources */
static snmpTlstmParamsTable_undo *
_allocUndo(snmpTlstmParamsTable_entry *entry)
{
if (!entry)
return NULL;
entry->undo = SNMP_MALLOC_TYPEDEF(snmpTlstmParamsTable_undo);
if (!entry->undo)
return NULL;
entry->undo->is_consistent = -1; /* don't know */
/* TODO: allocated any other resources needed */
return entry->undo;
}
/* free undo resources */
static void
_freeUndo(snmpTlstmParamsTable_entry *entry)
{
if (!entry || !entry->undo)
return;
/* TODO: release any allocated resources */
SNMP_FREE(entry->undo);
}
/* remove a row from the table */
void
snmpTlstmParamsTable_removeEntry(netsnmp_tdata *table_data,
netsnmp_tdata_row *row)
{
snmpTlstmParamsTable_entry *entry;
if (!row)
return; /* Nothing to remove */
entry = (snmpTlstmParamsTable_entry *)row->data;
DEBUGMSGT(("tlstmParamsTable:entry:delete", "entry %p / row %p\n",
entry, row));
if (table_data) {
DEBUGMSGTL(("tlstmParamsTable:row:remove", "row %p\n", row));
netsnmp_tdata_remove_and_delete_row( table_data, row );
}
else
netsnmp_tdata_delete_row( row );
if (entry && entry->undo)
_freeUndo(entry);
SNMP_FREE( entry ); /* TODO - release any other internal resources */
}
/** **************************************************************************
*
* handle cache / interactions with snmpTlstmParams container in snmplib
*
*/
static void
_params_add(snmpTlstmParamsTable_entry *entry)
{
snmpTlstmParams *params;
if (NULL == entry)
return;
DEBUGMSGTL(("tlstmParamsTable:params:add", "name %s, fp %s\n",
entry->snmpTargetParamsName, entry->snmpTlstmParamsClientFingerprint));
params =
netsnmp_tlstmParams_create(entry->snmpTargetParamsName,
entry->hashType,
entry->snmpTlstmParamsClientFingerprint,
entry->snmpTlstmParamsClientFingerprint_len);
if (NULL == params)
return;
params->flags = TLSTM_PARAMS_FROM_MIB;
if (entry->snmpTlstmParamsStorageType == ST_NONVOLATILE)
params->flags |= TLSTM_PARAMS_NONVOLATILE;
if (netsnmp_tlstmParams_add(params) != 0) {
netsnmp_tlstmParams_free(params);
}
}
static void
_params_remove(snmpTlstmParamsTable_entry *entry)
{
snmpTlstmParams index, *found;
if (NULL == entry)
return;
DEBUGMSGTL(("tlstmParamsTable:params:remove", "name %s\n",
entry->snmpTargetParamsName));
index.name = entry->snmpTargetParamsName;
found = netsnmp_tlstmParams_find(&index);
if (found) {
netsnmp_tlstmParams_remove(found);
netsnmp_tlstmParams_free(found);
}
entry->params_flags = 0;
}
static void
_params_tweak_storage(snmpTlstmParamsTable_entry *entry)
{
snmpTlstmParams *params, index;
if (NULL == entry)
return;
DEBUGMSGTL(("tlstmParamsTable:params:tweak", "name %s, st %d\n",
entry->snmpTargetParamsName, entry->snmpTlstmParamsStorageType));
index.name = entry->snmpTargetParamsName;
params = netsnmp_tlstmParams_find(&index);
if (NULL == params) {
DEBUGMSGTL(("tlstmParamsTable:params:tweak",
"couldn't find params!\n"));
return;
}
if (entry->snmpTlstmParamsStorageType == ST_NONVOLATILE)
params->flags |= TLSTM_PARAMS_NONVOLATILE;
else
params->flags &= ~TLSTM_PARAMS_NONVOLATILE;
}
static netsnmp_tdata_row *
_entry_from_params(snmpTlstmParams *params)
{
netsnmp_tdata_row *row;
snmpTlstmParamsTable_entry *entry;
row = snmpTlstmParamsTable_createEntry(NULL, params->name,
strlen(params->name));
if (NULL == row) {
snmp_log(LOG_ERR, "can create snmpTlstmParams row entry\n");
return NULL;
}
entry = row->data;
if (params->flags & TLSTM_PARAMS_FROM_CONFIG)
entry->snmpTlstmParamsStorageType = ST_PERMANENT;
else if (! (params->flags & TLSTM_PARAMS_NONVOLATILE))
entry->snmpTlstmParamsStorageType = ST_VOLATILE;
entry->snmpTlstmParamsRowStatus = RS_ACTIVE;
if (params->fingerprint) {
entry->snmpTlstmParamsClientFingerprint_len =
strlen(params->fingerprint);
if (entry->snmpTlstmParamsClientFingerprint_len >
sizeof(entry->snmpTlstmParamsClientFingerprint))
entry->snmpTlstmParamsClientFingerprint_len =
sizeof(entry->snmpTlstmParamsClientFingerprint) - 1;
memcpy(entry->snmpTlstmParamsClientFingerprint, params->fingerprint,
entry->snmpTlstmParamsClientFingerprint_len);
entry->snmpTlstmParamsClientFingerprint[sizeof(entry->snmpTlstmParamsClientFingerprint) - 1] = 0;
}
entry->hashType = params->hashType;
entry->params_flags = params->flags;
return row;
}
static int
snmpTlstmParamsTable_load( netsnmp_cache *cache, void *vmagic )
{
netsnmp_tdata *table = (netsnmp_tdata *)vmagic;
netsnmp_tdata_row *row;
netsnmp_container *active_params;
netsnmp_iterator *itr;
snmpTlstmParams *params;
int rc = 0;
active_params = netsnmp_tlstmParams_container();
if (NULL == active_params)
return 0;
DEBUGMSGTL(("tlstmParamsTable:cache:load", "snmpTlstmParams %" NETSNMP_PRIz "d rows\n",
CONTAINER_SIZE(active_params)));
itr = CONTAINER_ITERATOR(active_params);
if (NULL == itr) {
DEBUGMSGTL(("tlstmParamsTable:cache:load",
"cant get iterator\n"));
return -1;
}
/*
* insert rows for active params into tbl container
*/
params = ITERATOR_FIRST(itr);
for( ; params; params = ITERATOR_NEXT(itr)) {
row = _entry_from_params(params);
if (NULL == row) {
rc =-1;
break;
}
if (netsnmp_tdata_add_row(table, row) != SNMPERR_SUCCESS) {
snmpTlstmParamsTable_removeEntry(NULL, row);
rc = -1;
break;
}
}
ITERATOR_RELEASE(itr);
DEBUGMSGTL(("tlstmParamsTable:cache:load", "done, %" NETSNMP_PRIz "d rows\n",
CONTAINER_SIZE(table->container)));
return rc;
}
static void
snmpTlstmParamsTable_free( netsnmp_cache *cache, void *vmagic )
{
netsnmp_tdata *table = (netsnmp_tdata *)vmagic;
netsnmp_tdata_row *row;
netsnmp_iterator *tbl_itr;
snmpTlstmParamsTable_entry *entry;
DEBUGMSGTL(("tlstmParamsTable:cache:free", "called, %" NETSNMP_PRIz "d rows\n",
CONTAINER_SIZE(table->container)));
tbl_itr = CONTAINER_ITERATOR(table->container);
if (NULL == tbl_itr) {
DEBUGMSGTL(("tlstmParamsTable:cache:free",
"cant get entry iterator\n"));
return;
}
row = ITERATOR_FIRST(tbl_itr);
for( ; row; row = ITERATOR_NEXT(tbl_itr)) {
entry = row->data;
/*
* remove all active rows (they are in the params container kept
* by the library). Keep inactive ones for next time.
*/
if (entry->snmpTlstmParamsRowStatus == RS_ACTIVE) {
snmpTlstmParamsTable_removeEntry(NULL, row);
ITERATOR_REMOVE(tbl_itr);
continue;
}
}
ITERATOR_RELEASE(tbl_itr);
DEBUGMSGTL(("tlstmParamsTable:cache:free", "done, %" NETSNMP_PRIz "d rows\n",
CONTAINER_SIZE(table->container)));
}
/** **************************************************************************
*
* handles requests for the snmpTlstmParamsTable table
*
*/
static int
snmpTlstmParamsTable_handler(
netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests) {
netsnmp_request_info *request = NULL;
netsnmp_table_request_info *table_info;
netsnmp_tdata *table_data;
netsnmp_tdata_row *table_row;
snmpTlstmParamsTable_entry *table_entry;
int ret = SNMP_ERR_NOERROR;
DEBUGMSGTL(("tlstmParamsTable:handler", "Processing %s mode (%d) request\n",
se_find_label_in_slist("agent_mode", reqinfo->mode),
reqinfo->mode));
switch (reqinfo->mode) {
/** ######################################################### GET #####
*
* Read-support (also covers GetNext requests)
*/
case MODE_GET:
for (request=requests; request; request=request->next) {
if (request->processed)
continue;
table_entry = (snmpTlstmParamsTable_entry *)
netsnmp_tdata_extract_entry(request);
table_info = netsnmp_extract_table_info( request);
switch (table_info->colnum) {
case COLUMN_SNMPTLSTMPARAMSCLIENTFINGERPRINT:
{
u_char bin[42], *ptr = bin;
size_t len = sizeof(bin), offset = 1;
int rc;
bin[0] = table_entry->hashType;
netsnmp_assert(table_entry->hashType != 0);
rc = netsnmp_hex_to_binary(
&ptr, &len, &offset, 0,
table_entry->snmpTlstmParamsClientFingerprint, NULL);
if (1 != rc)
netsnmp_set_request_error(reqinfo, request,
SNMP_ERR_GENERR);
else
snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR,
bin, offset);
}
break; /* case COLUMN_SNMPTLSTMPARAMSCLIENTFINGERPRINT */
case COLUMN_SNMPTLSTMPARAMSSTORAGETYPE:
snmp_set_var_typed_integer( request->requestvb, ASN_INTEGER,
table_entry->snmpTlstmParamsStorageType);
break; /* case COLUMN_SNMPTLSTMPARAMSSTORAGETYPE */
case COLUMN_SNMPTLSTMPARAMSROWSTATUS:
snmp_set_var_typed_integer( request->requestvb, ASN_INTEGER,
table_entry->snmpTlstmParamsRowStatus);
break; /* case COLUMN_SNMPTLSTMPARAMSROWSTATUS */
default:
netsnmp_set_request_error(reqinfo, request,
SNMP_NOSUCHOBJECT);
break;
} /* switch colnum */
} /* for requests */
break; /* case MODE_GET */
/*
* Write-support
*/
/** #################################################### RESERVE1 #####
*
* In RESERVE1 we are just checking basic ASN.1 size/type restrictions.
* You probably don't need to change any of this code. Don't change any
* of the column values here. Save that for the ACTION phase.
*
* The next phase is RESERVE2 or FREE.
*/
case MODE_SET_RESERVE1:
for (request=requests; request; request=request->next) {
table_entry = (snmpTlstmParamsTable_entry *)
netsnmp_tdata_extract_entry(request);
table_info = netsnmp_extract_table_info( request);
if ((NULL != table_entry) &&
(ST_READONLY == table_entry->snmpTlstmParamsStorageType)) {
ret = SNMP_ERR_NOTWRITABLE;
break;
}
/*
* for each column, allocate any additional resources needed
* beyond what is in the undo structure.
*/
switch (table_info->colnum) {
case COLUMN_SNMPTLSTMPARAMSCLIENTFINGERPRINT:
ret = netsnmp_check_vb_type_and_max_size(
request->requestvb, ASN_OCTET_STR, sizeof(table_entry->snmpTlstmParamsClientFingerprint));
/** check len/algorithm MIB requirements */
if (SNMP_ERR_NOERROR == ret)
ret = netsnmp_cert_check_vb_fingerprint(request->requestvb);
break; /* case COLUMN_SNMPTLSTMPARAMSCLIENTFINGERPRINT */
case COLUMN_SNMPTLSTMPARAMSSTORAGETYPE:
ret = netsnmp_check_vb_storagetype(request->requestvb,
(table_entry ? table_entry->snmpTlstmParamsStorageType : ST_NONE ));
break; /* case COLUMN_SNMPTLSTMPARAMSSTORAGETYPE */
case COLUMN_SNMPTLSTMPARAMSROWSTATUS:
ret = netsnmp_check_vb_rowstatus_with_storagetype(request->requestvb,
(table_entry ? table_entry->snmpTlstmParamsRowStatus : RS_NONEXISTENT ),
(table_entry ? table_entry->snmpTlstmParamsStorageType : ST_NONE));
break; /* case COLUMN_SNMPTLSTMPARAMSROWSTATUS */
default:
ret = SNMP_ERR_NOTWRITABLE;
} /* switch colnum */
if ( ret != SNMP_ERR_NOERROR )
break;
}/* for requests */
break; /* case MODE_SET_RESERVE1 */
/** #################################################### RESERVE2 #####
*
* RESERVE2 is for checking additional restrictions from the MIB.
* Since these restrictions are often in the description of the object,
* mib2c can't generate code. It's possible that you need to add
* additional checks here. However, don't change any of the column
* values here. Save that for the ACTION phase.
*
* The next phase is ACTION or FREE.
*/
case MODE_SET_RESERVE2:
for (request=requests; request; request=request->next) {
table_entry = (snmpTlstmParamsTable_entry *)
netsnmp_tdata_extract_entry(request);
table_data = netsnmp_tdata_extract_table(request);
table_info = netsnmp_extract_table_info( request);
/*
* if no table_row, create one
*/
if ( !table_entry ) {
table_row = snmpTlstmParamsTable_createEntry
(table_data, (char*)table_info->indexes->val.string,
table_info->indexes->val_len);
if (!table_row) {
ret = SNMP_ERR_RESOURCEUNAVAILABLE;
break;
}
table_entry = table_row->data;
_allocUndo(table_entry);
if (table_entry && !table_entry->undo) {
snmpTlstmParamsTable_removeEntry(table_data, table_row);
table_row = NULL;
ret = SNMP_ERR_RESOURCEUNAVAILABLE;
break;
}
table_entry->undo->fate = FATE_NEWLY_CREATED;
/** associate row with requests */
netsnmp_insert_tdata_row( request, table_row );
}
/** allocate undo structure, if needed */
if(!table_entry->undo) {
_allocUndo(table_entry);
if (!table_entry->undo) {
ret = SNMP_ERR_RESOURCEUNAVAILABLE;
break;
}
}
/** don't allow multiple sets of same column */
if (table_entry->undo->req[table_info->colnum]) {
DEBUGMSGT(("tlstmParamsTable:reserve2",
"multiple sets to col %d in request\n",
table_info->colnum));
ret = SNMP_ERR_INCONSISTENTNAME;
break;
}
table_entry->undo->req[table_info->colnum] = request;
if ( ret != SNMP_ERR_NOERROR )
break;
} /* for requests */
/** make sure rowstatus is used to create rows */
if ( ret == SNMP_ERR_NOERROR ) {
for (request = requests; request; request = request->next) {
if (request->processed)
continue;
table_entry = (snmpTlstmParamsTable_entry *)
netsnmp_tdata_extract_entry(request);
if ((table_entry->undo->fate != FATE_NEWLY_CREATED) ||
(table_entry->undo->req[COLUMN_SNMPTLSTMPARAMSROWSTATUS]))
continue;
ret = SNMP_ERR_INCONSISTENTNAME;
break;
} /* for requests / creation */
} /* if no error */
break; /* case MODE_SET_RESERVE2 */
/** ######################################################## FREE #####
*
* FREE is for cleaning up after a failed request (during either
* RESERVE1 or RESERVE2). So any allocated resources need to be
* released.
*
* This the final phase for this path in the state machine.
*/
case MODE_SET_FREE:
/*
* release undo resources
* remove any newly created rows
*/
for (request=requests; request; request=request->next) {
table_row = netsnmp_tdata_extract_row( request);
table_data = netsnmp_tdata_extract_table(request);
table_entry = (snmpTlstmParamsTable_entry *)
netsnmp_tdata_extract_entry(request);
if ( !table_entry || !table_entry->undo )
continue;
/** disassociate row with requests */
netsnmp_remove_tdata_row( request, table_row );
if (FATE_NEWLY_CREATED == table_entry->undo->fate )
snmpTlstmParamsTable_removeEntry( table_data, table_row );
else
_freeUndo(table_entry);
}
break; /* case MODE_SET_FREE */
/** ###################################################### ACTION #####
*
* In the ACTION phase, we perform any sets that can be undone.
* (Save anything that can't be undone for the COMMIT phase.)
*
* After individual columns have been done, you should check that the
* row as a whole is consistent.
*
* The next phase is UNDO or COMMIT.
*/
case MODE_SET_ACTION:
for (request=requests; request; request=request->next) {
table_entry = (snmpTlstmParamsTable_entry *)
netsnmp_tdata_extract_entry(request);
table_info = netsnmp_extract_table_info( request);
switch (table_info->colnum) {
case COLUMN_SNMPTLSTMPARAMSCLIENTFINGERPRINT:
{
u_char *tmp = (u_char*)table_entry->snmpTlstmParamsClientFingerprint;
memcpy( table_entry->undo->snmpTlstmParamsClientFingerprint,
table_entry->snmpTlstmParamsClientFingerprint,
sizeof(table_entry->snmpTlstmParamsClientFingerprint));
table_entry->undo->snmpTlstmParamsClientFingerprint_len =
table_entry->snmpTlstmParamsClientFingerprint_len;
table_entry->hashType = request->requestvb->val.string[0];
memset( table_entry->snmpTlstmParamsClientFingerprint, 0,
sizeof(table_entry->snmpTlstmParamsClientFingerprint));
table_entry->snmpTlstmParamsClientFingerprint_len =
sizeof(table_entry->snmpTlstmParamsClientFingerprint);
table_entry->snmpTlstmParamsClientFingerprint_len =
netsnmp_binary_to_hex(&tmp, &table_entry->snmpTlstmParamsClientFingerprint_len,
0, &request->requestvb->val.string[1],
request->requestvb->val_len - 1);
if (0 == table_entry->snmpTlstmParamsClientFingerprint_len)
ret = SNMP_ERR_GENERR;
}
break; /* case COLUMN_SNMPTLSTMPARAMSCLIENTFINGERPRINT */
case COLUMN_SNMPTLSTMPARAMSSTORAGETYPE:
/* save snmpTlstmParamsStorageType value */
table_entry->undo->snmpTlstmParamsStorageType = table_entry->snmpTlstmParamsStorageType;
/* get value from varbind */
table_entry->snmpTlstmParamsStorageType = *request->requestvb->val.integer;
break; /* case COLUMN_SNMPTLSTMPARAMSSTORAGETYPE */
case COLUMN_SNMPTLSTMPARAMSROWSTATUS:
/* save snmpTlstmParamsRowStatus value */
table_entry->undo->snmpTlstmParamsRowStatus = table_entry->snmpTlstmParamsRowStatus;
/* get value from varbind */
table_entry->snmpTlstmParamsRowStatus = *request->requestvb->val.integer;
break; /* case COLUMN_SNMPTLSTMPARAMSROWSTATUS */
} /* switch colnum */
if ( ret != SNMP_ERR_NOERROR )
break;
} /* set values for requests */
if ( ret == SNMP_ERR_NOERROR ) {
/*
* All columns now have their final values set. check the
* internal consistency of each row.
*/
for (request=requests; request; request=request->next) {
table_entry = (snmpTlstmParamsTable_entry *)
netsnmp_tdata_extract_entry(request);
table_info = netsnmp_extract_table_info( request);
if (table_entry->undo->is_consistent != -1)
continue; /* already checked */
/** assume consistency */
table_entry->undo->is_consistent = 1;
if ((RS_IS_ACTIVE(table_entry->snmpTlstmParamsRowStatus)) &&
((!table_entry->undo->req[COLUMN_SNMPTLSTMPARAMSROWSTATUS]) ||
(RS_IS_ACTIVE(table_entry->undo->snmpTlstmParamsRowStatus)))) {
/*
* check mib restrictions on active rows.
*/
if (table_entry->undo->req[COLUMN_SNMPTLSTMPARAMSCLIENTFINGERPRINT]) {
table_entry->undo->is_consistent = 0;
request = table_entry->undo->req[COLUMN_SNMPTLSTMPARAMSCLIENTFINGERPRINT];
ret = SNMP_ERR_INCONSISTENTVALUE; /* per mib */
}
} /* active row */
else if (RS_IS_GOING_ACTIVE(table_entry->snmpTlstmParamsRowStatus)) {
/*
* check restrictions for activating a row
*/
/** if going active, inconsistency is fatal */
if (!table_entry->undo->is_consistent) {
if (FATE_NEWLY_CREATED == table_entry->undo->fate)
ret = SNMP_ERR_INCONSISTENTNAME;
else
ret = SNMP_ERR_INCONSISTENTVALUE;
request = table_entry->undo->req[COLUMN_SNMPTLSTMPARAMSROWSTATUS];
}
} /* going active */
else if (RS_DESTROY == table_entry->snmpTlstmParamsRowStatus) {
/*
* TODO: check restrictions for deleting a row
*/
/** can't delete active row */
if (RS_IS_ACTIVE(table_entry->undo->snmpTlstmParamsRowStatus)) {
ret = SNMP_ERR_INCONSISTENTVALUE;
request = table_entry->undo->req[COLUMN_SNMPTLSTMPARAMSROWSTATUS];
}
} /* destroy */
if ( ret != SNMP_ERR_NOERROR )
break;
} /* consistency for requests */
} /* if no error */
break; /* case MODE_SET_ACTION */
/** ######################################################## UNDO #####
*
* UNDO is for cleaning up any failed requests that went through the
* ACTION phase.
*
* This the final phase for this path in the state machine.
*/
case MODE_SET_UNDO:
for (request=requests; request; request=request->next) {
table_entry = (snmpTlstmParamsTable_entry *)
netsnmp_tdata_extract_entry(request);
table_row = netsnmp_tdata_extract_row( request);
table_data = netsnmp_tdata_extract_table(request);
table_info = netsnmp_extract_table_info( request);
switch (table_info->colnum) {
case COLUMN_SNMPTLSTMPARAMSCLIENTFINGERPRINT:
/* restore snmpTlstmParamsClientFingerprint value */
memcpy( table_entry->snmpTlstmParamsClientFingerprint,
table_entry->undo->snmpTlstmParamsClientFingerprint,
sizeof(table_entry->snmpTlstmParamsClientFingerprint));
table_entry->snmpTlstmParamsClientFingerprint_len =
table_entry->undo->snmpTlstmParamsClientFingerprint_len;
break; /* case COLUMN_SNMPTLSTMPARAMSCLIENTFINGERPRINT */
case COLUMN_SNMPTLSTMPARAMSSTORAGETYPE:
/* restore snmpTlstmParamsStorageType value */
table_entry->snmpTlstmParamsStorageType =
table_entry->undo->snmpTlstmParamsStorageType;
break; /* case COLUMN_SNMPTLSTMPARAMSSTORAGETYPE */
case COLUMN_SNMPTLSTMPARAMSROWSTATUS:
/* restore snmpTlstmParamsRowStatus value */
table_entry->snmpTlstmParamsRowStatus = table_entry->undo->snmpTlstmParamsRowStatus;
break; /* case COLUMN_SNMPTLSTMPARAMSROWSTATUS */
} /* switch colnum */
} /* for requests */
/*
* release undo data
* or remove any newly created rows
*/
for (request=requests; request; request=request->next) {
table_row = netsnmp_tdata_extract_row( request);
table_entry = (snmpTlstmParamsTable_entry *)
netsnmp_tdata_extract_entry(request);
if ( !table_entry || !table_entry->undo )
continue;
/** disassociate row with requests */
netsnmp_remove_tdata_row( request, table_row );
if (FATE_NEWLY_CREATED == table_entry->undo->fate )
snmpTlstmParamsTable_removeEntry( table_data, table_row );
else
_freeUndo(table_entry);
} /* for requests */
break; /* case MODE_SET_UNDO */
/** ###################################################### COMMIT #####
*
* COMMIT is the final success state, when all changes are finalized.
* There is not recovery state should something faile here.
*
* This the final phase for this path in the state machine.
*/
case MODE_SET_COMMIT:
for (request=requests; request; request=request->next) {
table_row = netsnmp_tdata_extract_row( request);
table_data = netsnmp_tdata_extract_table(request);
table_info = netsnmp_extract_table_info( request);
table_entry = (snmpTlstmParamsTable_entry *)
netsnmp_tdata_extract_entry(request);
if (!table_entry || !table_entry->undo)
continue;
if ((RS_NOTREADY == table_entry->snmpTlstmParamsRowStatus) &&
table_entry->undo->is_consistent)
table_entry->snmpTlstmParamsRowStatus = RS_NOTINSERVICE;
else if ((RS_NOTINSERVICE == table_entry->snmpTlstmParamsRowStatus) &&
(0 == table_entry->undo->is_consistent))
table_entry->snmpTlstmParamsRowStatus = RS_NOTREADY;
/** release undo data for requests with no rowstatus */
if (table_entry->undo &&
!table_entry->undo->req[COLUMN_SNMPTLSTMPARAMSROWSTATUS] != 0) {
_freeUndo(table_entry);
/** update active addrs */
if ((0 == table_entry->params_flags) &&
(table_entry->snmpTlstmParamsRowStatus == RS_ACTIVE))
_params_add(table_entry);
else if ((0 != table_entry->params_flags) &&
(table_entry->snmpTlstmParamsRowStatus == RS_DESTROY))
_params_remove(table_entry);
}
switch (table_info->colnum) {
case COLUMN_SNMPTLSTMPARAMSROWSTATUS:
switch (table_entry->snmpTlstmParamsRowStatus) {
case RS_CREATEANDGO:
/** Fall-through */
case RS_ACTIVE:
table_entry->snmpTlstmParamsRowStatus = RS_ACTIVE;
if (0 == table_entry->params_flags)
_params_add(table_entry);
break;
case RS_CREATEANDWAIT:
/** Fall-through */
case RS_NOTINSERVICE:
/** simply set status based on consistency */
if (table_entry->undo->is_consistent)
table_entry->snmpTlstmParamsRowStatus = RS_NOTINSERVICE;
else
table_entry->snmpTlstmParamsRowStatus = RS_NOTREADY;
if (0 != table_entry->params_flags)
_params_remove(table_entry);
break;
case RS_DESTROY:
if (0 != table_entry->params_flags)
_params_remove(table_entry);
/** disassociate row with requests */
netsnmp_remove_tdata_row( request, table_row );
snmpTlstmParamsTable_removeEntry(table_data, table_row );
table_row = NULL;
table_entry = NULL;
}
/** release undo data */
_freeUndo(table_entry);
break; /* case COLUMN_SNMPTLSTMPARAMSROWSTATUS */
case COLUMN_SNMPTLSTMPARAMSSTORAGETYPE:
if (RS_ACTIVE == table_entry->snmpTlstmParamsRowStatus)
_params_tweak_storage(table_entry);
break;
case COLUMN_SNMPTLSTMPARAMSCLIENTFINGERPRINT:
break;
} /* switch colnum */
} /* for requests */
/** update last changed */
_last_changed = netsnmp_get_agent_uptime();
/** set up to save persistent store */
snmp_store_needed(NULL);
break; /* case MODE_SET_COMMIT */
} /* switch (reqinfo->mode) */
if ( ret != SNMP_ERR_NOERROR )
netsnmp_set_request_error( reqinfo, request, ret);
return SNMP_ERR_NOERROR;
}
static int
_count_handler(netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests)
{
int val;
if (MODE_GET != reqinfo->mode) {
snmp_log(LOG_ERR, "bad mode in RO handler");
return SNMP_ERR_GENERR;
}
if (NULL == _table_data->container)
val = 0;
else
val = CONTAINER_SIZE(_table_data->container);
snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE,
(u_char *) &val, sizeof(val));
if (handler->next && handler->next->access_method)
return netsnmp_call_next_handler(handler, reginfo, reqinfo,
requests);
return SNMP_ERR_NOERROR;
}
/***********************************************************************
*
* PERSISTENCE
*
***********************************************************************/
static int _tlstmParamsTable_save(int majorID, int minorID,
void *serverarg, void *clientarg);
static int _save_params(snmpTlstmParams *params, void *app_type);
static int _save_entry(snmpTlstmParamsTable_entry *entry, void *type);
static void _tlstmParamsTable_row_restore_mib(const char *token, char *buf);
static const char mib_token[] = "snmpTlstmParamsEntry";
/************************************************************
* *_init_persistence should be called from the main table
* init routine.
*
* If your table depends on rows in another table,
* you should register your callback after the other table,
* which should ensure the rows on which you depend are saved
* (and re-created) before the dependent rows.
*/
void
_tlstmParams_init_persistence(void)
{
int rc;
register_config_handler(NULL, mib_token, _tlstmParamsTable_row_restore_mib,
NULL, NULL);
rc = snmp_register_callback(SNMP_CALLBACK_LIBRARY,
SNMP_CALLBACK_STORE_DATA,
_tlstmParamsTable_save,
_table_data->container);
if (rc != SNMP_ERR_NOERROR)
snmp_log(LOG_ERR, "error registering for STORE_DATA callback "
"in _tlstmParams_init_persistence\n");
}
static int
_tlstmParamsTable_save(int majorID, int minorID, void *serverarg,
void *clientarg)
{
char sep[] =
"##############################################################";
char buf[] = "#\n" "# tlstmParams persistent data\n" "#";
char *type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
NETSNMP_DS_LIB_APPTYPE);
netsnmp_container *active_params = netsnmp_tlstmParams_container();
netsnmp_tdata_row *row;
netsnmp_iterator *tbl_itr, *params_itr;
snmpTlstmParams *params;
snmpTlstmParamsTable_entry *entry;
if ((CONTAINER_SIZE(active_params) == 0) &&
(CONTAINER_SIZE(_table_data->container) == 0))
return SNMPERR_SUCCESS;
read_config_store((char *) type, sep);
read_config_store((char *) type, buf);
/*
* save active rows from params container
*/
if (NULL != active_params) {
params_itr = CONTAINER_ITERATOR(active_params);
if (NULL == params_itr) {
DEBUGMSGTL(("tlstmParamsTable:save",
"cant get params iterator\n"));
params = NULL;
}
else
params = ITERATOR_FIRST(params_itr);
for( ; params; params = ITERATOR_NEXT(params_itr)) {
/** don't store config rows */
if ((params->flags & TLSTM_PARAMS_FROM_CONFIG) ||
! (params->flags & TLSTM_PARAMS_NONVOLATILE))
continue;
_save_params(params, type);
}
}
ITERATOR_RELEASE(params_itr);
/*
* save inactive rows from mib
*/
tbl_itr = CONTAINER_ITERATOR(_table_data->container);
if (NULL == tbl_itr)
DEBUGMSGTL(("tlstmParamsTable:save", "cant get table iterator\n"));
else {
row = ITERATOR_FIRST(tbl_itr);
for( ; row; row = ITERATOR_NEXT(tbl_itr)) {
entry = row->data;
/*
* skip all active rows (should be in active_params and thus saved
* above) and volatile rows.
*/
if ((entry->snmpTlstmParamsRowStatus == RS_ACTIVE) ||
(entry->snmpTlstmParamsStorageType != ST_NONVOLATILE))
continue;
_save_entry(entry, type);
}
ITERATOR_RELEASE(tbl_itr);
}
read_config_store((char *) type, sep);
read_config_store((char *) type, "\n");
/*
* never fails
*/
return SNMPERR_SUCCESS;
}
/************************************************************
* _tlstmParamsTable_container_row_save
*/
static int
_save_entry(snmpTlstmParamsTable_entry *entry, void *type)
{
char buf[SNMP_MAXBUF_SMALL], *hashType;
hashType = se_find_label_in_slist("cert_hash_alg", entry->hashType);
if (NULL == hashType) {
snmp_log(LOG_ERR, "skipping entry unknown hash type %d\n",
entry->hashType);
return SNMP_ERR_GENERR;
}
/*
* build the line
*/
netsnmp_assert(0 == entry->snmpTargetParamsName[
entry->snmpTargetParamsName_len]);
netsnmp_assert(0 == entry->snmpTlstmParamsClientFingerprint[
entry->snmpTlstmParamsClientFingerprint_len]);
snprintf(buf, sizeof(buf), "%s %s %s %s %d", mib_token,
entry->snmpTargetParamsName, hashType,
entry->snmpTlstmParamsClientFingerprint,
entry->snmpTlstmParamsRowStatus);
buf[sizeof(buf)-1] = 0;
read_config_store(type, buf);
DEBUGMSGTL(("tlstmParamsTable:row:save", "saving entry '%s'\n", buf));
return SNMP_ERR_NOERROR;
}
static int
_save_params(snmpTlstmParams *params, void *app_type)
{
char buf[SNMP_MAXBUF_SMALL], *hashType;
if (NULL == params)
return SNMP_ERR_GENERR;
hashType = se_find_label_in_slist("cert_hash_alg", params->hashType);
if (NULL == hashType) {
snmp_log(LOG_ERR, "skipping entry unknown hash type %d\n",
params->hashType);
return SNMP_ERR_GENERR;
}
snprintf(buf, sizeof(buf), "%s %s --%s %s %d", mib_token, params->name,
hashType, params->fingerprint, RS_ACTIVE);
DEBUGMSGTL(("tlstmParamsTable:params:save", "saving params '%s'\n",
buf));
read_config_store(app_type, buf);
return SNMP_ERR_NOERROR;
}
static void
_tlstmParamsTable_row_restore_mib(const char *token, char *buf)
{
u_char rowStatus;
snmpTlstmParams *params;
/** need somewhere to save rows */
netsnmp_assert(_table_data && _table_data->container);
params = netsnmp_tlstmParams_restore_common(&buf);
if (NULL == params)
return;
if (NULL == buf) {
config_perror("incomplete line");
return;
}
rowStatus = atoi(buf);
/*
* if row is active, add it to the params container so it is available
* for use. Do not add it to the table, since it will be added
* during cache_load.
*/
if (RS_ACTIVE == rowStatus) {
params->flags = TLSTM_PARAMS_FROM_MIB | TLSTM_PARAMS_NONVOLATILE;
if (netsnmp_tlstmParams_add(params) != 0)
netsnmp_tlstmParams_free(params);
}
else {
netsnmp_tdata_row *row;
snmpTlstmParamsTable_entry *entry;
row = snmpTlstmParamsTable_createEntry(_table_data, params->name,
strlen(params->name));
if (!row)
return;
entry = row->data;
entry->hashType = params->hashType;
strlcpy(entry->snmpTlstmParamsClientFingerprint, params->fingerprint,
sizeof(entry->snmpTlstmParamsClientFingerprint));
entry->snmpTlstmParamsClientFingerprint_len =
strlen(entry->snmpTlstmParamsClientFingerprint);
entry->snmpTlstmParamsStorageType = ST_NONVOLATILE;
entry->snmpTlstmParamsRowStatus = rowStatus;
netsnmp_tlstmParams_free(params);
}
}