Coverage Report

Created: 2025-08-11 06:35

/src/net-snmp/agent/agent_registry.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * agent_registry.c
3
 */
4
/* Portions of this file are subject to the following copyright(s).  See
5
 * the Net-SNMP's COPYING file for more details and other copyrights
6
 * that may apply:
7
 */
8
/*
9
 * Portions of this file are copyrighted by:
10
 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
11
 * Use is subject to license terms specified in the COPYING file
12
 * distributed with the Net-SNMP package.
13
 *
14
 * Portions of this file are copyrighted by:
15
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
16
 * Use is subject to license terms specified in the COPYING file
17
 * distributed with the Net-SNMP package.
18
 */
19
/** @defgroup agent_registry Registry of MIB subtrees, modules, sessions, etc
20
 *     Maintain a registry of MIB subtrees, together with related information
21
 *     regarding MIB modules, sessions, etc
22
 *   @ingroup agent
23
 *
24
 * @{
25
 */
26
27
#define IN_SNMP_VARS_C
28
29
#include <net-snmp/net-snmp-config.h>
30
#include <net-snmp/net-snmp-features.h>
31
32
#include <signal.h>
33
#ifdef HAVE_STRING_H
34
#include <string.h>
35
#endif
36
#ifdef HAVE_STDLIB_H
37
#include <stdlib.h>
38
#endif
39
#include <sys/types.h>
40
#include <stdio.h>
41
#include <fcntl.h>
42
#ifdef TIME_WITH_SYS_TIME
43
# include <sys/time.h>
44
# include <time.h>
45
#else
46
# ifdef HAVE_SYS_TIME_H
47
#  include <sys/time.h>
48
# else
49
#  include <time.h>
50
# endif
51
#endif
52
#ifdef HAVE_NETINET_IN_H
53
#include <netinet/in.h>
54
#endif
55
56
#include <net-snmp/net-snmp-includes.h>
57
#include <net-snmp/library/snmp_assert.h>
58
#include <net-snmp/agent/net-snmp-agent-includes.h>
59
#include <net-snmp/agent/agent_callbacks.h>
60
61
#include "snmpd.h"
62
#include "agent_global_vars.h"
63
#include "mibgroup/struct.h"
64
#include <net-snmp/agent/old_api.h>
65
#include <net-snmp/agent/null.h>
66
#include <net-snmp/agent/table.h>
67
#include <net-snmp/agent/table_iterator.h>
68
#include <net-snmp/agent/agent_index.h>
69
#include <net-snmp/agent/agent_registry.h>
70
71
#ifdef USING_AGENTX_SUBAGENT_MODULE
72
#include "agentx/subagent.h"
73
#include "agentx/client.h"
74
#endif
75
76
netsnmp_feature_child_of(agent_registry_all, libnetsnmpagent);
77
78
netsnmp_feature_child_of(unregister_mib_table_row, agent_registry_all);
79
80
/** @defgroup agent_lookup_cache Lookup cache, storing the registered OIDs.
81
 *     Maintain the cache used for locating sub-trees and OIDs.
82
 *   @ingroup agent_registry
83
 *
84
 * @{
85
 */
86
87
/**  Lookup cache - default size.*/
88
3.20k
#define SUBTREE_DEFAULT_CACHE_SIZE 8
89
/**  Lookup cache - max acceptable size.*/
90
57.6k
#define SUBTREE_MAX_CACHE_SIZE     32
91
int lookup_cache_size = 0; /*enabled later after registrations are loaded */
92
93
typedef struct lookup_cache_s {
94
   netsnmp_subtree *next;
95
   netsnmp_subtree *previous;
96
} lookup_cache;
97
98
typedef struct lookup_cache_context_s {
99
   char *context;
100
   struct lookup_cache_context_s *next;
101
   int thecachecount;
102
   int currentpos;
103
   lookup_cache cache[SUBTREE_MAX_CACHE_SIZE];
104
} lookup_cache_context;
105
106
static lookup_cache_context *thecontextcache = NULL;
107
108
/** Set the lookup cache size for optimized agent registration performance.
109
 * Note that it is only used by master agent - sub-agent doesn't need the cache.
110
 * The rough guide is that the cache size should be equal to the maximum
111
 * number of simultaneous managers you expect to talk to the agent (M) times 80%
112
 * (or so, he says randomly) the average number (N) of varbinds you
113
 * expect to receive in a given request for a manager.  ie, M times N.
114
 * Bigger does NOT necessarily mean better.  Certainly 16 should be an
115
 * upper limit.  32 is the hard coded limit.
116
 *
117
 * @param newsize set to the maximum size of a cache for a given
118
 * context.  Set to 0 to completely disable caching, or to -1 to set
119
 * to the default cache size (8), or to a number of your choosing.  The
120
 */
121
void
122
60.8k
netsnmp_set_lookup_cache_size(int newsize) {
123
60.8k
    if (newsize < 0)
124
3.20k
        lookup_cache_size = SUBTREE_DEFAULT_CACHE_SIZE;
125
57.6k
    else if (newsize < SUBTREE_MAX_CACHE_SIZE)
126
57.6k
        lookup_cache_size = newsize;
127
0
    else
128
0
        lookup_cache_size = SUBTREE_MAX_CACHE_SIZE;
129
60.8k
}
130
131
/** Retrieves the current value of the lookup cache size
132
 *  Should be called from master agent only - sub-agent doesn't need the cache.
133
 *
134
 *  @return the current lookup cache size
135
 */
136
int
137
28.8k
netsnmp_get_lookup_cache_size(void) {
138
28.8k
    return lookup_cache_size;
139
28.8k
}
140
141
/** Returns lookup cache entry for the context of given name.
142
 *
143
 *  @param context Name of the context. Name is case sensitive.
144
 *
145
 *  @return the lookup cache context
146
 */
147
NETSNMP_STATIC_INLINE lookup_cache_context *
148
49.2k
get_context_lookup_cache(const char *context) {
149
49.2k
    lookup_cache_context *ptr;
150
49.2k
    if (!context)
151
20.4k
        context = "";
152
153
49.2k
    for(ptr = thecontextcache; ptr; ptr = ptr->next) {
154
46.0k
        if (strcmp(ptr->context, context) == 0)
155
46.0k
            break;
156
46.0k
    }
157
49.2k
    if (!ptr) {
158
3.20k
        if (netsnmp_subtree_find_first(context)) {
159
3.20k
            ptr = SNMP_MALLOC_TYPEDEF(lookup_cache_context);
160
3.20k
            if (!ptr)
161
0
                return NULL;
162
3.20k
            ptr->next = thecontextcache;
163
3.20k
            ptr->context = strdup(context);
164
3.20k
            if (!ptr->context) {
165
0
                free(ptr);
166
0
                return NULL;
167
0
            }
168
3.20k
            thecontextcache = ptr;
169
3.20k
        } else {
170
0
            return NULL;
171
0
        }
172
3.20k
    }
173
49.2k
    return ptr;
174
49.2k
}
175
176
/** Adds an entry to the Lookup Cache under specified context name.
177
 *
178
 *  @param context  Name of the context. Name is case sensitive.
179
 *
180
 *  @param next     Next subtree item.
181
 *
182
 *  @param previous Previous subtree item.
183
 */
184
NETSNMP_STATIC_INLINE void
185
lookup_cache_add(const char *context,
186
337
                 netsnmp_subtree *next, netsnmp_subtree *previous) {
187
337
    lookup_cache_context *cptr;
188
189
337
    if ((cptr = get_context_lookup_cache(context)) == NULL)
190
0
        return;
191
192
337
    if (cptr->thecachecount < lookup_cache_size)
193
336
        cptr->thecachecount++;
194
195
337
    cptr->cache[cptr->currentpos].next = next;
196
337
    cptr->cache[cptr->currentpos].previous = previous;
197
198
337
    if (++cptr->currentpos >= lookup_cache_size)
199
3
        cptr->currentpos = 0;
200
337
}
201
202
/** @private
203
 *  Replaces next and previous pointer in given Lookup Cache.
204
 *
205
 *  @param ptr      Lookup Cache pointer.
206
 *
207
 *  @param next     Next subtree item.
208
 *
209
 *  @param previous Previous subtree item.
210
 */
211
NETSNMP_STATIC_INLINE void
212
lookup_cache_replace(lookup_cache *ptr,
213
290
                     netsnmp_subtree *next, netsnmp_subtree *previous) {
214
215
290
    ptr->next = next;
216
290
    ptr->previous = previous;
217
290
}
218
219
/** Finds an entry in the Lookup Cache.
220
 *
221
 *  @param context  Case sensitive name of the context.
222
 *
223
 *  @param name     The OID we're searching for.
224
 *
225
 *  @param name_len Number of sub-ids (single integers) in the OID.
226
 *
227
 *  @param retcmp   Value set to snmp_oid_compare() call result.
228
 *                  The value, if set, is always nonnegative.
229
 *
230
 *  @return gives Lookup Cache entry, or NULL if not found.
231
 *
232
 *  @see snmp_oid_compare()
233
 */
234
NETSNMP_STATIC_INLINE lookup_cache *
235
lookup_cache_find(const char *context, const oid *name, size_t name_len,
236
10.5k
                  int *retcmp) {
237
10.5k
    lookup_cache_context *cptr;
238
10.5k
    lookup_cache *ret = NULL;
239
10.5k
    int cmp;
240
10.5k
    int i;
241
242
10.5k
    if ((cptr = get_context_lookup_cache(context)) == NULL)
243
0
        return NULL;
244
245
11.8k
    for(i = 0; i < cptr->thecachecount && i < lookup_cache_size; i++) {
246
1.29k
        if (cptr->cache[i].previous->start_a)
247
1.29k
            cmp = snmp_oid_compare(name, name_len,
248
1.29k
                                   cptr->cache[i].previous->start_a,
249
1.29k
                                   cptr->cache[i].previous->start_len);
250
0
        else
251
0
            cmp = 1;
252
1.29k
        if (cmp >= 0) {
253
995
            *retcmp = cmp;
254
995
            ret = &(cptr->cache[i]);
255
995
        }
256
1.29k
    }
257
10.5k
    return ret;
258
10.5k
}
259
260
/** @private
261
 *  Clears cache count and position in Lookup Cache.
262
 */
263
NETSNMP_STATIC_INLINE void
264
38.4k
invalidate_lookup_cache(const char *context) {
265
38.4k
    lookup_cache_context *cptr;
266
38.4k
    if ((cptr = get_context_lookup_cache(context)) != NULL) {
267
38.4k
        cptr->thecachecount = 0;
268
38.4k
        cptr->currentpos = 0;
269
38.4k
    }
270
38.4k
}
271
272
void
273
3.20k
clear_lookup_cache(void) {
274
275
3.20k
    lookup_cache_context *ptr = NULL, *next = NULL;
276
277
3.20k
    ptr = thecontextcache;
278
6.40k
    while (ptr) {
279
3.20k
  next = ptr->next;
280
3.20k
  SNMP_FREE(ptr->context);
281
3.20k
  SNMP_FREE(ptr);
282
3.20k
  ptr = next;
283
3.20k
    }
284
3.20k
    thecontextcache = NULL; /* !!! */
285
3.20k
}
286
287
/**  @} */
288
/* End of Lookup cache code */
289
290
/** @defgroup agent_context_cache Context cache, storing the OIDs under their contexts.
291
 *     Maintain the cache used for locating sub-trees registered under different contexts.
292
 *   @ingroup agent_registry
293
 *
294
 * @{
295
 */
296
subtree_context_cache *context_subtrees = NULL;
297
298
/** Returns the top element of context subtrees cache.
299
 *  Use it if you wish to sweep through the cache elements.
300
 *  Note that the return may be NULL (cache may be empty).
301
 *
302
 *  @return pointer to topmost context subtree cache element.
303
 */
304
subtree_context_cache *
305
get_top_context_cache(void)
306
3.20k
{
307
3.20k
    return context_subtrees;
308
3.20k
}
309
310
/** Finds the first subtree registered under given context.
311
 *
312
 *  @param context_name Text name of the context we're searching for.
313
 *
314
 *  @return pointer to the first subtree element, or NULL if not found.
315
 */
316
netsnmp_subtree *
317
netsnmp_subtree_find_first(const char *context_name)
318
80.3k
{
319
80.3k
    subtree_context_cache *ptr;
320
321
80.3k
    if (!context_name) {
322
58.1k
        context_name = "";
323
58.1k
    }
324
325
80.3k
    DEBUGMSGTL(("subtree", "looking for subtree for context: \"%s\"\n", 
326
80.3k
    context_name));
327
80.3k
    for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) {
328
64.3k
        if (ptr->context_name != NULL && 
329
64.3k
      strcmp(ptr->context_name, context_name) == 0) {
330
64.3k
            DEBUGMSGTL(("subtree", "found one for: \"%s\"\n", context_name));
331
64.3k
            return ptr->first_subtree;
332
64.3k
        }
333
64.3k
    }
334
16.0k
    DEBUGMSGTL(("subtree", "didn't find a subtree for context: \"%s\"\n", 
335
16.0k
    context_name));
