/* * Note: this file originally auto-generated by mib2c using * $ */ #include #include #include #include #include #include #include #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 */ char addr_flags; } tlstmAddrTable_entry; 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; int rc; 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; 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; } 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 { 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), "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\n", name, entry)); } 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] == NULL) { _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 = NULL, *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]); if (asprintf(&buf, "%s %s --%s %s %s %d", mib_token, entry->snmpTargetAddrName, hashType, entry->tlstmAddrServerFingerprint, entry->tlstmAddrServerIdentity, entry->tlstmAddrRowStatus) < 0) { return SNMP_ERR_GENERR; } read_config_store(type, buf); DEBUGMSGTL(("tlstmAddrTable:row:save", "saving entry '%s'\n", buf)); free(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; } }