Coverage Report

Created: 2025-11-11 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/net-snmp/snmplib/snmp_enum.c
Line
Count
Source
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
#ifdef 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
static unsigned int current_maj_num;
46
static 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
53
init_snmp_enum(const char *type)
54
3.24k
{
55
3.24k
    if (NULL != snmp_enum_lists)
56
0
        return SE_OK;
57
58
3.24k
    snmp_enum_lists = calloc(SE_MAX_IDS * SE_MAX_SUBIDS,
59
3.24k
                             sizeof(*snmp_enum_lists));
60
3.24k
    if (!snmp_enum_lists)
61
0
        return SE_NOMEM;
62
3.24k
    current_maj_num = SE_MAX_IDS;
63
3.24k
    current_min_num = SE_MAX_SUBIDS;
64
65
3.24k
    register_const_config_handler(type, "enum", se_read_conf, NULL, NULL);
66
3.24k
    return SE_OK;
67
3.24k
}
68
69
void
70
se_read_conf(const char *word, const char *cptr)
71
358
{
72
358
    int major, minor;
73
358
    int value;
74
358
    const char *cp, *cp2;
75
358
    char e_name[BUFSIZ];
76
358
    char e_enum[  BUFSIZ];
77
78
358
    if (!cptr || *cptr=='\0')
79
10
        return;
80
81
    /*
82
     * Extract the first token
83
     *   (which should be the name of the list)
84
     */
85
348
    cp = copy_nword_const(cptr, e_name, sizeof(e_name));
86
348
    cp = skip_white_const(cp);
87
348
    if (!cp || *cp=='\0')
88
37
        return;
89
90
91
    /*
92
     * Add each remaining enumeration to the list,
93
     *   using the appropriate style interface
94
     */
95
311
    if (sscanf(e_name, "%d:%d", &major, &minor) == 2) {
96
        /*
97
         *  Numeric major/minor style
98
         */
99
629
        while (1) {
100
629
            cp = copy_nword_const(cp, e_enum, sizeof(e_enum));
101
629
            if (sscanf(e_enum, "%d:", &value) != 1) {
102
67
                break;
103
67
            }
104
562
            cp2 = e_enum;
105
3.47k
            while (*cp2 != 0 && *cp2++ != ':')
106
2.91k
                ;
107
562
            se_add_pair(major, minor, strdup(cp2), value);
108
562
            if (!cp)
109
85
                break;
110
562
        }
111
159
    } else {
112
        /*
113
         *  Named enumeration
114
         */
115
529
        while (1) {
116
529
            cp = copy_nword_const(cp, e_enum, sizeof(e_enum));
117
529
            if (sscanf(e_enum, "%d:", &value) != 1) {
118
77
                break;
119
77
            }
120
452
            cp2 = e_enum;
121
3.26k
            while (*cp2 != 0 && *cp2++ != ':')
122
2.81k
                ;
123
452
            se_add_pair_to_slist(e_name, strdup(cp2), value);
124
452
            if (!cp)
125
82
                break;
126
452
        }
127
159
    }
128
311
}
129
130
void
131
se_store_enum_list(struct snmp_enum_list *new_list,
132
                   const char *token, const char *type)