336
16.0k
    return NULL;
337
80.3k
}
338
339
/** Adds the subtree to Context Cache under given context name.
340
 *
341
 *  @param context_name Text name of the context we're adding.
342
 *
343
 *  @param new_tree The subtree to be added.
344
 *
345
 *  @return copy of the new_tree pointer, or NULL if cannot add.
346
 */
347
netsnmp_subtree *
348
add_subtree(netsnmp_subtree *new_tree, const char *context_name)
349
3.20k
{
350
3.20k
    subtree_context_cache *ptr = SNMP_MALLOC_TYPEDEF(subtree_context_cache);
351
    
352
3.20k
    if (!context_name) {
353
0
        context_name = "";
354
0
    }
355
356
3.20k
    if (!ptr) {
357
0
        return NULL;
358
0
    }
359
    
360
3.20k
    DEBUGMSGTL(("subtree", "adding subtree for context: \"%s\"\n",  
361
3.20k
    context_name));
362
363
3.20k
    ptr->next = context_subtrees;
364
3.20k
    ptr->first_subtree = new_tree;
365
3.20k
    ptr->context_name = strdup(context_name);
366
3.20k
    if (!ptr->context_name) {
367
0
        free(ptr);
368
0
        return NULL;
369
0
    }
370
371
3.20k
    context_subtrees = ptr;
372
373
3.20k
    return ptr->first_subtree;
374
3.20k
}
375
376
void
377
netsnmp_remove_subtree(netsnmp_subtree *tree)
378
0
{
379
0
    subtree_context_cache *ptr;
380
381
0
    if (!tree->prev) {
382
0
        for (ptr = context_subtrees; ptr; ptr = ptr->next)
383
0
            if (ptr->first_subtree == tree)
384
0
                break;
385
0
        netsnmp_assert(ptr);
386
0
        if (ptr)
387
0
            ptr->first_subtree = tree->next;
388
0
    } else
389
0
        tree->prev->next = tree->next;
390
391
0
    if (tree->next)
392
0
        tree->next->prev = tree->prev;
393
0
}
394
395
/** Replaces first subtree registered under given context name.
396
 *  Overwrites a subtree pointer in Context Cache for the context name.
397
 *  The previous subtree pointer is lost. If there's no subtree
398
 *  under the supplied name, then a new cache item is created.
399
 *
400
 *  @param new_tree     The new subtree to be set.
401
 *
402
 *  @param context_name Text name of the context we're replacing.
403
 *                      It is case sensitive.
404
 *
405
 * @return copy of the new_tree pointer, or NULL on error.
406
 */
407
netsnmp_subtree *
408
netsnmp_subtree_replace_first(netsnmp_subtree *new_tree, 
409
            const char *context_name)
410
6.40k
{
411
6.40k
    subtree_context_cache *ptr;
412
6.40k
    if (!context_name) {
413
3.20k
        context_name = "";
414
3.20k
    }
415
6.40k
    for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) {
416
3.20k
        if (ptr->context_name != NULL &&
417
3.20k
      strcmp(ptr->context_name, context_name) == 0) {
418
3.20k
            ptr->first_subtree = new_tree;
419
3.20k
            return ptr->first_subtree;
420
3.20k
        }
421
3.20k
    }
422
3.20k
    return add_subtree(new_tree, context_name);
423
6.40k
}
424
425
426
void clear_subtree (netsnmp_subtree *sub);
427
428
/** Completely clears both the Context cache and the Lookup cache.
429
 */
430
void
431
3.20k
clear_context(void) {
432
433
3.20k
    subtree_context_cache *ptr = NULL, *next = NULL;
434
3.20k
    netsnmp_subtree *t, *u;
435
436
3.20k
    DEBUGMSGTL(("agent_registry", "clear context\n"));
437
438
3.20k
    ptr = get_top_context_cache(); 
439
6.40k
    while (ptr) {
440
3.20k
  next = ptr->next;
441
442
3.20k
  for (t = ptr->first_subtree; t; t = u) {
443
0
            u = t->next;
444
0
      clear_subtree(t);
445
0
  }
446
447
3.20k
        free(NETSNMP_REMOVE_CONST(char*, ptr->context_name));
448
3.20k
        SNMP_FREE(ptr);
449
450
3.20k
  ptr = next;
451
3.20k
    }
452
3.20k
    context_subtrees = NULL; /* !!! */
453
3.20k
    clear_lookup_cache();
454
3.20k
}
455
456
/**  @} */
457
/* End of Context cache code */
458
459
/** @defgroup agent_mib_subtree Maintaining MIB subtrees.
460
 *     Maintaining MIB nodes and subtrees.
461
 *   @ingroup agent_registry
462
 *
463
 * @{
464
 */
465
466
static void register_mib_detach_node(netsnmp_subtree *s);
467
468
/** Frees single subtree item.
469
 *  Deallocated memory for given netsnmp_subtree item, including
470
 *  Handle Registration structure stored inside this item.
471
 *  After calling this function, the pointer is invalid
472
 *  and should be set to NULL.
473
 *
474
 *  @param a The subtree item to dispose.
475
 */
476
void
477
netsnmp_subtree_free(netsnmp_subtree *a)
478
19.2k
{
479
19.2k
  if (a != NULL) {
480
19.2k
    if (a->variables != NULL && netsnmp_oid_equals(a->name_a, a->namelen, 
481
0
               a->start_a, a->start_len) == 0) {
482
0
      SNMP_FREE(a->variables);
483
0
    }
484
19.2k
    SNMP_FREE(a->name_a);
485
19.2k
    a->namelen = 0;
486
19.2k
    SNMP_FREE(a->start_a);
487
19.2k
    a->start_len = 0;
488
19.2k
    SNMP_FREE(a->end_a);
489
19.2k
    a->end_len = 0;
490
19.2k
    SNMP_FREE(a->label_a);
491
19.2k
    netsnmp_handler_registration_free(a->reginfo);
492
19.2k
    a->reginfo = NULL;
493
19.2k
    SNMP_FREE(a);
494
19.2k
  }
495
19.2k
}
496
497
/** Creates deep copy of a subtree item.
498
 *  Duplicates all properties stored in the structure, including
499
 *  Handle Registration structure stored inside the item.
500
 *
501
 *  @param a The subtree item to copy.
502
 *
503
 *  @return deep copy of the subtree item, or NULL on error.
504
 */
505
netsnmp_subtree *
506
netsnmp_subtree_deepcopy(netsnmp_subtree *a)
507
0
{
508
0
  netsnmp_subtree *b = calloc(1, sizeof(netsnmp_subtree));
509
510
0
  if (b != NULL) {
511
0
    memcpy(b, a, sizeof(netsnmp_subtree));
512
0
    b->name_a  = snmp_duplicate_objid(a->name_a,  a->namelen);
513
0
    b->start_a = snmp_duplicate_objid(a->start_a, a->start_len);
514
0
    b->end_a   = snmp_duplicate_objid(a->end_a,   a->end_len);
515
0
    b->label_a = strdup(a->label_a);
516
    
517
0
    if (b->name_a == NULL || b->start_a == NULL || 
518
0
  b->end_a  == NULL || b->label_a == NULL) {
519
0
      netsnmp_subtree_free(b);
520
0
      return NULL;
521
0
    }
522
523
0
    if (a->variables != NULL) {
524
0
      b->variables = (struct variable *)malloc(a->variables_len * 
525
0
                 a->variables_width);
526
0
      if (b->variables != NULL) {
527
0
  memcpy(b->variables, a->variables,a->variables_len*a->variables_width);
528
0
      } else {
529
0
  netsnmp_subtree_free(b);
530
0
  return NULL;
531
0
      }
532
0
    }
533
534
0
    if (a->reginfo != NULL) {
535
0
      b->reginfo = netsnmp_handler_registration_dup(a->reginfo);
536
0
      if (b->reginfo == NULL) {
537
0
  netsnmp_subtree_free(b);
538
0
  return NULL;
539
0
      }
540
0
    }
541
0
  }
542
0
  return b;
543
0
}
544
545
/** @private
546
 *  Replaces next subtree pointer in given subtree.
547
 */
548
NETSNMP_STATIC_INLINE void
549
netsnmp_subtree_change_next(netsnmp_subtree *ptr, netsnmp_subtree *thenext)
550
22.4k
{
551
22.4k
    ptr->next = thenext;
552
22.4k
    if (thenext)
553
6.40k
        netsnmp_oid_compare_ll(ptr->start_a,
554
6.40k
                               ptr->start_len,
555
6.40k
                               thenext->start_a,
556
6.40k
                               thenext->start_len,
557
6.40k
                               &thenext->oid_off);
558
22.4k
}
559
560
/** @private
561
 *  Replaces previous subtree pointer in given subtree.
562
 */
563
NETSNMP_STATIC_INLINE void
564
netsnmp_subtree_change_prev(netsnmp_subtree *ptr, netsnmp_subtree *theprev)
565
9.60k
{
566
9.60k
    ptr->prev = theprev;
567
9.60k
    if (theprev)
568
6.40k
        netsnmp_oid_compare_ll(theprev->start_a,
569
6.40k
                               theprev->start_len,
570
6.40k
                               ptr->start_a,
571
6.40k
                               ptr->start_len,
572
6.40k
                               &ptr->oid_off);
573
9.60k
}
574
575
netsnmp_feature_child_of(netsnmp_subtree_compare,netsnmp_unused);
576
#ifndef NETSNMP_FEATURE_REMOVE_NETSNMP_SUBTREE_COMPARE
577
/** Compares OIDs of given subtrees.
578
 *
579
 *  @param ap,bp Pointers to the subtrees to be compared.
580
 *
581
 *  @return OIDs lexicographical comparison result.
582
 *
583
 *  @see snmp_oid_compare()
584
 */
585
int
586
netsnmp_subtree_compare(const netsnmp_subtree *ap, const netsnmp_subtree *bp)
587
0
{
588
0
    return snmp_oid_compare(ap->name_a, ap->namelen, bp->name_a, bp->namelen);
589
0
}
590
#endif /* NETSNMP_FEATURE_REMOVE_NETSNMP_SUBTREE_COMPARE */
591
592
/** Joins the given subtree with the current tree.
593
 *  Trees are joined and the one supplied as parameter is freed.
594
 *
595
 *  @param root The subtree to be merged with current subtree.
596
 *              Do not use the pointer after joining - it may be invalid.
597
 */
598
void
599
netsnmp_subtree_join(netsnmp_subtree *root)
600
0
{
601
0
    netsnmp_subtree *s, *tmp, *c, *d;
602
603
0
    while (root != NULL) {
604
0
        s = root->next;
605
0
        while (s != NULL && root->reginfo == s->reginfo) {
606
0
            tmp = s->next;
607
0
            DEBUGMSGTL(("subtree", "root start "));
608
0
            DEBUGMSGOID(("subtree", root->start_a, root->start_len));
609
0
            DEBUGMSG(("subtree", " (original end "));
610
0
            DEBUGMSGOID(("subtree", root->end_a, root->end_len));
611
0
            DEBUGMSG(("subtree", ")\n"));
612
0
            DEBUGMSGTL(("subtree", "  JOINING to "));
613
0
            DEBUGMSGOID(("subtree", s->start_a, s->start_len));
614
615
0
      SNMP_FREE(root->end_a);
616
0
      root->end_a   = s->end_a;
617
0
            root->end_len = s->end_len;
618
0
      s->end_a      = NULL;
619
620
0
            for (c = root; c != NULL; c = c->children) {
621
0
                netsnmp_subtree_change_next(c, s->next);
622
0
            }
623
0
            for (c = s; c != NULL; c = c->children) {
624
0
                netsnmp_subtree_change_prev(c, root);
625
0
            }
626
0
            DEBUGMSG(("subtree", " so new end "));
627
0
            DEBUGMSGOID(("subtree", root->end_a, root->end_len));
628
0
            DEBUGMSG(("subtree", "\n"));
629
            /*
630
             * Probably need to free children too?  
631
             */
632
0
            for (c = s->children; c != NULL; c = d) {
633
0
                d = c->children;
634
0
                netsnmp_subtree_free(c);
635
0
            }
636
0
            netsnmp_subtree_free(s);
637
0
            s = tmp;
638
0
        }
639
0
        root = root->next;
640
0
    }
641
0
}
642
643
644
/** Split the subtree into two at the specified point.
645
 *  Subtrees of the given OID and separated and formed into the
646
 *  returned subtree.
647
 *
648
 *  @param current The element at which splitting is started.
649
 *
650
 *  @param name The OID we'd like to split.
651
 *
652
 *  @param name_len Length of the OID.
653
 *
654
 *  @return head of the new (second) subtree.
655
 */
