1 #include <net-snmp/net-snmp-config.h>
2 #include <net-snmp/net-snmp-features.h>
3
4 /*
5 * Portions of this file are copyrighted by:
6 * Copyright (c) 2016 VMware, Inc. All rights reserved.
7 * Use is subject to license terms specified in the COPYING file
8 * distributed with the Net-SNMP package.
9 */
10
11 #ifdef HAVE_STDLIB_H
12 #include <stdlib.h>
13 #endif
14 #include <stdio.h>
15 #if HAVE_STRING_H
16 #include <string.h>
17 #else
18 #include <strings.h>
19 #endif
20
21 #include <sys/types.h>
22
23 #include <net-snmp/types.h>
24 #include <net-snmp/config_api.h>
25
26 #include <net-snmp/library/snmp_enum.h>
27 #include <net-snmp/library/tools.h>
28 #include <net-snmp/library/system.h> /* strcasecmp() */
29 #include <net-snmp/library/snmp_assert.h>
30
31 netsnmp_feature_child_of(snmp_enum_all, libnetsnmp);
32
33 netsnmp_feature_child_of(se_find_free_value_in_slist, snmp_enum_all);
34 netsnmp_feature_child_of(snmp_enum_store_list, snmp_enum_all);
35 netsnmp_feature_child_of(snmp_enum_store_slist, snmp_enum_all);
36 netsnmp_feature_child_of(snmp_enum_clear, snmp_enum_all);
37
38 struct snmp_enum_list_str {
39 char *name;
40 struct snmp_enum_list *list;
41 struct snmp_enum_list_str *next;
42 };
43
44 static struct snmp_enum_list ***snmp_enum_lists;
45 unsigned int current_maj_num;
46 unsigned int current_min_num;
47 static struct snmp_enum_list_str *sliststorage;
48
49 static void
50 free_enum_list(struct snmp_enum_list *list);
51
52 int
init_snmp_enum(const char * type)53 init_snmp_enum(const char *type)
54 {
55 int i;
56
57 if (NULL != snmp_enum_lists)
58 return SE_OK;
59
60 snmp_enum_lists = (struct snmp_enum_list ***)
61 calloc(1, sizeof(struct snmp_enum_list **) * SE_MAX_IDS);
62 if (!snmp_enum_lists)
63 return SE_NOMEM;
64 current_maj_num = SE_MAX_IDS;
65
66 for (i = 0; i < SE_MAX_IDS; i++) {
67 if (!snmp_enum_lists[i])
68 snmp_enum_lists[i] = (struct snmp_enum_list **)
69 calloc(1, sizeof(struct snmp_enum_list *) * SE_MAX_SUBIDS);
70 if (!snmp_enum_lists[i])
71 return SE_NOMEM;
72 }
73 current_min_num = SE_MAX_SUBIDS;
74
75 register_const_config_handler(type, "enum", se_read_conf, NULL, NULL);
76 return SE_OK;
77 }
78
79 int
se_store_in_list(struct snmp_enum_list * new_list,unsigned int major,unsigned int minor)80 se_store_in_list(struct snmp_enum_list *new_list,
81 unsigned int major, unsigned int minor)
82 {
83 int ret = SE_OK;
84
85 if (major > current_maj_num || minor > current_min_num) {
86 /*
87 * XXX: realloc
88 */
89 return SE_NOMEM;
90 }
91 netsnmp_assert(NULL != snmp_enum_lists);
92
93 if (snmp_enum_lists[major][minor] != NULL)
94 ret = SE_ALREADY_THERE;
95
96 snmp_enum_lists[major][minor] = new_list;
97
98 return ret;
99 }
100
101 void
se_read_conf(const char * word,const char * cptr)102 se_read_conf(const char *word, const char *cptr)
103 {
104 int major, minor;
105 int value;
106 const char *cp, *cp2;
107 char e_name[BUFSIZ];
108 char e_enum[ BUFSIZ];
109
110 if (!cptr || *cptr=='\0')
111 return;
112
113 /*
114 * Extract the first token
115 * (which should be the name of the list)
116 */
117 cp = copy_nword_const(cptr, e_name, sizeof(e_name));
118 cp = skip_white_const(cp);
119 if (!cp || *cp=='\0')
120 return;
121
122
123 /*
124 * Add each remaining enumeration to the list,
125 * using the appropriate style interface
126 */
127 if (sscanf(e_name, "%d:%d", &major, &minor) == 2) {
128 /*
129 * Numeric major/minor style
130 */
131 while (1) {
132 cp = copy_nword_const(cp, e_enum, sizeof(e_enum));
133 if (sscanf(e_enum, "%d:", &value) != 1) {
134 break;
135 }
136 cp2 = e_enum;
137 while (*(cp2++) != ':')
138 ;
139 se_add_pair(major, minor, strdup(cp2), value);
140 if (!cp)
141 break;
142 }
143 } else {
144 /*
145 * Named enumeration
146 */
147 while (1) {
148 cp = copy_nword_const(cp, e_enum, sizeof(e_enum));
149 if (sscanf(e_enum, "%d:", &value) != 1) {
150 break;
151 }
152 cp2 = e_enum;
153 while (*(cp2++) != ':')
154 ;
155 se_add_pair_to_slist(e_name, strdup(cp2), value);
156 if (!cp)
157 break;
158 }
159 }
160 }
161
162 void
se_store_enum_list(struct snmp_enum_list * new_list,const char * token,const char * type)163 se_store_enum_list(struct snmp_enum_list *new_list,
164 const char *token, const char *type)
165 {
166 struct snmp_enum_list *listp = new_list;
167 char line[2048];
168 char buf[512];
169 int len;
170
171 snprintf(line, sizeof(line), "enum %s", token);
172 while (listp) {
173 snprintf(buf, sizeof(buf), " %d:%s", listp->value, listp->label);
174 /*
175 * Calculate the space left in the buffer.
176 * If this is not sufficient to include the next enum,
177 * then save the line so far, and start again.
178 */
179 len = sizeof(line) - strlen(line);
180 if ((int)strlen(buf) > len) {
181 read_config_store(type, line);
182 snprintf(line, sizeof(line), "enum %s", token);
183 len = sizeof(line) - strlen(line);
184 }
185
186 strncat(line, buf, len);
187 listp = listp->next;
188 }
189
190 read_config_store(type, line);
191 }
192
193 #ifndef NETSNMP_FEATURE_REMOVE_SNMP_ENUM_STORE_LIST
194 void
se_store_list(unsigned int major,unsigned int minor,const char * type)195 se_store_list(unsigned int major, unsigned int minor, const char *type)
196 {
197 char token[32];
198
199 snprintf(token, sizeof(token), "%d:%d", major, minor);
200 se_store_enum_list(se_find_list(major, minor), token, type);
201 }
202 #endif /* NETSNMP_FEATURE_REMOVE_SNMP_ENUM_STORE_LIST */
203
204 struct snmp_enum_list *
se_find_list(unsigned int major,unsigned int minor)205 se_find_list(unsigned int major, unsigned int minor)
206 {
207 if (major > current_maj_num || minor > current_min_num)
208 return NULL;
209 netsnmp_assert(NULL != snmp_enum_lists);
210
211 return snmp_enum_lists[major][minor];
212 }
213
214 int
se_find_value_in_list(struct snmp_enum_list * list,const char * label)215 se_find_value_in_list(struct snmp_enum_list *list, const char *label)
216 {
217 if (!list)
218 return SE_DNE; /* XXX: um, no good solution here */
219 while (list) {
220 if (strcmp(list->label, label) == 0)
221 return (list->value);
222 list = list->next;
223 }
224
225 return SE_DNE; /* XXX: um, no good solution here */
226 }
227
228 int
se_find_casevalue_in_list(struct snmp_enum_list * list,const char * label)229 se_find_casevalue_in_list(struct snmp_enum_list *list, const char *label)
230 {
231 if (!list)
232 return SE_DNE; /* XXX: um, no good solution here */
233 while (list) {
234 if (strcasecmp(list->label, label) == 0)
235 return (list->value);
236 list = list->next;
237 }
238
239 return SE_DNE; /* XXX: um, no good solution here */
240 }
241
242 int
se_find_free_value_in_list(struct snmp_enum_list * list)243 se_find_free_value_in_list(struct snmp_enum_list *list)
244 {
245 int max_value = 0;
246 if (!list)
247 return SE_DNE;
248
249 for (;list; list=list->next) {
250 if (max_value < list->value)
251 max_value = list->value;
252 }
253 return max_value+1;
254 }
255
256 int
se_find_value(unsigned int major,unsigned int minor,const char * label)257 se_find_value(unsigned int major, unsigned int minor, const char *label)
258 {
259 return se_find_value_in_list(se_find_list(major, minor), label);
260 }
261
262 int
se_find_free_value(unsigned int major,unsigned int minor)263 se_find_free_value(unsigned int major, unsigned int minor)
264 {
265 return se_find_free_value_in_list(se_find_list(major, minor));
266 }
267
268 char *
se_find_label_in_list(struct snmp_enum_list * list,int value)269 se_find_label_in_list(struct snmp_enum_list *list, int value)
270 {
271 if (!list)
272 return NULL;
273 while (list) {
274 if (list->value == value)
275 return (list->label);
276 list = list->next;
277 }
278 return NULL;
279 }
280
281 char *
se_find_label(unsigned int major,unsigned int minor,int value)282 se_find_label(unsigned int major, unsigned int minor, int value)
283 {
284 return se_find_label_in_list(se_find_list(major, minor), value);
285 }
286
287 int
se_add_pair_to_list(struct snmp_enum_list ** list,char * label,int value)288 se_add_pair_to_list(struct snmp_enum_list **list, char *label, int value)
289 {
290 struct snmp_enum_list *lastnode = NULL, *tmp;
291
292 if (!list)
293 return SE_DNE;
294
295 tmp = *list;
296 while (tmp) {
297 if (tmp->value == value) {
298 free(label);
299 return (SE_ALREADY_THERE);
300 }
301 lastnode = tmp;
302 tmp = tmp->next;
303 }
304
305 if (lastnode) {
306 lastnode->next = SNMP_MALLOC_STRUCT(snmp_enum_list);
307 lastnode = lastnode->next;
308 } else {
309 (*list) = SNMP_MALLOC_STRUCT(snmp_enum_list);
310 lastnode = (*list);
311 }
312 if (!lastnode) {
313 free(label);
314 return (SE_NOMEM);
315 }
316 lastnode->label = label;
317 lastnode->value = value;
318 lastnode->next = NULL;
319 return (SE_OK);
320 }
321
322 int
se_add_pair(unsigned int major,unsigned int minor,char * label,int value)323 se_add_pair(unsigned int major, unsigned int minor, char *label, int value)
324 {
325 struct snmp_enum_list *list = se_find_list(major, minor);
326 int created = (list) ? 1 : 0;
327 int ret = se_add_pair_to_list(&list, label, value);
328 if (!created)
329 se_store_in_list(list, major, minor);
330 return ret;
331 }
332
333 /*
334 * remember a list of enums based on a lookup name.
335 */
336 static struct snmp_enum_list **
se_find_slist_ptr(const char * listname)337 se_find_slist_ptr(const char *listname)
338 {
339 struct snmp_enum_list_str *sptr;
340 if (!listname)
341 return NULL;
342
343 for (sptr = sliststorage; sptr != NULL; sptr = sptr->next)
344 if (sptr->name && strcmp(sptr->name, listname) == 0)
345 return &sptr->list;
346
347 return NULL;
348 }
349
350 struct snmp_enum_list *
se_find_slist(const char * listname)351 se_find_slist(const char *listname)
352 {
353 struct snmp_enum_list **ptr = se_find_slist_ptr(listname);
354 return ptr ? *ptr : NULL;
355 }
356
357 char *
se_find_label_in_slist(const char * listname,int value)358 se_find_label_in_slist(const char *listname, int value)
359 {
360 return (se_find_label_in_list(se_find_slist(listname), value));
361 }
362
363 int
se_find_value_in_slist(const char * listname,const char * label)364 se_find_value_in_slist(const char *listname, const char *label)
365 {
366 return (se_find_value_in_list(se_find_slist(listname), label));
367 }
368
369 int
se_find_casevalue_in_slist(const char * listname,const char * label)370 se_find_casevalue_in_slist(const char *listname, const char *label)
371 {
372 return (se_find_casevalue_in_list(se_find_slist(listname), label));
373 }
374
375 #ifndef NETSNMP_FEATURE_REMOVE_SE_FIND_FREE_VALUE_IN_SLIST
376 int
se_find_free_value_in_slist(const char * listname)377 se_find_free_value_in_slist(const char *listname)
378 {
379 return (se_find_free_value_in_list(se_find_slist(listname)));
380 }
381 #endif /* NETSNMP_FEATURE_REMOVE_SE_FIND_FREE_VALUE_IN_SLIST */
382
383 int
se_add_pair_to_slist(const char * listname,char * label,int value)384 se_add_pair_to_slist(const char *listname, char *label, int value)
385 {
386 struct snmp_enum_list *list = se_find_slist(listname);
387 int created = (list) ? 1 : 0;
388 int ret = se_add_pair_to_list(&list, label, value);
389
390 if (!created) {
391 struct snmp_enum_list_str *sptr =
392 SNMP_MALLOC_STRUCT(snmp_enum_list_str);
393 if (!sptr) {
394 free_enum_list(list);
395 return SE_NOMEM;
396 }
397 sptr->next = sliststorage;
398 sptr->name = strdup(listname);
399 sptr->list = list;
400 sliststorage = sptr;
401 }
402 return ret;
403 }
404
405 static void
free_enum_list(struct snmp_enum_list * list)406 free_enum_list(struct snmp_enum_list *list)
407 {
408 struct snmp_enum_list *next;
409
410 while (list) {
411 next = list->next;
412 SNMP_FREE(list->label);
413 SNMP_FREE(list);
414 list = next;
415 }
416 }
417
418 void
clear_snmp_enum(void)419 clear_snmp_enum(void)
420 {
421 struct snmp_enum_list_str *sptr = sliststorage, *next = NULL;
422 int i, j;
423
424 while (sptr != NULL) {
425 next = sptr->next;
426 free_enum_list(sptr->list);
427 SNMP_FREE(sptr->name);
428 SNMP_FREE(sptr);
429 sptr = next;
430 }
431 sliststorage = NULL;
432
433 if (snmp_enum_lists) {
434 for (i = 0; i < SE_MAX_IDS; i++) {
435 if (snmp_enum_lists[i]) {
436 for (j = 0; j < SE_MAX_SUBIDS; j++) {
437 if (snmp_enum_lists[i][j])
438 free_enum_list(snmp_enum_lists[i][j]);
439 }
440 SNMP_FREE(snmp_enum_lists[i]);
441 }
442 }
443 SNMP_FREE(snmp_enum_lists);
444 }
445 }
446
447 void
se_clear_list(struct snmp_enum_list ** list)448 se_clear_list(struct snmp_enum_list **list)
449 {
450 struct snmp_enum_list *this_entry, *next_entry;
451
452 if (!list)
453 return;
454
455 this_entry = *list;
456 while (this_entry) {
457 next_entry = this_entry->next;
458 SNMP_FREE(this_entry->label);
459 SNMP_FREE(this_entry);
460 this_entry = next_entry;
461 }
462 *list = NULL;
463 return;
464 }
465
466 #ifndef NETSNMP_FEATURE_REMOVE_SNMP_ENUM_STORE_SLIST
467 void
se_store_slist(const char * listname,const char * type)468 se_store_slist(const char *listname, const char *type)
469 {
470 struct snmp_enum_list *list = se_find_slist(listname);
471 se_store_enum_list(list, listname, type);
472 }
473
474 int
se_store_slist_callback(int majorID,int minorID,void * serverargs,void * clientargs)475 se_store_slist_callback(int majorID, int minorID,
476 void *serverargs, void *clientargs)
477 {
478 char *appname = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
479 NETSNMP_DS_LIB_APPTYPE);
480 se_store_slist((char *)clientargs, appname);
481 return SNMPERR_SUCCESS;
482 }
483 #endif /* NETSNMP_FEATURE_REMOVE_SNMP_ENUM_STORE_SLIST */
484
485 #ifndef NETSNMP_FEATURE_REMOVE_SNMP_ENUM_CLEAR
486 void
se_clear_slist(const char * listname)487 se_clear_slist(const char *listname)
488 {
489 se_clear_list(se_find_slist_ptr(listname));
490 }
491
492 void
se_clear_all_lists(void)493 se_clear_all_lists(void)
494 {
495 struct snmp_enum_list_str *sptr = NULL;
496
497 for (sptr = sliststorage; sptr != NULL; sptr = sptr->next)
498 se_clear_list(&(sptr->list));
499 }
500 #endif /* NETSNMP_FEATURE_REMOVE_SNMP_ENUM_CLEAR */
501