#include #include /* * 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. */ #ifdef HAVE_STDLIB_H #include #endif #include #if HAVE_STRING_H #include #else #include #endif #include #include #include #include #include #include /* strcasecmp() */ #include netsnmp_feature_child_of(snmp_enum_all, libnetsnmp); netsnmp_feature_child_of(se_find_free_value_in_slist, snmp_enum_all); netsnmp_feature_child_of(snmp_enum_store_list, snmp_enum_all); netsnmp_feature_child_of(snmp_enum_store_slist, snmp_enum_all); netsnmp_feature_child_of(snmp_enum_clear, snmp_enum_all); struct snmp_enum_list_str { char *name; struct snmp_enum_list *list; struct snmp_enum_list_str *next; }; static struct snmp_enum_list ***snmp_enum_lists; unsigned int current_maj_num; unsigned int current_min_num; static struct snmp_enum_list_str *sliststorage; static void free_enum_list(struct snmp_enum_list *list); int init_snmp_enum(const char *type) { int i; if (NULL != snmp_enum_lists) return SE_OK; snmp_enum_lists = (struct snmp_enum_list ***) calloc(1, sizeof(struct snmp_enum_list **) * SE_MAX_IDS); if (!snmp_enum_lists) return SE_NOMEM; current_maj_num = SE_MAX_IDS; for (i = 0; i < SE_MAX_IDS; i++) { if (!snmp_enum_lists[i]) snmp_enum_lists[i] = (struct snmp_enum_list **) calloc(1, sizeof(struct snmp_enum_list *) * SE_MAX_SUBIDS); if (!snmp_enum_lists[i]) return SE_NOMEM; } current_min_num = SE_MAX_SUBIDS; register_const_config_handler(type, "enum", se_read_conf, NULL, NULL); return SE_OK; } int se_store_in_list(struct snmp_enum_list *new_list, unsigned int major, unsigned int minor) { int ret = SE_OK; if (major > current_maj_num || minor > current_min_num) { /* * XXX: realloc */ return SE_NOMEM; } netsnmp_assert(NULL != snmp_enum_lists); if (snmp_enum_lists[major][minor] != NULL) ret = SE_ALREADY_THERE; snmp_enum_lists[major][minor] = new_list; return ret; } void se_read_conf(const char *word, const char *cptr) { int major, minor; int value; const char *cp, *cp2; char e_name[BUFSIZ]; char e_enum[ BUFSIZ]; if (!cptr || *cptr=='\0') return; /* * Extract the first token * (which should be the name of the list) */ cp = copy_nword_const(cptr, e_name, sizeof(e_name)); cp = skip_white_const(cp); if (!cp || *cp=='\0') return; /* * Add each remaining enumeration to the list, * using the appropriate style interface */ if (sscanf(e_name, "%d:%d", &major, &minor) == 2) { /* * Numeric major/minor style */ while (1) { cp = copy_nword_const(cp, e_enum, sizeof(e_enum)); if (sscanf(e_enum, "%d:", &value) != 1) { break; } cp2 = e_enum; while (*(cp2++) != ':') ; se_add_pair(major, minor, strdup(cp2), value); if (!cp) break; } } else { /* * Named enumeration */ while (1) { cp = copy_nword_const(cp, e_enum, sizeof(e_enum)); if (sscanf(e_enum, "%d:", &value) != 1) { break; } cp2 = e_enum; while (*(cp2++) != ':') ; se_add_pair_to_slist(e_name, strdup(cp2), value); if (!cp) break; } } } void se_store_enum_list(struct snmp_enum_list *new_list, const char *token, const char *type) { struct snmp_enum_list *listp = new_list; char line[2048]; char buf[512]; int len; snprintf(line, sizeof(line), "enum %s", token); while (listp) { snprintf(buf, sizeof(buf), " %d:%s", listp->value, listp->label); /* * Calculate the space left in the buffer. * If this is not sufficient to include the next enum, * then save the line so far, and start again. */ len = sizeof(line) - strlen(line); if ((int)strlen(buf) > len) { read_config_store(type, line); snprintf(line, sizeof(line), "enum %s", token); len = sizeof(line) - strlen(line); } strncat(line, buf, len); listp = listp->next; } read_config_store(type, line); } #ifndef NETSNMP_FEATURE_REMOVE_SNMP_ENUM_STORE_LIST void se_store_list(unsigned int major, unsigned int minor, const char *type) { char token[32]; snprintf(token, sizeof(token), "%d:%d", major, minor); se_store_enum_list(se_find_list(major, minor), token, type); } #endif /* NETSNMP_FEATURE_REMOVE_SNMP_ENUM_STORE_LIST */ struct snmp_enum_list * se_find_list(unsigned int major, unsigned int minor) { if (major > current_maj_num || minor > current_min_num) return NULL; netsnmp_assert(NULL != snmp_enum_lists); return snmp_enum_lists[major][minor]; } int se_find_value_in_list(struct snmp_enum_list *list, const char *label) { if (!list) return SE_DNE; /* XXX: um, no good solution here */ while (list) { if (strcmp(list->label, label) == 0) return (list->value); list = list->next; } return SE_DNE; /* XXX: um, no good solution here */ } int se_find_casevalue_in_list(struct snmp_enum_list *list, const char *label) { if (!list) return SE_DNE; /* XXX: um, no good solution here */ while (list) { if (strcasecmp(list->label, label) == 0) return (list->value); list = list->next; } return SE_DNE; /* XXX: um, no good solution here */ } int se_find_free_value_in_list(struct snmp_enum_list *list) { int max_value = 0; if (!list) return SE_DNE; for (;list; list=list->next) { if (max_value < list->value) max_value = list->value; } return max_value+1; } int se_find_value(unsigned int major, unsigned int minor, const char *label) { return se_find_value_in_list(se_find_list(major, minor), label); } int se_find_free_value(unsigned int major, unsigned int minor) { return se_find_free_value_in_list(se_find_list(major, minor)); } char * se_find_label_in_list(struct snmp_enum_list *list, int value) { if (!list) return NULL; while (list) { if (list->value == value) return (list->label); list = list->next; } return NULL; } char * se_find_label(unsigned int major, unsigned int minor, int value) { return se_find_label_in_list(se_find_list(major, minor), value); } int se_add_pair_to_list(struct snmp_enum_list **list, char *label, int value) { struct snmp_enum_list *lastnode = NULL, *tmp; if (!list) return SE_DNE; tmp = *list; while (tmp) { if (tmp->value == value) { free(label); return (SE_ALREADY_THERE); } lastnode = tmp; tmp = tmp->next; } if (lastnode) { lastnode->next = SNMP_MALLOC_STRUCT(snmp_enum_list); lastnode = lastnode->next; } else { (*list) = SNMP_MALLOC_STRUCT(snmp_enum_list); lastnode = (*list); } if (!lastnode) { free(label); return (SE_NOMEM); } lastnode->label = label; lastnode->value = value; lastnode->next = NULL; return (SE_OK); } int se_add_pair(unsigned int major, unsigned int minor, char *label, int value) { struct snmp_enum_list *list = se_find_list(major, minor); int created = (list) ? 1 : 0; int ret = se_add_pair_to_list(&list, label, value); if (!created) se_store_in_list(list, major, minor); return ret; } /* * remember a list of enums based on a lookup name. */ static struct snmp_enum_list ** se_find_slist_ptr(const char *listname) { struct snmp_enum_list_str *sptr; if (!listname) return NULL; for (sptr = sliststorage; sptr != NULL; sptr = sptr->next) if (sptr->name && strcmp(sptr->name, listname) == 0) return &sptr->list; return NULL; } struct snmp_enum_list * se_find_slist(const char *listname) { struct snmp_enum_list **ptr = se_find_slist_ptr(listname); return ptr ? *ptr : NULL; } char * se_find_label_in_slist(const char *listname, int value) { return (se_find_label_in_list(se_find_slist(listname), value)); } int se_find_value_in_slist(const char *listname, const char *label) { return (se_find_value_in_list(se_find_slist(listname), label)); } int se_find_casevalue_in_slist(const char *listname, const char *label) { return (se_find_casevalue_in_list(se_find_slist(listname), label)); } #ifndef NETSNMP_FEATURE_REMOVE_SE_FIND_FREE_VALUE_IN_SLIST int se_find_free_value_in_slist(const char *listname) { return (se_find_free_value_in_list(se_find_slist(listname))); } #endif /* NETSNMP_FEATURE_REMOVE_SE_FIND_FREE_VALUE_IN_SLIST */ int se_add_pair_to_slist(const char *listname, char *label, int value) { struct snmp_enum_list *list = se_find_slist(listname); int created = (list) ? 1 : 0; int ret = se_add_pair_to_list(&list, label, value); if (!created) { struct snmp_enum_list_str *sptr = SNMP_MALLOC_STRUCT(snmp_enum_list_str); if (!sptr) { free_enum_list(list); return SE_NOMEM; } sptr->next = sliststorage; sptr->name = strdup(listname); sptr->list = list; sliststorage = sptr; } return ret; } static void free_enum_list(struct snmp_enum_list *list) { struct snmp_enum_list *next; while (list) { next = list->next; SNMP_FREE(list->label); SNMP_FREE(list); list = next; } } void clear_snmp_enum(void) { struct snmp_enum_list_str *sptr = sliststorage, *next = NULL; int i, j; while (sptr != NULL) { next = sptr->next; free_enum_list(sptr->list); SNMP_FREE(sptr->name); SNMP_FREE(sptr); sptr = next; } sliststorage = NULL; if (snmp_enum_lists) { for (i = 0; i < SE_MAX_IDS; i++) { if (snmp_enum_lists[i]) { for (j = 0; j < SE_MAX_SUBIDS; j++) { if (snmp_enum_lists[i][j]) free_enum_list(snmp_enum_lists[i][j]); } SNMP_FREE(snmp_enum_lists[i]); } } SNMP_FREE(snmp_enum_lists); } } void se_clear_list(struct snmp_enum_list **list) { struct snmp_enum_list *this_entry, *next_entry; if (!list) return; this_entry = *list; while (this_entry) { next_entry = this_entry->next; SNMP_FREE(this_entry->label); SNMP_FREE(this_entry); this_entry = next_entry; } *list = NULL; return; } #ifndef NETSNMP_FEATURE_REMOVE_SNMP_ENUM_STORE_SLIST void se_store_slist(const char *listname, const char *type) { struct snmp_enum_list *list = se_find_slist(listname); se_store_enum_list(list, listname, type); } int se_store_slist_callback(int majorID, int minorID, void *serverargs, void *clientargs) { char *appname = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE); se_store_slist((char *)clientargs, appname); return SNMPERR_SUCCESS; } #endif /* NETSNMP_FEATURE_REMOVE_SNMP_ENUM_STORE_SLIST */ #ifndef NETSNMP_FEATURE_REMOVE_SNMP_ENUM_CLEAR void se_clear_slist(const char *listname) { se_clear_list(se_find_slist_ptr(listname)); } void se_clear_all_lists(void) { struct snmp_enum_list_str *sptr = NULL; for (sptr = sliststorage; sptr != NULL; sptr = sptr->next) se_clear_list(&(sptr->list)); } #endif /* NETSNMP_FEATURE_REMOVE_SNMP_ENUM_CLEAR */