1 #include <net-snmp/net-snmp-config.h>
2
3 #ifdef NETSNMP_CAN_USE_NLIST
4 #if HAVE_STRING_H
5 #include <string.h>
6 #else
7 #include <strings.h>
8 #endif
9
10 #if HAVE_STDLIB_H
11 #include <stdlib.h>
12 #endif
13 #include <stdio.h>
14 #include <errno.h>
15 #include <fcntl.h>
16 #include <netinet/in.h>
17 #if HAVE_KVM_H
18 #include <kvm.h>
19 #elif defined(HAVE_NLIST_H)
20 #include <nlist.h>
21 #endif
22
23 #include <net-snmp/agent/auto_nlist.h>
24 #include "autonlist.h"
25 #include "kernel.h"
26
27 #include <net-snmp/net-snmp-includes.h>
28 #include <net-snmp/agent/ds_agent.h>
29
30 struct autonlist *nlists = 0;
31 static void init_nlist(struct nlist *);
32
33 long
auto_nlist_value(const char * string)34 auto_nlist_value(const char *string)
35 {
36 struct autonlist **ptr, *it = 0;
37 int cmp;
38
39 if (string == 0)
40 return 0;
41
42 ptr = &nlists;
43 while (*ptr != 0 && it == 0) {
44 cmp = strcmp((*ptr)->symbol, string);
45 if (cmp == 0)
46 it = *ptr;
47 else if (cmp < 0) {
48 ptr = &((*ptr)->left);
49 } else {
50 ptr = &((*ptr)->right);
51 }
52 }
53 if (*ptr == 0) {
54 *ptr = (struct autonlist *) malloc(sizeof(struct autonlist));
55 memset(*ptr, 0, sizeof(struct autonlist));
56 it = *ptr;
57 it->left = 0;
58 it->right = 0;
59 it->symbol = (char *) malloc(strlen(string) + 1);
60 strcpy(it->symbol, string);
61 /*
62 * allocate an extra byte for inclusion of a preceding '_' later
63 */
64 it->nl[0].n_name = (char *) malloc(strlen(string) + 2);
65 #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
66 strcpy(it->nl[0].n_name, string);
67 it->nl[0].n_name[strlen(string)+1] = '\0';
68 #elif defined(freebsd9)
69 sprintf(__DECONST(char*, it->nl[0].n_name), "_%s", string);
70 #else
71 {
72 static char *name;
73
74 free(name);
75 name = NULL;
76 if (asprintf(&name, "_%s", string) < 0) {
77 snmp_log(LOG_ERR, "nlist err: failed to allocate memory");
78 return -1;
79 }
80 it->nl[0].n_name = name;
81 }
82 #endif
83 it->nl[1].n_name = 0;
84 init_nlist(it->nl);
85 #if !(defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7) || \
86 defined(netbsd1) || defined(dragonfly))
87 if (it->nl[0].n_type == 0) {
88 #if defined(freebsd9)
89 strcpy(__DECONST(char*, it->nl[0].n_name), string);
90 __DECONST(char*, it->nl[0].n_name)[strlen(string)+1] = '\0';
91 #else
92 static char *n_name2 = NULL;
93
94 if (n_name2 != NULL)
95 free(n_name2);
96
97 n_name2 = malloc(strlen(string) + 1);
98 if (n_name2 == NULL) {
99 snmp_log(LOG_ERR, "nlist err: failed to allocate memory");
100 return (-1);
101 }
102 strcpy(n_name2, string);
103 it->nl[0].n_name = n_name2;
104 #endif
105 init_nlist(it->nl);
106 }
107 #endif
108 if (it->nl[0].n_type == 0) {
109 if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
110 NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
111 snmp_log(LOG_ERR, "nlist err: neither %s nor _%s found.\n",
112 string, string);
113 }
114 return (-1);
115 } else {
116 DEBUGMSGTL(("auto_nlist:auto_nlist_value",
117 "found symbol %s at %lx.\n",
118 it->symbol, it->nl[0].n_value));
119 return (it->nl[0].n_value);
120 }
121 } else
122 return (it->nl[0].n_value);
123 }
124
125 int
auto_nlist(const char * string,char * var,size_t size)126 auto_nlist(const char *string, char *var, size_t size)
127 {
128 long result;
129 int ret;
130 result = auto_nlist_value(string);
131 if (result != -1) {
132 if (var != NULL) {
133 ret = klookup(result, var, size);
134 if (!ret)
135 snmp_log(LOG_ERR,
136 "auto_nlist failed on %s at location %lx\n",
137 string, result);
138 return ret;
139 } else
140 return 1;
141 }
142 return 0;
143 }
144
145 static void
init_nlist(struct nlist nl[])146 init_nlist(struct nlist nl[])
147 {
148 int ret;
149 #if HAVE_KVM_OPENFILES
150 kvm_t *kernel;
151 char kvm_errbuf[4096];
152
153 if ((kernel = kvm_openfiles(KERNEL_LOC, NULL, NULL, O_RDONLY, kvm_errbuf))
154 == NULL) {
155 if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
156 NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
157 return;
158 } else {
159 snmp_log_perror("kvm_openfiles");
160 snmp_log(LOG_ERR, "kvm_openfiles: %s\n", kvm_errbuf);
161 exit(1);
162 }
163 }
164 if ((ret = kvm_nlist(kernel, nl)) == -1) {
165 if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
166 NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
167 return;
168 } else {
169 snmp_log_perror("kvm_nlist");
170 exit(1);
171 }
172 }
173 kvm_close(kernel);
174 #else /* ! HAVE_KVM_OPENFILES */
175 #if (defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)) && defined(HAVE_KNLIST)
176 if (knlist(nl, 1, sizeof(struct nlist)) == -1) {
177 DEBUGMSGTL(("auto_nlist:init_nlist", "knlist failed on symbol: %s\n",
178 nl[0].n_name));
179 if (errno == EFAULT) {
180 nl[0].n_type = 0;
181 nl[0].n_value = 0;
182 } else {
183 snmp_log_perror("knlist");
184 if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
185 NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
186 return;
187 } else {
188 exit(1);
189 }
190 }
191 }
192 #else
193 if ((ret = nlist(KERNEL_LOC, nl)) == -1) {
194 if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
195 NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
196 return;
197 } else {
198 snmp_log_perror("nlist");
199 exit(1);
200 }
201 }
202 #endif /*aix4 */
203 #endif /* ! HAVE_KVM_OPENFILES */
204 for (ret = 0; nl[ret].n_name != NULL; ret++) {
205 #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
206 if (nl[ret].n_type == 0 && nl[ret].n_value != 0)
207 nl[ret].n_type = 1;
208 #endif
209 if (nl[ret].n_type == 0) {
210 if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
211 NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
212 DEBUGMSGTL(("auto_nlist:init_nlist", "nlist err: %s not found\n",
213 nl[ret].n_name));
214 }
215 } else {
216 DEBUGMSGTL(("auto_nlist:init_nlist", "nlist: %s 0x%X\n", nl[ret].n_name,
217 (unsigned int) nl[ret].n_value));
218 }
219 }
220 }
221
222 int
KNLookup(struct nlist nl[],int nl_which,char * buf,size_t s)223 KNLookup(struct nlist nl[], int nl_which, char *buf, size_t s)
224 {
225 struct nlist *nlp = &nl[nl_which];
226
227 if (nlp->n_value == 0) {
228 snmp_log(LOG_ERR, "Accessing non-nlisted variable: %s\n",
229 nlp->n_name);
230 nlp->n_value = -1; /* only one error message ... */
231 return 0;
232 }
233 if (nlp->n_value == -1)
234 return 0;
235
236 return klookup(nlp->n_value, buf, s);
237 }
238
239 #ifdef TESTING
240 void
auto_nlist_print_tree(int indent,struct autonlist * ptr)241 auto_nlist_print_tree(int indent, struct autonlist *ptr)
242 {
243 char buf[1024];
244 if (indent == -2) {
245 snmp_log(LOG_ERR, "nlist tree:\n");
246 auto_nlist_print_tree(12, nlists);
247 } else {
248 if (ptr == 0)
249 return;
250 sprintf(buf, "%%%ds\n", indent);
251 /*
252 * DEBUGMSGTL(("auto_nlist", "buf: %s\n",buf));
253 */
254 DEBUGMSGTL(("auto_nlist", buf, ptr->symbol));
255 auto_nlist_print_tree(indent + 2, ptr->left);
256 auto_nlist_print_tree(indent + 2, ptr->right);
257 }
258 }
259 #endif
260 #else /* !NETSNMP_CAN_USE_NLIST */
261 #include <net-snmp/agent/auto_nlist.h>
262 int
auto_nlist_noop(void)263 auto_nlist_noop(void)
264 {
265 return 0;
266 }
267 #endif /* NETSNMP_CAN_USE_NLIST */
268