133
0
{
134
0
    struct snmp_enum_list *listp = new_list;
135
0
    char line[2048];
136
0
    char buf[512];
137
0
    int  len;
138
139
0
    snprintf(line, sizeof(line), "enum %s", token);
140
0
    while (listp) {
141
0
        snprintf(buf, sizeof(buf), " %d:%s", listp->value, listp->label);
142
        /*
143
         * Calculate the space left in the buffer.
144
         * If this is not sufficient to include the next enum,
145
         *   then save the line so far, and start again.
146
         */
147
0
  len = sizeof(line) - strlen(line);
148
0
  if ((int)strlen(buf) > len) {
149
0
      read_config_store(type, line);
150
0
            snprintf(line, sizeof(line), "enum %s", token);
151
0
      len = sizeof(line) - strlen(line);
152
0
  }
153
154
0
  strncat(line, buf, len);
155
0
        listp = listp->next;
156
0
    }
157
158
0
    read_config_store(type, line);
159
0
}
160
161
#ifndef NETSNMP_FEATURE_REMOVE_SNMP_ENUM_STORE_LIST
162
void
163
se_store_list(unsigned int major, unsigned int minor, const char *type)
164
0
{
165
0
    char token[32];
166
167
0
    snprintf(token, sizeof(token), "%d:%d", major, minor);
168
0
    se_store_enum_list(se_find_list(major, minor), token, type);
169
0
}
170
#endif /* NETSNMP_FEATURE_REMOVE_SNMP_ENUM_STORE_LIST */
171
172
static struct snmp_enum_list **
173
se_find_list_ptr(unsigned int major, unsigned int minor)
174
519k
{
175
519k
    if (major >= current_maj_num || minor >= current_min_num)
176
249
        return NULL;
177
519k
    netsnmp_assert(NULL != snmp_enum_lists);
178
179
519k
    return &snmp_enum_lists[major * current_min_num + minor];
180
519k
}
181
182
struct snmp_enum_list *
183
se_find_list(unsigned int major, unsigned int minor)
184
0
{
185
0
    struct snmp_enum_list **p = se_find_list_ptr(major, minor);
186
187
0
    return p ? *p : NULL;
188
0
}
189
190
int
191
se_find_value_in_list(struct snmp_enum_list *list, const char *label)
192
0
{
193
0
    if (!list)
194
0
        return SE_DNE;          /* XXX: um, no good solution here */
195
0
    while (list) {
196
0
        if (strcmp(list->label, label) == 0)
197
0
            return (list->value);
198
0
        list = list->next;
199
0
    }
200
201
0
    return SE_DNE;              /* XXX: um, no good solution here */
202
0
}
203
204
int
205
se_find_casevalue_in_list(struct snmp_enum_list *list, const char *label)
206
0
{
207
0
    if (!list)
208
0
        return SE_DNE;          /* XXX: um, no good solution here */
209
0
    while (list) {
210
0
        if (strcasecmp(list->label, label) == 0)
211
0
            return (list->value);
212
0
        list = list->next;
213
0
    }
214
215
0
    return SE_DNE;              /* XXX: um, no good solution here */
216
0
}
217
218
int
219
se_find_free_value_in_list(struct snmp_enum_list *list)
220
0
{
221
0
    int max_value = 0;
222
0
    if (!list)
223
0
        return SE_DNE;
224
225
0
    for (;list; list=list->next) {
226
0
        if (max_value < list->value)
227
0
            max_value = list->value;
228
0
    }
229
0
    return max_value+1;
230
0
}
231
232
int
233
se_find_value(unsigned int major, unsigned int minor, const char *label)
234
0
{
235
0
    return se_find_value_in_list(se_find_list(major, minor), label);
236
0
}
237
238
int
239
se_find_free_value(unsigned int major, unsigned int minor)
240
0
{
241
0
    return se_find_free_value_in_list(se_find_list(major, minor));
242
0
}
243
244
char           *
245
se_find_label_in_list(struct snmp_enum_list *list, int value)
246
0
{
247
0
    if (!list)
248
0
        return NULL;
249
0
    while (list) {
250
0
        if (list->value == value)
251
0
            return (list->label);
252
0
        list = list->next;
253
0
    }
254
0
    return NULL;
255
0
}
256
257
char           *
258
se_find_label(unsigned int major, unsigned int minor, int value)
259
0
{
260
0
    return se_find_label_in_list(se_find_list(major, minor), value);
261
0
}
262
263
/*
264
 * Ownership of 'label' is transferred from the caller to this function.
265
 * 'label' is freed if list insertion fails.
266
 */
