/* * snmpTargetAddrEntry MIB * * This file was created to separate notification data storage from * the MIB implementation. * * Portions of this file are copyrighted by: * Copyright (c) 2016 VMware, Inc. All rights reserved. * Use is subject to license terms specified in the COPYING file * distributed with the Net-SNMP package. */ #include #if HAVE_STRING_H #include #else #include #endif #include #include #include #include #include "snmpTargetAddrEntry_data.h" #include "util_funcs/header_generic.h" netsnmp_feature_require(container_compare_mem); static struct targetAddrTable_struct *aAddrTable = NULL; static int _active = 0; /* * Utility routines */ static int store_snmpTargetAddrEntry(int majorID, int minorID, void *serverarg, void *clientarg); static void snmpd_parse_config_targetAddr(const char *token, char *char_ptr); struct targetAddrTable_struct * get_addrTable(void) { return aAddrTable; } struct targetAddrTable_struct * get_addrForName2(const char *name, size_t nameLen) { struct targetAddrTable_struct *ptr; for (ptr = aAddrTable; ptr != NULL; ptr = ptr->next) { if (ptr->nameLen == nameLen && ptr->nameData && memcmp(ptr->nameData, name, nameLen) == 0) return ptr; } return NULL; } /* * TargetAddrTable_create creates and returns a pointer * to a targetAddrTable_struct with default values set */ struct targetAddrTable_struct * snmpTargetAddrTable_create(void) { struct targetAddrTable_struct *newEntry; newEntry = (struct targetAddrTable_struct *) calloc(1, sizeof(struct targetAddrTable_struct)); if (newEntry) { ++_active; newEntry->timeout = 1500; newEntry->retryCount = 3; newEntry->tagListData = strdup(""); newEntry->tagListLen = 0; newEntry->storageType = SNMP_STORAGE_NONVOLATILE; newEntry->rowStatus = SNMP_ROW_NONEXISTENT; } return newEntry; } /* snmpTargetAddrTable_create */ /* * TargetAddrTable_dispose frees the space allocated to a * targetAddrTable_struct */ void snmpTargetAddrTable_dispose(struct targetAddrTable_struct *reaped) { if (NULL == reaped) return; if (reaped->sess) snmp_close(reaped->sess); else SNMP_FREE(reaped->tAddress); SNMP_FREE(reaped->nameData); SNMP_FREE(reaped->tagListData); SNMP_FREE(reaped->paramsData); SNMP_FREE(reaped); --_active; } /* snmpTargetAddrTable_dispose */ /* * snmpTargetAddrTable_addToList adds a targetAddrTable_struct * to a list passed in. The list is assumed to be in a sorted order, * low to high and this procedure inserts a new struct in the proper * location. Sorting uses OID values based on name. A new equal value * overwrites a current one. */ void snmpTargetAddrTable_addToList(struct targetAddrTable_struct *newEntry, struct targetAddrTable_struct **listPtr) { static struct targetAddrTable_struct *curr_struct, *prev_struct; int i; /* * if the list is empty, add the new entry to the top */ if ((prev_struct = curr_struct = *listPtr) == NULL) { *listPtr = newEntry; return; } else { /* * search through the list for an equal or greater OID value */ while (curr_struct != NULL) { i = netsnmp_compare_mem(newEntry->nameData, newEntry->nameLen, curr_struct->nameData, curr_struct->nameLen); if (i == 0) { /* Exact match, overwrite with new struct */ newEntry->next = curr_struct->next; /* * if curr_struct is the top of the list */ if (*listPtr == curr_struct) *listPtr = newEntry; else prev_struct->next = newEntry; snmpTargetAddrTable_dispose(curr_struct); return; } else if (i < 0) { /* Found a greater OID, insert struct in front of it. */ newEntry->next = curr_struct; /* * if curr_struct is the top of the list */ if (*listPtr == curr_struct) *listPtr = newEntry; else prev_struct->next = newEntry; return; } prev_struct = curr_struct; curr_struct = curr_struct->next; } } /* * if we're here, no larger OID was ever found, insert on end of list */ prev_struct->next = newEntry; } /* snmpTargeAddrTable_addToList */ void snmpTargetAddrTable_add(struct targetAddrTable_struct *newEntry) { snmpTargetAddrTable_addToList(newEntry, &aAddrTable); } /* * snmpTargetAddrTable_remFromList removes a targetAddrTable_struct * from the list passed in */ void snmpTargetAddrTable_remFromList(struct targetAddrTable_struct *oldEntry, struct targetAddrTable_struct **listPtr) { struct targetAddrTable_struct *tptr; if ((tptr = *listPtr) == NULL) return; else if (tptr == oldEntry) { *listPtr = (*listPtr)->next; snmpTargetAddrTable_dispose(tptr); return; } else { while (tptr->next != NULL) { if (tptr->next == oldEntry) { tptr->next = tptr->next->next; snmpTargetAddrTable_dispose(oldEntry); return; } tptr = tptr->next; } } } /* snmpTargetAddrTable_remFromList */ void snmpTargetAddrTable_remove(struct targetAddrTable_struct *entry) { snmpTargetAddrTable_remFromList(entry, &aAddrTable); } /* * lookup OID in the link list of Addr Table Entries */ struct targetAddrTable_struct * search_snmpTargetAddrTable(oid * baseName, size_t baseNameLen, oid * name, size_t * length, int exact) { static struct targetAddrTable_struct *temp_struct; int i; size_t myOIDLen = 0; oid newNum[128]; /* * lookup entry in addrTable linked list, Get Current MIB ID */ memcpy(newNum, baseName, baseNameLen * sizeof(oid)); for (temp_struct = aAddrTable; temp_struct != NULL; temp_struct = temp_struct->next) { for (i = 0; i < temp_struct->nameLen; i++) { newNum[baseNameLen + i] = temp_struct->nameData[i]; } myOIDLen = baseNameLen + i; i = snmp_oid_compare(name, *length, newNum, myOIDLen); /* * Assumes that the linked list sorted by OID, low to high */ if ((i == 0 && exact != 0) || (i < 0 && exact == 0)) { if (exact == 0) { memcpy(name, newNum, myOIDLen * sizeof(oid)); *length = myOIDLen; } return temp_struct; } } return NULL; } /* search_snmpTargetAddrTable */ /* * Init routines */ void init_snmpTargetAddrEntry_data(void) { static int done = 0; if (++done != 1) return; snmpd_register_config_handler("targetAddr", snmpd_parse_config_targetAddr, (void (*)(void))0, NULL); /* * we need to be called back later */ snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, store_snmpTargetAddrEntry, NULL); } /* init_snmpTargetAddrEntry */ /* * Shutdown routines */ void shutdown_snmpTargetAddrEntry_data(void) { struct targetAddrTable_struct *ptr; struct targetAddrTable_struct *next; snmp_unregister_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, store_snmpTargetAddrEntry, NULL, FALSE); DEBUGMSGTL(("trap:targetAddr:shutdown", "clearing %d object(s)\n", _active)); for (ptr = aAddrTable; ptr; ptr = next) { next = ptr->next; snmpTargetAddrTable_dispose(ptr); } aAddrTable = NULL; DEBUGMSGTL(("trap:targetAddr:shutdown", "active count %d\n",_active)); if (_active != 0) { DEBUGMSGTL(("trap:targetAddr:shutdown", "unexpected count %d after cleanup!\n", _active)); snmp_log(LOG_WARNING, "targetAddr count %d, not 0, after shutdown.\n", _active); } } /* * store_snmpTargetAddrEntry handles the persistent storage proccess * for this MIB table. It writes out all the non-volatile rows * to permanent storage on a shutdown */ static int store_snmpTargetAddrEntry(int majorID, int minorID, void *serverarg, void *clientarg) { const struct targetAddrTable_struct *curr_struct; char line[1024], *ep = line + sizeof(line); int i; curr_struct = aAddrTable; while (curr_struct != NULL) { if ((curr_struct->storageType == SNMP_STORAGE_NONVOLATILE || curr_struct->storageType == SNMP_STORAGE_PERMANENT) && (curr_struct->rowStatus == SNMP_ROW_ACTIVE || curr_struct->rowStatus == SNMP_ROW_NOTINSERVICE)) { char *cur; cur = line + snprintf(line, sizeof(line), "targetAddr "); cur = read_config_save_octet_string( cur, (const u_char*)curr_struct->nameData, curr_struct->nameLen); *cur++ = ' '; for (i = 0; i < curr_struct->tDomainLen; i++) { cur += snprintf(cur, ep - cur, ".%i", (int) curr_struct->tDomain[i]); } *cur++ = ' '; cur = read_config_save_octet_string( cur, curr_struct->tAddress, curr_struct->tAddressLen); snprintf(cur, ep - cur, " %i %i \"%s\" %s %i %i", curr_struct->timeout, curr_struct->retryCount, curr_struct->tagListData, curr_struct->paramsData, curr_struct->storageType, curr_struct->rowStatus); /* * store to file */ snmpd_store_config(line); } curr_struct = curr_struct->next; } return SNMPERR_SUCCESS; } /* store_snmpTargetAddrEntry */ static int snmpTargetAddr_addTDomain(struct targetAddrTable_struct *entry, char *cptr) { size_t len = 128; if (cptr == NULL) { DEBUGMSGTL(("snmpTargetAddrEntry", "ERROR snmpTargetAddrEntry: no tDomain in config string\n")); return (0); } if (!read_objid(cptr, entry->tDomain, &len)) { DEBUGMSGTL(("snmpTargetAddrEntry", "ERROR snmpTargetAddrEntry: tDomain unreadable in config string\n")); return (0); } /* * spec check for oid 1-128 */ if (len < 1 || len > 128) { DEBUGMSGTL(("snmpTargetAddrEntry", "ERROR snmpTargetAddrEntry: tDomain out of range in config string\n")); return (0); } entry->tDomainLen = len; return (1); } /* snmpTargetAddr_addTDomain */ static int snmpTargetAddr_addTimeout(struct targetAddrTable_struct *entry, char *cptr) { if (cptr == NULL) { DEBUGMSGTL(("snmpTargetAddrEntry", "ERROR snmpTargetParamsEntry: no Timeout in config string\n")); return (0); } else if (!(isdigit((unsigned char)(*cptr)))) { DEBUGMSGTL(("snmpTargetAddrEntry", "ERROR snmpTargeParamsEntry: Timeout is not a digit in config string\n")); return (0); } /* * check Timeout >= 0 */ else if ((entry->timeout = (int) strtol(cptr, (char **) NULL, 0)) < 0) { DEBUGMSGTL(("snmpTargetAddrEntry", "ERROR snmpTargeParamsEntry: Timeout out of range in config string\n")); return (0); } return (1); } /* snmpTargetAddr_addTimeout */ static int snmpTargetAddr_addRetryCount(struct targetAddrTable_struct *entry, char *cptr) { if (cptr == NULL) { DEBUGMSGTL(("snmpTargetAddrEntry", "ERROR snmpTargetParamsEntry: no Retry Count in config string\n")); return (0); } else if (!(isdigit((unsigned char)(*cptr)))) { DEBUGMSGTL(("snmpTargetAddrEntry", "ERROR snmpTargeParamsEntry: Retry Count is not a digit in config string\n")); return (0); } /* * spec check 0..255 */ else { entry->retryCount = (int) strtol(cptr, (char **) NULL, 0); if ((entry->retryCount < 0) || (entry->retryCount > 255)) { DEBUGMSGTL(("snmpTargetAddrEntry", "ERROR snmpTargeParamsEntry: Retry Count is out of range in config string\n")); return (0); } } return (1); } /* snmpTargetAddr_addRetryCount */ static int snmpTargetAddr_addTagList(struct targetAddrTable_struct *entry, char *cptr) { if (cptr == NULL) { DEBUGMSGTL(("snmpTargetAddrEntry", "ERROR snmpTargetAddrEntry: no tag list in config string\n")); return (0); } else { size_t len = strlen(cptr); /* * spec check for string 0-255 */ if (len > 255) { DEBUGMSGTL(("snmpTargetAddrEntry", "ERROR snmpTargetAddrEntry: tag list out of range in config string\n")); return (0); } SNMP_FREE(entry->tagListData); entry->tagListData = strdup(cptr); entry->tagListLen = strlen(cptr); } return (1); } /* snmpTargetAddr_addTagList */ static int snmpTargetAddr_addParams(struct targetAddrTable_struct *entry, char *cptr) { size_t len; if (cptr == NULL) { DEBUGMSGTL(("snmpTargetAddrEntry", "ERROR snmpTargetAddrEntry: no params in config string\n")); return (0); } else { len = strlen(cptr); /* * spec check for string 1-32 */ if (len < 1 || len > 32) { DEBUGMSGTL(("snmpTargetAddrEntry", "ERROR snmpTargetAddrEntry: params out of range in config string\n")); return (0); } entry->paramsData = strdup(cptr); entry->paramsLen = strlen(cptr); } return (1); } /* snmpTargetAddr_addParams */ static int snmpTargetAddr_addStorageType(struct targetAddrTable_struct *entry, char *cptr) { if (cptr == NULL) { DEBUGMSGTL(("snmpTargetAddrEntry", "ERROR snmpTargetAddrEntry: no storage type in config " "string\n")); return (0); } else if (!(isdigit((unsigned char)(*cptr)))) { DEBUGMSGTL(("snmpTargetAddrEntry", "ERROR snmpTargetAddrEntry: storage type is not a digit " "in config string\n")); return (0); } /* * check that storage type is a possible value */ else if (((entry->storageType = (int) strtol(cptr, (char **) NULL, 0)) != SNMP_STORAGE_OTHER) && (entry->storageType != SNMP_STORAGE_VOLATILE) && (entry->storageType != SNMP_STORAGE_NONVOLATILE) && (entry->storageType != SNMP_STORAGE_PERMANENT) && (entry->storageType != SNMP_STORAGE_READONLY)) { DEBUGMSGTL(("snmpTargetAddrEntry", "ERROR snmpTargetAddrEntry: storage type not a valid " "value of other(%d), volatile(%d), nonvolatile(%d), " "permanent(%d), or readonly(%d) in config string.\n", SNMP_STORAGE_OTHER, SNMP_STORAGE_VOLATILE, SNMP_STORAGE_NONVOLATILE, SNMP_STORAGE_PERMANENT, SNMP_STORAGE_READONLY)); return (0); } return (1); } /* snmpTargetAddr_addStorageType */ static int snmpTargetAddr_addRowStatus(struct targetAddrTable_struct *entry, char *cptr) { if (cptr == NULL) { DEBUGMSGTL(("snmpTargetAddrEntry", "ERROR snmpTargetAddrEntry: no Row Status in config " "string\n")); return (0); } else if (!(isdigit((unsigned char)(*cptr)))) { DEBUGMSGTL(("snmpTargetAddrEntry", "ERROR snmpTargetAddrEntry: Row Status is not a digit in " "config string\n")); return (0); } /* * check that row status is a valid value */ else if (((entry->rowStatus = (int) strtol(cptr, (char **) NULL, 0)) != SNMP_ROW_ACTIVE) && (entry->rowStatus != SNMP_ROW_NOTINSERVICE) && (entry->rowStatus != SNMP_ROW_NOTREADY)) { DEBUGMSGTL(("snmpTargetAddrEntry", "ERROR snmpTargetAddrEntry: Row Status is not a valid " "value of active(%d), notinservice(%d), or notready(%d) " "in config string.\n", SNMP_ROW_ACTIVE, SNMP_ROW_NOTINSERVICE, SNMP_ROW_NOTREADY)); return (0); } return (1); } /* snmpTargetAddr_addRowStatus */ static void snmpd_parse_config_targetAddr(const char *token, char *char_ptr) { const char *cptr = char_ptr; char buff[1024], *bptr; struct targetAddrTable_struct *newEntry; int i; size_t bufl; newEntry = snmpTargetAddrTable_create(); cptr = skip_white_const(cptr); if (cptr == NULL) { DEBUGMSGTL(("snmpTargetAddrEntry", "ERROR snmpTargetAddrEntry: no name in config string\n")); snmpTargetAddrTable_dispose(newEntry); return; } bufl = 0; cptr = read_config_read_octet_string_const(cptr, (u_char**)&newEntry->nameData, &bufl); if (bufl < 1 || bufl > 32) { DEBUGMSGTL(("snmpTargetAddrEntry", "ERROR snmpTargetAddrEntry: name out of range in config " "string\n")); snmpTargetAddrTable_dispose(newEntry); return; } newEntry->nameLen = bufl; cptr = copy_nword_const(cptr, buff, sizeof(buff)); if (snmpTargetAddr_addTDomain(newEntry, buff) == 0) { snmpTargetAddrTable_dispose(newEntry); return; } cptr = read_config_read_octet_string_const(cptr, (u_char **) & newEntry->tAddress, &newEntry->tAddressLen); if (!cptr || !newEntry->tAddress || (newEntry->tAddressLen < 1) || (newEntry->tAddressLen > 32)) { DEBUGMSGTL(("snmpTargetAddrEntry", "ERROR snmpTargetAddrEntry: no/bd TAddress in config string\n")); snmpTargetAddrTable_dispose(newEntry); return; } cptr = copy_nword_const(cptr, buff, sizeof(buff)); if (snmpTargetAddr_addTimeout(newEntry, buff) == 0) { snmpTargetAddrTable_dispose(newEntry); return; } cptr = copy_nword_const(cptr, buff, sizeof(buff)); if (snmpTargetAddr_addRetryCount(newEntry, buff) == 0) { snmpTargetAddrTable_dispose(newEntry); return; } cptr = copy_nword_const(cptr, buff, sizeof(buff)); if (snmpTargetAddr_addTagList(newEntry, buff) == 0) { snmpTargetAddrTable_dispose(newEntry); return; } cptr = copy_nword_const(cptr, buff, sizeof(buff)); if (snmpTargetAddr_addParams(newEntry, buff) == 0) { snmpTargetAddrTable_dispose(newEntry); return; } cptr = copy_nword_const(cptr, buff, sizeof(buff)); if (snmpTargetAddr_addStorageType(newEntry, buff) == 0) { snmpTargetAddrTable_dispose(newEntry); return; } cptr = copy_nword_const(cptr, buff, sizeof(buff)); if (snmpTargetAddr_addRowStatus(newEntry, buff) == 0) { snmpTargetAddrTable_dispose(newEntry); return; } bptr = buff; bptr += sprintf(bptr, "snmp_parse_config_targetAddr, read: "); bptr = read_config_save_octet_string(bptr, (u_char*)newEntry->nameData, newEntry->nameLen); *bptr++ = '\n'; for (i = 0; i < newEntry->tDomainLen; i++) { bptr += snprintf(bptr, buff + sizeof(buff) - bptr, ".%d", (int) newEntry->tDomain[i]); } for (i = 0; i < newEntry->tAddressLen; i++) bptr += snprintf(bptr, buff + sizeof(buff) - bptr, " %02x", ((u_char *)newEntry->tAddress)[i]); bptr += snprintf(bptr, buff + sizeof(buff) - bptr, " %d %d %s %s %d %d\n", newEntry->timeout, newEntry->retryCount, newEntry->tagListData, newEntry->paramsData, newEntry->storageType, newEntry->rowStatus); buff[ sizeof(buff) - 1 ] = 0; DEBUGMSGTL(("snmpTargetAddrEntry", "%s", buff)); snmpTargetAddrTable_addToList(newEntry, &aAddrTable); } /* snmpd_parse_config_target */