blob: 5493ff954626dea0f045c30cd36d1ffe60921f44 [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 "snmpTlstmAddrTable.h"
netsnmp_feature_require(table_tdata)
netsnmp_feature_require(tlstmaddr_container)
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(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
/***********************************************************************
*
* PERSISTENCE
*
***********************************************************************/
/*
* structure for undo storage and other vars for set processing
*/
typedef struct tlstmAddrTable_undo_s {
char fate;
char copied;
char is_consistent;
netsnmp_request_info *req[TLSTMADDRTABLE_MAX_COLUMN + 1];
/*
* undo Column space
*/
char tlstmAddrServerFingerprint[TLSTMADDRSERVERFINGERPRINT_MAX_SIZE];
size_t tlstmAddrServerFingerprint_len;
char tlstmAddrServerIdentity[TLSTMADDRSERVERIDENTITY_MAX_SIZE];
size_t tlstmAddrServerIdentity_len;
char tlstmAddrStorageType;
char tlstmAddrRowStatus;
char hashType;
} tlstmAddrTable_undo;
/*
* Typical data structure for a row entry
*/
typedef struct tlstmAddrTable_entry_s {
/*
* Index values
*/
char snmpTargetAddrName[SNMPTARGETADDRNAME_MAX_SIZE];
size_t snmpTargetAddrName_len;
/*
* Column values
*/
char tlstmAddrServerFingerprint[TLSTMADDRSERVERFINGERPRINT_MAX_SIZE];
size_t tlstmAddrServerFingerprint_len;
char tlstmAddrServerIdentity[TLSTMADDRSERVERIDENTITY_MAX_SIZE];
size_t tlstmAddrServerIdentity_len;
char tlstmAddrStorageType;
char tlstmAddrRowStatus;
char hashType;
/*
* used during set processing
*/
tlstmAddrTable_undo *undo;
/*
* user data
*/
struct netsnmp_cert_s *cert;
char addr_flags;
} tlstmAddrTable_entry;
netsnmp_tdata_row *tlstmAddrTable_createEntry(netsnmp_tdata * table_data,
char *snmpTargetAddrName,
size_t snmpTargetAddrName_len);
void tlstmAddrTable_removeEntry(netsnmp_tdata * table_data,
netsnmp_tdata_row * row);
static Netsnmp_Node_Handler tlstmAddrTable_handler;
static int _cache_load(netsnmp_cache *cache, netsnmp_tdata *table);
static void _cache_free(netsnmp_cache *cache, netsnmp_tdata *table);
static uint32_t _last_changed = 0;
static int _count_handler(netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests);
static void _tlstmAddr_init_persistence(void);
static void _addrs_add(tlstmAddrTable_entry *entry);
static void _addrs_remove(tlstmAddrTable_entry *entry);
static void _addr_tweak_storage(tlstmAddrTable_entry *entry);
static netsnmp_tdata *_table_data = NULL;
/***********************************************************************
*
* PERSISTENCE
*
***********************************************************************/
/** Initializes the tlstmAddrTable module */
void
init_snmpTlstmAddrTable(void)
{
oid reg_oid[] = { SNMP_TLS_TM_ADDR_TABLE };
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(("tlstmAddrTable:init",
"initializing table tlstmAddrTable\n"));
reg =
netsnmp_create_handler_registration("tlstmAddrTable",
tlstmAddrTable_handler,
reg_oid, reg_oid_len,
HANDLER_CAN_RWRITE);
_table_data = netsnmp_tdata_create_table("tlstmAddrTable", 0);
if (NULL == _table_data) {
snmp_log(LOG_ERR, "error creating tdata table for tlstmAddrTable\n");
return;
}
table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
if (NULL == table_info) {
snmp_log(LOG_ERR, "error creating table info for tlstmAddrTable\n");
netsnmp_tdata_delete_table(_table_data);
_table_data = NULL;
return;
}
/*
* cache init
*/
cache = netsnmp_cache_create(30, (NetsnmpCacheLoad*)_cache_load,
(NetsnmpCacheFree*)_cache_free,
reg_oid, reg_oid_len);
if (NULL == cache) {
snmp_log(LOG_ERR,"error creating cache for tlstmCertToTSNTable\n");
netsnmp_tdata_delete_table(_table_data);
_table_data = NULL;
return;
}
cache->magic = (void *)_table_data;
cache->flags = NETSNMP_CACHE_DONT_INVALIDATE_ON_SET;
/*
* populate index types
*/
netsnmp_table_helper_add_indexes(table_info,
/* index: snmpTargetAddrName */
ASN_PRIV_IMPLIED_OCTET_STR,
0);
table_info->min_column = TLSTMADDRTABLE_MIN_COLUMN;
table_info->max_column = TLSTMADDRTABLE_MAX_COLUMN;
netsnmp_tdata_register(reg, _table_data, table_info);
if (cache)
netsnmp_inject_handler_before( reg, netsnmp_cache_handler_get(cache),
"table_container");
/*
* register scalars
*/
reg_oid[10] = 7;
reg = netsnmp_create_handler_registration("snmpTlstmAddrCount",
_count_handler, reg_oid,
OID_LENGTH(reg_oid),
HANDLER_CAN_RONLY);
if (NULL == reg)
snmp_log(LOG_ERR,
"could not create handler for snmpTlstmAddrCount\n");
else {
netsnmp_register_scalar(reg);
if (cache)
netsnmp_inject_handler_before(reg,
netsnmp_cache_handler_get(cache),
"snmpTlstmAddrCount");
}
reg_oid[10] = 8;
reg = netsnmp_create_handler_registration(
"snmpTlstmAddrTableLastChanged", 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 snmpTlstmAddrTableLastChanged\n");
else
netsnmp_register_watched_scalar2(reg, watcher);
/*
* Initialise the contents of the table here
*/
_tlstmAddr_init_persistence();
}
/***********************************************************************
*
* PERSISTENCE
*
***********************************************************************/
/*
* create a new row in the table
*/
netsnmp_tdata_row *
tlstmAddrTable_createEntry(netsnmp_tdata * table_data,
char *snmpTargetAddrName,
size_t snmpTargetAddrName_len)
{
tlstmAddrTable_entry *entry;
netsnmp_tdata_row *row;
if (snmpTargetAddrName_len > sizeof(entry->snmpTargetAddrName))
return NULL;
entry = SNMP_MALLOC_TYPEDEF(tlstmAddrTable_entry);
if (!entry)
return NULL;
row = netsnmp_tdata_create_row();
if (!row) {
SNMP_FREE(entry);
return NULL;
}
row->data = entry;
DEBUGIF("tlstmAddrTable:entry:create") {
char name[sizeof(entry->snmpTargetAddrName)+1];
snprintf(name, sizeof(name), "%s", snmpTargetAddrName);
DEBUGMSGT(("tlstmAddrTable:entry:create", "entry %s %p / row %p\n",
name, entry, row));
}
/*
* populate index
*/
memcpy(entry->snmpTargetAddrName, snmpTargetAddrName,
snmpTargetAddrName_len);
entry->snmpTargetAddrName_len = snmpTargetAddrName_len;
netsnmp_tdata_row_add_index(row, ASN_PRIV_IMPLIED_OCTET_STR,
entry->snmpTargetAddrName,
snmpTargetAddrName_len);
/*
* defaults
*/
entry->tlstmAddrServerFingerprint[0] = '\0';
entry->tlstmAddrServerFingerprint_len = 0;
entry->hashType = 0;
entry->tlstmAddrServerIdentity[0] = '\0';
entry->tlstmAddrServerIdentity_len = 0;
entry->tlstmAddrStorageType = ST_NONVOLATILE;
entry->tlstmAddrRowStatus = RS_NOTREADY;
if (table_data) {
DEBUGMSGTL(("tlstmAddrTable:row:insert", "row %p\n",row));
netsnmp_tdata_add_row(table_data, row);
}
return row;
}
/*
* allocate undo resources
*/
static tlstmAddrTable_undo *
_allocUndo(tlstmAddrTable_entry * entry)
{
if (!entry)
return NULL;
entry->undo = SNMP_MALLOC_TYPEDEF(tlstmAddrTable_undo);
if (!entry->undo)
return NULL;
entry->undo->is_consistent = -1; /* don't know */
return entry->undo;
}
/*
* free undo resources
*/
static void
_freeUndo(tlstmAddrTable_entry * entry)
{
if (!entry || !entry->undo)
return;
SNMP_FREE(entry->undo);
}
/*
* remove a row from the table
*/
void
tlstmAddrTable_removeEntry(netsnmp_tdata * table_data,
netsnmp_tdata_row * row)
{
tlstmAddrTable_entry *entry;
if (!row)
return; /* Nothing to remove */
entry = (tlstmAddrTable_entry *) row->data;
if (table_data) {
DEBUGMSGTL(("tlstmAddrTable:row:remove", "row %p\n",row));
netsnmp_tdata_remove_and_delete_row(table_data, row);
}
else
netsnmp_tdata_delete_row(row);
DEBUGIF("tlstmAddrTable:entry:delete") {
char name[sizeof(entry->snmpTargetAddrName)+1];
snprintf(name, sizeof(name), "%s", entry->snmpTargetAddrName);
DEBUGMSGT(("tlstmAddrTable:entry:delete", "entry %s %p / row %p\n",
name, entry, row));
}
if (entry && entry->undo)
_freeUndo(entry);
SNMP_FREE(entry);
}
/***********************************************************************
*
* PERSISTENCE
*
***********************************************************************/
/** handles requests for the tlstmAddrTable table */
static int
tlstmAddrTable_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;
tlstmAddrTable_entry *table_entry;
int ret = SNMP_ERR_NOERROR;
DEBUGMSGTL(("tlstmAddrTable:handler", "Processing mode %s (%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 = (tlstmAddrTable_entry *)
netsnmp_tdata_extract_entry(request);
table_info = netsnmp_extract_table_info(request);
switch (table_info->colnum) {
case COLUMN_SNMPTLSTMADDRSERVERFINGERPRINT:
{
u_char bin[42], *ptr = bin;
size_t len = sizeof(bin), offset = 1;
int rc;
if ((table_entry->hashType == 0) ||
(table_entry->tlstmAddrServerFingerprint_len ==0))
offset = 0;
else {
bin[0] = table_entry->hashType;
rc = netsnmp_hex_to_binary(
&ptr, &len, &offset, 0,
table_entry->tlstmAddrServerFingerprint, NULL);
if (1 != rc)
ret = SNMP_ERR_GENERR;
}
if (ret == SNMP_ERR_NOERROR)
snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR,
bin, offset);
}
break; /* case COLUMN_SNMPTLSTMADDRSERVERFINGERPRINT */
case COLUMN_SNMPTLSTMADDRSERVERIDENTITY:
snmp_set_var_typed_value
(request->requestvb, ASN_OCTET_STR,
(u_char *) table_entry->tlstmAddrServerIdentity,
table_entry->tlstmAddrServerIdentity_len);
break; /* case COLUMN_SNMPTLSTMADDRSERVERIDENTITY */
case COLUMN_SNMPTLSTMADDRSTORAGETYPE:
snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER,
table_entry->tlstmAddrStorageType);
break; /* case COLUMN_SNMPTLSTMADDRSTORAGETYPE */
case COLUMN_SNMPTLSTMADDRROWSTATUS:
snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER,
table_entry->tlstmAddrRowStatus);
break; /* case COLUMN_SNMPTLSTMADDRROWSTATUS */
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 = (tlstmAddrTable_entry *)
netsnmp_tdata_extract_entry(request);
table_info = netsnmp_extract_table_info(request);
if ((NULL != table_entry) &&
(ST_READONLY == table_entry->tlstmAddrStorageType)) {
ret = SNMP_ERR_NOTWRITABLE;
break;
}
switch (table_info->colnum) {
case COLUMN_SNMPTLSTMADDRSERVERFINGERPRINT:
ret = netsnmp_check_vb_type_and_max_size
(request->requestvb, ASN_OCTET_STR,
sizeof(table_entry->tlstmAddrServerFingerprint));
/** check len/algorithm MIB requirements */
if (ret == SNMP_ERR_NOERROR)
ret = netsnmp_cert_check_vb_fingerprint(request->requestvb);
break; /* case COLUMN_SNMPTLSTMADDRSERVERFINGERPRINT */
case COLUMN_SNMPTLSTMADDRSERVERIDENTITY:
ret = netsnmp_check_vb_type_and_max_size
(request->requestvb, ASN_OCTET_STR,
sizeof(table_entry->tlstmAddrServerIdentity));
break; /* case COLUMN_SNMPTLSTMADDRSERVERIDENTITY */
case COLUMN_SNMPTLSTMADDRSTORAGETYPE:
ret = netsnmp_check_vb_storagetype
(request->requestvb,
(table_entry ?
table_entry->tlstmAddrStorageType : ST_NONE));
break; /* case COLUMN_SNMPTLSTMADDRSTORAGETYPE */
case COLUMN_SNMPTLSTMADDRROWSTATUS:
ret = netsnmp_check_vb_rowstatus_with_storagetype
(request->requestvb,
(table_entry ?
table_entry->tlstmAddrRowStatus : RS_NONEXISTENT),
(table_entry ?
table_entry->tlstmAddrStorageType : ST_NONE));
break; /* case COLUMN_SNMPTLSTMADDRROWSTATUS */
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 = (tlstmAddrTable_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 = tlstmAddrTable_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) {
tlstmAddrTable_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(("tlstmAddrTable: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 = (tlstmAddrTable_entry *)
netsnmp_tdata_extract_entry(request);
if ((table_entry->undo->fate != FATE_NEWLY_CREATED) ||
(table_entry->undo->req[COLUMN_SNMPTLSTMADDRROWSTATUS]))
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 =
(tlstmAddrTable_entry *) table_row ? table_row->
data : NULL;
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)
tlstmAddrTable_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 = (tlstmAddrTable_entry *)
netsnmp_tdata_extract_entry(request);
table_info = netsnmp_extract_table_info(request);
switch (table_info->colnum) {
case COLUMN_SNMPTLSTMADDRSERVERFINGERPRINT:
{
u_char *tmp = (u_char*)table_entry->tlstmAddrServerFingerprint;
memcpy(table_entry->undo->tlstmAddrServerFingerprint,
table_entry->tlstmAddrServerFingerprint,
sizeof(table_entry->tlstmAddrServerFingerprint));
table_entry->undo->tlstmAddrServerFingerprint_len =
table_entry->tlstmAddrServerFingerprint_len;
table_entry->undo->hashType = table_entry->hashType;
table_entry->hashType = request->requestvb->val.string[0];
table_entry->tlstmAddrServerFingerprint_len =
sizeof(table_entry->tlstmAddrServerFingerprint);
memset(table_entry->tlstmAddrServerFingerprint, 0,
sizeof(table_entry->tlstmAddrServerFingerprint));
table_entry->tlstmAddrServerFingerprint_len =
netsnmp_binary_to_hex(&tmp, &table_entry->tlstmAddrServerFingerprint_len,
0, &request->requestvb->val.string[1],
request->requestvb->val_len - 1);
if (0 == table_entry->tlstmAddrServerFingerprint_len)
ret = SNMP_ERR_GENERR;
}
break; /* case COLUMN_SNMPTLSTMADDRSERVERFINGERPRINT */
case COLUMN_SNMPTLSTMADDRSERVERIDENTITY:
memcpy(table_entry->undo->tlstmAddrServerIdentity,
table_entry->tlstmAddrServerIdentity,
sizeof(table_entry->tlstmAddrServerIdentity));
table_entry->undo->tlstmAddrServerIdentity_len =
table_entry->tlstmAddrServerIdentity_len;
memset(table_entry->tlstmAddrServerIdentity, 0,
sizeof(table_entry->tlstmAddrServerIdentity));
memcpy(table_entry->tlstmAddrServerIdentity,
request->requestvb->val.string,
request->requestvb->val_len);
table_entry->tlstmAddrServerIdentity_len =
request->requestvb->val_len;
break; /* case COLUMN_SNMPTLSTMADDRSERVERIDENTITY */
case COLUMN_SNMPTLSTMADDRSTORAGETYPE:
table_entry->undo->tlstmAddrStorageType =
table_entry->tlstmAddrStorageType;
table_entry->tlstmAddrStorageType =
*request->requestvb->val.integer;
break; /* case COLUMN_SNMPTLSTMADDRSTORAGETYPE */
case COLUMN_SNMPTLSTMADDRROWSTATUS:
table_entry->undo->tlstmAddrRowStatus =
table_entry->tlstmAddrRowStatus;
table_entry->tlstmAddrRowStatus =
*request->requestvb->val.integer;
break; /* case COLUMN_SNMPTLSTMADDRROWSTATUS */
} /* 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 = (tlstmAddrTable_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;
/*
* per mib, can't have empty fingerprint and wildcard id
*/
if ( (0 == table_entry->tlstmAddrServerFingerprint_len) &&
(1 == table_entry->tlstmAddrServerIdentity_len) &&
('*' == table_entry->tlstmAddrServerIdentity[0]) ) {
DEBUGMSGTL(("tlstmAddrTable", "fingerprint must not "
"be empty for wildcard (*) identity\n"));
table_entry->undo->is_consistent = 0;
}
if ((RS_IS_ACTIVE(table_entry->tlstmAddrRowStatus)) &&
((!table_entry->undo->req[COLUMN_SNMPTLSTMADDRROWSTATUS]) ||
(RS_IS_ACTIVE(table_entry->undo->tlstmAddrRowStatus)))) {
/*
* check mib restrictions on active rows.
*/
if (table_entry->undo->req[COLUMN_SNMPTLSTMADDRSERVERFINGERPRINT]) {
table_entry->undo->is_consistent = 0;
request = table_entry->undo->req[COLUMN_SNMPTLSTMADDRSERVERFINGERPRINT];
}
else if (table_entry->undo->req[COLUMN_SNMPTLSTMADDRSERVERIDENTITY]) {
table_entry->undo->is_consistent = 0;
request = table_entry->undo->req[COLUMN_SNMPTLSTMADDRSERVERIDENTITY];
}
else if (table_entry->undo->req[COLUMN_SNMPTLSTMADDRSTORAGETYPE]) {
table_entry->undo->is_consistent = 0;
request = table_entry->undo->req[COLUMN_SNMPTLSTMADDRSTORAGETYPE];
}
if (!table_entry->undo->is_consistent)
ret = SNMP_ERR_INCONSISTENTVALUE; /* per mib */
} /* active row */
else if (RS_IS_GOING_ACTIVE
(table_entry->tlstmAddrRowStatus)) {
/** 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_SNMPTLSTMADDRROWSTATUS];
}
} /* going active */
else if (RS_DESTROY == table_entry->tlstmAddrRowStatus) {
/** can't delete active row */
if (RS_IS_ACTIVE(table_entry->undo->tlstmAddrRowStatus)) {
ret = SNMP_ERR_INCONSISTENTVALUE;
request = table_entry->undo->req[COLUMN_SNMPTLSTMADDRROWSTATUS];
}
} /* 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_row = netsnmp_tdata_extract_row(request);
table_entry =
(tlstmAddrTable_entry *) table_row ? table_row->
data : NULL;
table_data = netsnmp_tdata_extract_table(request);
table_info = netsnmp_extract_table_info(request);
switch (table_info->colnum) {
case COLUMN_SNMPTLSTMADDRSERVERFINGERPRINT:
/*
* restore tlstmAddrServerFingerprint value
*/
memcpy(table_entry->tlstmAddrServerFingerprint,
table_entry->undo->tlstmAddrServerFingerprint,
sizeof(table_entry->tlstmAddrServerFingerprint));
table_entry->tlstmAddrServerFingerprint_len =
table_entry->undo->tlstmAddrServerFingerprint_len;
table_entry->hashType = table_entry->undo->hashType;
break; /* case COLUMN_SNMPTLSTMADDRSERVERFINGERPRINT */
case COLUMN_SNMPTLSTMADDRSERVERIDENTITY:
/*
* restore tlstmAddrServerIdentity value
*/
memcpy(table_entry->tlstmAddrServerIdentity,
table_entry->undo->tlstmAddrServerIdentity,
sizeof(table_entry->tlstmAddrServerIdentity));
table_entry->tlstmAddrServerIdentity_len =
table_entry->undo->tlstmAddrServerIdentity_len;
break; /* case COLUMN_SNMPTLSTMADDRSERVERIDENTITY */
case COLUMN_SNMPTLSTMADDRSTORAGETYPE:
/*
* restore tlstmAddrStorageType value
*/
table_entry->tlstmAddrStorageType =
table_entry->undo->tlstmAddrStorageType;
break; /* case COLUMN_SNMPTLSTMADDRSTORAGETYPE */
case COLUMN_SNMPTLSTMADDRROWSTATUS:
/*
* restore tlstmAddrRowStatus value
*/
table_entry->tlstmAddrRowStatus =
table_entry->undo->tlstmAddrRowStatus;
break; /* case COLUMN_SNMPTLSTMADDRROWSTATUS */
} /* 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 =
(tlstmAddrTable_entry *) table_row ? table_row->
data : NULL;
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)
tlstmAddrTable_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 = (tlstmAddrTable_entry *)
netsnmp_tdata_extract_entry(request);
if (!table_entry || !table_entry->undo)
continue;
if ((RS_NOTREADY == table_entry->tlstmAddrRowStatus) &&
table_entry->undo->is_consistent)
table_entry->tlstmAddrRowStatus = RS_NOTINSERVICE;
else if ((RS_NOTINSERVICE == table_entry->tlstmAddrRowStatus) &&
(0 == table_entry->undo->is_consistent))
table_entry->tlstmAddrRowStatus = RS_NOTREADY;
/** release undo data for requests with no rowstatus */
if (table_entry->undo &&
!table_entry->undo->req[COLUMN_SNMPTLSTMADDRROWSTATUS] != 0) {
_freeUndo(table_entry);
/** update active addrs */
if ((0 == table_entry->addr_flags) &&
(table_entry->tlstmAddrRowStatus == RS_ACTIVE))
_addrs_add(table_entry);
else if ((0 != table_entry->addr_flags) &&
(table_entry->tlstmAddrRowStatus == RS_DESTROY))
_addrs_remove(table_entry);
}
switch (table_info->colnum) {
case COLUMN_SNMPTLSTMADDRROWSTATUS:
switch (table_entry->tlstmAddrRowStatus) {
case RS_CREATEANDGO:
/** Fall-through */
case RS_ACTIVE:
table_entry->tlstmAddrRowStatus = RS_ACTIVE;
if (0 == table_entry->addr_flags)
_addrs_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->tlstmAddrRowStatus =
RS_NOTINSERVICE;
else
table_entry->tlstmAddrRowStatus = RS_NOTREADY;
if (0 != table_entry->addr_flags)
_addrs_remove(table_entry);
break;
case RS_DESTROY:
if (0 != table_entry->addr_flags)
_addrs_remove(table_entry);
/** disassociate row with requests */
netsnmp_remove_tdata_row(request, table_row);
tlstmAddrTable_removeEntry(table_data, table_row);
table_row = NULL;
table_entry = NULL;
}
/** release undo data */
_freeUndo(table_entry);
break; /* case COLUMN_SNMPTLSTMADDRROWSTATUS */
case COLUMN_SNMPTLSTMADDRSTORAGETYPE:
if (RS_ACTIVE == table_entry->tlstmAddrRowStatus)
_addr_tweak_storage(table_entry);
break;
case COLUMN_SNMPTLSTMADDRSERVERFINGERPRINT:
case COLUMN_SNMPTLSTMADDRSERVERIDENTITY:
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;
}
/***********************************************************************
*
* PERSISTENCE
*
***********************************************************************/
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) || (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;
}
/** **************************************************************************
*
* handle cache / interactions with tlstmAddr container in snmplib
*
** *************************************************************************/
static void
_addrs_add(tlstmAddrTable_entry *entry)
{
netsnmp_container *addrs;
snmpTlstmAddr *addr;
if (NULL == entry)
return;
DEBUGMSGTL(("tlstmAddrTable:addrs:add", "name %s, fp %s\n",
entry->snmpTargetAddrName, entry->tlstmAddrServerFingerprint));
/** get current active addrs */
addrs = netsnmp_tlstmAddr_container();
if (NULL == addrs)
return;
addr = netsnmp_tlstmAddr_create(entry->snmpTargetAddrName);
if (NULL == addr)
return;
if (entry->tlstmAddrServerFingerprint_len)
addr->fingerprint = strdup(entry->tlstmAddrServerFingerprint);
if (entry->tlstmAddrServerIdentity_len)
addr->identity = strdup(entry->tlstmAddrServerIdentity);
addr->hashType = entry->hashType;
addr->flags = TLSTM_ADDR_FROM_MIB;
if (entry->tlstmAddrStorageType == ST_NONVOLATILE)
addr->flags |= TLSTM_ADDR_NONVOLATILE;
if (CONTAINER_INSERT(addrs, addr) != 0) {
netsnmp_tlstmAddr_free(addr);
snmp_log(LOG_ERR, "could not insert new tlstm addr");
}
}
static void
_addrs_remove(tlstmAddrTable_entry *entry)
{
netsnmp_container *addrs;
snmpTlstmAddr addr;
if (NULL == entry)
return;
DEBUGMSGTL(("tlstmAddrTable:addr:remove", "name %s, fp %s\n",
entry->snmpTargetAddrName, entry->tlstmAddrServerFingerprint));
/** get current active addrs */
addrs = netsnmp_tlstmAddr_container();
if (NULL == addrs)
return;
addr.name = entry->snmpTargetAddrName;
if (CONTAINER_REMOVE(addrs, &addr) != 0) {
snmp_log(LOG_ERR, "could not remove tlstm addr");
}
entry->addr_flags = 0;
}
static void
_addr_tweak_storage(tlstmAddrTable_entry *entry)
{
netsnmp_container *addrs;
snmpTlstmAddr *addr, index;
if (NULL == entry)
return;
DEBUGMSGTL(("tlstmAddrTable:addr:tweak", "name %s, st %d\n",
entry->snmpTargetAddrName, entry->tlstmAddrStorageType));
/** get current active addrs */
addrs = netsnmp_tlstmAddr_container();
if (NULL == addrs)
return;
index.name = entry->snmpTargetAddrName;
addr = CONTAINER_FIND(addrs, &index);
if (NULL == addr) {
DEBUGMSGTL(("tlstmAddrTable:addr:tweak", "couldn't find addr!\n"));
return;
}
if (entry->tlstmAddrStorageType == ST_NONVOLATILE)
addr->flags |= TLSTM_ADDR_NONVOLATILE;
else
addr->flags &= ~TLSTM_ADDR_NONVOLATILE;
}
static netsnmp_tdata_row *
_entry_from_addr(snmpTlstmAddr *addr)
{
netsnmp_tdata_row *row;
tlstmAddrTable_entry *entry;
row = tlstmAddrTable_createEntry(NULL, addr->name, strlen(addr->name));
if (NULL == row) {
snmp_log(LOG_ERR, "can create tlstmAddr row entry\n");
return NULL;
}
entry = row->data;
if (addr->flags & TLSTM_ADDR_FROM_CONFIG)
entry->tlstmAddrStorageType = ST_PERMANENT;
else if (! (addr->flags & TLSTM_ADDR_NONVOLATILE))
entry->tlstmAddrStorageType = ST_VOLATILE;
entry->tlstmAddrRowStatus = RS_ACTIVE;
if (addr->fingerprint) {
entry->tlstmAddrServerFingerprint_len = strlen(addr->fingerprint);
if (entry->tlstmAddrServerFingerprint_len >
sizeof(entry->tlstmAddrServerFingerprint))
entry->tlstmAddrServerFingerprint_len =
sizeof(entry->tlstmAddrServerFingerprint) - 1;
memcpy(entry->tlstmAddrServerFingerprint, addr->fingerprint,
entry->tlstmAddrServerFingerprint_len);
entry->tlstmAddrServerFingerprint[sizeof(entry->tlstmAddrServerFingerprint) - 1] = 0;
}
if (addr->identity) {
entry->tlstmAddrServerIdentity_len = strlen(addr->identity);
if (entry->tlstmAddrServerIdentity_len >
sizeof(entry->tlstmAddrServerIdentity))
entry->tlstmAddrServerIdentity_len =
sizeof(entry->tlstmAddrServerIdentity) - 1;
memcpy(entry->tlstmAddrServerIdentity, addr->identity,
entry->tlstmAddrServerIdentity_len);
entry->tlstmAddrServerIdentity[sizeof(entry->tlstmAddrServerIdentity) - 1] = 0;
}
entry->hashType = addr->hashType;
entry->addr_flags = addr->flags;
return row;
}
static int
_cache_load(netsnmp_cache *cache, netsnmp_tdata *table)
{
netsnmp_container *addrs;
netsnmp_iterator *itr;
snmpTlstmAddr *addr;
netsnmp_tdata_row *row;
int rc = 0;
DEBUGMSGTL(("tlstmAddrTable:cache:load", "called, %" NETSNMP_PRIz "d rows\n",
CONTAINER_SIZE(table->container)));
/** get current active rows */
addrs = netsnmp_tlstmAddr_container();
if (NULL == addrs)
return 0;
DEBUGMSGTL(("tlstmAddrTable:cache:load", "tlstmAddr %" NETSNMP_PRIz "d rows\n",
CONTAINER_SIZE(addrs)));
itr = CONTAINER_ITERATOR(addrs);
if (NULL == itr) {
DEBUGMSGTL(("tlstmAddrTable:cache:load",
"cant get iterator\n"));
return -1;
}
/*
* insert rows for active addrs into tbl container
*/
addr = ITERATOR_FIRST(itr);
for( ; addr; addr = ITERATOR_NEXT(itr)) {
row = _entry_from_addr(addr);
if (NULL == row) {
rc =-1;
break;
}
if (netsnmp_tdata_add_row(table, row) != SNMPERR_SUCCESS) {
tlstmAddrTable_removeEntry(NULL, row);
rc = -1;
break;
}
}
ITERATOR_RELEASE(itr);
DEBUGMSGTL(("tlstmAddrTable:cache:load", "done, %" NETSNMP_PRIz "d rows\n",
CONTAINER_SIZE(table->container)));
return rc;
}
static void
_cache_free(netsnmp_cache *cache, netsnmp_tdata *table)
{
netsnmp_tdata_row *row;
netsnmp_iterator *tbl_itr;
tlstmAddrTable_entry *entry;
DEBUGMSGTL(("tlstmAddrTable:cache:free", "called, %" NETSNMP_PRIz "d rows\n",
CONTAINER_SIZE(table->container)));
tbl_itr = CONTAINER_ITERATOR(table->container);
if (NULL == tbl_itr) {
DEBUGMSGTL(("tlstmAddrTable: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 addrs container kept
* by the library). Keep inactive ones for next time.
*/
if (entry->tlstmAddrRowStatus == RS_ACTIVE) {
tlstmAddrTable_removeEntry(NULL, row);
ITERATOR_REMOVE(tbl_itr);
continue;
}
}
ITERATOR_RELEASE(tbl_itr);
DEBUGMSGTL(("tlstmAddrTable:cache:free", "done, %" NETSNMP_PRIz "d rows\n",
CONTAINER_SIZE(table->container)));
}
/***********************************************************************
*
* PERSISTENCE
*
***********************************************************************/
static int _tlstmAddrTable_save_rows(int majorID, int minorID,
void *serverarg,
void *clientarg);
static void _tlstmAddrTable_row_restore_mib(const char *token,
char *buf);
static const char mib_token[] = "snmpTlstmAddrEntry";
/************************************************************
* *_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.
*/
static void
_tlstmAddr_init_persistence(void)
{
int rc;
if (NULL == _table_data) {
snmp_log(LOG_ERR, "no table data for tlstmAddr persistence!\n");
return;
}
register_config_handler(NULL, mib_token,
_tlstmAddrTable_row_restore_mib, NULL,
NULL);
rc = snmp_register_callback(SNMP_CALLBACK_LIBRARY,
SNMP_CALLBACK_STORE_DATA,
_tlstmAddrTable_save_rows,
_table_data->container);
if (rc != SNMP_ERR_NOERROR)
snmp_log(LOG_ERR, "error registering for STORE_DATA callback "
"in _tlstmAddrTable_init_persistence\n");
}
static int
_save_entry(tlstmAddrTable_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->snmpTargetAddrName[
entry->snmpTargetAddrName_len]);
netsnmp_assert(0 == entry->tlstmAddrServerFingerprint[
entry->tlstmAddrServerFingerprint_len]);
snprintf(buf, sizeof(buf), "%s %s --%s %s %s %d", mib_token,
entry->snmpTargetAddrName, hashType,
entry->tlstmAddrServerFingerprint,
entry->tlstmAddrServerIdentity,
entry->tlstmAddrRowStatus);
buf[sizeof(buf)-1] = 0;
read_config_store(type, buf);
DEBUGMSGTL(("tlstmAddrTable:row:save", "saving entry '%s'\n", buf));
return SNMP_ERR_NOERROR;
}
static int
_save_addrs(snmpTlstmAddr *addrs, void *app_type)
{
char buf[SNMP_MAXBUF_SMALL], *hashType;
if (NULL == addrs)
return SNMP_ERR_GENERR;
hashType = se_find_label_in_slist("cert_hash_alg", addrs->hashType);
if (NULL == hashType) {
snmp_log(LOG_ERR, "skipping entry unknown hash type %d\n",
addrs->hashType);
return SNMP_ERR_GENERR;
}
snprintf(buf, sizeof(buf), "%s %s --%s %s %s %d", mib_token, addrs->name,
hashType, addrs->fingerprint, addrs->identity, RS_ACTIVE);
DEBUGMSGTL(("tlstmAddrTable:addrs:save", "saving addrs '%s'\n",
buf));
read_config_store(app_type, buf);
return SNMP_ERR_NOERROR;
}
static int
_tlstmAddrTable_save_rows(int majorID, int minorID, void *serverarg,
void *clientarg)
{
char sep[] =
"##############################################################";
char buf[] = "#\n" "# tlstmAddr persistent data\n" "#";
char *type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
NETSNMP_DS_LIB_APPTYPE);
netsnmp_container *mib_addrs = (netsnmp_container *) clientarg;
netsnmp_container *active_addrs = netsnmp_tlstmAddr_container();
netsnmp_iterator *tbl_itr, *addrs_itr = NULL;
netsnmp_tdata_row *row;
snmpTlstmAddr *addr;
tlstmAddrTable_entry *entry;
if (((NULL == mib_addrs) || (CONTAINER_SIZE(mib_addrs) == 0)) &&
((NULL == active_addrs) || (CONTAINER_SIZE(active_addrs) == 0)))
return SNMPERR_SUCCESS;
read_config_store((char *) type, sep);
read_config_store((char *) type, buf);
/*
* save active rows from addr container
*/
if (NULL != active_addrs) {
addrs_itr = CONTAINER_ITERATOR(active_addrs);
if (NULL == addrs_itr) {
DEBUGMSGTL(("tlstmAddrTable:save", "cant get addrs iterator\n"));
addr = NULL;
}
else
addr = ITERATOR_FIRST(addrs_itr);
for( ; addr; addr = ITERATOR_NEXT(addrs_itr)) {
/** don't store config rows */
if ((addr->flags & TLSTM_ADDR_FROM_CONFIG) ||
! (addr->flags & TLSTM_ADDR_NONVOLATILE))
continue;
_save_addrs(addr, type);
}
}
ITERATOR_RELEASE(addrs_itr);
/*
* save inactive rows from mib
*/
tbl_itr = CONTAINER_ITERATOR(mib_addrs);
if (NULL == tbl_itr)
DEBUGMSGTL(("tlstmAddrTable: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_addrs and thus saved
* above) and volatile rows.
*/
if ((entry->tlstmAddrRowStatus == RS_ACTIVE) ||
(entry->tlstmAddrStorageType != 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;
}
static void
_tlstmAddrTable_row_restore_mib(const char *token, char *buf)
{
char name[SNMPADMINLENGTH + 1], id[SNMPADMINLENGTH + 1],
fingerprint[SNMPTLSFINGERPRINT_MAX_LEN + 1];
size_t name_len = sizeof(name), id_len = sizeof(id),
fp_len = sizeof(fingerprint);
u_char hashType, rowStatus;
int rc;
/** need somewhere to save rows */
netsnmp_assert(_table_data && _table_data->container);
rc = netsnmp_tlstmAddr_restore_common(&buf, name, &name_len, id, &id_len,
fingerprint, &fp_len, &hashType);
if (rc < 0)
return;
if (NULL == buf) {
config_perror("incomplete line");
return;
}
rowStatus = atoi(buf);
/*
* if row is active, add it to the addrs 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) {
snmpTlstmAddr *addr;
addr = netsnmp_tlstmAddr_create(name);
if (!addr)
return;
if (fp_len)
addr->fingerprint = strdup(fingerprint);
if (id_len)
addr->identity = strdup(id);
addr->hashType = hashType;
addr->flags = TLSTM_ADDR_FROM_MIB | TLSTM_ADDR_NONVOLATILE;
netsnmp_tlstmAddr_add(addr);
}
else {
netsnmp_tdata_row *row;
tlstmAddrTable_entry *entry;
row = tlstmAddrTable_createEntry(_table_data, name, name_len);
if (!row)
return;
entry = row->data;
entry->hashType = hashType;
memcpy(entry->tlstmAddrServerFingerprint,fingerprint, fp_len);
entry->tlstmAddrServerFingerprint_len = fp_len;
memcpy(entry->tlstmAddrServerIdentity, id, id_len);
entry->tlstmAddrServerIdentity_len = id_len;
entry->tlstmAddrStorageType = ST_NONVOLATILE;
entry->tlstmAddrRowStatus = rowStatus;
}
}