/* * Note: this file originally auto-generated by mib2c using * $ */ #include #include #include #include #include #include #include #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; int rc; 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; rc = netsnmp_tdata_register(reg, _table_data, table_info); if (rc) { snmp_log(LOG_ERR, "%s: netsnmp_tdata_register() returned %d\n", __func__, rc); return; } 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 { const int rc = netsnmp_register_scalar(reg); if (rc) { snmp_log(LOG_ERR, "%s: netsnmp_register_scalar() returned %d\n", __func__, rc); return; } 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; netsnmp_tlstmParams_add(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] == NULL) { _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; netsnmp_tlstmParams_add(params); } else { netsnmp_tdata_row *row; snmpTlstmParamsTable_entry *entry; row = snmpTlstmParamsTable_createEntry(_table_data, params->name, strlen(params->name)); if (!row) { netsnmp_tlstmParams_free(params); 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); } }