267
int
268
se_add_pair_to_list(struct snmp_enum_list **list, char *label, int value)
269
182k
{
270
182k
    struct snmp_enum_list *lastnode = NULL, *new_node, *tmp;
271
272
182k
    if (!list) {
273
249
        free(label);
274
249
        return SE_DNE;
275
249
    }
276
277
182k
    tmp = *list;
278
826k
    while (tmp) {
279
657k
        if (tmp->value == value) {
280
13.3k
            free(label);
281
13.3k
            return (SE_ALREADY_THERE);
282
13.3k
        }
283
644k
        lastnode = tmp;
284
644k
        tmp = tmp->next;
285
644k
    }
286
287
169k
    new_node = SNMP_MALLOC_STRUCT(snmp_enum_list);
288
169k
    if (!new_node) {
289
0
        free(label);
290
0
        return (SE_NOMEM);
291
0
    }
292
293
169k
    if (lastnode)
294
143k
        lastnode->next = new_node;
295
26.1k
    else
296
26.1k
        *list = new_node;
297
169k
    new_node->label = label;
298
169k
    new_node->value = value;
299
169k
    new_node->next = NULL;
300
169k
    return (SE_OK);
301
169k
}
302
303
int
304
se_add_pair(unsigned int major, unsigned int minor, char *label, int value)
305
562
{
306
562
    return se_add_pair_to_list(se_find_list_ptr(major, minor), label, value);
307
562
}
308
309
/*
310
 * remember a list of enums based on a lookup name.
311
 */
312
static struct snmp_enum_list **
313
se_find_slist_ptr(const char *listname)
314
182k
{
315
182k
    struct snmp_enum_list_str *sptr;
316
182k
    if (!listname)
317
0
        return NULL;
318
319
282k
    for (sptr = sliststorage; sptr != NULL; sptr = sptr->next)
320
255k
        if (sptr->name && strcmp(sptr->name, listname) == 0)
321
156k
            return &sptr->list;
322
323
26.0k
    return NULL;
324
182k
}
325
326
struct snmp_enum_list *
327
se_find_slist(const char *listname)
328
0
{
329
0
    struct snmp_enum_list **ptr = se_find_slist_ptr(listname);
330
0
    return ptr ? *ptr : NULL;
331
0
}
332
333
char           *
334
se_find_label_in_slist(const char *listname, int value)
335
0
{
336
0
    return (se_find_label_in_list(se_find_slist(listname), value));
337
0
}
338
339
int
340
se_find_value_in_slist(const char *listname, const char *label)
341
0
{
342
0
    return (se_find_value_in_list(se_find_slist(listname), label));
343
0
}
344
345
int
346
se_find_casevalue_in_slist(const char *listname, const char *label)
347
0
{
348
0
    return (se_find_casevalue_in_list(se_find_slist(listname), label));
349
0
}
350
351
#ifndef NETSNMP_FEATURE_REMOVE_SE_FIND_FREE_VALUE_IN_SLIST
352
int
353
se_find_free_value_in_slist(const char *listname)
354
0
{
355
0
    return (se_find_free_value_in_list(se_find_slist(listname)));
356
0
}
357
#endif /* NETSNMP_FEATURE_REMOVE_SE_FIND_FREE_VALUE_IN_SLIST */
358
359
/*
360
 * Ownership of 'label' is transferred from the caller to this function.
361
 * 'label' is freed if list insertion fails.
362
 */