656
netsnmp_subtree *
657
netsnmp_subtree_split(netsnmp_subtree *current, oid name[], int name_len)
658
0
{
659
0
    struct variable *vp = NULL;
660
0
    netsnmp_subtree *new_sub, *ptr;
661
0
    int i = 0, rc = 0, rc2 = 0;
662
0
    size_t common_len = 0;
663
0
    char *cp;
664
0
    oid *tmp_a, *tmp_b;
665
666
0
    if (snmp_oid_compare(name, name_len, current->end_a, current->end_len)>0) {
667
  /* Split comes after the end of this subtree */
668
0
        return NULL;
669
0
    }
670
671
0
    new_sub = netsnmp_subtree_deepcopy(current);
672
0
    if (new_sub == NULL) {
673
0
        return NULL;
674
0
    }
675
676
    /*  Set up the point of division.  */
677
0
    tmp_a = snmp_duplicate_objid(name, name_len);
678
0
    if (tmp_a == NULL) {
679
0
  netsnmp_subtree_free(new_sub);
680
0
  return NULL;
681
0
    }
682
0
    tmp_b = snmp_duplicate_objid(name, name_len);
683
0
    if (tmp_b == NULL) {
684
0
  netsnmp_subtree_free(new_sub);
685
0
  SNMP_FREE(tmp_a);
686
0
  return NULL;
687
0
    }
688
689
0
    SNMP_FREE(current->end_a);
690
0
    current->end_a = tmp_a;
691
0
    current->end_len = name_len;
692
0
    if (new_sub->start_a != NULL) {
693
0
  SNMP_FREE(new_sub->start_a);
694
0
    }
695
0
    new_sub->start_a = tmp_b;
696
0
    new_sub->start_len = name_len;
697
698
    /*  Split the variables between the two new subtrees.  */
699
0
    i = current->variables_len;
700
0
    current->variables_len = 0;
701
702
0
    for (vp = current->variables; i > 0; i--) {
703
  /*  Note that the variable "name" field omits the prefix common to the
704
      whole registration, hence the strange comparison here.  */
705
706
0
  rc = snmp_oid_compare(vp->name, vp->namelen,
707
0
            name     + current->namelen, 
708
0
            name_len - current->namelen);
709
710
0
        if (name_len - current->namelen > vp->namelen) {
711
0
            common_len = vp->namelen;
712
0
        } else {
713
0
            common_len = name_len - current->namelen;
714
0
        }
715
716
0
        rc2 = snmp_oid_compare(vp->name, common_len,
717
0
                               name + current->namelen, common_len);
718
719
0
        if (rc >= 0) {
720
0
            break;  /* All following variables belong to the second subtree */
721
0
  }
722
723
0
        current->variables_len++;
724
0
        if (rc2 < 0) {
725
0
            new_sub->variables_len--;
726
0
            cp = (char *) new_sub->variables;
727
0
            new_sub->variables = (struct variable *)(cp + 
728
0
                 new_sub->variables_width);
729
0
        }
730
0
        vp = (struct variable *) ((char *) vp + current->variables_width);
731
0
    }
732
733
    /* Delegated trees should retain their variables regardless */
734
0
    if (current->variables_len > 0 &&
735
0
        IS_DELEGATED((u_char) current->variables[0].type)) {
736
0
        new_sub->variables_len = 1;
737
0
        new_sub->variables = current->variables;
738
0
    }
739
740
    /* Propagate this split down through any children */
741
0
    if (current->children) {
742
0
        new_sub->children = netsnmp_subtree_split(current->children, 
743
0
              name, name_len);
744
0
    }
745
746
    /* Retain the correct linking of the list */
747
0
    for (ptr = current; ptr != NULL; ptr = ptr->children) {
748
0
        netsnmp_subtree_change_next(ptr, new_sub);
749
0
    }
750
0
    for (ptr = new_sub; ptr != NULL; ptr = ptr->children) {
751
0
        netsnmp_subtree_change_prev(ptr, current);
752
0
    }
753
0
    for (ptr = new_sub->next; ptr != NULL; ptr=ptr->children) {
754
0
        netsnmp_subtree_change_prev(ptr, new_sub);
755
0
    }
756
757
0
    return new_sub;
758
0
}
759
760
/** Loads the subtree under given context name.
761
 *
762
 *  @param new_sub The subtree to be loaded into current subtree.
763
 *
764
 *  @param context_name Text name of the context we're searching for.
765
 *
766
 *  @return gives MIB_REGISTERED_OK on success, error code otherwise.
767
 */
768
int
769
netsnmp_subtree_load(netsnmp_subtree *new_sub, const char *context_name)
770
19.2k
{
771
19.2k
    netsnmp_subtree *tree1, *tree2;
772
19.2k
    netsnmp_subtree *prev, *next;
773
774
19.2k
    if (new_sub == NULL) {
775
0
        return MIB_REGISTERED_OK;       /* Degenerate case */
776
0
    }
777
778
19.2k
    if (!netsnmp_subtree_find_first(context_name)) {
779
6.40k
        static int inloop = 0;
780
6.40k
        if (!inloop) {
781
3.20k
            oid ccitt[1]           = { 0 };
782
3.20k
            oid iso[1]             = { 1 };
783
3.20k
            oid joint_ccitt_iso[1] = { 2 };
784
3.20k
            inloop = 1;
785
3.20k
            netsnmp_register_null_context(snmp_duplicate_objid(ccitt, 1), 1,
786
3.20k
                                          context_name);
787
3.20k
            netsnmp_register_null_context(snmp_duplicate_objid(iso, 1), 1,
788
3.20k
                                          context_name);
789
3.20k
            netsnmp_register_null_context(snmp_duplicate_objid(joint_ccitt_iso, 1),
790
3.20k
                                          1, context_name);
791
3.20k
            inloop = 0;
792
3.20k
        }
793
6.40k
    }
794
795
    /*  Find the subtree that contains the start of the new subtree (if
796
  any)...*/
797
798
19.2k
    tree1 = netsnmp_subtree_find(new_sub->start_a, new_sub->start_len, 
799
19.2k
         NULL, context_name);
800
801
    /*  ... and the subtree that follows the new one (NULL implies this is the
802
  final region covered).  */
803
804
19.2k
    if (tree1 == NULL) {
805
9.60k
  tree2 = netsnmp_subtree_find_next(new_sub->start_a, new_sub->start_len,
806
9.60k
            NULL, context_name);
807
9.60k
    } else {
808
9.60k
  tree2 = tree1->next;
809
9.60k
    }
810
811
    /*  Handle new subtrees that start in virgin territory.  */
812
813
19.2k
    if (tree1 == NULL) {
814
        /*netsnmp_subtree *new2 = NULL;*/
815
  /*  Is there any overlap with later subtrees?  */
816
9.60k
  if (tree2 && snmp_oid_compare(new_sub->end_a, new_sub->end_len,
817
0
              tree2->start_a, tree2->start_len) > 0) {
818
      /*new2 =*/
819
0
            netsnmp_subtree_split(new_sub, tree2->start_a, tree2->start_len);
820
0
  }
821
822
  /*  Link the new subtree (less any overlapping region) with the list of
823
      existing registrations.  */
824
825
9.60k
  if (tree2) {
826
0
            netsnmp_subtree_change_prev(new_sub, tree2->prev);
827
0
            netsnmp_subtree_change_prev(tree2, new_sub);
828
9.60k
  } else {
829
9.60k
            netsnmp_subtree_change_prev(new_sub,
830
9.60k
                                        netsnmp_subtree_find_prev(new_sub->start_a,
831
9.60k
                                                                  new_sub->start_len, NULL, context_name));
832
833
9.60k
      if (new_sub->prev) {
834
6.40k
                netsnmp_subtree_change_next(new_sub->prev, new_sub);
835
6.40k
      } else {
836
3.20k
    netsnmp_subtree_replace_first(new_sub, context_name);
837
3.20k
      }
838
839
9.60k
            netsnmp_subtree_change_next(new_sub, tree2);
840
841
#if 0
842
            /* The code below cannot be reached which is why it has been
843
               surrounded with #if 0 / #endif. */
844
      /* If there was any overlap, recurse to merge in the overlapping
845
         region (including anything that may follow the overlap).  */
846
      if (new2) {
847
    return netsnmp_subtree_load(new2, context_name);
848
      }
849
#endif
850
9.60k
  }
851
9.60k
    } else {
852
  /*  If the new subtree starts *within* an existing registration
853
      (rather than at the same point as it), then split the existing
854
      subtree at this point.  */
855
856
9.60k
  if (netsnmp_oid_equals(new_sub->start_a, new_sub->start_len, 
857
9.60k
           tree1->start_a,   tree1->start_len) != 0) {
858
0
      tree1 = netsnmp_subtree_split(tree1, new_sub->start_a, 
859
0
            new_sub->start_len);
860
0
  }
861
862
9.60k
        if (tree1 == NULL) {
863
0
            return MIB_REGISTRATION_FAILED;
864
0
  }
865
866
  /*  Now consider the end of this existing subtree:
867
      
868
      If it matches the new subtree precisely,
869
              simply merge the new one into the list of children
870
871
      If it includes the whole of the new subtree,
872
        split it at the appropriate point, and merge again
873
     
874
      If the new subtree extends beyond this existing region,
875
              split it, and recurse to merge the two parts.  */
876
877
9.60k
  switch (snmp_oid_compare(new_sub->end_a, new_sub->end_len,
878
9.60k
                                 tree1->end_a, tree1->end_len)) {
879
880
0
  case -1:
881
      /*  Existing subtree contains new one.  */
882
0
      netsnmp_subtree_split(tree1, new_sub->end_a, new_sub->end_len);
883
0
      NETSNMP_FALLTHROUGH;
884
885
9.60k
  case  0:
886
      /*  The two trees match precisely.  */
887
888
      /*  Note: This is the only point where the original registration
889
          OID ("name") is used.  */
890
891
9.60k
      prev = NULL;
892
9.60k
      next = tree1;
893
  
894
9.60k
      while (next && next->namelen > new_sub->namelen) {
895
0
    prev = next;
896
0
    next = next->children;
897
0
      }
898
899
9.60k
      while (next && next->namelen == new_sub->namelen &&
900
9.60k
       next->priority < new_sub->priority ) {
901
0
    prev = next;
902
0
    next = next->children;
903
0
      }
904
  
905
9.60k
      if (next && (next->namelen  == new_sub->namelen) &&
906
9.60k
    (next->priority == new_sub->priority)) {
907
9.60k
                if (new_sub->namelen != 1) {    /* ignore root OID dups */
908
0
                    size_t          out_len = 0;
909
0
                    size_t          buf_len = 0;
910
0
                    char           *buf = NULL;
911
0
                    int             buf_overflow = 0;
912
913
0
                    netsnmp_sprint_realloc_objid((u_char **) &buf, &buf_len, &out_len,
914
0
                                                 1, &buf_overflow,
915
0
                                                 new_sub->start_a,
916
0
                                                 new_sub->start_len);
917
0
                    snmp_log(LOG_ERR,
918
0
                             "duplicate registration: MIB modules %s and %s (oid %s%s).\n",
919
0
                             next->label_a, new_sub->label_a,
920
0
                             buf ? buf : "",
921
0
                             buf_overflow ? " [TRUNCATED]" : "");
922
0
                    free(buf);
923
0
                }
924
9.60k
    return MIB_DUPLICATE_REGISTRATION;
925
9.60k
      }
926
927
0
      if (prev) {
928
0
    prev->children    = new_sub;
929
0
    new_sub->children = next;
930
0
                netsnmp_subtree_change_prev(new_sub, prev->prev);
931
0
                netsnmp_subtree_change_next(new_sub, prev->next);
932
0
      } else {
933
0
    new_sub->children = next;
934
0
                netsnmp_subtree_change_prev(new_sub, next->prev);
935
0
                netsnmp_subtree_change_next(new_sub, next->next);
936
  
937
0
    for (next = new_sub->next; next != NULL;next = next->children){
938
0
                    netsnmp_subtree_change_prev(next, new_sub);
939
0
    }
940
941
0
    for (prev = new_sub->prev; prev != NULL;prev = prev->children){
942
0
                    netsnmp_subtree_change_next(prev, new_sub);
943
0
    }
944
0
      }
945
0
      break;
946
947
0
  case  1:
948
      /*  New subtree contains the existing one.  */
949
0
            {
950
0
                netsnmp_subtree *new2 =
951
0
                    netsnmp_subtree_split(new_sub, tree1->end_a,tree1->end_len);
952
0
                int res = netsnmp_subtree_load(new_sub, context_name);
953
0
                if (res != MIB_REGISTERED_OK) {
954
0
                    netsnmp_remove_subtree(new2);
955
0
                    netsnmp_subtree_free(new2);
956
0
                    return res;
957
0
                }
958
0
                return netsnmp_subtree_load(new2, context_name);
959
0
            }
960
9.60k
        }
961
9.60k
    }
962
9.60k
    return 0;
963
19.2k
}
964
965
/** Free the given subtree and all its children.
966
 *
967
 *  @param sub Subtree branch to be cleared and freed.
968
 *             After the call, this pointer is invalid
969
 *             and should be set to NULL.
970
 */
