/* * Note: this file originally auto-generated by mib2c using * $ */ #include #include #include #include #include #include #include #include "tlstm-mib.h" #include "snmpTlstmCertToTSNTable.h" netsnmp_feature_require(table_tdata); netsnmp_feature_require(cert_fingerprints); netsnmp_feature_require(table_tdata_delete_table); netsnmp_feature_require(table_tdata_extract_table); netsnmp_feature_require(table_tdata_remove_row); netsnmp_feature_require(tls_fingerprint_build); #ifndef NETSNMP_NO_WRITE_SUPPORT netsnmp_feature_require(check_vb_storagetype); netsnmp_feature_require(check_vb_type_and_max_size); netsnmp_feature_require(check_vb_rowstatus_with_storagetype); netsnmp_feature_require(table_tdata_insert_row); #endif /* NETSNMP_NO_WRITE_SUPPORT */ /** XXX - move these to table_data header? */ #define FATE_NEWLY_CREATED 1 #define FATE_NO_CHANGE 0 #define FATE_DELETE_ME -1 #define MAP_MIB_CONFIG_TOKEN "snmpTlstmCertToTSNEntry" /* * structure for undo storage and other vars for set processing */ typedef struct certToTSN_undo_s { char fate; char copied; char is_consistent; netsnmp_request_info *req[SNMPTLSTMCERTTOTSN_TABLE_MAX_COL+1]; /* * undo Column space */ char fingerprint[SNMPTLSTMCERTTOTSN_FINGERPRINT_MAX_SIZE]; size_t fingerprint_len; int mapType; char data[SNMPTLSTMCERTTOTSN_DATA_MAX_SIZE]; size_t data_len; u_char hashType; char storageType; char rowStatus; } certToTSN_undo; /* * Typical data structure for a row entry */ typedef struct certToTSN_entry_s { /* * Index values */ u_long tlstmCertToTSNID; /* * Column values */ char fingerprint[SNMPTLSTMCERTTOTSN_FINGERPRINT_MAX_SIZE]; size_t fingerprint_len; int mapType; char data[SNMPTLSTMCERTTOTSN_DATA_MAX_SIZE]; size_t data_len; char storageType; char rowStatus; u_char hashType; char map_flags; /* * used during set processing */ certToTSN_undo *undo; } certToTSN_entry; static Netsnmp_Node_Handler tlstmCertToTSNTable_handler; static oid _oid2type(oid *val, int val_len); /** static int _type2oid(int type, oid *val, int *val_len); */ static int _cache_load(netsnmp_cache *cache, netsnmp_tdata *table); static void _cache_free(netsnmp_cache *cache, netsnmp_tdata *table); static void _cert_map_add(certToTSN_entry *entry); static void _cert_map_remove(certToTSN_entry *entry); static int _count_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests); static void _parse_mib_maps(const char *token, char *line); static int _save_maps(int majorID, int minorID, void *server, void *client); static int _save_map(netsnmp_cert_map *map, int row_status, void *type); static void _cert_map_tweak_storage(certToTSN_entry *entry); static netsnmp_tdata *_table = NULL; static uint32_t _last_changed = 0; /** Initializes the tlstmCertToTSNTable module */ void init_snmpTlstmCertToTSNTable(void) { init_snmpTlstmCertToTSNTable_context(NULL); } void init_snmpTlstmCertToTSNTable_context(const char *contextName) { oid reg_oid[] = { SNMP_TLS_TM_CERT_TABLE }; const size_t reg_oid_len = OID_LENGTH(reg_oid); netsnmp_handler_registration *reg; netsnmp_table_registration_info *info; netsnmp_cache *cache; netsnmp_watcher_info *watcher; static const char mib_map_help[] = MAP_MIB_CONFIG_TOKEN " table persistence (internal use)"; int rc; DEBUGMSGTL(("tlstmCertToSN:init", "initializing table tlstmCertToTSNTable\n")); reg = netsnmp_create_handler_registration ("tlstmCertToTSNTable", tlstmCertToTSNTable_handler, reg_oid, reg_oid_len, HANDLER_CAN_RWRITE); if (NULL == reg) { snmp_log(LOG_ERR, "error creating handler registration for tlstmCertToSN\n"); return; } if (NULL != contextName) reg->contextName = strdup(contextName); _table = netsnmp_tdata_create_table("tlstmCertToTSNTable", 0); if (NULL == _table) { snmp_log(LOG_ERR, "error creating tdata table for tlstmCertToTSNTable\n"); return; } info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info); if (NULL == info) { snmp_log(LOG_ERR, "error creating table info for tlstmCertToTSNTable\n"); netsnmp_tdata_delete_table(_table); _table = NULL; return; } netsnmp_table_helper_add_indexes(info, /* index: tlstmCertToTSNID */ ASN_UNSIGNED, 0); info->min_column = SNMPTLSTMCERTTOTSN_TABLE_MIN_COL; info->max_column = SNMPTLSTMCERTTOTSN_TABLE_MAX_COL; /* * cache init */ cache = netsnmp_cache_create(30, (NetsnmpCacheLoad*)_cache_load, (NetsnmpCacheFree*)_cache_free, reg_oid, reg_oid_len); if (NULL == cache) { snmp_log(LOG_ERR,"error creating cache for tlstmCertToTSNTable\n"); netsnmp_tdata_delete_table(_table); _table = NULL; return; } cache->magic = (void *)_table; cache->flags = NETSNMP_CACHE_DONT_INVALIDATE_ON_SET; rc = netsnmp_tdata_register(reg, _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] = 1; reg = netsnmp_create_handler_registration("snmpTlstmCertToTSNCount", _count_handler, reg_oid, OID_LENGTH(reg_oid), HANDLER_CAN_RONLY); if (NULL == reg) snmp_log(LOG_ERR, "could not create handler for snmpTlstmCertToTSNCount\n"); else { int rc; if (NULL != contextName) reg->contextName = strdup(contextName); 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), "snmpTlstmCertToTSNCount"); } reg_oid[10] = 2; reg = netsnmp_create_handler_registration( "snmpTlstmCertToTSNTableLastChanged", NULL, reg_oid, OID_LENGTH(reg_oid), HANDLER_CAN_RONLY); watcher = netsnmp_create_watcher_info((void*)&_last_changed, sizeof(_last_changed), ASN_TIMETICKS, WATCHER_FIXED_SIZE); if ((NULL == reg) || (NULL == watcher)) snmp_log(LOG_ERR, "could not create handler for snmpTlstmCertToTSNCount\n"); else { if (NULL != contextName) reg->contextName = strdup(contextName); netsnmp_register_watched_scalar2(reg, watcher); } /* * persistence */ register_config_handler(NULL, MAP_MIB_CONFIG_TOKEN, _parse_mib_maps, NULL, mib_map_help); if (snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, _save_maps, NULL) != SNMP_ERR_NOERROR) snmp_log(LOG_ERR, "error registering for STORE_DATA callback " "for certToTSN\n"); } /* * create a new row in the table */ netsnmp_tdata_row * tlstmCertToTSNTable_createEntry(netsnmp_tdata * table, u_long tlstmCertToTSNID) { certToTSN_entry *entry; netsnmp_tdata_row *row; entry = SNMP_MALLOC_TYPEDEF(certToTSN_entry); if (!entry) return NULL; row = netsnmp_tdata_create_row(); if (!row) { SNMP_FREE(entry); return NULL; } row->data = entry; DEBUGMSGT(("tlstmCertToSN:entry:create", "entry %p / row %p\n", entry, row)); /* * populate index */ entry->tlstmCertToTSNID = tlstmCertToTSNID; netsnmp_tdata_row_add_index(row, ASN_UNSIGNED, &(entry->tlstmCertToTSNID), sizeof(entry->tlstmCertToTSNID)); /* * assign default column values */ entry->mapType = TSNM_tlstmCertSpecified; entry->storageType = ST_NONVOLATILE; entry->rowStatus = RS_NOTREADY; if (table) { DEBUGMSGTL(("tlstmCertToTSN:row:insert", "row %p\n", row)); netsnmp_tdata_add_row(table, row); } return row; } /* * allocate undo resources */ static certToTSN_undo * _allocUndo(certToTSN_entry * entry) { if (!entry) return NULL; netsnmp_assert(!entry->undo); entry->undo = SNMP_MALLOC_TYPEDEF(certToTSN_undo); if (!entry->undo) return NULL; entry->undo->is_consistent = -1; /* don't know */ return entry->undo; } /* * free undo resources */ static void _freeUndo(certToTSN_entry * entry) { if (!entry || !entry->undo) return; /* * TODO: release any allocated resources */ SNMP_FREE(entry->undo); } /* * remove a row from the table */ void tlstmCertToTSNTable_removeEntry(netsnmp_tdata * table, netsnmp_tdata_row * row) { certToTSN_entry *entry; if (!row) return; /* Nothing to remove */ entry = (certToTSN_entry *) row->data; DEBUGMSGT(("tlstmCertToSN:entry:delete", "entry %p / row %p\n", entry, row)); if (entry && entry->undo) _freeUndo(entry); SNMP_FREE(entry); if (table) { DEBUGMSGTL(("tlstmCertToSN:row:remove", "row %p\n", row)); netsnmp_tdata_remove_and_delete_row(table, row); } else netsnmp_tdata_delete_row(row); } /** handles requests for the tlstmCertToTSNTable table */ static int tlstmCertToTSNTable_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { oid tsnm[] = { SNMP_TLS_TM_BASE, 1, 1, 0 }; static const int tsnm_pos = OID_LENGTH(tsnm) - 1; netsnmp_request_info *request = NULL; netsnmp_table_request_info *info; netsnmp_tdata *table; netsnmp_tdata_row *row; certToTSN_entry *entry; int ret = SNMP_ERR_NOERROR; DEBUGMSGTL(("tlstmCertToSN:handler", "Processing request (mode %s (%d))\n", se_find_label_in_slist("agent_mode", reqinfo->mode), reqinfo->mode)); switch (reqinfo->mode) { /** ######################################################### GET ##### * * Read-support (also covers GetNext requests) */ case MODE_GET: for (request = requests; request; request = request->next) { if (request->processed) continue; entry = (certToTSN_entry *) netsnmp_tdata_extract_entry(request); info = netsnmp_extract_table_info(request); netsnmp_assert(entry && info); switch (info->colnum) { case COL_SNMPTLSTMCERTTOTSN_FINGERPRINT: { /* * build SnmpTLSFingerprint */ u_char bin[EVP_MAX_MD_SIZE+1], *ptr = bin; size_t len = sizeof(bin); int rc; rc = netsnmp_tls_fingerprint_build(entry->hashType, entry->fingerprint, &ptr, &len, 0); if (SNMPERR_SUCCESS != rc) netsnmp_set_request_error(reqinfo, request, SNMP_ERR_GENERR); else snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR, bin, len); } break; /* case COL_SNMPTLSTMCERTTOTSN_FINGERPRINT */ case COL_SNMPTLSTMCERTTOTSN_MAPTYPE: tsnm[tsnm_pos] = entry->mapType; snmp_set_var_typed_value(request->requestvb, ASN_OBJECT_ID, tsnm, sizeof(tsnm)); break; /* case COL_SNMPTLSTMCERTTOTSN_MAPTYPE */ case COL_SNMPTLSTMCERTTOTSN_DATA: snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR, entry->data, entry->data_len); break; /* case COL_SNMPTLSTMCERTTOTSN_DATA */ case COL_SNMPTLSTMCERTTOTSN_STORAGETYPE: snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER, entry->storageType); break; /* case COL_SNMPTLSTMCERTTOTSN_STORAGETYPE */ case COL_SNMPTLSTMCERTTOTSN_ROWSTATUS: snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER, entry->rowStatus); break; /* case COL_SNMPTLSTMCERTTOTSN_ROWSTATUS */ default: netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT); break; } /* switch colnum */ } /* for requests */ break; /* case MODE_GET */ /* * Write-support */ /** #################################################### RESERVE1 ##### * * In RESERVE1 we are just checking basic ASN.1 size/type restrictions. * You probably don't need to change any of this code. Don't change any * of the column values here. Save that for the ACTION phase. * * The next phase is RESERVE2 or FREE. */ case MODE_SET_RESERVE1: for (request = requests; request; request = request->next) { netsnmp_assert(request->processed == 0); entry = (certToTSN_entry *) netsnmp_tdata_extract_entry(request); info = netsnmp_extract_table_info(request); if ((NULL != entry) && (ST_READONLY == entry->storageType)) { ret = SNMP_ERR_NOTWRITABLE; break; } switch (info->colnum) { case COL_SNMPTLSTMCERTTOTSN_FINGERPRINT: ret = netsnmp_check_vb_type_and_max_size (request->requestvb, ASN_OCTET_STR, sizeof(entry->fingerprint)); /** check len/algorithm MIB requirements */ if (ret == SNMP_ERR_NOERROR) ret = netsnmp_cert_check_vb_fingerprint(request->requestvb); break; /* case COL_SNMPTLSTMCERTTOTSN_FINGERPRINT */ case COL_SNMPTLSTMCERTTOTSN_MAPTYPE: ret = netsnmp_check_vb_type_and_max_size (request->requestvb, ASN_OBJECT_ID, SNMPTLSTMCERTTOTSN_MAPTYPE_MAX_SIZE); if (ret == SNMP_ERR_NOERROR) { if (_oid2type(request->requestvb->val.objid, request->requestvb->val_len) > TSNM_tlstmCert_MAX) ret = SNMP_ERR_WRONGVALUE; } break; /* case COL_SNMPTLSTMCERTTOTSN_MAPTYPE */ case COL_SNMPTLSTMCERTTOTSN_DATA: ret = netsnmp_check_vb_type_and_max_size (request->requestvb, ASN_OCTET_STR, sizeof(entry->data)); break; /* case COL_SNMPTLSTMCERTTOTSN_DATA */ case COL_SNMPTLSTMCERTTOTSN_STORAGETYPE: ret = netsnmp_check_vb_storagetype (request->requestvb,(entry ? entry->storageType : ST_NONE)); break; /* case COL_SNMPTLSTMCERTTOTSN_STORAGETYPE */ case COL_SNMPTLSTMCERTTOTSN_ROWSTATUS: ret = netsnmp_check_vb_rowstatus_with_storagetype (request->requestvb, (entry ? entry->rowStatus :RS_NONEXISTENT), (entry ? entry->storageType :ST_NONE)); break; /* case COL_SNMPTLSTMCERTTOTSN_ROWSTATUS */ default: ret = SNMP_ERR_NOTWRITABLE; } /* switch colnum */ if (ret != SNMP_ERR_NOERROR) break; } /* for requests */ break; /* case MODE_SET_RESERVE1 */ /** #################################################### RESERVE2 ##### * * RESERVE2 is for checking additional restrictions from the MIB. * Since these restrictions are often in the description of the object, * mib2c can't generate code. It's possible that you need to add * additional checks here. However, don't change any of the column * values here. Save that for the ACTION phase. * * The next phase is ACTION or FREE. */ case MODE_SET_RESERVE2: for (request = requests; request; request = request->next) { netsnmp_assert(request->processed == 0); entry = (certToTSN_entry *) netsnmp_tdata_extract_entry(request); table = netsnmp_tdata_extract_table(request); info = netsnmp_extract_table_info(request); /* * if no row, create one */ if (!entry) { row = tlstmCertToTSNTable_createEntry (table,*info->indexes->val.integer); if (!row) { ret = SNMP_ERR_RESOURCEUNAVAILABLE; break; } entry = row->data; _allocUndo(entry); if (!entry->undo) { tlstmCertToTSNTable_removeEntry(table, row); row = NULL; ret = SNMP_ERR_RESOURCEUNAVAILABLE; break; } entry->undo->fate = FATE_NEWLY_CREATED; /** associate row with requests */ netsnmp_insert_tdata_row(request, row); } /** allocate undo structure, if needed */ if (!entry->undo) { _allocUndo(entry); if (!entry->undo) { ret = SNMP_ERR_RESOURCEUNAVAILABLE; break; } } /* * save request ptr for column. if we already * have a value, bail. */ if (entry->undo->req[info->colnum]) { DEBUGMSGT(("tlstmCertToSN:reserve2", "multiple sets to col %d in request\n", info->colnum)); if (FATE_NEWLY_CREATED == entry->undo->fate) ret = SNMP_ERR_INCONSISTENTNAME; else ret = SNMP_ERR_INCONSISTENTVALUE; break; } entry->undo->req[info->colnum] = request; if (ret != SNMP_ERR_NOERROR) break; } /* for requests */ if (ret == SNMP_ERR_NOERROR) { /** make sure rowstatus is used to create rows */ for (request = requests; request; request = request->next) { if (request->processed) continue; entry = (certToTSN_entry *) netsnmp_tdata_extract_entry(request); if ((entry->undo->fate != FATE_NEWLY_CREATED) || (entry->undo->req[COL_SNMPTLSTMCERTTOTSN_ROWSTATUS])) continue; ret = SNMP_ERR_INCONSISTENTNAME; break; } /* creation for requests */ } /* no error */ break; /* case MODE_SET_RESERVE2 */ /** ######################################################## FREE ##### * * FREE is for cleaning up after a failed request (during either * RESERVE1 or RESERVE2). So any allocated resources need to be * released. * * This the final phase for this path in the state machine. */ case MODE_SET_FREE: /* * release undo resources * remove any newly created rows */ for (request = requests; request; request = request->next) { table = netsnmp_tdata_extract_table(request); row = netsnmp_tdata_extract_row(request); entry = (certToTSN_entry *) netsnmp_tdata_extract_entry(request); if (!entry || !entry->undo) continue; /** disassociate row with requests */ netsnmp_remove_tdata_row(request, row); if (FATE_NEWLY_CREATED == entry->undo->fate) tlstmCertToTSNTable_removeEntry(table, row); else _freeUndo(entry); } break; /* case MODE_SET_FREE */ /** ###################################################### ACTION ##### * * In the ACTION phase, we perform any sets that can be undone. * (Save anything that can't be undone for the COMMIT phase.) * * After individual columns have been done, you should check that the * row as a whole is consistent. * * The next phase is UNDO or COMMIT. */ case MODE_SET_ACTION: for (request = requests; request; request = request->next) { entry = (certToTSN_entry *) netsnmp_tdata_extract_entry(request); info = netsnmp_extract_table_info(request); /** reserve2 should enforce this */ netsnmp_assert(request == entry->undo->req[info->colnum]); /* * for each col, save old value and the set new value */ switch (info->colnum) { case COL_SNMPTLSTMCERTTOTSN_FINGERPRINT: { u_char *tmp = (u_char*)entry->fingerprint; u_int size = sizeof(entry->fingerprint); netsnmp_variable_list *vb = request->requestvb; memcpy(entry->undo->fingerprint, entry->fingerprint, sizeof(entry->fingerprint)); entry->undo->fingerprint_len = entry->fingerprint_len; entry->undo->hashType = entry->hashType; memset(entry->fingerprint, 0, sizeof(entry->fingerprint)); (void)netsnmp_tls_fingerprint_parse(vb->val.string, vb->val_len, (char**)&tmp, &size, 0, &entry->hashType); entry->fingerprint_len = size; if (0 == entry->fingerprint_len) ret = SNMP_ERR_GENERR; } break; /* case COL_SNMPTLSTMCERTTOTSN_FINGERPRINT */ case COL_SNMPTLSTMCERTTOTSN_MAPTYPE: entry->undo->mapType = entry->mapType; entry->mapType = _oid2type(request->requestvb->val.objid, request->requestvb->val_len); break; /* case COL_SNMPTLSTMCERTTOTSN_MAPTYPE */ case COL_SNMPTLSTMCERTTOTSN_DATA: memcpy(entry->undo->data, entry->data, sizeof(entry->data)); entry->undo->data_len = entry->data_len; memset(entry->data, 0, sizeof(entry->data)); memcpy(entry->data, request->requestvb->val.string, request->requestvb->val_len); entry->data_len = request->requestvb->val_len; break; /* case COL_SNMPTLSTMCERTTOTSN_DATA */ case COL_SNMPTLSTMCERTTOTSN_STORAGETYPE: entry->undo->storageType = entry->storageType; entry->storageType = *request->requestvb->val.integer; break; /* case COL_SNMPTLSTMCERTTOTSN_STORAGETYPE */ case COL_SNMPTLSTMCERTTOTSN_ROWSTATUS: entry->undo->rowStatus = entry->rowStatus; entry->rowStatus = *request->requestvb->val.integer; break; /* case COL_SNMPTLSTMCERTTOTSN_ROWSTATUS */ } /* switch colnum */ } /* set values for requests */ if (ret != SNMP_ERR_NOERROR) break; /* skip consistency if we've already got error */ /* * All columns now have their final values set. check the * internal consistency of each row. */ for (request = requests; request; request = request->next) { entry = (certToTSN_entry *) netsnmp_tdata_extract_entry(request); info = netsnmp_extract_table_info(request); if (entry->undo->is_consistent != -1) continue; /* already checked */ /** assume consistency */ entry->undo->is_consistent = 1; /* * per mib, can't have empty fingerprint and must * have data if indicated by map type. */ if (0 == entry->fingerprint_len) { DEBUGMSGTL(("tlstmCertToTSNTable:inconsistent", "fingerprint must not be empty\n")); entry->undo->is_consistent = 0; } else if ((TSNM_tlstmCertSpecified == entry->mapType) && (0 == entry->data_len)) { DEBUGMSGTL(("tlstmCertToTSNTable:inconsistent", "must specify Data for CertSpecified identity\n")); entry->undo->is_consistent = 0; } if ((RS_IS_ACTIVE(entry->rowStatus)) && ((!entry->undo->req[COL_SNMPTLSTMCERTTOTSN_ROWSTATUS]) || (RS_IS_ACTIVE(entry->undo->rowStatus)))) { /* * per mib, can't modify these while row active */ char _cols[3] = { COL_SNMPTLSTMCERTTOTSN_FINGERPRINT, COL_SNMPTLSTMCERTTOTSN_MAPTYPE, COL_SNMPTLSTMCERTTOTSN_DATA }; int i; for (i=0; i < 3; ++i ) { if (!entry->undo->req[i]) continue; DEBUGMSGTL(("tlstmCertToTSNTable:inconsistent", "can't modify row %d while active\n", _cols[i])); entry->undo->is_consistent = 0; ret = SNMP_ERR_NOTWRITABLE; request= entry->undo->req[i]; break; } } else if (RS_IS_GOING_ACTIVE(entry->rowStatus)) { /* * if going active, inconsistency is fatal */ if (!entry->undo->is_consistent) { netsnmp_assert(entry->undo->req[COL_SNMPTLSTMCERTTOTSN_ROWSTATUS]); if (FATE_NEWLY_CREATED == entry->undo->fate) ret = SNMP_ERR_INCONSISTENTNAME; else ret = SNMP_ERR_INCONSISTENTVALUE; request = entry->undo->req[COL_SNMPTLSTMCERTTOTSN_ROWSTATUS]; } } else if (RS_DESTROY == entry->rowStatus) { /* * can't destroy active row */ if (RS_IS_ACTIVE(entry->undo->rowStatus)) { DEBUGMSGTL(("tlstmCertToTSNTable:inconsistent", "can't destroy active row\n")); netsnmp_assert(entry->undo->req[COL_SNMPTLSTMCERTTOTSN_ROWSTATUS]); ret = SNMP_ERR_INCONSISTENTVALUE; request = entry->undo->req[COL_SNMPTLSTMCERTTOTSN_ROWSTATUS]; } } if (ret != SNMP_ERR_NOERROR) break; } /* consistency for requests */ break; /* case MODE_SET_ACTION */ /** ######################################################## UNDO ##### * * UNDO is for cleaning up any failed requests that went through the * ACTION phase. * * This the final phase for this path in the state machine. */ case MODE_SET_UNDO: for (request = requests; request; request = request->next) { row = netsnmp_tdata_extract_row(request); entry = (certToTSN_entry *) netsnmp_tdata_extract_entry(request); info = netsnmp_extract_table_info(request); /* * skip newly created rows, as we're going to delete * them below anyways */ if (FATE_NEWLY_CREATED == entry->undo->fate) continue; /* * restore values */ switch (info->colnum) { case COL_SNMPTLSTMCERTTOTSN_FINGERPRINT: memcpy(entry->fingerprint, entry->undo->fingerprint, sizeof(entry->fingerprint)); entry->fingerprint_len = entry->undo->fingerprint_len; entry->hashType = entry->undo->hashType; break; /* case COL_SNMPTLSTMCERTTOTSN_FINGERPRINT */ case COL_SNMPTLSTMCERTTOTSN_MAPTYPE: entry->mapType = entry->undo->mapType; break; /* case COL_SNMPTLSTMCERTTOTSN_MAPTYPE */ case COL_SNMPTLSTMCERTTOTSN_DATA: memcpy(entry->data, entry->undo->data, sizeof(entry->data)); entry->data_len = entry->undo->data_len; break; /* case COL_SNMPTLSTMCERTTOTSN_DATA */ case COL_SNMPTLSTMCERTTOTSN_STORAGETYPE: entry->storageType = entry->undo->storageType; break; /* case COL_SNMPTLSTMCERTTOTSN_STORAGETYPE */ case COL_SNMPTLSTMCERTTOTSN_ROWSTATUS: entry->rowStatus = entry->undo->rowStatus; break; /* case COL_SNMPTLSTMCERTTOTSN_ROWSTATUS */ } /* switch colnum */ } /* for requests */ /* * release undo data * or remove any newly created rows */ for (request = requests; request; request = request->next) { table = netsnmp_tdata_extract_table(request); row = netsnmp_tdata_extract_row(request); entry = (certToTSN_entry *) netsnmp_tdata_extract_entry(request); if (!entry || !entry->undo) continue; /** disassociate row with requests */ netsnmp_remove_tdata_row(request, row); if (FATE_NEWLY_CREATED == entry->undo->fate) tlstmCertToTSNTable_removeEntry(table, row); else _freeUndo(entry); } /* for requests */ break; /* case MODE_SET_UNDO */ /** ###################################################### COMMIT ##### * * COMMIT is the final success state, when all changes are finalized. * There is not recovery state should something faile here. * * This the final phase for this path in the state machine. */ case MODE_SET_COMMIT: for (request = requests; request; request = request->next) { row = netsnmp_tdata_extract_row(request); table = netsnmp_tdata_extract_table(request); info = netsnmp_extract_table_info(request); entry = (certToTSN_entry *) netsnmp_tdata_extract_entry(request); if ((RS_NOTREADY == entry->rowStatus) && entry->undo->is_consistent) entry->rowStatus = RS_NOTINSERVICE; else if ((RS_NOTINSERVICE == entry->rowStatus) && (0 == entry->undo->is_consistent)) entry->rowStatus = RS_NOTREADY; /** release undo data for requests with no rowstatus */ if (entry->undo && !entry->undo->req[COL_SNMPTLSTMCERTTOTSN_ROWSTATUS]) { _freeUndo(entry); if ((0 == entry->map_flags) && (entry->rowStatus == RS_ACTIVE)) _cert_map_add(entry); else if ((0 != entry->map_flags) && (entry->rowStatus == RS_DESTROY)) _cert_map_remove(entry); } switch (info->colnum) { case COL_SNMPTLSTMCERTTOTSN_ROWSTATUS: switch (entry->rowStatus) { case RS_CREATEANDGO: /** Fall-through */ case RS_ACTIVE: netsnmp_assert(entry->undo->is_consistent); entry->rowStatus = RS_ACTIVE; if (0 == entry->map_flags) _cert_map_add(entry); break; case RS_CREATEANDWAIT: /** Fall-through */ case RS_NOTINSERVICE: /** simply set status based on consistency */ if (entry->undo->is_consistent) entry->rowStatus = RS_NOTINSERVICE; else entry->rowStatus = RS_NOTREADY; if (0 != entry->map_flags) _cert_map_remove(entry); break; case RS_DESTROY: /** remove from cert map */ if (0 != entry->map_flags) _cert_map_remove(entry); /** disassociate row with requests */ netsnmp_remove_tdata_row(request, row); tlstmCertToTSNTable_removeEntry(table, row); row = NULL; entry = NULL; } /** release undo data */ _freeUndo(entry); break; /* case COL_SNMPTLSTMCERTTOTSN_ROWSTATUS */ case COL_SNMPTLSTMCERTTOTSN_STORAGETYPE: if (RS_ACTIVE == entry->rowStatus) _cert_map_tweak_storage(entry); break; /* case COL_SNMPTLSTMCERTTOTSN_STORAGETYPE */ case COL_SNMPTLSTMCERTTOTSN_FINGERPRINT: case COL_SNMPTLSTMCERTTOTSN_MAPTYPE: case COL_SNMPTLSTMCERTTOTSN_DATA: break; } /* switch colnum */ } /* for requests */ /** update last changed */ _last_changed = netsnmp_get_agent_uptime(); /** set up to save persistent store */ snmp_store_needed(NULL); break; /* case MODE_SET_COMMIT */ } /* switch (reqinfo->mode) */ if (ret != SNMP_ERR_NOERROR) netsnmp_set_request_error(reqinfo, request, ret); return SNMP_ERR_NOERROR; } static int _count_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { int val; if (MODE_GET != reqinfo->mode) { snmp_log(LOG_ERR, "bad mode in RO handler"); return SNMP_ERR_GENERR; } if (NULL == _table->container) val = 0; else val = CONTAINER_SIZE(_table->container); snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, (u_char *) &val, sizeof(val)); if (handler->next && handler->next->access_method) return netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); return SNMP_ERR_NOERROR; } static void _cert_map_add(certToTSN_entry *entry) { netsnmp_cert_map *map; if (NULL == entry) return; DEBUGMSGTL(("tlstmCertToTSNTable:map:add", "pri %ld, fp %s\n", entry->tlstmCertToTSNID, entry->fingerprint)); map = netsnmp_cert_map_alloc(entry->fingerprint, NULL); if (NULL == map) return; map->priority = entry->tlstmCertToTSNID; map->mapType = entry->mapType; map->data = strdup(entry->data); map->hashType = entry->hashType; map->flags = NSCM_FROM_MIB; if (entry->storageType == ST_NONVOLATILE) map->flags |= NSCM_NONVOLATILE; if (netsnmp_cert_map_add(map) != 0) netsnmp_cert_map_free(map); } static void _cert_map_tweak_storage(certToTSN_entry *entry) { netsnmp_container *maps; netsnmp_cert_map *map, index; if (NULL == entry) return; DEBUGMSGTL(("tlstmCertToTSNTable:map:tweak", "pri %ld, st %d\n", entry->tlstmCertToTSNID, entry->storageType)); /** get current active maps */ maps = netsnmp_cert_map_container(); if (NULL == maps) return; index.priority = entry->tlstmCertToTSNID; map = CONTAINER_FIND(maps, &index); if (NULL == map) { DEBUGMSGTL(("tlstmCertToTSNTable:map:tweak", "couldn't find map!\n")); return; } if (entry->storageType == ST_NONVOLATILE) map->flags |= NSCM_NONVOLATILE; else map->flags &= ~NSCM_NONVOLATILE; } static void _cert_map_remove(certToTSN_entry *entry) { netsnmp_container *maps; netsnmp_cert_map map; if (NULL == entry) return; DEBUGMSGTL(("tlstmCertToTSNTable:map:remove", "pri %ld, fp %s\n", entry->tlstmCertToTSNID, entry->fingerprint)); /** get current active maps */ maps = netsnmp_cert_map_container(); if (NULL == maps) return; map.priority = entry->tlstmCertToTSNID; map.fingerprint = entry->fingerprint; if (CONTAINER_REMOVE(maps, &map) != 0) { snmp_log(LOG_ERR, "could not remove certificate map"); } entry->map_flags = 0; } static netsnmp_tdata_row * _entry_from_map(netsnmp_cert_map *map) { netsnmp_tdata_row *row; certToTSN_entry *entry; row = tlstmCertToTSNTable_createEntry(NULL, map->priority); if (NULL == row) { snmp_log(LOG_ERR, "can create tlstmCertToTSN row entry\n"); return NULL; } entry = row->data; if (map->flags & NSCM_FROM_CONFIG) entry->storageType = ST_PERMANENT; else if (! (map->flags & NSCM_NONVOLATILE)) entry->storageType = ST_VOLATILE; entry->map_flags = map->flags; entry->fingerprint_len = strlen(map->fingerprint); if (entry->fingerprint_len > sizeof(entry->fingerprint)) entry->fingerprint_len = sizeof(entry->fingerprint) - 1; memcpy(entry->fingerprint, map->fingerprint, entry->fingerprint_len); entry->fingerprint[sizeof(entry->fingerprint) - 1] = 0; entry->hashType = map->hashType; if (map->data) { entry->data_len = strlen(map->data); if (entry->data_len) { if (entry->data_len > sizeof(entry->data)) entry->data_len = sizeof(entry->data) - 1; memcpy(entry->data, map->data, entry->data_len); entry->data[sizeof(entry->data) - 1] = 0; } } entry->mapType = map->mapType; return row; } static int _cache_load(netsnmp_cache *cache, netsnmp_tdata *table) { netsnmp_container *maps; netsnmp_iterator *map_itr; netsnmp_cert_map *map; netsnmp_tdata_row *row; certToTSN_entry *entry; int rc = 0; DEBUGMSGTL(("tlstmCertToTSNTable:cache:load", "called, %" NETSNMP_PRIz "d rows\n", CONTAINER_SIZE(table->container))); /** get current active maps */ maps = netsnmp_cert_map_container(); if (NULL == maps) return 0; DEBUGMSGTL(("tlstmCertToTSNTable:cache:load", "maps %" NETSNMP_PRIz "d rows\n", CONTAINER_SIZE(maps))); map_itr = CONTAINER_ITERATOR(maps); if (NULL == map_itr) { DEBUGMSGTL(("tlstmCertToTSNTable:cache:load", "cant get map iterator\n")); return -1; } /* * insert rows for active maps into tbl container */ map = ITERATOR_FIRST(map_itr); for( ; map; map = ITERATOR_NEXT(map_itr)) { row = _entry_from_map(map); if (NULL == row) { rc =-1; break; } entry = (certToTSN_entry*)row->data; entry->rowStatus = RS_ACTIVE; if (netsnmp_tdata_add_row(table, row) != SNMPERR_SUCCESS) { tlstmCertToTSNTable_removeEntry(NULL, row); rc = -1; break; } } ITERATOR_RELEASE(map_itr); DEBUGMSGTL(("tlstmCertToTSNTable:cache:load", "done, %" NETSNMP_PRIz "d rows\n", CONTAINER_SIZE(table->container))); return rc; } static void _cache_free(netsnmp_cache *cache, netsnmp_tdata *table) { netsnmp_tdata_row *row; netsnmp_iterator *tbl_itr; certToTSN_entry *entry; DEBUGMSGTL(("tlstmCertToTSNTable:cache:free", "called, %" NETSNMP_PRIz "d rows\n", CONTAINER_SIZE(table->container))); /** insert rows for active maps into tbl container */ tbl_itr = CONTAINER_ITERATOR(table->container); if (NULL == tbl_itr) { DEBUGMSGTL(("tlstmCertToTSNTable:cache:free", "cant get map iterator\n")); return; } row = ITERATOR_FIRST(tbl_itr); for( ; row; row = ITERATOR_NEXT(tbl_itr)) { entry = row->data; /* * remove all active rows (they are in the maps container kept * by the library). Keep inactive ones for next time. */ if (entry->rowStatus == RS_ACTIVE) { tlstmCertToTSNTable_removeEntry(NULL, row); ITERATOR_REMOVE(tbl_itr); continue; } } ITERATOR_RELEASE(tbl_itr); DEBUGMSGTL(("tlstmCertToTSNTable:cache:free", "done, %" NETSNMP_PRIz "d rows\n", CONTAINER_SIZE(table->container))); } static void _parse_mib_maps(const char *token, char *line) { netsnmp_tdata_row *row; certToTSN_entry *entry; netsnmp_cert_map *map = netsnmp_certToTSN_parse_common(&line); if (NULL == line) { netsnmp_config_error("incomplete line"); netsnmp_cert_map_free(map); return; } map->flags = NSCM_FROM_MIB | NSCM_NONVOLATILE; row = _entry_from_map(map); if (NULL == row) { netsnmp_cert_map_free(map); return; } entry = (certToTSN_entry*)row->data; entry->rowStatus = atoi(line); entry->storageType = ST_NONVOLATILE; /* * if row is active, add it to the maps container so it is available * for use. Do not add it to the table, since it will be added * during cache_load. */ if (RS_ACTIVE == entry->rowStatus) { if (netsnmp_cert_map_add(map) != 0) netsnmp_cert_map_free(map); } else { netsnmp_cert_map_free(map); if (netsnmp_tdata_add_row(_table, row) != SNMPERR_SUCCESS) tlstmCertToTSNTable_removeEntry(NULL, row); } } static int _save_entry(certToTSN_entry *entry, void *app_type) { char *buf = NULL, *hashType, *mapType, *data = NULL; if (NULL == entry) return SNMP_ERR_GENERR; hashType = se_find_label_in_slist("cert_hash_alg", entry->hashType); if (NULL == hashType) { snmp_log(LOG_ERR, "skipping entry unknown hash type %d\n", entry->hashType); return SNMP_ERR_GENERR; } mapType = se_find_label_in_slist("cert_map_type", entry->mapType); if (TSNM_tlstmCertSpecified == entry->mapType) data = entry->data; if (asprintf(&buf, "%s %ld --%s %s --%s %s %d", MAP_MIB_CONFIG_TOKEN, entry->tlstmCertToTSNID, hashType, entry->fingerprint, mapType, data ? data : "", entry->rowStatus) < 0) { return SNMP_ERR_GENERR; } DEBUGMSGTL(("tlstmCertToTSNTable:save", "saving '%s'\n", buf)); read_config_store(app_type, buf); free(buf); return SNMP_ERR_NOERROR; } static int _save_map(netsnmp_cert_map *map, int row_status, void *app_type) { char buf[SNMP_MAXBUF_SMALL], *hashType, *mapType, *data = NULL; if (NULL == map) return SNMP_ERR_GENERR; /** don't store values from conf files */ if (! (map->flags & NSCM_NONVOLATILE)) { DEBUGMSGT(("tlstmCertToTSNTable:save", "skipping RO/permanent/volatile row\n")); return SNMP_ERR_NOERROR; } hashType = se_find_label_in_slist("cert_hash_alg", map->hashType); if (NULL == hashType) { snmp_log(LOG_ERR, "skipping entry unknown hash type %d\n", map->hashType); return SNMP_ERR_GENERR; } mapType = se_find_label_in_slist("cert_map_type", map->mapType); if (TSNM_tlstmCertSpecified == map->mapType) data = (char*)map->data; snprintf(buf, sizeof(buf), "%s %d --%s %s --%s %s %d", MAP_MIB_CONFIG_TOKEN, map->priority, hashType, map->fingerprint, mapType, data ? data : "", row_status); DEBUGMSGTL(("tlstmCertToTSNTable:save", "saving '%s'\n", buf)); read_config_store(app_type, buf); return SNMP_ERR_NOERROR; } static int _save_maps(int majorID, int minorID, void *serverarg, void *clientarg) { char sep[] = "\n##############################################################"; char buf[] = "#\n" "# certificate secName mapping persistent data\n" "#"; char *type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE); netsnmp_container *maps = netsnmp_cert_map_container(); netsnmp_tdata_row *row; netsnmp_iterator *tbl_itr, *map_itr; netsnmp_cert_map *map; certToTSN_entry *entry; if ((NULL == maps) || ((CONTAINER_SIZE(maps) == 0) && (CONTAINER_SIZE(_table->container) == 0))) return SNMPERR_SUCCESS; read_config_store((char *) type, sep); read_config_store((char *) type, buf); /* * save active rows from maps */ if (NULL != maps) { map_itr = CONTAINER_ITERATOR(maps); if (NULL == map_itr) { DEBUGMSGTL(("tlstmCertToTSNTable:save", "cant get map iterator\n")); map = NULL; } else map = ITERATOR_FIRST(map_itr); for( ; map; map = ITERATOR_NEXT(map_itr)) { /** don't store config rows */ if (map->flags & NSCM_FROM_CONFIG) continue; _save_map(map, RS_ACTIVE, type); } ITERATOR_RELEASE(map_itr); } /* * save inactive rows from mib */ tbl_itr = CONTAINER_ITERATOR(_table->container); if (NULL == tbl_itr) DEBUGMSGTL(("tlstmCertToTSNTable:save", "cant get table iterator\n")); else { row = ITERATOR_FIRST(tbl_itr); for( ; row; row = ITERATOR_NEXT(tbl_itr)) { entry = row->data; /* * skip all active rows (should be in maps and thus saved * above) and volatile rows. */ if ((entry->rowStatus == RS_ACTIVE) || (entry->storageType != ST_NONVOLATILE)) continue; _save_entry(entry, type); } ITERATOR_RELEASE(tbl_itr); } read_config_store((char *) type, sep); read_config_store((char *) type, "\n"); /* * never fails */ return SNMPERR_SUCCESS; } static const oid _tsnm_base[] = { SNMP_TLS_TM_BASE, 1, 1 }; static const int _tsnm_base_len = sizeof(_tsnm_base); static oid _oid2type(oid *val, int val_len) { netsnmp_assert(val); if (val_len != (_tsnm_base_len + sizeof(oid))) return -1; if (memcmp(_tsnm_base,val,_tsnm_base_len) != 0) return -2; if ((val[OID_LENGTH(_tsnm_base)] > TSNM_tlstmCert_MAX) || (0 == val[OID_LENGTH(_tsnm_base)])) return -3; return val[OID_LENGTH(_tsnm_base)]; } #if 0 static int _type2oid(int type, oid *val, int *val_len) { netsnmp_assert( val && val_len ); if (*val_len < _tsnm_base_len + sizeof(oid)) return -1; memcpy(val, _tsnm_base, _tsnm_base_len + sizeof(oid)); val[_tsnm_base_len + sizeof(oid)] = type; return 0; } #endif