#include #ifdef NETSNMP_CAN_USE_NLIST #if HAVE_STRING_H #include #else #include #endif #if HAVE_STDLIB_H #include #endif #include #include #include #include #ifdef HAVE_NLIST_H #include #endif #if HAVE_KVM_H #include #endif #include #include "autonlist.h" #include "kernel.h" #include #include struct autonlist *nlists = 0; static void init_nlist(struct nlist *); long auto_nlist_value(const char *string) { struct autonlist **ptr, *it = 0; int cmp; if (string == 0) return 0; ptr = &nlists; while (*ptr != 0 && it == 0) { cmp = strcmp((*ptr)->symbol, string); if (cmp == 0) it = *ptr; else if (cmp < 0) { ptr = &((*ptr)->left); } else { ptr = &((*ptr)->right); } } if (*ptr == 0) { #if !(defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)) static char *n_name = NULL; #endif *ptr = (struct autonlist *) malloc(sizeof(struct autonlist)); memset(*ptr, 0, sizeof(struct autonlist)); it = *ptr; it->left = 0; it->right = 0; it->symbol = (char *) malloc(strlen(string) + 1); strcpy(it->symbol, string); /* * allocate an extra byte for inclusion of a preceding '_' later */ it->nl[0].n_name = (char *) malloc(strlen(string) + 2); #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) strcpy(it->nl[0].n_name, string); it->nl[0].n_name[strlen(string)+1] = '\0'; #elif defined(freebsd9) sprintf(__DECONST(char*, it->nl[0].n_name), "_%s", string); #else if (n_name != NULL) free(n_name); n_name = malloc(strlen(string) + 2); if (n_name == NULL) { snmp_log(LOG_ERR, "nlist err: failed to allocate memory"); return (-1); } snprintf(n_name, strlen(string) + 2, "_%s", string); it->nl[0].n_name = (const char*)n_name; #endif it->nl[1].n_name = 0; init_nlist(it->nl); #if !(defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) || \ defined(netbsd1) || defined(dragonfly)) if (it->nl[0].n_type == 0) { #if defined(freebsd9) strcpy(__DECONST(char*, it->nl[0].n_name), string); __DECONST(char*, it->nl[0].n_name)[strlen(string)+1] = '\0'; #else static char *n_name2 = NULL; if (n_name2 != NULL) free(n_name2); n_name2 = malloc(strlen(string) + 1); if (n_name2 == NULL) { snmp_log(LOG_ERR, "nlist err: failed to allocate memory"); return (-1); } strcpy(n_name2, string); it->nl[0].n_name = (const char*)n_name2; #endif init_nlist(it->nl); } #endif if (it->nl[0].n_type == 0) { if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { snmp_log(LOG_ERR, "nlist err: neither %s nor _%s found.\n", string, string); } return (-1); } else { DEBUGMSGTL(("auto_nlist:auto_nlist_value", "found symbol %s at %lx.\n", it->symbol, it->nl[0].n_value)); return (it->nl[0].n_value); } } else return (it->nl[0].n_value); } int auto_nlist(const char *string, char *var, size_t size) { long result; int ret; result = auto_nlist_value(string); if (result != -1) { if (var != NULL) { ret = klookup(result, var, size); if (!ret) snmp_log(LOG_ERR, "auto_nlist failed on %s at location %lx\n", string, result); return ret; } else return 1; } return 0; } static void init_nlist(struct nlist nl[]) { int ret; #if HAVE_KVM_OPENFILES kvm_t *kernel; char kvm_errbuf[4096]; if ((kernel = kvm_openfiles(KERNEL_LOC, NULL, NULL, O_RDONLY, kvm_errbuf)) == NULL) { if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { return; } else { snmp_log_perror("kvm_openfiles"); snmp_log(LOG_ERR, "kvm_openfiles: %s\n", kvm_errbuf); exit(1); } } if ((ret = kvm_nlist(kernel, nl)) == -1) { if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { return; } else { snmp_log_perror("kvm_nlist"); exit(1); } } kvm_close(kernel); #else /* ! HAVE_KVM_OPENFILES */ #if (defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)) && defined(HAVE_KNLIST) if (knlist(nl, 1, sizeof(struct nlist)) == -1) { DEBUGMSGTL(("auto_nlist:init_nlist", "knlist failed on symbol: %s\n", nl[0].n_name)); if (errno == EFAULT) { nl[0].n_type = 0; nl[0].n_value = 0; } else { snmp_log_perror("knlist"); if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { return; } else { exit(1); } } } #else if ((ret = nlist(KERNEL_LOC, nl)) == -1) { if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { return; } else { snmp_log_perror("nlist"); exit(1); } } #endif /*aix4 */ #endif /* ! HAVE_KVM_OPENFILES */ for (ret = 0; nl[ret].n_name != NULL; ret++) { #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) if (nl[ret].n_type == 0 && nl[ret].n_value != 0) nl[ret].n_type = 1; #endif if (nl[ret].n_type == 0) { if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { DEBUGMSGTL(("auto_nlist:init_nlist", "nlist err: %s not found\n", nl[ret].n_name)); } } else { DEBUGMSGTL(("auto_nlist:init_nlist", "nlist: %s 0x%X\n", nl[ret].n_name, (unsigned int) nl[ret].n_value)); } } } int KNLookup(struct nlist nl[], int nl_which, char *buf, size_t s) { struct nlist *nlp = &nl[nl_which]; if (nlp->n_value == 0) { snmp_log(LOG_ERR, "Accessing non-nlisted variable: %s\n", nlp->n_name); nlp->n_value = -1; /* only one error message ... */ return 0; } if (nlp->n_value == -1) return 0; return klookup(nlp->n_value, buf, s); } #ifdef TESTING void auto_nlist_print_tree(int indent, struct autonlist *ptr) { char buf[1024]; if (indent == -2) { snmp_log(LOG_ERR, "nlist tree:\n"); auto_nlist_print_tree(12, nlists); } else { if (ptr == 0) return; sprintf(buf, "%%%ds\n", indent); /* * DEBUGMSGTL(("auto_nlist", "buf: %s\n",buf)); */ DEBUGMSGTL(("auto_nlist", buf, ptr->symbol)); auto_nlist_print_tree(indent + 2, ptr->left); auto_nlist_print_tree(indent + 2, ptr->right); } } #endif #else /* !NETSNMP_CAN_USE_NLIST */ #include int auto_nlist_noop(void) { return 0; } #endif /* NETSNMP_CAN_USE_NLIST */