971
void
972
0
clear_subtree (netsnmp_subtree *sub) {
973
974
0
    netsnmp_subtree *c;
975
    
976
0
    if (sub == NULL)
977
0
  return;
978
979
0
    for(c = sub; c;) {
980
0
        sub = c;
981
0
        c = c->children;
982
0
        netsnmp_subtree_free(sub);
983
0
    }
984
985
0
}
986
987
netsnmp_subtree *
988
netsnmp_subtree_find_prev(const oid *name, size_t len, netsnmp_subtree *subtree,
989
        const char *context_name)
990
58.5k
{
991
58.5k
    lookup_cache *lookup_cache = NULL;
992
58.5k
    netsnmp_subtree *myptr = NULL, *previous = NULL;
993
58.5k
    int cmp = 1;
994
58.5k
    size_t ll_off = 0;
995
996
58.5k
    if (subtree) {
997
9.60k
        myptr = subtree;
998
48.9k
    } else {
999
  /* look through everything */
1000
48.9k
        if (lookup_cache_size) {
1001
10.5k
            lookup_cache = lookup_cache_find(context_name, name, len, &cmp);
1002
10.5k
            if (lookup_cache) {
1003
622
                myptr = lookup_cache->next;
1004
622
                previous = lookup_cache->previous;
1005
622
            }
1006
10.5k
            if (!myptr)
1007
9.92k
                myptr = netsnmp_subtree_find_first(context_name);
1008
38.4k
        } else {
1009
38.4k
            myptr = netsnmp_subtree_find_first(context_name);
1010
38.4k
        }
1011
48.9k
    }
1012
1013
    /*
1014
     * this optimization causes a segfault on sf cf alpha-linux1.
1015
     * ifdef out until someone figures out why and fixes it. xxx-rks 20051117
1016
     */
1017
58.5k
#ifndef __alpha
1018
58.5k
#define WTEST_OPTIMIZATION 1
1019
58.5k
#endif
1020
58.5k
#ifdef WTEST_OPTIMIZATION
1021
58.5k
    DEBUGMSGTL(("wtest","oid in: "));
1022
58.5k
    DEBUGMSGOID(("wtest", name, len));
1023
58.5k
    DEBUGMSG(("wtest","\n"));
1024
58.5k
#endif
1025
146k
    for (; myptr != NULL; previous = myptr, myptr = myptr->next) {
1026
94.4k
#ifdef WTEST_OPTIMIZATION
1027
        /* Compare the incoming oid with the linked list.  If we have
1028
           results of previous compares, its faster to make sure the
1029
           length we differed in the last check is greater than the
1030
           length between this pointer and the last then we don't need
1031
           to actually perform a comparison */
1032
94.4k
        DEBUGMSGTL(("wtest","oid cmp: "));
1033
94.4k
        DEBUGMSGOID(("wtest", myptr->start_a, myptr->start_len));
1034
94.4k
        DEBUGMSG(("wtest","  --- off = %lu, in off = %lu test = %d\n",
1035
94.4k
                  (unsigned long)myptr->oid_off, (unsigned long)ll_off,
1036
94.4k
                  !(ll_off && myptr->oid_off &&
1037
94.4k
                    myptr->oid_off > ll_off)));
1038
94.4k
        if (!(ll_off && myptr->oid_off && myptr->oid_off > ll_off) &&
1039
94.4k
            netsnmp_oid_compare_ll(name, len,
1040
94.4k
                                   myptr->start_a, myptr->start_len,
1041
94.4k
                                   &ll_off) < 0) {
1042
#else
1043
        if (snmp_oid_compare(name, len, myptr->start_a, myptr->start_len) < 0) {
1044
#endif
1045
7.02k
            if (lookup_cache_size && previous && cmp) {
1046
627
                if (lookup_cache) {
1047
290
                    lookup_cache_replace(lookup_cache, myptr, previous);
1048
337
                } else {
1049
337
                    lookup_cache_add(context_name, myptr, previous);
1050
337
                }
1051
627
            }
1052
7.02k
            return previous;
1053
7.02k
        }
1054
94.4k
    }
1055
51.5k
    return previous;
1056
58.5k
}
1057
1058
netsnmp_subtree *
1059
netsnmp_subtree_find_next(const oid *name, size_t len,
1060
        netsnmp_subtree *subtree, const char *context_name)
1061
9.60k
{
1062
9.60k
    netsnmp_subtree *myptr = NULL;
1063
1064
9.60k
    myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name);
1065
1066
9.60k
    if (myptr != NULL) {
1067
6.40k
        myptr = myptr->next;
1068
6.40k
        while (myptr != NULL && (myptr->variables == NULL || 
1069
0
         myptr->variables_len == 0)) {
1070
0
            myptr = myptr->next;
1071
0
        }
1072
6.40k
        return myptr;
1073
6.40k
    } else if (subtree != NULL && snmp_oid_compare(name, len, 
1074
0
           subtree->start_a, subtree->start_len) < 0) {
1075
0
        return subtree;
1076
3.20k
    } else {
1077
3.20k
        return NULL;
1078
3.20k
    }
1079
9.60k
}
1080
1081
netsnmp_subtree *
1082
netsnmp_subtree_find(const oid *name, size_t len, netsnmp_subtree *subtree, 
1083
         const char *context_name)
1084
39.3k
{
1085
39.3k
    netsnmp_subtree *myptr;
1086
1087
39.3k
    myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name);
1088
39.3k
    if (myptr && myptr->end_a &&
1089
39.3k
        snmp_oid_compare(name, len, myptr->end_a, myptr->end_len)<0) {
1090
29.7k
        return myptr;
1091
29.7k
    }
1092
1093
9.60k
    return NULL;
1094
39.3k
}
1095
1096
/**  @} */
1097
/* End of Subtrees maintaining code */
1098
1099
/** @defgroup agent_mib_registering Registering and unregistering MIB subtrees.
1100
 *     Adding and removing MIB nodes to the database under their contexts.
1101
 *   @ingroup agent_registry
1102
 *
1103
 * @{
1104
 */
1105
1106
1107
/** Registers a MIB handler.
1108
 *
1109
 *  @param moduleName
1110
 *  @param var
1111
 *  @param varsize
1112
 *  @param numvars
1113
 *  @param  mibloc
1114
 *  @param mibloclen
1115
 *  @param priority
1116
 *  @param range_subid
1117
 *  @param range_ubound
1118
 *  @param  ss
1119
 *  @param context
1120
 *  @param timeout
1121
 *  @param flags
1122
 *  @param reginfo Registration handler structure.
1123
 *                 In a case of failure, it will be freed.
1124
 *  @param perform_callback
1125
 *
1126
 *  @return gives MIB_REGISTERED_OK or MIB_* error code.
1127
 *
1128
 *  @see netsnmp_register_handler()
1129
 *  @see register_agentx_list()
1130
 *  @see netsnmp_handler_registration_free()
1131
 */
1132
int
1133
netsnmp_register_mib(const char *moduleName,
1134
                     struct variable *var,
1135
                     size_t varsize,
1136
                     size_t numvars,
1137
                     oid * mibloc,
1138
                     size_t mibloclen,
1139
                     int priority,
1140
                     int range_subid,
1141
                     oid range_ubound,
1142
                     netsnmp_session * ss,
1143
                     const char *context,
1144
                     int timeout,
1145
                     int flags,
1146
                     netsnmp_handler_registration *reginfo,
1147
                     int perform_callback)
1148
19.2k
{
1149
19.2k
    netsnmp_subtree *subtree, *sub2;
1150
19.2k
    int             res;
1151
19.2k
    struct register_parameters reg_parms;
1152
19.2k
    int old_lookup_cache_val = netsnmp_get_lookup_cache_size();
1153
1154
19.2k
    if (moduleName == NULL ||
1155
19.2k
        mibloc     == NULL) {
1156
        /* Shouldn't happen ??? */
1157
0
        netsnmp_handler_registration_free(reginfo);
1158
0
        return MIB_REGISTRATION_FAILED;
1159
0
    }
1160
19.2k
    subtree = calloc(1, sizeof(netsnmp_subtree));
1161
19.2k
    if (subtree == NULL) {
1162
0
        netsnmp_handler_registration_free(reginfo);
1163
0
        return MIB_REGISTRATION_FAILED;
1164
0
    }
1165
1166
19.2k
    DEBUGMSGTL(("register_mib", "registering \"%s\" at ", moduleName));
1167
19.2k
    DEBUGMSGOIDRANGE(("register_mib", mibloc, mibloclen, range_subid,
1168
19.2k
                      range_ubound));
1169
19.2k
    DEBUGMSG(("register_mib", " with context \"%s\"\n",
1170
19.2k
              SNMP_STRORNULL(context)));
1171
1172
    /*
1173
     * verify that the passed context is equal to the context
1174
     * in the reginfo.
1175
     * (which begs the question, why do we have both? It appears that the
1176
     *  reginfo item didn't appear til 5.2)
1177
     */
1178
19.2k
    if( ((NULL == context) && (NULL != reginfo->contextName)) ||
1179
19.2k
        ((NULL != context) && (NULL == reginfo->contextName)) ||
1180
19.2k
        ( ((NULL != context) && (NULL != reginfo->contextName)) &&
1181
19.2k
          (0 != strcmp(context, reginfo->contextName))) ) {
1182
0
        snmp_log(LOG_WARNING,"context passed during registration does not "
1183
0
                 "equal the reginfo contextName! ('%s' != '%s')\n",
1184
0
                 context, reginfo->contextName);
1185
0
        netsnmp_assert(!"register context == reginfo->contextName"); /* always false */
1186
0
    }
1187
1188
    /*  Create the new subtree node being registered.  */
1189
1190
19.2k
    subtree->reginfo = reginfo;
1191
19.2k
    subtree->name_a  = snmp_duplicate_objid(mibloc, mibloclen);
1192
19.2k
    subtree->start_a = snmp_duplicate_objid(mibloc, mibloclen);
1193
19.2k
    subtree->end_a   = snmp_duplicate_objid(mibloc, mibloclen);
1194
19.2k
    subtree->label_a = strdup(moduleName);
1195
19.2k
    if (subtree->name_a == NULL || subtree->start_a == NULL || 
1196
19.2k
  subtree->end_a  == NULL || subtree->label_a == NULL) {
1197
0
  netsnmp_subtree_free(subtree); /* also frees reginfo */
1198
0
  return MIB_REGISTRATION_FAILED;
1199
0
    }
1200
19.2k
    subtree->namelen   = (u_char)mibloclen;
1201
19.2k
    subtree->start_len = (u_char)mibloclen;
1202
19.2k
    subtree->end_len   = (u_char)mibloclen;
1203
19.2k
    subtree->end_a[mibloclen - 1]++;
1204
1205
19.2k
    if (var != NULL) {
1206
0
  subtree->variables = (struct variable *)malloc(varsize*numvars);
1207
0
  if (subtree->variables == NULL) {
1208
0
      netsnmp_subtree_free(subtree); /* also frees reginfo */
1209
0
      return MIB_REGISTRATION_FAILED;
1210
0
  }
1211
0
  memcpy(subtree->variables, var, numvars*varsize);
1212
0
  subtree->variables_len = numvars;
1213
0
  subtree->variables_width = varsize;
1214
0
    }
1215
19.2k
    subtree->priority = priority;
1216
19.2k
    subtree->timeout = timeout;
1217
19.2k
    subtree->range_subid = range_subid;
1218
19.2k
    subtree->range_ubound = range_ubound;
1219
19.2k
    subtree->session = ss;
1220
19.2k
    subtree->flags = (u_char)flags;    /*  used to identify instance oids  */
1221
19.2k
    subtree->flags |= SUBTREE_ATTACHED;
1222
19.2k
    subtree->global_cacheid = reginfo->global_cacheid;
1223
1224
19.2k
    netsnmp_set_lookup_cache_size(0);
1225
19.2k
    res = netsnmp_subtree_load(subtree, context);
1226
1227
    /*  If registering a range, use the first subtree as a template for the
1228
  rest of the range.  */
1229
1230
19.2k
    if (res == MIB_REGISTERED_OK && range_subid != 0) {
1231
0
        int i;
1232
0
  for (i = mibloc[range_subid - 1] + 1; i <= (int)range_ubound; i++) {
1233
0
      sub2 = netsnmp_subtree_deepcopy(subtree);
1234
1235
0
      if (sub2 == NULL) {
1236
0
                unregister_mib_context(mibloc, mibloclen, priority,
1237
0
                                       range_subid, range_ubound, context);
1238
0
                netsnmp_set_lookup_cache_size(old_lookup_cache_val);
1239
0
                invalidate_lookup_cache(context);
1240
0
                return MIB_REGISTRATION_FAILED;
1241
0
            }
1242
1243
0
            sub2->name_a[range_subid - 1]  = i;
1244
0
            sub2->start_a[range_subid - 1] = i;
1245
0
            sub2->end_a[range_subid - 1]   = i;     /* XXX - ???? */
1246
0
            if (range_subid == (int)mibloclen) {
1247
0
                ++sub2->end_a[range_subid - 1];
1248
0
            }
1249
0
            sub2->flags |= SUBTREE_ATTACHED;
1250
0
            sub2->global_cacheid = reginfo->global_cacheid;
1251
            /* FRQ This is essential for requests to succeed! */
1252
0
            sub2->reginfo->rootoid[range_subid - 1]  = i;
1253
1254
0
            res = netsnmp_subtree_load(sub2, context);
1255
0
            if (res != MIB_REGISTERED_OK) {
1256
0
                unregister_mib_context(mibloc, mibloclen, priority,
1257
0
                                       range_subid, range_ubound, context);
1258
0
                netsnmp_remove_subtree(sub2);
1259
0
    netsnmp_subtree_free(sub2);
1260
0
                netsnmp_set_lookup_cache_size(old_lookup_cache_val);
1261
0
                invalidate_lookup_cache(context);
1262
0
                return res;
1263
0
            }
1264
0
        }
1265
19.2k
    } else if (res == MIB_DUPLICATE_REGISTRATION ||
1266
19.2k
               res == MIB_REGISTRATION_FAILED) {
1267
9.60k
        netsnmp_set_lookup_cache_size(old_lookup_cache_val);
1268
9.60k
        invalidate_lookup_cache(context);
1269
9.60k
        netsnmp_subtree_free(subtree);
1270
9.60k
        return res;
1271
9.60k
    }
1272
1273
    /*
1274
     * mark the MIB as detached, if there's no master agent present as of now 
1275
     */
1276
9.60k
    if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
1277
9.60k
             NETSNMP_DS_AGENT_ROLE) != MASTER_AGENT) {
1278
0
        if (main_session == NULL) {
1279
0
            register_mib_detach_node(subtree);
1280
0
  }
1281
0
    }
