| /* |
| * 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; |
| } |
| } |