| #include <net-snmp/net-snmp-config.h> |
| |
| #ifdef NETSNMP_CAN_USE_NLIST |
| #if HAVE_STRING_H |
| #include <string.h> |
| #else |
| #include <strings.h> |
| #endif |
| |
| #if HAVE_STDLIB_H |
| #include <stdlib.h> |
| #endif |
| #include <stdio.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <netinet/in.h> |
| #ifdef HAVE_NLIST_H |
| #include <nlist.h> |
| #endif |
| #if HAVE_KVM_H |
| #include <kvm.h> |
| #endif |
| |
| #include <net-snmp/agent/auto_nlist.h> |
| #include "autonlist.h" |
| #include "kernel.h" |
| |
| #include <net-snmp/net-snmp-includes.h> |
| #include <net-snmp/agent/ds_agent.h> |
| |
| 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) |
| 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[]) |
| { |
| #ifdef NETSNMP_CAN_USE_NLIST |
| 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(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) |
| 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)); |
| } |
| } |
| #endif /* NETSNMP_CAN_USE_NLIST */ |
| } |
| |
| 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 <net-snmp/agent/auto_nlist.h> |
| int |
| auto_nlist_noop(void) |
| { |
| return 0; |
| } |
| #endif /* NETSNMP_CAN_USE_NLIST */ |