1282
1283
9.60k
    if (res == MIB_REGISTERED_OK && perform_callback) {
1284
9.60k
        memset(&reg_parms, 0x0, sizeof(reg_parms));
1285
9.60k
        reg_parms.name = mibloc;
1286
9.60k
        reg_parms.namelen = mibloclen;
1287
9.60k
        reg_parms.priority = priority;
1288
9.60k
        reg_parms.range_subid = range_subid;
1289
9.60k
        reg_parms.range_ubound = range_ubound;
1290
9.60k
        reg_parms.timeout = timeout;
1291
9.60k
        reg_parms.flags = (u_char) flags;
1292
9.60k
        reg_parms.session = ss;
1293
9.60k
        reg_parms.reginfo = reginfo;
1294
9.60k
        reg_parms.contextName = context;
1295
9.60k
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
1296
9.60k
                            SNMPD_CALLBACK_REGISTER_OID, &reg_parms);
1297
9.60k
    }
1298
1299
9.60k
    netsnmp_set_lookup_cache_size(old_lookup_cache_val);
1300
9.60k
    invalidate_lookup_cache(context);
1301
9.60k
    return res;
1302
19.2k
}
1303
1304
/** @private
1305
 *  Reattach a particular node.  
1306
 */
1307
static void
1308
register_mib_reattach_node(netsnmp_subtree *s)
1309
0
{
1310
0
    if ((s != NULL) && (s->namelen > 1) && !(s->flags & SUBTREE_ATTACHED)) {
1311
0
        struct register_parameters reg_parms;
1312
        /*
1313
         * only do registrations that are not the top level nodes 
1314
         */
1315
0
        memset(&reg_parms, 0x0, sizeof(reg_parms));
1316
1317
        /*
1318
         * XXX: do this better 
1319
         */
1320
0
        reg_parms.name = s->name_a;
1321
0
        reg_parms.namelen = s->namelen;
1322
0
        reg_parms.priority = s->priority;
1323
0
        reg_parms.range_subid = s->range_subid;
1324
0
        reg_parms.range_ubound = s->range_ubound;
1325
0
        reg_parms.timeout = s->timeout;
1326
0
        reg_parms.flags = s->flags;
1327
0
        reg_parms.session = s->session;
1328
0
        reg_parms.reginfo = s->reginfo;
1329
        /* XXX: missing in subtree: reg_parms.contextName = s->context; */
1330
0
        if ((NULL != s->reginfo) && (NULL != s->reginfo->contextName))
1331
0
            reg_parms.contextName = s->reginfo->contextName;
1332
0
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
1333
0
                            SNMPD_CALLBACK_REGISTER_OID, &reg_parms);
1334
0
        s->flags |= SUBTREE_ATTACHED;
1335
0
    }
1336
0
}
1337
1338
/** Call callbacks to reattach all our nodes.  
1339
 */
1340
void
1341
register_mib_reattach(void)
1342
0
{
1343
0
    netsnmp_subtree *s, *t;
1344
0
    subtree_context_cache *ptr;
1345
1346
0
    for (ptr = context_subtrees; ptr; ptr = ptr->next) {
1347
0
        for (s = ptr->first_subtree; s != NULL; s = s->next) {
1348
0
            register_mib_reattach_node(s);
1349
0
            for (t = s->children; t != NULL; t = t->children) {
1350
0
                register_mib_reattach_node(t);
1351
0
            }
1352
0
        }
1353
0
    }
1354
0
}
1355
1356
/** @private
1357
 *  Mark a node as detached.
1358
 *
1359
 *  @param s The note to be marked
1360
 */
1361
static void
1362
register_mib_detach_node(netsnmp_subtree *s)
1363
0
{
1364
0
    if (s != NULL) {
1365
0
        s->flags = s->flags & ~SUBTREE_ATTACHED;
1366
0
    }
1367
0
}
1368
1369
/** Mark all our registered OIDs as detached.
1370
 *  This is only really useful for subagent protocols, when
1371
 *  a connection is lost or the subagent is being shut down.  
1372
 */
1373
void
1374
register_mib_detach(void)
1375
0
{
1376
0
    netsnmp_subtree *s, *t;
1377
0
    subtree_context_cache *ptr;
1378
0
    for (ptr = context_subtrees; ptr; ptr = ptr->next) {
1379
0
        for (s = ptr->first_subtree; s != NULL; s = s->next) {
1380
0
            register_mib_detach_node(s);
1381
0
            for (t = s->children; t != NULL; t = t->children) {
1382
0
                register_mib_detach_node(t);
1383
0
            }
1384
0
        }
1385
0
    }
1386
0
}
1387
1388
/** Register a new module into the MIB database, with all possible custom options
1389
 *
1390
 *  @param  moduleName Text name of the module.
1391
 *                     The given name will be used to identify the module
1392
 *                     inside the agent.
1393
 *
1394
 *  @param  var        Array of variables to be registered in the module.
1395
 *
1396
 *  @param  varsize    Size of a single variable in var array.
1397
 *                     The size is normally equal to sizeof(struct variable),
1398
 *                     but if we wish to use shorter (or longer) OIDs, then we
1399
 *                     could use different variant of the variable structure.
1400
 *
1401
 *  @param  numvars    Number of variables in the var array.
1402
 *                     This is how many variables the function will try to register.
1403
 *
1404
 *  @param  mibloc     Base OID of the module.
1405
 *                     All OIDs in var array should be sub-oids of the base OID.
1406
 *
1407
 *  @param  mibloclen  Length of the base OID.
1408
 *                     Number of integers making up the base OID.
1409
 *
1410
 *  @param  priority   Registration priority.
1411
 *                     Used to achieve a desired configuration when different
1412
 *                     sessions register identical or overlapping regions.
1413
 *                     Primarily used with AgentX subagent registrations.
1414
 *
1415
 *  @param range_subid If non-zero, the module is registered against a range
1416
 *                     of OIDs, with this parameter identifying the relevant
1417
 *                     subidentifier - see RFC 2741 for details.
1418
 *                     Typically used to register a single row of a table.
1419
 *                     If zero, then register the module against the full OID subtree.
1420
 *
1421
 *  @param range_ubound The end of the range being registered (see RFC 2741)
1422
 *                     If range_subid is zero, then this parameter is ignored.
1423
 *
1424
 *  @param ss 
1425
 *  @param context
1426
 *  @param timeout 
1427
 *  @param flags 
1428
 *
1429
 *  @return gives SNMPERR_SUCCESS or SNMPERR_* error code.
1430
 *
1431
 *  @see register_mib()
1432
 *  @see register_mib_priority()
1433
 *  @see register_mib_range()
1434
 *  @see unregister_mib()
1435
 */
1436
int
1437
register_mib_context(const char *moduleName,
1438
                     const struct variable *var,
1439
                     size_t varsize,
1440
                     size_t numvars,
1441
                     const oid * mibloc,
1442
                     size_t mibloclen,
1443
                     int priority,
1444
                     int range_subid,
1445
                     oid range_ubound,
1446
                     netsnmp_session * ss,
1447
                     const char *context, int timeout, int flags)
1448
0
{
1449
0
    return netsnmp_register_old_api(moduleName, var, varsize, numvars,
1450
0
                                    mibloc, mibloclen, priority,
1451
0
                                    range_subid, range_ubound, ss, context,
1452
0
                                    timeout, flags);
1453
0
}
1454
1455
/** Register a new module into the MIB database, as being responsible
1456
 *   for a range of OIDs (typically a single row of a table).
1457
 *
1458
 *  @param  moduleName Text name of the module.
1459
 *                     The given name will be used to identify the module
1460
 *                     inside the agent.
1461
 *
1462
 *  @param  var        Array of variables to be registered in the module.
1463
 *
1464
 *  @param  varsize    Size of a single variable in var array.
1465
 *                     The size is normally equal to sizeof(struct variable),
1466
 *                     but if we wish to use shorter (or longer) OIDs, then we
1467
 *                     could use different variant of the variable structure.
1468
 *
1469
 *  @param  numvars    Number of variables in the var array.
1470
 *                     This is how many variables the function will try to register.
1471
 *
1472
 *  @param  mibloc     Base OID of the module.
1473
 *                     All OIDs in var array should be sub-oids of the base OID.
1474
 *
1475
 *  @param  mibloclen  Length of the base OID.
1476
 *                     Number of integers making up the base OID.
1477
 *
1478
 *  @param  priority   Registration priority.
1479
 *                     Used to achieve a desired configuration when different
1480
 *                     sessions register identical or overlapping regions.
1481
 *                     Primarily used with AgentX subagent registrations.
1482
 *
1483
 *  @param range_subid If non-zero, the module is registered against a range
1484
 *                     of OIDs, with this parameter identifying the relevant
1485
 *                     subidentifier - see RFC 2741 for details.
1486
 *                     Typically used to register a single row of a table.
1487
 *                     If zero, then register the module against the full OID subtree.
1488
 *
1489
 *  @param range_ubound The end of the range being registered (see RFC 2741)
1490
 *                     If range_subid is zero, then this parameter is ignored.
1491
 *
1492
 *  @param ss 
1493
 *
1494
 *  @return gives SNMPERR_SUCCESS or SNMPERR_* error code.
1495
 *
1496
 *  @see register_mib()
1497
 *  @see register_mib_priority()
1498
 *  @see register_mib_context()
1499
 *  @see unregister_mib()
1500
 */
1501
int
1502
register_mib_range(const char *moduleName,
1503
                   const struct variable *var,
1504
                   size_t varsize,
1505
                   size_t numvars,
1506
                   const oid * mibloc,
1507
                   size_t mibloclen,
1508
                   int priority,
1509
                   int range_subid, oid range_ubound, netsnmp_session * ss)
1510
0
{
1511
0
    return register_mib_context(moduleName, var, varsize, numvars,
1512
0
                                mibloc, mibloclen, priority,
1513
0
                                range_subid, range_ubound, ss, "", -1, 0);
1514
0
}
1515
1516
/** Register a new module into the MIB database, with a non-default priority
1517
 *
1518
 *  @param  moduleName Text name of the module.
1519
 *                     The given name will be used to identify the module
1520
 *                     inside the agent.
1521
 *
1522
 *  @param  var        Array of variables to be registered in the module.
1523
 *
1524
 *  @param  varsize    Size of a single variable in var array.
1525
 *                     The size is normally equal to sizeof(struct variable),
1526
 *                     but if we wish to use shorter (or longer) OIDs, then we
1527
 *                     could use different variant of the variable structure.
1528
 *
1529
 *  @param  numvars    Number of variables in the var array.
1530
 *                     This is how many variables the function will try to register.
1531
 *
1532
 *  @param  mibloc     Base OID of the module.
1533
 *                     All OIDs in var array should be sub-oids of the base OID.
1534
 *
1535
 *  @param  mibloclen  Length of the base OID.
1536
 *                     Number of integers making up the base OID.
1537
 *
1538
 *  @param  priority   Registration priority.
1539
 *                     Used to achieve a desired configuration when different
1540
 *                     sessions register identical or overlapping regions.
1541
 *                     Primarily used with AgentX subagent registrations.
1542
 *
1543
 *  @return gives SNMPERR_SUCCESS or SNMPERR_* error code.
1544
 *
1545
 *  @see register_mib()
1546
 *  @see register_mib_range()
1547
 *  @see register_mib_context()
1548
 *  @see unregister_mib()
1549
 */