363
int
364
se_add_pair_to_slist(const char *listname, char *label, int value)
365
182k
{
366
182k
    struct snmp_enum_list **list_p = se_find_slist_ptr(listname);
367
368
182k
    if (!list_p) {
369
26.0k
        struct snmp_enum_list_str *sptr =
370
26.0k
            SNMP_MALLOC_STRUCT(snmp_enum_list_str);
371
26.0k
        if (!sptr) {
372
0
            free(label);
373
0
            return SE_NOMEM;
374
0
        }
375
26.0k
        sptr->next = sliststorage;
376
26.0k
        sptr->name = strdup(listname);
377
26.0k
        if (!sptr->name) {
378
0
            free(sptr);
379
0
            free(label);
380
0
            return SE_NOMEM;
381
0
        }
382
26.0k
        list_p = &sptr->list;
383
26.0k
        sliststorage = sptr;
384
26.0k
    }
385
386
182k
    return se_add_pair_to_list(list_p, label, value);
387
182k
}
388
389
static void
390
free_enum_list(struct snmp_enum_list *list)
391
25.9k
{
392
25.9k
    struct snmp_enum_list *next;
393
394
194k
    while (list) {
395
168k
        next = list->next;
396
168k
        SNMP_FREE(list->label);
397
168k
        SNMP_FREE(list);
398
168k
        list = next;
399
168k
    }
400
25.9k
}
401
402
void
403
clear_snmp_enum(void)
404
6.48k
{
405
6.48k
    struct snmp_enum_list_str *sptr = sliststorage, *next = NULL;
406
6.48k
    unsigned int major, minor;
407
408
32.4k
    while (sptr != NULL) {
409
25.9k
  next = sptr->next;
410
25.9k
  free_enum_list(sptr->list);
411
25.9k
  SNMP_FREE(sptr->name);
412
25.9k
  SNMP_FREE(sptr);
413
25.9k
  sptr = next;
414
25.9k
    }
415
6.48k
    sliststorage = NULL;
416
417
22.7k
    for (major = 0; major < current_maj_num; major++) {
418
535k
        for (minor = 0; minor < current_min_num; minor++) {
419
519k
            struct snmp_enum_list **list_ptr = se_find_list_ptr(major, minor);
420
421
519k
            if (!list_ptr || !*list_ptr)
422
519k
                continue;
423
0
            free_enum_list(*list_ptr);
424
0
        }
425
16.2k
    }
426
6.48k
    current_maj_num = 0;
427
6.48k
    current_min_num = 0;
428
6.48k
    SNMP_FREE(snmp_enum_lists);
429
6.48k
}
430
431
void
432
se_clear_list(struct snmp_enum_list **list)
433
0
{
434
0
    struct snmp_enum_list *this_entry, *next_entry;
435
436
0
    if (!list)
437
0
        return;
438
439
0
    this_entry = *list;
440
0
    while (this_entry) {
441
0
        next_entry = this_entry->next;
442
0
        SNMP_FREE(this_entry->label);
443
0
        SNMP_FREE(this_entry);
444
0
        this_entry = next_entry;
445
0
    }
446
0
    *list = NULL;
447
0
    return;
448
0
}
449
450
#ifndef NETSNMP_FEATURE_REMOVE_SNMP_ENUM_STORE_SLIST
451
void
452
se_store_slist(const char *listname, const char *type)
453
0
{
454
0
    struct snmp_enum_list *list = se_find_slist(listname);
455
0
    se_store_enum_list(list, listname, type);
456
0
}
457
458
int
459
se_store_slist_callback(int majorID, int minorID,
460
                        void *serverargs, void *clientargs)
461
0
{
462
0
    char *appname = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
463
0
                                          NETSNMP_DS_LIB_APPTYPE);
464
0
    se_store_slist((char *)clientargs, appname);
465
0
    return SNMPERR_SUCCESS;
466
0
}
467
#endif /* NETSNMP_FEATURE_REMOVE_SNMP_ENUM_STORE_SLIST */
468
469
#ifndef NETSNMP_FEATURE_REMOVE_SNMP_ENUM_CLEAR
470
void
471
se_clear_slist(const char *listname)
472
0
{
473
0
    se_clear_list(se_find_slist_ptr(listname));
474
0
}
475
476
void
477
se_clear_all_lists(void)
478
0
{
479
0
    struct snmp_enum_list_str *sptr = NULL;
480
481
0
    for (sptr = sliststorage; sptr != NULL; sptr = sptr->next)
482
0
        se_clear_list(&(sptr->list));
483
0
}
484
#endif /* NETSNMP_FEATURE_REMOVE_SNMP_ENUM_CLEAR */