blob: 84d1afb90efbcc6e8d3f424c080ccecedd378be8 [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 "snmpTlstmCertToTSNTable.h"
netsnmp_feature_require(table_tdata)
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)
netsnmp_feature_require(tls_fingerprint_build)
#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
#define MAP_MIB_CONFIG_TOKEN "snmpTlstmCertToTSNEntry"
extern netsnmp_cert_map *netsnmp_certToTSN_parse_common(char **line);
/*
* structure for undo storage and other vars for set processing
*/
typedef struct certToTSN_undo_s {
char fate;
char copied;
char is_consistent;
netsnmp_request_info *req[SNMPTLSTMCERTTOTSN_TABLE_MAX_COL+1];
/*
* undo Column space
*/
char fingerprint[SNMPTLSTMCERTTOTSN_FINGERPRINT_MAX_SIZE];
size_t fingerprint_len;
int mapType;
char data[SNMPTLSTMCERTTOTSN_DATA_MAX_SIZE];
size_t data_len;
u_char hashType;
char storageType;
char rowStatus;
} certToTSN_undo;
/*
* Typical data structure for a row entry
*/
typedef struct certToTSN_entry_s {
/*
* Index values
*/
u_long tlstmCertToTSNID;
/*
* Column values
*/
char fingerprint[SNMPTLSTMCERTTOTSN_FINGERPRINT_MAX_SIZE];
size_t fingerprint_len;
int mapType;
char data[SNMPTLSTMCERTTOTSN_DATA_MAX_SIZE];
size_t data_len;
char storageType;
char rowStatus;
u_char hashType;
char map_flags;
/*
* used during set processing
*/
certToTSN_undo *undo;
} certToTSN_entry;
static Netsnmp_Node_Handler tlstmCertToTSNTable_handler;
static oid _oid2type(oid *val, int val_len);
/** static int _type2oid(int type, oid *val, int *val_len); */
static int _cache_load(netsnmp_cache *cache, netsnmp_tdata *table);
static void _cache_free(netsnmp_cache *cache, netsnmp_tdata *table);
static void _cert_map_add(certToTSN_entry *entry);
static void _cert_map_remove(certToTSN_entry *entry);
static int _count_handler(netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests);
static void _parse_mib_maps(const char *token, char *line);
static int _save_maps(int majorID, int minorID, void *server, void *client);
static int _save_map(netsnmp_cert_map *map, int row_status, void *type);
static void _cert_map_tweak_storage(certToTSN_entry *entry);
static netsnmp_tdata *_table = NULL;
static uint32_t _last_changed = 0;
/** Initializes the tlstmCertToTSNTable module */
void
init_snmpTlstmCertToTSNTable(void)
{
init_snmpTlstmCertToTSNTable_context(NULL);
}
void
init_snmpTlstmCertToTSNTable_context(const char *contextName)
{
oid reg_oid[] = { SNMP_TLS_TM_CERT_TABLE };
const size_t reg_oid_len = OID_LENGTH(reg_oid);
netsnmp_handler_registration *reg;
netsnmp_table_registration_info *info;
netsnmp_cache *cache;
netsnmp_watcher_info *watcher;
const char *mib_map_help =
MAP_MIB_CONFIG_TOKEN " table persistence (internal use)";
DEBUGMSGTL(("tlstmCertToSN:init",
"initializing table tlstmCertToTSNTable\n"));
reg = netsnmp_create_handler_registration
("tlstmCertToTSNTable", tlstmCertToTSNTable_handler,
reg_oid, reg_oid_len,
HANDLER_CAN_RWRITE);
if (NULL == reg) {
snmp_log(LOG_ERR,
"error creating handler registration for tlstmCertToSN\n");
return;
}
if (NULL != contextName)
reg->contextName = strdup(contextName);
_table = netsnmp_tdata_create_table("tlstmCertToTSNTable", 0);
if (NULL == _table) {
snmp_log(LOG_ERR,
"error creating tdata table for tlstmCertToTSNTable\n");
return;
}
info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
if (NULL == info) {
snmp_log(LOG_ERR,
"error creating table info for tlstmCertToTSNTable\n");
netsnmp_tdata_delete_table(_table);
_table = NULL;
return;
}
netsnmp_table_helper_add_indexes(info,
/* index: tlstmCertToTSNID */
ASN_UNSIGNED, 0);
info->min_column = SNMPTLSTMCERTTOTSN_TABLE_MIN_COL;
info->max_column = SNMPTLSTMCERTTOTSN_TABLE_MAX_COL;
/*
* 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);
_table = NULL;
return;
}
cache->magic = (void *)_table;
cache->flags = NETSNMP_CACHE_DONT_INVALIDATE_ON_SET;
netsnmp_tdata_register(reg, _table, info);
if (cache)
netsnmp_inject_handler_before( reg, netsnmp_cache_handler_get(cache),
"table_container");
/*
* register scalars
*/
reg_oid[10] = 1;
reg = netsnmp_create_handler_registration("snmpTlstmCertToTSNCount",
_count_handler, reg_oid,
OID_LENGTH(reg_oid),
HANDLER_CAN_RONLY);
if (NULL == reg)
snmp_log(LOG_ERR,
"could not create handler for snmpTlstmCertToTSNCount\n");
else {
if (NULL != contextName)
reg->contextName = strdup(contextName);
netsnmp_register_scalar(reg);
if (cache)
netsnmp_inject_handler_before(reg, netsnmp_cache_handler_get(cache),
"table_container");
}
reg_oid[10] = 2;
reg = netsnmp_create_handler_registration(
"snmpTlstmCertToTSNTableLastChanged", 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 snmpTlstmCertToTSNCount\n");
else {
if (NULL != contextName)
reg->contextName = strdup(contextName);
netsnmp_register_watched_scalar2(reg, watcher);
}
/*
* persistence
*/
register_config_handler(NULL, MAP_MIB_CONFIG_TOKEN, _parse_mib_maps, NULL,
mib_map_help);
if (snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
_save_maps, NULL) != SNMP_ERR_NOERROR)
snmp_log(LOG_ERR, "error registering for STORE_DATA callback "
"for certToTSN\n");
}
/*
* create a new row in the table
*/
netsnmp_tdata_row *
tlstmCertToTSNTable_createEntry(netsnmp_tdata * table, u_long tlstmCertToTSNID)
{
certToTSN_entry *entry;
netsnmp_tdata_row *row;
entry = SNMP_MALLOC_TYPEDEF(certToTSN_entry);
if (!entry)
return NULL;
row = netsnmp_tdata_create_row();
if (!row) {
SNMP_FREE(entry);
return NULL;
}
row->data = entry;
DEBUGMSGT(("tlstmCertToSN:entry:create", "entry %p / row %p\n",
entry, row));
/*
* populate index
*/
entry->tlstmCertToTSNID = tlstmCertToTSNID;
netsnmp_tdata_row_add_index(row, ASN_UNSIGNED,
&(entry->tlstmCertToTSNID),
sizeof(entry->tlstmCertToTSNID));
/*
* assign default column values
*/
entry->mapType = TSNM_tlstmCertSpecified;
entry->storageType = ST_NONVOLATILE;
entry->rowStatus = RS_NOTREADY;
if (table) {
DEBUGMSGTL(("tlstmCertToTSN:row:insert", "row %p\n", row));
netsnmp_tdata_add_row(table, row);
}
return row;
}
/*
* allocate undo resources
*/
static certToTSN_undo *
_allocUndo(certToTSN_entry * entry)
{
if (!entry)
return NULL;
netsnmp_assert(!entry->undo);
entry->undo = SNMP_MALLOC_TYPEDEF(certToTSN_undo);
if (!entry->undo)
return NULL;
entry->undo->is_consistent = -1; /* don't know */
return entry->undo;
}
/*
* free undo resources
*/
static void
_freeUndo(certToTSN_entry * entry)
{
if (!entry || !entry->undo)
return;
/*
* TODO: release any allocated resources
*/
SNMP_FREE(entry->undo);
}
/*
* remove a row from the table
*/
void
tlstmCertToTSNTable_removeEntry(netsnmp_tdata * table,
netsnmp_tdata_row * row)
{
certToTSN_entry *entry;
if (!row)
return; /* Nothing to remove */
entry = (certToTSN_entry *) row->data;
DEBUGMSGT(("tlstmCertToSN:entry:delete", "entry %p / row %p\n",
entry, row));
if (entry && entry->undo)
_freeUndo(entry);
SNMP_FREE(entry);
if (table) {
DEBUGMSGTL(("tlstmCertToSN:row:remove", "row %p\n", row));
netsnmp_tdata_remove_and_delete_row(table, row);
}
else
netsnmp_tdata_delete_row(row);
}
/** handles requests for the tlstmCertToTSNTable table */
static int
tlstmCertToTSNTable_handler(netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests)
{
oid tsnm[] = { SNMP_TLS_TM_BASE, 1, 1, 0 };
static const int tsnm_pos = OID_LENGTH(tsnm) - 1;
netsnmp_request_info *request = NULL;
netsnmp_table_request_info *info;
netsnmp_tdata *table;
netsnmp_tdata_row *row;
certToTSN_entry *entry;
int ret = SNMP_ERR_NOERROR;
DEBUGMSGTL(("tlstmCertToSN:handler", "Processing request (mode %s (%d))\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;
entry = (certToTSN_entry *) netsnmp_tdata_extract_entry(request);
info = netsnmp_extract_table_info(request);
netsnmp_assert(entry && info);
switch (info->colnum) {
case COL_SNMPTLSTMCERTTOTSN_FINGERPRINT:
{
/*
* build SnmpTLSFingerprint
*/
u_char bin[42], *ptr = bin;
size_t len = sizeof(bin);
int rc;
rc = netsnmp_tls_fingerprint_build(entry->hashType,
entry->fingerprint,
&ptr, &len, 0);
if (SNMPERR_SUCCESS != rc)
netsnmp_set_request_error(reqinfo, request,
SNMP_ERR_GENERR);
else
snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR,
bin, len);
}
break; /* case COL_SNMPTLSTMCERTTOTSN_FINGERPRINT */
case COL_SNMPTLSTMCERTTOTSN_MAPTYPE:
tsnm[tsnm_pos] = entry->mapType;
snmp_set_var_typed_value(request->requestvb, ASN_OBJECT_ID,
tsnm, sizeof(tsnm));
break; /* case COL_SNMPTLSTMCERTTOTSN_MAPTYPE */
case COL_SNMPTLSTMCERTTOTSN_DATA:
snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR,
entry->data, entry->data_len);
break; /* case COL_SNMPTLSTMCERTTOTSN_DATA */
case COL_SNMPTLSTMCERTTOTSN_STORAGETYPE:
snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER,
entry->storageType);
break; /* case COL_SNMPTLSTMCERTTOTSN_STORAGETYPE */
case COL_SNMPTLSTMCERTTOTSN_ROWSTATUS:
snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER,
entry->rowStatus);
break; /* case COL_SNMPTLSTMCERTTOTSN_ROWSTATUS */
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) {
netsnmp_assert(request->processed == 0);
entry = (certToTSN_entry *) netsnmp_tdata_extract_entry(request);
info = netsnmp_extract_table_info(request);
if ((NULL != entry) && (ST_READONLY == entry->storageType)) {
ret = SNMP_ERR_NOTWRITABLE;
break;
}
switch (info->colnum) {
case COL_SNMPTLSTMCERTTOTSN_FINGERPRINT:
ret = netsnmp_check_vb_type_and_max_size
(request->requestvb, ASN_OCTET_STR,
sizeof(entry->fingerprint));
/** check len/algorithm MIB requirements */
if (ret == SNMP_ERR_NOERROR)
ret = netsnmp_cert_check_vb_fingerprint(request->requestvb);
break; /* case COL_SNMPTLSTMCERTTOTSN_FINGERPRINT */
case COL_SNMPTLSTMCERTTOTSN_MAPTYPE:
ret = netsnmp_check_vb_type_and_max_size
(request->requestvb, ASN_OBJECT_ID,
SNMPTLSTMCERTTOTSN_MAPTYPE_MAX_SIZE);
if (ret == SNMP_ERR_NOERROR) {
if (_oid2type(request->requestvb->val.objid,
request->requestvb->val_len) >
TSNM_tlstmCert_MAX)
ret = SNMP_ERR_WRONGVALUE;
}
break; /* case COL_SNMPTLSTMCERTTOTSN_MAPTYPE */
case COL_SNMPTLSTMCERTTOTSN_DATA:
ret = netsnmp_check_vb_type_and_max_size
(request->requestvb, ASN_OCTET_STR, sizeof(entry->data));
break; /* case COL_SNMPTLSTMCERTTOTSN_DATA */
case COL_SNMPTLSTMCERTTOTSN_STORAGETYPE:
ret = netsnmp_check_vb_storagetype
(request->requestvb,(entry ? entry->storageType : ST_NONE));
break; /* case COL_SNMPTLSTMCERTTOTSN_STORAGETYPE */
case COL_SNMPTLSTMCERTTOTSN_ROWSTATUS:
ret = netsnmp_check_vb_rowstatus_with_storagetype
(request->requestvb,
(entry ? entry->rowStatus :RS_NONEXISTENT),
(entry ? entry->storageType :ST_NONE));
break; /* case COL_SNMPTLSTMCERTTOTSN_ROWSTATUS */
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) {
netsnmp_assert(request->processed == 0);
entry = (certToTSN_entry *) netsnmp_tdata_extract_entry(request);
table = netsnmp_tdata_extract_table(request);
info = netsnmp_extract_table_info(request);
/*
* if no row, create one
*/
if (!entry) {
row = tlstmCertToTSNTable_createEntry
(table,*info->indexes->val.integer);
if (!row) {
ret = SNMP_ERR_RESOURCEUNAVAILABLE;
break;
}
entry = row->data;
_allocUndo(entry);
if (!entry->undo) {
tlstmCertToTSNTable_removeEntry(table, row);
row = NULL;
ret = SNMP_ERR_RESOURCEUNAVAILABLE;
break;
}
entry->undo->fate = FATE_NEWLY_CREATED;
/** associate row with requests */
netsnmp_insert_tdata_row(request, row);
}
/** allocate undo structure, if needed */
if (!entry->undo) {
_allocUndo(entry);
if (!entry->undo) {
ret = SNMP_ERR_RESOURCEUNAVAILABLE;
break;
}
}
/*
* save request ptr for column. if we already
* have a value, bail.
*/
if (entry->undo->req[info->colnum]) {
DEBUGMSGT(("tlstmCertToSN:reserve2",
"multiple sets to col %d in request\n",
info->colnum));
if (FATE_NEWLY_CREATED == entry->undo->fate)
ret = SNMP_ERR_INCONSISTENTNAME;
else
ret = SNMP_ERR_INCONSISTENTVALUE;
break;
}
entry->undo->req[info->colnum] = request;
if (ret != SNMP_ERR_NOERROR)
break;
} /* for requests */
if (ret == SNMP_ERR_NOERROR) {
/** make sure rowstatus is used to create rows */
for (request = requests; request; request = request->next) {
if (request->processed)
continue;
entry = (certToTSN_entry *)
netsnmp_tdata_extract_entry(request);
if ((entry->undo->fate != FATE_NEWLY_CREATED) ||
(entry->undo->req[COL_SNMPTLSTMCERTTOTSN_ROWSTATUS]))
continue;
ret = SNMP_ERR_INCONSISTENTNAME;
break;
} /* creation for requests */
} /* 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 = netsnmp_tdata_extract_table(request);
row = netsnmp_tdata_extract_row(request);
entry = (certToTSN_entry *) netsnmp_tdata_extract_entry(request);
if (!entry || !entry->undo)
continue;
/** disassociate row with requests */
netsnmp_remove_tdata_row(request, row);
if (FATE_NEWLY_CREATED == entry->undo->fate)
tlstmCertToTSNTable_removeEntry(table, row);
else
_freeUndo(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) {
entry = (certToTSN_entry *) netsnmp_tdata_extract_entry(request);
info = netsnmp_extract_table_info(request);
/** reserve2 should enforce this */
netsnmp_assert(request == entry->undo->req[info->colnum]);
/*
* for each col, save old value and the set new value
*/
switch (info->colnum) {
case COL_SNMPTLSTMCERTTOTSN_FINGERPRINT:
{
u_char *tmp = (u_char*)entry->fingerprint;
u_int size = sizeof(entry->fingerprint);
netsnmp_variable_list *vb = request->requestvb;
memcpy(entry->undo->fingerprint,
entry->fingerprint, sizeof(entry->fingerprint));
entry->undo->fingerprint_len = entry->fingerprint_len;
entry->undo->hashType = entry->hashType;
memset(entry->fingerprint, 0, sizeof(entry->fingerprint));
(void)netsnmp_tls_fingerprint_parse(vb->val.string, vb->val_len,
(char**)&tmp, &size, 0,
&entry->hashType);
entry->fingerprint_len = size;
if (0 == entry->fingerprint_len)
ret = SNMP_ERR_GENERR;
}
break; /* case COL_SNMPTLSTMCERTTOTSN_FINGERPRINT */
case COL_SNMPTLSTMCERTTOTSN_MAPTYPE:
entry->undo->mapType = entry->mapType;
entry->mapType = _oid2type(request->requestvb->val.objid,
request->requestvb->val_len);
break; /* case COL_SNMPTLSTMCERTTOTSN_MAPTYPE */
case COL_SNMPTLSTMCERTTOTSN_DATA:
memcpy(entry->undo->data, entry->data, sizeof(entry->data));
entry->undo->data_len = entry->data_len;
memset(entry->data, 0, sizeof(entry->data));
memcpy(entry->data, request->requestvb->val.string,
request->requestvb->val_len);
entry->data_len = request->requestvb->val_len;
break; /* case COL_SNMPTLSTMCERTTOTSN_DATA */
case COL_SNMPTLSTMCERTTOTSN_STORAGETYPE:
entry->undo->storageType = entry->storageType;
entry->storageType = *request->requestvb->val.integer;
break; /* case COL_SNMPTLSTMCERTTOTSN_STORAGETYPE */
case COL_SNMPTLSTMCERTTOTSN_ROWSTATUS:
entry->undo->rowStatus = entry->rowStatus;
entry->rowStatus = *request->requestvb->val.integer;
break; /* case COL_SNMPTLSTMCERTTOTSN_ROWSTATUS */
} /* switch colnum */
} /* set values for requests */
if (ret != SNMP_ERR_NOERROR)
break; /* skip consistency if we've already got error */
/*
* All columns now have their final values set. check the
* internal consistency of each row.
*/
for (request = requests; request; request = request->next) {
entry = (certToTSN_entry *) netsnmp_tdata_extract_entry(request);
info = netsnmp_extract_table_info(request);
if (entry->undo->is_consistent != -1)
continue; /* already checked */
/** assume consistency */
entry->undo->is_consistent = 1;
/*
* per mib, can't have empty fingerprint and must
* have data if indicated by map type.
*/
if (0 == entry->fingerprint_len) {
DEBUGMSGTL(("tlstmCertToTSNTable:inconsistent",
"fingerprint must not be empty\n"));
entry->undo->is_consistent = 0;
}
else if ((TSNM_tlstmCertSpecified == entry->mapType) &&
(0 == entry->data_len)) {
DEBUGMSGTL(("tlstmCertToTSNTable:inconsistent",
"must specify Data for CertSpecified identity\n"));
entry->undo->is_consistent = 0;
}
if ((RS_IS_ACTIVE(entry->rowStatus)) &&
((!entry->undo->req[COL_SNMPTLSTMCERTTOTSN_ROWSTATUS]) ||
(RS_IS_ACTIVE(entry->undo->rowStatus)))) {
/*
* per mib, can't modify these while row active
*/
char _cols[3] = { COL_SNMPTLSTMCERTTOTSN_FINGERPRINT,
COL_SNMPTLSTMCERTTOTSN_MAPTYPE, COL_SNMPTLSTMCERTTOTSN_DATA };
int i;
for (i=0; i < 3; ++i ) {
if (!entry->undo->req[i])
continue;
DEBUGMSGTL(("tlstmCertToTSNTable:inconsistent",
"can't modify row %d while active\n",
_cols[i]));
entry->undo->is_consistent = 0;
ret = SNMP_ERR_NOTWRITABLE;
request= entry->undo->req[i];
break;
}
} else if (RS_IS_GOING_ACTIVE(entry->rowStatus)) {
/*
* if going active, inconsistency is fatal
*/
if (!entry->undo->is_consistent) {
netsnmp_assert(entry->undo->req[COL_SNMPTLSTMCERTTOTSN_ROWSTATUS]);
if (FATE_NEWLY_CREATED == entry->undo->fate)
ret = SNMP_ERR_INCONSISTENTNAME;
else
ret = SNMP_ERR_INCONSISTENTVALUE;
request = entry->undo->req[COL_SNMPTLSTMCERTTOTSN_ROWSTATUS];
}
} else if (RS_DESTROY == entry->rowStatus) {
/*
* can't destroy active row
*/
if (RS_IS_ACTIVE(entry->undo->rowStatus)) {
DEBUGMSGTL(("tlstmCertToTSNTable:inconsistent",
"can't destroy active row\n"));
netsnmp_assert(entry->undo->req[COL_SNMPTLSTMCERTTOTSN_ROWSTATUS]);
ret = SNMP_ERR_INCONSISTENTVALUE;
request = entry->undo->req[COL_SNMPTLSTMCERTTOTSN_ROWSTATUS];
}
}
if (ret != SNMP_ERR_NOERROR)
break;
} /* consistency for requests */
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) {
row = netsnmp_tdata_extract_row(request);
entry = (certToTSN_entry *) netsnmp_tdata_extract_entry(request);
info = netsnmp_extract_table_info(request);
/*
* skip newly created rows, as we're going to delete
* them below anyways
*/
if (FATE_NEWLY_CREATED == entry->undo->fate)
continue;
/*
* restore values
*/
switch (info->colnum) {
case COL_SNMPTLSTMCERTTOTSN_FINGERPRINT:
memcpy(entry->fingerprint, entry->undo->fingerprint,
sizeof(entry->fingerprint));
entry->fingerprint_len = entry->undo->fingerprint_len;
entry->hashType = entry->undo->hashType;
break; /* case COL_SNMPTLSTMCERTTOTSN_FINGERPRINT */
case COL_SNMPTLSTMCERTTOTSN_MAPTYPE:
entry->mapType = entry->undo->mapType;
break; /* case COL_SNMPTLSTMCERTTOTSN_MAPTYPE */
case COL_SNMPTLSTMCERTTOTSN_DATA:
memcpy(entry->data, entry->undo->data, sizeof(entry->data));
entry->data_len = entry->undo->data_len;
break; /* case COL_SNMPTLSTMCERTTOTSN_DATA */
case COL_SNMPTLSTMCERTTOTSN_STORAGETYPE:
entry->storageType = entry->undo->storageType;
break; /* case COL_SNMPTLSTMCERTTOTSN_STORAGETYPE */
case COL_SNMPTLSTMCERTTOTSN_ROWSTATUS:
entry->rowStatus = entry->undo->rowStatus;
break; /* case COL_SNMPTLSTMCERTTOTSN_ROWSTATUS */
} /* switch colnum */
} /* for requests */
/*
* release undo data
* or remove any newly created rows
*/
for (request = requests; request; request = request->next) {
table = netsnmp_tdata_extract_table(request);
row = netsnmp_tdata_extract_row(request);
entry = (certToTSN_entry *) netsnmp_tdata_extract_entry(request);
if (!entry || !entry->undo)
continue;
/** disassociate row with requests */
netsnmp_remove_tdata_row(request, row);
if (FATE_NEWLY_CREATED == entry->undo->fate)
tlstmCertToTSNTable_removeEntry(table, row);
else
_freeUndo(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) {
row = netsnmp_tdata_extract_row(request);
table = netsnmp_tdata_extract_table(request);
info = netsnmp_extract_table_info(request);
entry = (certToTSN_entry *) netsnmp_tdata_extract_entry(request);
if ((RS_NOTREADY == entry->rowStatus) && entry->undo->is_consistent)
entry->rowStatus = RS_NOTINSERVICE;
else if ((RS_NOTINSERVICE == entry->rowStatus) &&
(0 == entry->undo->is_consistent))
entry->rowStatus = RS_NOTREADY;
/** release undo data for requests with no rowstatus */
if (entry->undo && !entry->undo->req[COL_SNMPTLSTMCERTTOTSN_ROWSTATUS]) {
_freeUndo(entry);
if ((0 == entry->map_flags) && (entry->rowStatus == RS_ACTIVE))
_cert_map_add(entry);
else if ((0 != entry->map_flags) &&
(entry->rowStatus == RS_DESTROY))
_cert_map_remove(entry);
}
switch (info->colnum) {
case COL_SNMPTLSTMCERTTOTSN_ROWSTATUS:
switch (entry->rowStatus) {
case RS_CREATEANDGO:
/** Fall-through */
case RS_ACTIVE:
netsnmp_assert(entry->undo->is_consistent);
entry->rowStatus = RS_ACTIVE;
if (0 == entry->map_flags)
_cert_map_add(entry);
break;
case RS_CREATEANDWAIT:
/** Fall-through */
case RS_NOTINSERVICE:
/** simply set status based on consistency */
if (entry->undo->is_consistent)
entry->rowStatus = RS_NOTINSERVICE;
else
entry->rowStatus = RS_NOTREADY;
if (0 != entry->map_flags)
_cert_map_remove(entry);
break;
case RS_DESTROY:
/** remove from cert map */
if (0 != entry->map_flags)
_cert_map_remove(entry);
/** disassociate row with requests */
netsnmp_remove_tdata_row(request, row);
tlstmCertToTSNTable_removeEntry(table, row);
row = NULL;
entry = NULL;
}
/** release undo data */
_freeUndo(entry);
break; /* case COL_SNMPTLSTMCERTTOTSN_ROWSTATUS */
case COL_SNMPTLSTMCERTTOTSN_STORAGETYPE:
if (RS_ACTIVE == entry->rowStatus)
_cert_map_tweak_storage(entry);
break; /* case COL_SNMPTLSTMCERTTOTSN_STORAGETYPE */
case COL_SNMPTLSTMCERTTOTSN_FINGERPRINT:
case COL_SNMPTLSTMCERTTOTSN_MAPTYPE:
case COL_SNMPTLSTMCERTTOTSN_DATA:
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->container)
val = 0;
else
val = CONTAINER_SIZE(_table->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;
}
static void
_cert_map_add(certToTSN_entry *entry)
{
netsnmp_cert_map *map;
if (NULL == entry)
return;
DEBUGMSGTL(("tlstmCertToTSNTable:map:add", "pri %ld, fp %s\n",
entry->tlstmCertToTSNID, entry->fingerprint));
map = netsnmp_cert_map_alloc(entry->fingerprint, NULL);
if (NULL == map)
return;
map->priority = entry->tlstmCertToTSNID;
map->mapType = entry->mapType;
if (entry->data)
map->data = strdup(entry->data);
map->hashType = entry->hashType;
map->flags = NSCM_FROM_MIB;
if (entry->storageType == ST_NONVOLATILE)
map->flags |= NSCM_NONVOLATILE;
if (netsnmp_cert_map_add(map) != 0)
netsnmp_cert_map_free(map);
}
static void
_cert_map_tweak_storage(certToTSN_entry *entry)
{
netsnmp_container *maps;
netsnmp_cert_map *map, index;
if (NULL == entry)
return;
DEBUGMSGTL(("tlstmCertToTSNTable:map:tweak", "pri %ld, st %d\n",
entry->tlstmCertToTSNID, entry->storageType));
/** get current active maps */
maps = netsnmp_cert_map_container();
if (NULL == maps)
return;
index.priority = entry->tlstmCertToTSNID;
map = CONTAINER_FIND(maps, &index);
if (NULL == map) {
DEBUGMSGTL(("tlstmCertToTSNTable:map:tweak", "couldn't find map!\n"));
return;
}
if (entry->storageType == ST_NONVOLATILE)
map->flags |= NSCM_NONVOLATILE;
else
map->flags &= ~NSCM_NONVOLATILE;
}
static void
_cert_map_remove(certToTSN_entry *entry)
{
netsnmp_container *maps;
netsnmp_cert_map map;
if (NULL == entry)
return;
DEBUGMSGTL(("tlstmCertToTSNTable:map:remove", "pri %ld, fp %s\n",
entry->tlstmCertToTSNID, entry->fingerprint));
/** get current active maps */
maps = netsnmp_cert_map_container();
if (NULL == maps)
return;
map.priority = entry->tlstmCertToTSNID;
map.fingerprint = entry->fingerprint;
if (CONTAINER_REMOVE(maps, &map) != 0) {
snmp_log(LOG_ERR, "could not remove certificate map");
}
entry->map_flags = 0;
}
static netsnmp_tdata_row *
_entry_from_map(netsnmp_cert_map *map)
{
netsnmp_tdata_row *row;
certToTSN_entry *entry;
row = tlstmCertToTSNTable_createEntry(NULL, map->priority);
if (NULL == row) {
snmp_log(LOG_ERR, "can create tlstmCertToTSN row entry\n");
return NULL;
}
entry = row->data;
if (map->flags & NSCM_FROM_CONFIG)
entry->storageType = ST_PERMANENT;
else if (! (map->flags & NSCM_NONVOLATILE))
entry->storageType = ST_VOLATILE;
entry->map_flags = map->flags;
entry->fingerprint_len = strlen(map->fingerprint);
if (entry->fingerprint_len > sizeof(entry->fingerprint))
entry->fingerprint_len = sizeof(entry->fingerprint) - 1;
memcpy(entry->fingerprint, map->fingerprint, entry->fingerprint_len);
entry->fingerprint[sizeof(entry->fingerprint) - 1] = 0;
entry->hashType = map->hashType;
if (map->data) {
entry->data_len = strlen(map->data);
if (entry->data_len) {
if (entry->data_len > sizeof(entry->data))
entry->data_len = sizeof(entry->data) - 1;
memcpy(entry->data, map->data, entry->data_len);
entry->data[sizeof(entry->data) - 1] = 0;
}
}
entry->mapType = map->mapType;
return row;
}
static int
_cache_load(netsnmp_cache *cache, netsnmp_tdata *table)
{
netsnmp_container *maps;
netsnmp_iterator *map_itr;
netsnmp_cert_map *map;
netsnmp_tdata_row *row;
certToTSN_entry *entry;
int rc = 0;
DEBUGMSGTL(("tlstmCertToTSNTable:cache:load", "called, %" NETSNMP_PRIz "d rows\n",
CONTAINER_SIZE(table->container)));
/** get current active maps */
maps = netsnmp_cert_map_container();
if (NULL == maps)
return 0;
DEBUGMSGTL(("tlstmCertToTSNTable:cache:load", "maps %" NETSNMP_PRIz "d rows\n",
CONTAINER_SIZE(maps)));
map_itr = CONTAINER_ITERATOR(maps);
if (NULL == map_itr) {
DEBUGMSGTL(("tlstmCertToTSNTable:cache:load",
"cant get map iterator\n"));
return -1;
}
/*
* insert rows for active maps into tbl container
*/
map = ITERATOR_FIRST(map_itr);
for( ; map; map = ITERATOR_NEXT(map_itr)) {
row = _entry_from_map(map);
if (NULL == row) {
rc =-1;
break;
}
entry = (certToTSN_entry*)row->data;
entry->rowStatus = RS_ACTIVE;
if (netsnmp_tdata_add_row(table, row) != SNMPERR_SUCCESS) {
tlstmCertToTSNTable_removeEntry(NULL, row);
rc = -1;
break;
}
}
ITERATOR_RELEASE(map_itr);
DEBUGMSGTL(("tlstmCertToTSNTable: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;
certToTSN_entry *entry;
DEBUGMSGTL(("tlstmCertToTSNTable:cache:free", "called, %" NETSNMP_PRIz "d rows\n",
CONTAINER_SIZE(table->container)));
/** insert rows for active maps into tbl container */
tbl_itr = CONTAINER_ITERATOR(table->container);
if (NULL == tbl_itr) {
DEBUGMSGTL(("tlstmCertToTSNTable:cache:free",
"cant get map 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 maps container kept
* by the library). Keep inactive ones for next time.
*/
if (entry->rowStatus == RS_ACTIVE) {
tlstmCertToTSNTable_removeEntry(NULL, row);
ITERATOR_REMOVE(tbl_itr);
continue;
}
}
ITERATOR_RELEASE(tbl_itr);
DEBUGMSGTL(("tlstmCertToTSNTable:cache:free", "done, %" NETSNMP_PRIz "d rows\n",
CONTAINER_SIZE(table->container)));
}
static void
_parse_mib_maps(const char *token, char *line)
{
netsnmp_tdata_row *row;
certToTSN_entry *entry;
netsnmp_cert_map *map = netsnmp_certToTSN_parse_common(&line);
if (NULL == line) {
netsnmp_config_error("incomplete line");
netsnmp_cert_map_free(map);
return;
}
map->flags = NSCM_FROM_MIB | NSCM_NONVOLATILE;
row = _entry_from_map(map);
if (NULL == row) {
netsnmp_cert_map_free(map);
return;
}
entry = (certToTSN_entry*)row->data;
entry->rowStatus = atoi(line);
entry->storageType = ST_NONVOLATILE;
/*
* if row is active, add it to the maps 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 == entry->rowStatus) {
if (netsnmp_cert_map_add(map) != 0)
netsnmp_cert_map_free(map);
}
else {
netsnmp_cert_map_free(map);
if (netsnmp_tdata_add_row(_table, row) != SNMPERR_SUCCESS)
tlstmCertToTSNTable_removeEntry(NULL, row);
}
}
static int
_save_entry(certToTSN_entry *entry, void *app_type)
{
char buf[SNMP_MAXBUF_SMALL], *hashType, *mapType, *data = NULL;
if (NULL == entry)
return SNMP_ERR_GENERR;
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;
}
mapType = se_find_label_in_slist("cert_map_type", entry->mapType);
if (TSNM_tlstmCertSpecified == entry->mapType)
data = entry->data;
snprintf(buf, sizeof(buf), "%s %ld --%s %s --%s %s %d",
MAP_MIB_CONFIG_TOKEN, entry->tlstmCertToTSNID, hashType,
entry->fingerprint, mapType, data ? data : "", entry->rowStatus);
DEBUGMSGTL(("tlstmCertToTSNTable:save", "saving '%s'\n", buf));
read_config_store(app_type, buf);
return SNMP_ERR_NOERROR;
}
static int
_save_map(netsnmp_cert_map *map, int row_status, void *app_type)
{
char buf[SNMP_MAXBUF_SMALL], *hashType, *mapType, *data = NULL;
if (NULL == map)
return SNMP_ERR_GENERR;
/** don't store values from conf files */
if (! (map->flags & NSCM_NONVOLATILE)) {
DEBUGMSGT(("tlstmCertToTSNTable:save",
"skipping RO/permanent/volatile row\n"));
return SNMP_ERR_NOERROR;
}
hashType = se_find_label_in_slist("cert_hash_alg", map->hashType);
if (NULL == hashType) {
snmp_log(LOG_ERR, "skipping entry unknown hash type %d\n",
map->hashType);
return SNMP_ERR_GENERR;
}
mapType = se_find_label_in_slist("cert_map_type", map->mapType);
if (TSNM_tlstmCertSpecified == map->mapType)
data = (char*)map->data;
snprintf(buf, sizeof(buf), "%s %d --%s %s --%s %s %d",
MAP_MIB_CONFIG_TOKEN, map->priority, hashType, map->fingerprint,
mapType, data ? data : "", row_status);
DEBUGMSGTL(("tlstmCertToTSNTable:save", "saving '%s'\n", buf));
read_config_store(app_type, buf);
return SNMP_ERR_NOERROR;
}
static int
_save_maps(int majorID, int minorID, void *serverarg, void *clientarg)
{
char sep[] =
"\n##############################################################";
char buf[] =
"#\n" "# certificate secName mapping persistent data\n" "#";
char *type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
NETSNMP_DS_LIB_APPTYPE);
netsnmp_container *maps = netsnmp_cert_map_container();
netsnmp_tdata_row *row;
netsnmp_iterator *tbl_itr, *map_itr;
netsnmp_cert_map *map;
certToTSN_entry *entry;
if ((NULL == maps) || ((CONTAINER_SIZE(maps) == 0) &&
(CONTAINER_SIZE(_table->container) == 0)))
return SNMPERR_SUCCESS;
read_config_store((char *) type, sep);
read_config_store((char *) type, buf);
/*
* save active rows from maps
*/
if (NULL != maps) {
map_itr = CONTAINER_ITERATOR(maps);
if (NULL == map_itr) {
DEBUGMSGTL(("tlstmCertToTSNTable:save",
"cant get map iterator\n"));
map = NULL;
}
else
map = ITERATOR_FIRST(map_itr);
for( ; map; map = ITERATOR_NEXT(map_itr)) {
/** don't store config rows */
if (map->flags & NSCM_FROM_CONFIG)
continue;
_save_map(map, RS_ACTIVE, type);
}
}
ITERATOR_RELEASE(map_itr);
/*
* save inactive rows from mib
*/
tbl_itr = CONTAINER_ITERATOR(_table->container);
if (NULL == tbl_itr)
DEBUGMSGTL(("tlstmCertToTSNTable: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 maps and thus saved
* above) and volatile rows.
*/
if ((entry->rowStatus == RS_ACTIVE) ||
(entry->storageType != 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 const oid _tsnm_base[] = { SNMP_TLS_TM_BASE, 1, 1 };
static const int _tsnm_base_len = sizeof(_tsnm_base);
static oid
_oid2type(oid *val, int val_len)
{
netsnmp_assert(val);
if (val_len != (_tsnm_base_len + sizeof(oid)))
return -1;
if (memcmp(_tsnm_base,val,_tsnm_base_len) != 0)
return -2;
if ((val[OID_LENGTH(_tsnm_base)] > TSNM_tlstmCert_MAX) ||
(0 == val[OID_LENGTH(_tsnm_base)]))
return -3;
return val[OID_LENGTH(_tsnm_base)];
}
#if 0
static int
_type2oid(int type, oid *val, int *val_len)
{
netsnmp_assert( val && val_len );
if (*val_len < _tsnm_base_len + sizeof(oid))
return -1;
memcpy(val, _tsnm_base, _tsnm_base_len + sizeof(oid));
val[_tsnm_base_len + sizeof(oid)] = type;
return 0;
}
#endif