1550
int
1551
register_mib_priority(const char *moduleName,
1552
                      const struct variable *var,
1553
                      size_t varsize,
1554
                      size_t numvars,
1555
                      const oid * mibloc, size_t mibloclen, int priority)
1556
0
{
1557
0
    return register_mib_range(moduleName, var, varsize, numvars,
1558
0
                              mibloc, mibloclen, priority, 0, 0, NULL);
1559
0
}
1560
1561
/** Register a new module into the MIB database, using default priority and context
1562
 *
1563
 *  @param  moduleName Text name of the module.
1564
 *                     The given name will be used to identify the module
1565
 *                     inside the agent.
1566
 *
1567
 *  @param  var        Array of variables to be registered in the module.
1568
 *
1569
 *  @param  varsize    Size of a single variable in var array.
1570
 *                     The size is normally equal to sizeof(struct variable),
1571
 *                     but if we wish to use shorter (or longer) OIDs, then we
1572
 *                     could use different variant of the variable structure.
1573
 *
1574
 *  @param  numvars    Number of variables in the var array.
1575
 *                     This is how many variables the function will try to register.
1576
 *
1577
 *  @param  mibloc     Base OID of the module.
1578
 *                     All OIDs in var array should be sub-oids of the base OID.
1579
 *
1580
 *  @param  mibloclen  Length of the base OID.
1581
 *                     Number of integers making up the base OID.
1582
 *
1583
 *  @return gives SNMPERR_SUCCESS or SNMPERR_* error code.
1584
 *
1585
 *  @see register_mib_priority()
1586
 *  @see register_mib_range()
1587
 *  @see register_mib_context()
1588
 *  @see unregister_mib()
1589
 */
1590
int
1591
register_mib(const char *moduleName,
1592
             const struct variable *var,
1593
             size_t varsize,
1594
             size_t numvars, const oid * mibloc, size_t mibloclen)
1595
0
{
1596
0
    return register_mib_priority(moduleName, var, varsize, numvars,
1597
0
                                 mibloc, mibloclen, DEFAULT_MIB_PRIORITY);
1598
0
}
1599
1600
/** @private
1601
 *  Unloads a subtree from MIB tree.
1602
 *
1603
 *  @param  sub     The sub-tree which is being removed.
1604
 *
1605
 *  @param  prev    Previous entry, before the unloaded one.
1606
 *
1607
 *  @param  context Name of the context which is being removed.
1608
 *
1609
 *  @see unregister_mib_context()
1610
 */
1611
void
1612
netsnmp_subtree_unload(netsnmp_subtree *sub, netsnmp_subtree *prev, const char *context)
1613
9.60k
{
1614
9.60k
    netsnmp_subtree *ptr;
1615
1616
9.60k
    DEBUGMSGTL(("register_mib", "unload("));
1617
9.60k
    if (sub != NULL) {
1618
9.60k
        DEBUGMSGOID(("register_mib", sub->start_a, sub->start_len));
1619
9.60k
    } else {
1620
0
        DEBUGMSG(("register_mib", "[NIL]"));
1621
0
        return;
1622
0
    }
1623
9.60k
    DEBUGMSG(("register_mib", ", "));
1624
9.60k
    if (prev != NULL) {
1625
0
        DEBUGMSGOID(("register_mib", prev->start_a, prev->start_len));
1626
9.60k
    } else {
1627
9.60k
        DEBUGMSG(("register_mib", "[NIL]"));
1628
9.60k
    }
1629
9.60k
    DEBUGMSG(("register_mib", ")\n"));
1630
1631
9.60k
    if (prev != NULL) {         /* non-leading entries are easy */
1632
0
        prev->children = sub->children;
1633
0
        invalidate_lookup_cache(context);
1634
0
        return;
1635
0
    }
1636
    /*
1637
     * otherwise, we need to amend our neighbours as well 
1638
     */
1639
1640
9.60k
    if (sub->children == NULL) {        /* just remove this node completely */
1641
16.0k
        for (ptr = sub->prev; ptr; ptr = ptr->children) {
1642
6.40k
            netsnmp_subtree_change_next(ptr, sub->next);
1643
6.40k
        }
1644
9.60k
        for (ptr = sub->next; ptr; ptr = ptr->children) {
1645
0
            netsnmp_subtree_change_prev(ptr, sub->prev);
1646
0
        }
1647
1648
9.60k
  if (sub->prev == NULL) {
1649
3.20k
      netsnmp_subtree_replace_first(sub->next, context);
1650
3.20k
  }
1651
1652
9.60k
    } else {
1653
0
        for (ptr = sub->prev; ptr; ptr = ptr->children)
1654
0
            netsnmp_subtree_change_next(ptr, sub->children);
1655
0
        for (ptr = sub->next; ptr; ptr = ptr->children)
1656
0
            netsnmp_subtree_change_prev(ptr, sub->children);
1657
1658
0
  if (sub->prev == NULL) {
1659
0
      netsnmp_subtree_replace_first(sub->children, context);
1660
0
  }
1661
0
    }
1662
9.60k
    invalidate_lookup_cache(context);
1663
9.60k
}
1664
1665
/**
1666
 * Unregisters a module registered against a given OID (or range) in a specified context. 
1667
 * Typically used when a module has multiple contexts defined.
1668
 * The parameters priority, range_subid, range_ubound and context
1669
 * should match those used to register the module originally.
1670
 *
1671
 * @param name  the specific OID to unregister if it contains the associated
1672
 *              context.
1673
 *
1674
 * @param len   the length of the OID, use  OID_LENGTH macro.
1675
 *
1676
 * @param priority  a value between 1 and 255, used to achieve a desired
1677
 *                  configuration when different sessions register identical or
1678
 *                  overlapping regions.  Subagents with no particular
1679
 *                  knowledge of priority should register with the default
1680
 *                  value of 127.
1681
 *
1682
 * @param range_subid  permits specifying a range in place of one of a subtree
1683
 *                     sub-identifiers.  When this value is zero, no range is
1684
 *                     being specified.
1685
 *
1686
 * @param range_ubound  the upper bound of a sub-identifier's range.
1687
 *                      This field is present only if range_subid is not 0.
1688
 *
1689
 * @param context  a context name that has been created
1690
 *
1691
 * @return gives MIB_UNREGISTERED_OK or MIB_* error code.
1692
 * 
1693
 * @see unregister_mib()
1694
 * @see unregister_mib_priority()
1695
 * @see unregister_mib_range()
1696
 */
1697
int
1698
unregister_mib_context(oid * name, size_t len, int priority,
1699
                       int range_subid, oid range_ubound,
1700
                       const char *context)
1701
9.60k
{
1702
9.60k
    netsnmp_subtree *list, *myptr = NULL;
1703
9.60k
    netsnmp_subtree *prev, *child, *next; /* loop through children */
1704
9.60k
    struct register_parameters reg_parms;
1705
9.60k
    int old_lookup_cache_val = netsnmp_get_lookup_cache_size();
1706
9.60k
    int unregistering = 1;
1707
9.60k
    int orig_subid_val = -1;
1708
1709
9.60k
    netsnmp_set_lookup_cache_size(0);
1710
1711
9.60k
    if ((range_subid > 0) &&  ((size_t)range_subid <= len))
1712
0
        orig_subid_val = name[range_subid-1];
1713
1714
19.2k
    while(unregistering){
1715
9.60k
        DEBUGMSGTL(("register_mib", "unregistering "));
1716
9.60k
        DEBUGMSGOIDRANGE(("register_mib", name, len, range_subid, range_ubound));
1717
9.60k
        DEBUGMSG(("register_mib", "\n"));
1718
1719
9.60k
        list = netsnmp_subtree_find(name, len, netsnmp_subtree_find_first(context),
1720
9.60k
                    context);
1721
9.60k
        if (list == NULL) {
1722
0
            return MIB_NO_SUCH_REGISTRATION;
1723
0
        }
1724
1725
9.60k
        for (child = list, prev = NULL; child != NULL;
1726
9.60k
            prev = child, child = child->children) {
1727
9.60k
            if (netsnmp_oid_equals(child->name_a, child->namelen, name, len) == 0 &&
1728
9.60k
                child->priority == priority) {
1729
9.60k
                break;              /* found it */
1730
9.60k
             }
1731
9.60k
        }
1732
1733
9.60k
        if (child == NULL) {
1734
0
            return MIB_NO_SUCH_REGISTRATION;
1735
0
        }
1736
1737
9.60k
        netsnmp_subtree_unload(child, prev, context);
1738
9.60k
        myptr = child;              /* remember this for later */
1739
1740
        /*
1741
        *  Now handle any occurrences in the following subtrees,
1742
        *      as a result of splitting this range.  Due to the
1743
        *      nature of the way such splits work, the first
1744
        *      subtree 'slice' that doesn't refer to the given
1745
        *      name marks the end of the original region.
1746
        *
1747
        *  This should also serve to register ranges.
1748
        */
1749
1750
9.60k
        for (list = myptr->next; list != NULL; list = next) {
1751
0
            next = list->next; /* list gets freed sometimes; cache next */
1752
0
            for (child = list, prev = NULL; child != NULL;
1753
0
                prev = child, child = child->children) {
1754
0
                if ((netsnmp_oid_equals(child->name_a, child->namelen,
1755
0
                    name, len) == 0) &&
1756
0
            (child->priority == priority)) {
1757
0
                    netsnmp_subtree_unload(child, prev, context);
1758
0
                    netsnmp_subtree_free(child);
1759
0
                    break;
1760
0
                }
1761
0
            }
1762
0
            if (child == NULL)      /* Didn't find the given name */
1763
0
                break;
1764
0
        }
1765
1766
        /* Maybe we are in a range... */
1767
9.60k
        if (orig_subid_val != -1){
1768
0
            if (++name[range_subid-1] >= orig_subid_val+range_ubound)
1769
0
                {
1770
0
                unregistering=0;
1771
0
                name[range_subid-1] = orig_subid_val;
1772
0
                }
1773
0
        }
1774
9.60k
        else {
1775
9.60k
            unregistering=0;
1776
9.60k
        }
1777
9.60k
    }
1778
1779
9.60k
    memset(&reg_parms, 0x0, sizeof(reg_parms));
1780
9.60k
    reg_parms.name = name;
1781
9.60k
    reg_parms.namelen = len;
1782
9.60k
    reg_parms.priority = priority;
1783
9.60k
    reg_parms.range_subid = range_subid;
1784
9.60k
    reg_parms.range_ubound = range_ubound;
1785
9.60k
    reg_parms.flags = 0x00;     /*  this is okay I think  */
1786
9.60k
    reg_parms.contextName = context;
1787
9.60k
    snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
1788
9.60k
                        SNMPD_CALLBACK_UNREGISTER_OID, &reg_parms);
1789
1790
    /*
1791
     * netsnmp_subtree_free() may free the 'context' pointer. Hence, call
1792
     * invalidate_lookup_cache() before calling netsnmp_subtree_free().
1793
     */
1794
9.60k
    invalidate_lookup_cache(context);
1795
9.60k
    netsnmp_subtree_free(myptr);
1796
9.60k
    netsnmp_set_lookup_cache_size(old_lookup_cache_val);
1797
9.60k
    return MIB_UNREGISTERED_OK;
1798
9.60k
}
1799
1800
#ifndef NETSNMP_FEATURE_REMOVE_UNREGISTER_MIB_TABLE_ROW
1801
int
1802
netsnmp_unregister_mib_table_row(oid * name, size_t len, int priority,
1803
                                 int var_subid, oid range_ubound,
1804
                                 const char *context)
