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