1805
0
{
1806
0
    netsnmp_subtree *list, *myptr, *futureptr;
1807
0
    netsnmp_subtree *prev, *child;       /* loop through children */
1808
0
    struct register_parameters reg_parms;
1809
0
    oid             range_lbound = name[var_subid - 1];
1810
1811
0
    DEBUGMSGTL(("register_mib", "unregistering "));
1812
0
    DEBUGMSGOIDRANGE(("register_mib", name, len, var_subid, range_ubound));
1813
0
    DEBUGMSG(("register_mib", "\n"));
1814
1815
0
    for (; name[var_subid - 1] <= range_ubound; name[var_subid - 1]++) {
1816
0
        list = netsnmp_subtree_find(name, len, 
1817
0
        netsnmp_subtree_find_first(context), context);
1818
1819
0
        if (list == NULL) {
1820
0
            continue;
1821
0
        }
1822
1823
0
        for (child = list, prev = NULL; child != NULL;
1824
0
             prev = child, child = child->children) {
1825
1826
0
            if (netsnmp_oid_equals(child->name_a, child->namelen, 
1827
0
         name, len) == 0 && 
1828
0
    (child->priority == priority)) {
1829
0
                break;          /* found it */
1830
0
            }
1831
0
        }
1832
1833
0
        if (child == NULL) {
1834
0
            continue;
1835
0
        }
1836
1837
0
        netsnmp_subtree_unload(child, prev, context);
1838
0
        myptr = child;          /* remember this for later */
1839
1840
0
        for (list = myptr->next; list != NULL; list = futureptr) {
1841
            /* remember the next spot in the list in case we free this node */
1842
0
            futureptr = list->next;
1843
1844
            /* check each child */
1845
0
            for (child = list, prev = NULL; child != NULL;
1846
0
                 prev = child, child = child->children) {
1847
1848
0
                if (netsnmp_oid_equals(child->name_a, child->namelen, 
1849
0
              name, len) == 0 &&
1850
0
                    (child->priority == priority)) {
1851
0
                    netsnmp_subtree_unload(child, prev, context);
1852
0
                    netsnmp_subtree_free(child);
1853
0
                    break;
1854
0
                }
1855
0
            }
1856
1857
            /* XXX: wjh: not sure why we're bailing here */
1858
0
            if (child == NULL) {        /* Didn't find the given name */
1859
0
                break;
1860
0
            }
1861
0
        }
1862
0
        netsnmp_subtree_free(myptr);
1863
0
    }
1864
1865
0
    name[var_subid - 1] = range_lbound;
1866
0
    memset(&reg_parms, 0x0, sizeof(reg_parms));
1867
0
    reg_parms.name = name;
1868
0
    reg_parms.namelen = len;
1869
0
    reg_parms.priority = priority;
1870
0
    reg_parms.range_subid = var_subid;
1871
0
    reg_parms.range_ubound = range_ubound;
1872
0
    reg_parms.flags = 0x00;     /*  this is okay I think  */
1873
0
    reg_parms.contextName = context;
1874
0
    snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
1875
0
                        SNMPD_CALLBACK_UNREGISTER_OID, &reg_parms);
1876
1877
0
    return 0;
1878
0
}
1879
#endif /* NETSNMP_FEATURE_REMOVE_UNREGISTER_MIB_TABLE_ROW */
1880
1881
/**
1882
 * Unregisters a module registered against a given OID (or range) in the default context. 
1883
 * Typically used when a module has multiple contexts defined.
1884
 * The parameters priority, range_subid, and range_ubound should
1885
 * match those used to register the module originally.
1886
 *
1887
 * @param name  the specific OID to unregister if it contains the associated
1888
 *              context.
1889
 *
1890
 * @param len   the length of the OID, use  OID_LENGTH macro.
1891
 *
1892
 * @param priority  a value between 1 and 255, used to achieve a desired
1893
 *                  configuration when different sessions register identical or
1894
 *                  overlapping regions.  Subagents with no particular
1895
 *                  knowledge of priority should register with the default
1896
 *                  value of 127.
1897
 *
1898
 * @param range_subid  permits specifying a range in place of one of a subtree
1899
 *                     sub-identifiers.  When this value is zero, no range is
1900
 *                     being specified.
1901
 *
1902
 * @param range_ubound  the upper bound of a sub-identifier's range.
1903
 *                      This field is present only if range_subid is not 0.
1904
 *
1905
 * @return gives MIB_UNREGISTERED_OK or MIB_* error code.
1906
 * 
1907
 * @see unregister_mib()
1908
 * @see unregister_mib_priority()
1909
 * @see unregister_mib_context()
1910
 */
1911
int
1912
unregister_mib_range(oid * name, size_t len, int priority,
1913
                     int range_subid, oid range_ubound)
1914
0
{
1915
0
    return unregister_mib_context(name, len, priority, range_subid,
1916
0
                                  range_ubound, "");
1917
0
}
1918
1919
/**
1920
 * Unregisters a module registered against a given OID at the specified priority.
1921
 * The priority parameter should match that used to register the module originally.
1922
 *
1923
 * @param name  the specific OID to unregister if it contains the associated
1924
 *              context.
1925
 *
1926
 * @param len   the length of the OID, use  OID_LENGTH macro.
1927
 *
1928
 * @param priority  a value between 1 and 255, used to achieve a desired
1929
 *                  configuration when different sessions register identical or
1930
 *                  overlapping regions.  Subagents with no particular
1931
 *                  knowledge of priority should register with the default
1932
 *                  value of 127.
1933
 *
1934
 * @return gives MIB_UNREGISTERED_OK or MIB_* error code.
1935
 * 
1936
 * @see unregister_mib()
1937
 * @see unregister_mib_range()
1938
 * @see unregister_mib_context()
1939
 */
1940
int
1941
unregister_mib_priority(oid * name, size_t len, int priority)
1942
0
{
1943
0
    return unregister_mib_range(name, len, priority, 0, 0);
1944
0
}
1945
1946
/**
1947
 * Unregisters a module registered against a given OID at the default priority.
1948
 *
1949
 * @param name  the specific OID to unregister if it contains the associated
1950
 *              context.
1951
 *
1952
 * @param len   the length of the OID, use  OID_LENGTH macro.
1953
 *
1954
 * @return gives MIB_UNREGISTERED_OK or MIB_* error code.
1955
 * 
1956
 * @see unregister_mib_priority()
1957
 * @see unregister_mib_context()
1958
 * @see unregister_mib_range()
1959
 * @see unregister_agentx_list()
1960
 */
1961
int
1962
unregister_mib(oid * name, size_t len)
1963
0
{
1964
0
    return unregister_mib_priority(name, len, DEFAULT_MIB_PRIORITY);
1965
0
}
1966
1967
/** Unregisters subtree of OIDs bounded to given session.
1968
 *
1969
 *  @param ss Session which OIDs will be removed from tree.
1970
 *
1971
 *  @see unregister_mib()
1972
 *  @see unregister_agentx_list()
1973
 */
1974
void
1975
unregister_mibs_by_session(netsnmp_session * ss)
1976
0
{
1977
0
    netsnmp_subtree *list, *list2;
1978
0
    netsnmp_subtree *child, *prev, *next_child;
1979
0
    struct register_parameters rp;
1980
0
    subtree_context_cache *contextptr;
1981
1982
0
    DEBUGMSGTL(("register_mib", "unregister_mibs_by_session(%p) ctxt \"%s\"\n",
1983
0
    ss, (ss && ss->contextName) ? ss->contextName : "[NIL]"));
1984
1985
0
    for (contextptr = get_top_context_cache(); contextptr != NULL;
1986
0
         contextptr = contextptr->next) {
1987
0
        for (list = contextptr->first_subtree; list != NULL; list = list2) {
1988
0
            list2 = list->next;
1989
1990
0
            for (child = list, prev = NULL; child != NULL; child = next_child){
1991
0
                next_child = child->children;
1992
1993
0
                if (((!ss || ss->flags & SNMP_FLAGS_SUBSESSION) &&
1994
0
         child->session == ss) ||
1995
0
                    (!(!ss || ss->flags & SNMP_FLAGS_SUBSESSION) && child->session &&
1996
0
                     child->session->subsession == ss)) {
1997
1998
0
                    memset(&rp,0x0,sizeof(rp));
1999
0
                    rp.name = child->name_a;
2000
0
        child->name_a = NULL;
2001
0
                    rp.namelen = child->namelen;
2002
0
                    rp.priority = child->priority;
2003
0
                    rp.range_subid = child->range_subid;
2004
0
                    rp.range_ubound = child->range_ubound;
2005
0
                    rp.timeout = child->timeout;
2006
0
                    rp.flags = child->flags;
2007
0
                    if ((NULL != child->reginfo) &&
2008
0
                        (NULL != child->reginfo->contextName))
2009
0
                        rp.contextName = child->reginfo->contextName;
2010
2011
0
                    if (child->reginfo != NULL) {
2012
                        /*
2013
                         * Don't let's free the session pointer just yet!  
2014
                         */
2015
0
                        child->reginfo->handler->myvoid = NULL;
2016
0
                        netsnmp_handler_registration_free(child->reginfo);
2017
0
      child->reginfo = NULL;
2018
0
                    }
2019
2020
0
                    netsnmp_subtree_unload(child, prev, contextptr->context_name);
2021
0
                    netsnmp_subtree_free(child);
2022
2023
0
                    snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
2024
0
                                        SNMPD_CALLBACK_UNREGISTER_OID, &rp);
2025
0
        SNMP_FREE(rp.name);
2026
0
                } else {
2027
0
                    prev = child;
2028
0
                }
2029
0
            }
2030
0
        }
2031
0
        netsnmp_subtree_join(contextptr->first_subtree);
2032
0
    }
2033
0
}
2034
2035
/** Determines if given PDU is allowed to see (or update) a given OID.
2036
 *
2037
 * @param name    The OID to check access for.
2038
 *                On return, this parameter holds the OID actually matched
2039
 *
2040
 * @param namelen Number of sub-identifiers in the OID.
2041
 *                On return, this parameter holds the length of the matched OID
2042
 *
2043
 * @param pdu     PDU requesting access to the OID.
2044
 *
2045
 * @param type    ANS.1 type of the value at given OID.
2046
 *                (Used for catching SNMPv1 requests for SMIv2-only objects)
2047
 *
2048
 * @return gives VACM_SUCCESS if the OID is in the PDU, otherwise error code.
2049
 */
2050
int
2051
in_a_view(oid *name, size_t *namelen, netsnmp_pdu *pdu, int type)
2052
601
{
2053
601
    struct view_parameters view_parms;
2054
2055
601
    if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
2056
  /* Enable bypassing of view-based access control */
2057
601
        return VACM_SUCCESS;
2058
601
    }
2059
2060
    /*
2061
     * check for v1 and counter64s, since snmpv1 doesn't support it 
2062
     */
2063
0
#ifndef NETSNMP_DISABLE_SNMPV1
2064
0
    if (pdu->version == SNMP_VERSION_1 && type == ASN_COUNTER64) {
2065
0
        return VACM_NOTINVIEW;
2066
0
    }
2067
0
#endif
2068
2069
0
    view_parms.pdu = pdu;
2070
0
    view_parms.name = name;
2071
0
    if (namelen != NULL) {
2072
0
        view_parms.namelen = *namelen;
2073
0
    } else {
2074
0
        view_parms.namelen = 0;
2075
0
    }
2076
0
    view_parms.errorcode = 0;
2077
0
    view_parms.check_subtree = 0;
2078
2079
0
    switch (pdu->version) {
2080
0
#ifndef NETSNMP_DISABLE_SNMPV1
2081
0
    case SNMP_VERSION_1:
2082
0
#endif
2083
0
#ifndef NETSNMP_DISABLE_SNMPV2C
2084
0
    case SNMP_VERSION_2c:
2085
0
#endif
2086
0
   case SNMP_VERSION_3:
2087
0
        NETSNMP_RUNTIME_PROTOCOL_CHECK(pdu->version,unsupported_version);
2088
0
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
2089
0
                            SNMPD_CALLBACK_ACM_CHECK, &view_parms);
2090
0
        return view_parms.errorcode;
2091
0
    }
2092
0
  unsupported_version:
2093
0
    return VACM_NOSECNAME;
2094
0
}
2095
2096
/** Determines if the given PDU request could potentially succeed.
2097
 *  (Preliminary, OID-independent validation)
2098
 *
2099
 * @param pdu     PDU requesting access
2100
 *
2101
 * @return gives VACM_SUCCESS   if the entire MIB tree is accessible
2102
 *               VACM_NOTINVIEW if the entire MIB tree is inaccessible
2103
 *               VACM_SUBTREE_UNKNOWN if some portions are accessible
2104
 *               other codes may returned on error
2105
 */
2106
int
2107
check_access(netsnmp_pdu *pdu)
2108
12.0k
{                               /* IN - pdu being checked */
2109
12.0k
    struct view_parameters view_parms;
2110
12.0k
    view_parms.pdu = pdu;
2111
12.0k
    view_parms.name = NULL;
2112
12.0k
    view_parms.namelen = 0;
2113
12.0k
    view_parms.errorcode = 0;
2114
12.0k
    view_parms.check_subtree = 0;
2115
2116
12.0k
    if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
2117
  /* Enable bypassing of view-based access control */
2118
12.0k
        return 0;
2119
12.0k
    }
2120
2121
0
    switch (pdu->version) {
2122
0
#ifndef NETSNMP_DISABLE_SNMPV1
2123
0
    case SNMP_VERSION_1:
2124
0
#endif
2125
0
#ifndef NETSNMP_DISABLE_SNMPV2C
2126
0
    case SNMP_VERSION_2c:
2127
0
#endif
2128
0
    case SNMP_VERSION_3:
2129
0
        NETSNMP_RUNTIME_PROTOCOL_CHECK(pdu->version,unsupported_version);
2130
0
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
2131
0
                            SNMPD_CALLBACK_ACM_CHECK_INITIAL, &view_parms);
2132
0
        return view_parms.errorcode;
2133
0
    }
2134
0
  unsupported_version:
2135
0
    return 1;
2136
0
}
2137
2138
/** Determines if the given PDU request could potentially access
2139
 *   the specified MIB subtree
2140
 *
2141
 * @param pdu     PDU requesting access
2142
 *
2143
 * @param name    The OID to check access for.
2144
 *
2145
 * @param namelen Number of sub-identifiers in the OID.
2146
 *
2147
 * @return gives VACM_SUCCESS   if the entire MIB tree is accessible
2148
 *               VACM_NOTINVIEW if the entire MIB tree is inaccessible
2149
 *               VACM_SUBTREE_UNKNOWN if some portions are accessible
2150
 *               other codes may returned on error
2151
 */
2152
int
2153
netsnmp_acm_check_subtree(netsnmp_pdu *pdu, oid *name, size_t namelen)
2154
0
{                               /* IN - pdu being checked */
2155
0
    struct view_parameters view_parms;
2156
0
    view_parms.pdu = pdu;
2157
0
    view_parms.name = name;
2158
0
    view_parms.namelen = namelen;
2159
0
    view_parms.errorcode = 0;
2160
0
    view_parms.check_subtree = 1;
2161
2162
0
    if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
2163
  /* Enable bypassing of view-based access control */
2164
0
        return 0;
2165
0
    }
2166
2167
0
    switch (pdu->version) {
2168
0
#ifndef NETSNMP_DISABLE_SNMPV1
2169
0
    case SNMP_VERSION_1:
2170
0
#endif
2171
0
#ifndef NETSNMP_DISABLE_SNMPV2C
2172
0
    case SNMP_VERSION_2c:
2173
0
#endif
2174
0
    case SNMP_VERSION_3:
2175
0
        NETSNMP_RUNTIME_PROTOCOL_CHECK(pdu->version,unsupported_version);
2176
0
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
2177
0
                            SNMPD_CALLBACK_ACM_CHECK_SUBTREE, &view_parms);
2178
0
        return view_parms.errorcode;
2179
0
    }
2180
0
  unsupported_version:
2181
0
    return 1;
2182
0
}
2183
2184
netsnmp_feature_child_of(get_session_for_oid,netsnmp_unused);
2185
#ifndef NETSNMP_FEATURE_REMOVE_GET_SESSION_FOR_OID
2186
netsnmp_session *
2187
get_session_for_oid(const oid *name, size_t len, const char *context_name)
2188
0
{
2189
0
    netsnmp_subtree *myptr;
2190
2191
0
    myptr = netsnmp_subtree_find_prev(name, len, 
2192
0
              netsnmp_subtree_find_first(context_name),
2193
0
              context_name);
2194
2195
0
    while (myptr && myptr->variables == NULL) {
2196
0
        myptr = myptr->next;
2197
0
    }
2198
2199
0
    if (myptr == NULL) {
2200
0
        return NULL;
2201
0
    } else {
2202
0
        return myptr->session;
2203
0
    }
2204
0
}
2205
#endif /* NETSNMP_FEATURE_REMOVE_GET_SESSION_FOR_OID */
2206
2207
void
2208
setup_tree(void)
2209
3.20k
{
2210
3.20k
    oid ccitt[1]           = { 0 };
2211
3.20k
    oid iso[1]             = { 1 };
2212
3.20k
    oid joint_ccitt_iso[1] = { 2 };
2213
2214
3.20k
#ifdef USING_AGENTX_SUBAGENT_MODULE
2215
3.20k
    int role =  netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
2216
3.20k
               NETSNMP_DS_AGENT_ROLE);
2217
2218
3.20k
    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 
2219
3.20k
         MASTER_AGENT);
2220
3.20k
#endif
2221
2222
    /* 
2223
     * we need to have the oid's in the heap, that we can *free* it for every case, 
2224
     * that's the purpose of the duplicate_objid's
2225
     */
2226
3.20k
    netsnmp_register_null(snmp_duplicate_objid(ccitt, 1), 1);
2227
3.20k
    netsnmp_register_null(snmp_duplicate_objid(iso, 1), 1);
2228
3.20k
    netsnmp_register_null(snmp_duplicate_objid(joint_ccitt_iso, 1), 1);
2229
2230
3.20k
#ifdef USING_AGENTX_SUBAGENT_MODULE
2231
3.20k
    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 
2232
3.20k
         role);
2233
3.20k
#endif
2234
3.20k
}
2235
2236
int 
2237
9.60k
remove_tree_entry (oid *name, size_t len) {
2238
2239
9.60k
    netsnmp_subtree *sub = NULL;
2240
2241
9.60k
    if ((sub = netsnmp_subtree_find(name, len, NULL, "")) == NULL) {
2242
0
  return MIB_NO_SUCH_REGISTRATION;
2243
0
    }
2244
2245
9.60k
    return unregister_mib_context(name, len, sub->priority,
2246
9.60k
          sub->range_subid, sub->range_ubound, "");
2247
2248
9.60k
}
2249
2250
2251
void
2252
3.20k
shutdown_tree(void) {
2253
3.20k
    oid ccitt[1]           = { 0 };
2254
3.20k
    oid iso[1]             = { 1 };
2255
3.20k
    oid joint_ccitt_iso[1] = { 2 };
2256
2257
3.20k
    DEBUGMSGTL(("agent_registry", "shut down tree\n"));
2258
2259
3.20k
    remove_tree_entry(joint_ccitt_iso, 1);
2260
3.20k
    remove_tree_entry(iso, 1);
2261
3.20k
    remove_tree_entry(ccitt, 1);
2262
2263
3.20k
}
2264
2265
void
2266
dump_registry(void)
2267
0
{
2268
0
    struct variable *vp = NULL;
2269
0
    netsnmp_subtree *myptr, *myptr2;
2270
0
    u_char *s = NULL, *e = NULL, *v = NULL;
2271
0
    size_t sl = 256, el = 256, vl = 256, sl_o = 0, el_o = 0, vl_o = 0;
2272
0
    int i = 0;
2273
2274
0
    if ((s = calloc(sl, 1)) != NULL &&
2275
0
        (e = calloc(sl, 1)) != NULL &&
2276
0
        (v = calloc(sl, 1)) != NULL) {
2277
2278
0
        subtree_context_cache *ptr;
2279
0
        for (ptr = context_subtrees; ptr; ptr = ptr->next) {
2280
0
            printf("Subtrees for Context: %s\n", ptr->context_name);
2281
0
            for (myptr = ptr->first_subtree; myptr != NULL;
2282
0
                 myptr = myptr->next) {
2283
0
                sl_o = el_o = vl_o = 0;
2284
2285
0
                if (!sprint_realloc_objid(&s, &sl, &sl_o, 1,
2286
0
                                          myptr->start_a,
2287
0
                                          myptr->start_len)) {
2288
0
                    break;
2289
0
                }
2290
0
                if (!sprint_realloc_objid(&e, &el, &el_o, 1,
2291
0
                                          myptr->end_a,
2292
0
            myptr->end_len)) {
2293
0
                    break;
2294
0
                }
2295
2296
0
                if (myptr->variables) {
2297
0
                    printf("%02x ( %s - %s ) [", myptr->flags, s, e);
2298
0
                    for (i = 0, vp = myptr->variables;
2299
0
                         i < myptr->variables_len; i++) {
2300
0
                        vl_o = 0;
2301
0
                        if (!sprint_realloc_objid
2302
0
                            (&v, &vl, &vl_o, 1, vp->name, vp->namelen)) {
2303
0
                            break;
2304
0
                        }
2305
0
                        printf("%s, ", v);
2306
0
                        vp = (struct variable *) ((char *) vp +
2307
0
                                                  myptr->variables_width);
2308
0
                    }
2309
0
                    printf("]\n");
2310
0
                } else {
2311
0
                    printf("%02x   %s - %s  \n", myptr->flags, s, e);
2312
0
                }
2313
0
                for (myptr2 = myptr; myptr2 != NULL;
2314
0
                     myptr2 = myptr2->children) {
2315
0
                    if (myptr2->label_a && myptr2->label_a[0]) {
2316
0
                        if (strcmp(myptr2->label_a, "old_api") == 0) {
2317
0
                            struct variable *vp =
2318
0
                                (struct variable*)myptr2->reginfo->handler->myvoid;
2319
2320
0
                            if (!sprint_realloc_objid(&s, &sl, &sl_o, 1,
2321
0
                                                 vp->name, vp->namelen)) {
2322
0
                                continue;
2323
0
                            }
2324
0
                            printf("\t%s[%s] %p var %s\n", myptr2->label_a,
2325
0
                                   myptr2->reginfo->handlerName ?
2326
0
                                   myptr2->reginfo->handlerName : "no-name",
2327
0
                                   myptr2->reginfo, s);
2328
0
                        } else {
2329
0
                            printf("\t%s %s %p\n", myptr2->label_a,
2330
0
                                   myptr2->reginfo->handlerName ?
2331
0
                                   myptr2->reginfo->handlerName : "no-handler-name",
2332
0
                                   myptr2->reginfo);
2333
0
                        }
2334
0
                    }
2335
0
                }
2336
0
            }
2337
0
        }
2338
0
    }
2339
2340
0
    SNMP_FREE(s);
2341
0
    SNMP_FREE(e);
2342
0
    SNMP_FREE(v);
2343
2344
0
    dump_idx_registry();
2345
0
}
2346
2347
/**  @} */
2348
/* End of MIB registration code */
2349
2350
2351
netsnmp_feature_child_of(register_signal, netsnmp_unused);
2352
#ifndef NETSNMP_FEATURE_REMOVE_REGISTER_SIGNAL
2353
2354
/** @defgroup agent_signals POSIX signals support for agents.
2355
 *     Registering and unregistering signal handlers.
2356
 *   @ingroup agent_registry
2357
 *
2358
 * @{
2359
 */
2360
2361
int             external_signal_scheduled[NUM_EXTERNAL_SIGS];
2362
void            (*external_signal_handler[NUM_EXTERNAL_SIGS]) (int);
2363
2364
#ifndef WIN32
2365
2366
/*
2367
 * TODO: add agent_SIGXXX_handler functions and `case SIGXXX: ...' lines
2368
 *       below for every single that might be handled by register_signal().
2369
 */
2370
2371
RETSIGTYPE
2372
agent_SIGCHLD_handler(int sig)
2373
0
{
2374
0
    external_signal_scheduled[SIGCHLD]++;
2375
#ifndef HAVE_SIGACTION
2376
    /*
2377
     * signal() sucks. It *might* have SysV semantics, which means that
2378
     * * a signal handler is reset once it gets called. Ensure that it
2379
     * * remains active.
2380
     */
2381
    signal(SIGCHLD, agent_SIGCHLD_handler);
2382
#endif
2383
0
}
2384
2385
/** Registers a POSIX Signal handler.
2386
 *  Implements the signal registering process for POSIX and non-POSIX
2387
 *  systems. Also, unifies the way signals work.
2388
 *  Note that the signal handler should register itself again with
2389
 *  signal() call before end of execution to prevent possible problems.
2390
 *
2391
 *  @param sig POSIX Signal ID number, as defined in signal.h.
2392
 *
2393
 *  @param func New signal handler function.
2394
 *
2395
 *  @return value is SIG_REGISTERED_OK for success and
2396
 *        SIG_REGISTRATION_FAILED if the registration can't
2397
 *        be handled.
2398
 */
2399
int
2400
register_signal(int sig, void (*func) (int))
2401
0
{
2402
2403
0
    switch (sig) {
2404
0
#if defined(SIGCHLD)
2405
0
    case SIGCHLD:
2406
0
#ifdef HAVE_SIGACTION
2407
0
        {
2408
0
            static struct sigaction act;
2409
0
            act.sa_handler = agent_SIGCHLD_handler;
2410
0
            sigemptyset(&act.sa_mask);
2411
0
            act.sa_flags = 0;
2412
0
            sigaction(SIGCHLD, &act, NULL);
2413
0
        }
2414
#else
2415
        signal(SIGCHLD, agent_SIGCHLD_handler);
2416
#endif
2417
0
        break;
2418
0
#endif
2419
0
    default:
2420
0
        snmp_log(LOG_CRIT,
2421
0
                 "register_signal: signal %d cannot be handled\n", sig);
2422
0
        return SIG_REGISTRATION_FAILED;
2423
0
    }
2424
2425
0
    external_signal_handler[sig] = func;
2426
0
    external_signal_scheduled[sig] = 0;
2427
2428
0
    DEBUGMSGTL(("register_signal", "registered signal %d\n", sig));
2429
0
    return SIG_REGISTERED_OK;
2430
0
}
2431
2432
/** Unregisters a POSIX Signal handler.
2433
 *
2434
 *  @param sig POSIX Signal ID number, as defined in signal.h.
2435
 *
2436
 *  @return value is SIG_UNREGISTERED_OK for success, or error code.
2437
 */
2438
int
2439
unregister_signal(int sig)
2440
0
{
2441
0
    signal(sig, SIG_DFL);
2442
0
    DEBUGMSGTL(("unregister_signal", "unregistered signal %d\n", sig));
2443
0
    return SIG_UNREGISTERED_OK;
2444
0
}
2445
2446
#endif                          /* !WIN32 */
2447
2448
/**  @} */
2449
/* End of signals support code */
2450
2451
#endif /* NETSNMP_FEATURE_REMOVE_REGISTER_SIGNAL */
2452
2453
/**  @} */
2454