Coverage Report

Created: 2023-09-25 06:12

/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
2.61k
#define SUBTREE_DEFAULT_CACHE_SIZE 8
89
/**  Lookup cache - max acceptable size.*/
90
47.1k
#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 chosing.  The
120
 */
121
void
122
49.7k
netsnmp_set_lookup_cache_size(int newsize) {
123
49.7k
    if (newsize < 0)
124
2.61k
        lookup_cache_size = SUBTREE_DEFAULT_CACHE_SIZE;
125
47.1k
    else if (newsize < SUBTREE_MAX_CACHE_SIZE)
126
47.1k
        lookup_cache_size = newsize;
127
0
    else
128
0
        lookup_cache_size = SUBTREE_MAX_CACHE_SIZE;
129
49.7k
}
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
23.5k
netsnmp_get_lookup_cache_size(void) {
138
23.5k
    return lookup_cache_size;
139
23.5k
}
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
40.4k
get_context_lookup_cache(const char *context) {
149
40.4k
    lookup_cache_context *ptr;
150
40.4k
    if (!context)
151
16.8k
        context = "";
152
153
40.4k
    for(ptr = thecontextcache; ptr; ptr = ptr->next) {
154
37.7k
        if (strcmp(ptr->context, context) == 0)
155
37.7k
            break;
156
37.7k
    }
157
40.4k
    if (!ptr) {
158
2.61k
        if (netsnmp_subtree_find_first(context)) {
159
2.61k
            ptr = SNMP_MALLOC_TYPEDEF(lookup_cache_context);
160
2.61k
            if (!ptr)
161
0
                return NULL;
162
2.61k
            ptr->next = thecontextcache;
163
2.61k
            ptr->context = strdup(context);
164
2.61k
            if (!ptr->context) {
165
0
                free(ptr);
166
0
                return NULL;
167
0
            }
168
2.61k
            thecontextcache = ptr;
169
2.61k
        } else {
170
0
            return NULL;
171
0
        }
172
2.61k
    }
173
40.4k
    return ptr;
174
40.4k
}
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
296
                 netsnmp_subtree *next, netsnmp_subtree *previous) {
187
296
    lookup_cache_context *cptr;
188
189
296
    if ((cptr = get_context_lookup_cache(context)) == NULL)
190
0
        return;
191
192
296
    if (cptr->thecachecount < lookup_cache_size)
193
296
        cptr->thecachecount++;
194
195
296
    cptr->cache[cptr->currentpos].next = next;
196
296
    cptr->cache[cptr->currentpos].previous = previous;
197
198
296
    if (++cptr->currentpos >= lookup_cache_size)
199
0
        cptr->currentpos = 0;
200
296
}
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
335
                     netsnmp_subtree *next, netsnmp_subtree *previous) {
214
215
335
    ptr->next = next;
216
335
    ptr->previous = previous;
217
335
}
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
8.69k
                  int *retcmp) {
237
8.69k
    lookup_cache_context *cptr;
238
8.69k
    lookup_cache *ret = NULL;
239
8.69k
    int cmp;
240
8.69k
    int i;
241
242
8.69k
    if ((cptr = get_context_lookup_cache(context)) == NULL)
243
0
        return NULL;
244
245
9.67k
    for(i = 0; i < cptr->thecachecount && i < lookup_cache_size; i++) {
246
986
        if (cptr->cache[i].previous->start_a)
247
986
            cmp = snmp_oid_compare(name, name_len,
248
986
                                   cptr->cache[i].previous->start_a,
249
986
                                   cptr->cache[i].previous->start_len);
250
0
        else
251
0
            cmp = 1;
252
986
        if (cmp >= 0) {
253
808
            *retcmp = cmp;
254
808
            ret = &(cptr->cache[i]);
255
808
        }
256
986
    }
257
8.69k
    return ret;
258
8.69k
}
259
260
/** @private
261
 *  Clears cache count and position in Lookup Cache.
262
 */
263
NETSNMP_STATIC_INLINE void
264
31.4k
invalidate_lookup_cache(const char *context) {
265
31.4k
    lookup_cache_context *cptr;
266
31.4k
    if ((cptr = get_context_lookup_cache(context)) != NULL) {
267
31.4k
        cptr->thecachecount = 0;
268
31.4k
        cptr->currentpos = 0;
269
31.4k
    }
270
31.4k
}
271
272
void
273
2.61k
clear_lookup_cache(void) {
274
275
2.61k
    lookup_cache_context *ptr = NULL, *next = NULL;
276
277
2.61k
    ptr = thecontextcache;
278
5.23k
    while (ptr) {
279
2.61k
  next = ptr->next;
280
2.61k
  SNMP_FREE(ptr->context);
281
2.61k
  SNMP_FREE(ptr);
282
2.61k
  ptr = next;
283
2.61k
    }
284
2.61k
    thecontextcache = NULL; /* !!! */
285
2.61k
}
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
2.61k
{
307
2.61k
    return context_subtrees;
308
2.61k
}
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
65.6k
{
319
65.6k
    subtree_context_cache *ptr;
320
321
65.6k
    if (!context_name) {
322
47.5k
        context_name = "";
323
47.5k
    }
324
325
65.6k
    DEBUGMSGTL(("subtree", "looking for subtree for context: \"%s\"\n", 
326
65.6k
    context_name));
327
65.6k
    for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) {
328
52.5k
        if (ptr->context_name != NULL && 
329
52.5k
      strcmp(ptr->context_name, context_name) == 0) {
330
52.5k
            DEBUGMSGTL(("subtree", "found one for: \"%s\"\n", context_name));
331
52.5k
            return ptr->first_subtree;
332
52.5k
        }
333
52.5k
    }
334
13.0k
    DEBUGMSGTL(("subtree", "didn't find a subtree for context: \"%s\"\n", 
335
13.0k
    context_name));
336
13.0k
    return NULL;
337
65.6k
}
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
2.61k
{
350
2.61k
    subtree_context_cache *ptr = SNMP_MALLOC_TYPEDEF(subtree_context_cache);
351
    
352
2.61k
    if (!context_name) {
353
0
        context_name = "";
354
0
    }
355
356
2.61k
    if (!ptr) {
357
0
        return NULL;
358
0
    }
359
    
360
2.61k
    DEBUGMSGTL(("subtree", "adding subtree for context: \"%s\"\n",  
361
2.61k
    context_name));
362
363
2.61k
    ptr->next = context_subtrees;
364
2.61k
    ptr->first_subtree = new_tree;
365
2.61k
    ptr->context_name = strdup(context_name);
366
2.61k
    if (!ptr->context_name) {
367
0
        free(ptr);
368
0
        return NULL;
369
0
    }
370
371
2.61k
    context_subtrees = ptr;
372
373
2.61k
    return ptr->first_subtree;
374
2.61k
}
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
5.23k
{
411
5.23k
    subtree_context_cache *ptr;
412
5.23k
    if (!context_name) {
413
2.61k
        context_name = "";
414
2.61k
    }
415
5.23k
    for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) {
416
2.61k
        if (ptr->context_name != NULL &&
417
2.61k
      strcmp(ptr->context_name, context_name) == 0) {
418
2.61k
            ptr->first_subtree = new_tree;
419
2.61k
            return ptr->first_subtree;
420
2.61k
        }
421
2.61k
    }
422
2.61k
    return add_subtree(new_tree, context_name);
423
5.23k
}
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
2.61k
clear_context(void) {
432
433
2.61k
    subtree_context_cache *ptr = NULL, *next = NULL;
434
2.61k
    netsnmp_subtree *t, *u;
435
436
2.61k
    DEBUGMSGTL(("agent_registry", "clear context\n"));
437
438
2.61k
    ptr = get_top_context_cache(); 
439
5.23k
    while (ptr) {
440
2.61k
  next = ptr->next;
441
442
2.61k
  for (t = ptr->first_subtree; t; t = u) {
443
0
            u = t->next;
444
0
      clear_subtree(t);
445
0
  }
446
447
2.61k
        free(NETSNMP_REMOVE_CONST(char*, ptr->context_name));
448
2.61k
        SNMP_FREE(ptr);
449
450
2.61k
  ptr = next;
451
2.61k
    }
452
2.61k
    context_subtrees = NULL; /* !!! */
453
2.61k
    clear_lookup_cache();
454
2.61k
}
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
15.7k
{
479
15.7k
  if (a != NULL) {
480
15.7k
    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
15.7k
    SNMP_FREE(a->name_a);
485
15.7k
    a->namelen = 0;
486
15.7k
    SNMP_FREE(a->start_a);
487
15.7k
    a->start_len = 0;
488
15.7k
    SNMP_FREE(a->end_a);
489
15.7k
    a->end_len = 0;
490
15.7k
    SNMP_FREE(a->label_a);
491
15.7k
    netsnmp_handler_registration_free(a->reginfo);
492
15.7k
    a->reginfo = NULL;
493
15.7k
    SNMP_FREE(a);
494
15.7k
  }
495
15.7k
}
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
18.3k
{
551
18.3k
    ptr->next = thenext;
552
18.3k
    if (thenext)
553
5.23k
        netsnmp_oid_compare_ll(ptr->start_a,
554
5.23k
                               ptr->start_len,
555
5.23k
                               thenext->start_a,
556
5.23k
                               thenext->start_len,
557
5.23k
                               &thenext->oid_off);
558
18.3k
}
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
7.85k
{
566
7.85k
    ptr->prev = theprev;
567
7.85k
    if (theprev)
568
5.23k
        netsnmp_oid_compare_ll(theprev->start_a,
569
5.23k
                               theprev->start_len,
570
5.23k
                               ptr->start_a,
571
5.23k
                               ptr->start_len,
572
5.23k
                               &ptr->oid_off);
573
7.85k
}
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
    /* Propogate 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
15.7k
{
771
15.7k
    netsnmp_subtree *tree1, *tree2;
772
15.7k
    netsnmp_subtree *prev, *next;
773
774
15.7k
    if (new_sub == NULL) {
775
0
        return MIB_REGISTERED_OK;       /* Degenerate case */
776
0
    }
777
778
15.7k
    if (!netsnmp_subtree_find_first(context_name)) {
779
5.23k
        static int inloop = 0;
780
5.23k
        if (!inloop) {
781
2.61k
            oid ccitt[1]           = { 0 };
782
2.61k
            oid iso[1]             = { 1 };
783
2.61k
            oid joint_ccitt_iso[1] = { 2 };
784
2.61k
            inloop = 1;
785
2.61k
            netsnmp_register_null_context(snmp_duplicate_objid(ccitt, 1), 1,
786
2.61k
                                          context_name);
787
2.61k
            netsnmp_register_null_context(snmp_duplicate_objid(iso, 1), 1,
788
2.61k
                                          context_name);
789
2.61k
            netsnmp_register_null_context(snmp_duplicate_objid(joint_ccitt_iso, 1),
790
2.61k
                                          1, context_name);
791
2.61k
            inloop = 0;
792
2.61k
        }
793
5.23k
    }
794
795
    /*  Find the subtree that contains the start of the new subtree (if
796
  any)...*/
797
798
15.7k
    tree1 = netsnmp_subtree_find(new_sub->start_a, new_sub->start_len, 
799
15.7k
         NULL, context_name);
800
801
    /*  ... and the subtree that follows the new one (NULL implies this is the
802
  final region covered).  */
803
804
15.7k
    if (tree1 == NULL) {
805
7.85k
  tree2 = netsnmp_subtree_find_next(new_sub->start_a, new_sub->start_len,
806
7.85k
            NULL, context_name);
807
7.85k
    } else {
808
7.85k
  tree2 = tree1->next;
809
7.85k
    }
810
811
    /*  Handle new subtrees that start in virgin territory.  */
812
813
15.7k
    if (tree1 == NULL) {
814
        /*netsnmp_subtree *new2 = NULL;*/
815
  /*  Is there any overlap with later subtrees?  */
816
7.85k
  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
7.85k
  if (tree2) {
826
0
            netsnmp_subtree_change_prev(new_sub, tree2->prev);
827
0
            netsnmp_subtree_change_prev(tree2, new_sub);
828
7.85k
  } else {
829
7.85k
            netsnmp_subtree_change_prev(new_sub,
830
7.85k
                                        netsnmp_subtree_find_prev(new_sub->start_a,
831
7.85k
                                                                  new_sub->start_len, NULL, context_name));
832
833
7.85k
      if (new_sub->prev) {
834
5.23k
                netsnmp_subtree_change_next(new_sub->prev, new_sub);
835
5.23k
      } else {
836
2.61k
    netsnmp_subtree_replace_first(new_sub, context_name);
837
2.61k
      }
838
839
7.85k
            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
7.85k
  }
851
7.85k
    } 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
7.85k
  if (netsnmp_oid_equals(new_sub->start_a, new_sub->start_len, 
857
7.85k
           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
7.85k
        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
7.85k
  switch (snmp_oid_compare(new_sub->end_a, new_sub->end_len,
878
7.85k
                                 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
7.85k
  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
7.85k
      prev = NULL;
892
7.85k
      next = tree1;
893
  
894
7.85k
      while (next && next->namelen > new_sub->namelen) {
895
0
    prev = next;
896
0
    next = next->children;
897
0
      }
898
899
7.85k
      while (next && next->namelen == new_sub->namelen &&
900
7.85k
       next->priority < new_sub->priority ) {
901
0
    prev = next;
902
0
    next = next->children;
903
0
      }
904
  
905
7.85k
      if (next && (next->namelen  == new_sub->namelen) &&
906
7.85k
    (next->priority == new_sub->priority)) {
907
7.85k
                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
7.85k
    return MIB_DUPLICATE_REGISTRATION;
925
7.85k
      }
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
7.85k
        }
961
7.85k
    }
962
7.85k
    return 0;
963
15.7k
}
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
47.9k
{
991
47.9k
    lookup_cache *lookup_cache = NULL;
992
47.9k
    netsnmp_subtree *myptr = NULL, *previous = NULL;
993
47.9k
    int cmp = 1;
994
47.9k
    size_t ll_off = 0;
995
996
47.9k
    if (subtree) {
997
7.85k
        myptr = subtree;
998
40.1k
    } else {
999
  /* look through everything */
1000
40.1k
        if (lookup_cache_size) {
1001
8.69k
            lookup_cache = lookup_cache_find(context_name, name, len, &cmp);
1002
8.69k
            if (lookup_cache) {
1003
628
                myptr = lookup_cache->next;
1004
628
                previous = lookup_cache->previous;
1005
628
            }
1006
8.69k
            if (!myptr)
1007
8.06k
                myptr = netsnmp_subtree_find_first(context_name);
1008
31.4k
        } else {
1009
31.4k
            myptr = netsnmp_subtree_find_first(context_name);
1010
31.4k
        }
1011
40.1k
    }
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
47.9k
#ifndef __alpha
1018
47.9k
#define WTEST_OPTIMIZATION 1
1019
47.9k
#endif
1020
47.9k
#ifdef WTEST_OPTIMIZATION
1021
47.9k
    DEBUGMSGTL(("wtest","oid in: "));
1022
47.9k
    DEBUGMSGOID(("wtest", name, len));
1023
47.9k
    DEBUGMSG(("wtest","\n"));
1024
47.9k
#endif
1025
119k
    for (; myptr != NULL; previous = myptr, myptr = myptr->next) {
1026
77.2k
#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
77.2k
        DEBUGMSGTL(("wtest","oid cmp: "));
1033
77.2k
        DEBUGMSGOID(("wtest", myptr->start_a, myptr->start_len));
1034
77.2k
        DEBUGMSG(("wtest","  --- off = %lu, in off = %lu test = %d\n",
1035
77.2k
                  (unsigned long)myptr->oid_off, (unsigned long)ll_off,
1036
77.2k
                  !(ll_off && myptr->oid_off &&
1037
77.2k
                    myptr->oid_off > ll_off)));
1038
77.2k
        if (!(ll_off && myptr->oid_off && myptr->oid_off > ll_off) &&
1039
77.2k
            netsnmp_oid_compare_ll(name, len,
1040
77.2k
                                   myptr->start_a, myptr->start_len,
1041
77.2k
                                   &ll_off) < 0) {
1042
#else
1043
        if (snmp_oid_compare(name, len, myptr->start_a, myptr->start_len) < 0) {
1044
#endif
1045
5.86k
            if (lookup_cache_size && previous && cmp) {
1046
631
                if (lookup_cache) {
1047
335
                    lookup_cache_replace(lookup_cache, myptr, previous);
1048
335
                } else {
1049
296
                    lookup_cache_add(context_name, myptr, previous);
1050
296
                }
1051
631
            }
1052
5.86k
            return previous;
1053
5.86k
        }
1054
77.2k
    }
1055
42.0k
    return previous;
1056
47.9k
}
1057
1058
netsnmp_subtree *
1059
netsnmp_subtree_find_next(const oid *name, size_t len,
1060
        netsnmp_subtree *subtree, const char *context_name)
1061
7.85k
{
1062
7.85k
    netsnmp_subtree *myptr = NULL;
1063
1064
7.85k
    myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name);
1065
1066
7.85k
    if (myptr != NULL) {
1067
5.23k
        myptr = myptr->next;
1068
5.23k
        while (myptr != NULL && (myptr->variables == NULL || 
1069
0
         myptr->variables_len == 0)) {
1070
0
            myptr = myptr->next;
1071
0
        }
1072
5.23k
        return myptr;
1073
5.23k
    } else if (subtree != NULL && snmp_oid_compare(name, len, 
1074
0
           subtree->start_a, subtree->start_len) < 0) {
1075
0
        return subtree;
1076
2.61k
    } else {
1077
2.61k
        return NULL;
1078
2.61k
    }
1079
7.85k
}
1080
1081
netsnmp_subtree *
1082
netsnmp_subtree_find(const oid *name, size_t len, netsnmp_subtree *subtree, 
1083
         const char *context_name)
1084
32.2k
{
1085
32.2k
    netsnmp_subtree *myptr;
1086
1087
32.2k
    myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name);
1088
32.2k
    if (myptr && myptr->end_a &&
1089
32.2k
        snmp_oid_compare(name, len, myptr->end_a, myptr->end_len)<0) {
1090
24.4k
        return myptr;
1091
24.4k
    }
1092
1093
7.85k
    return NULL;
1094
32.2k
}
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
15.7k
{
1149
15.7k
    netsnmp_subtree *subtree, *sub2;
1150
15.7k
    int             res;
1151
15.7k
    struct register_parameters reg_parms;
1152
15.7k
    int old_lookup_cache_val = netsnmp_get_lookup_cache_size();
1153
1154
15.7k
    if (moduleName == NULL ||
1155
15.7k
        mibloc     == NULL) {
1156
        /* Shouldn't happen ??? */
1157
0
        netsnmp_handler_registration_free(reginfo);
1158
0
        return MIB_REGISTRATION_FAILED;
1159
0
    }
1160
15.7k
    subtree = calloc(1, sizeof(netsnmp_subtree));
1161
15.7k
    if (subtree == NULL) {
1162
0
        netsnmp_handler_registration_free(reginfo);
1163
0
        return MIB_REGISTRATION_FAILED;
1164
0
    }
1165
1166
15.7k
    DEBUGMSGTL(("register_mib", "registering \"%s\" at ", moduleName));
1167
15.7k
    DEBUGMSGOIDRANGE(("register_mib", mibloc, mibloclen, range_subid,
1168
15.7k
                      range_ubound));
1169
15.7k
    DEBUGMSG(("register_mib", " with context \"%s\"\n",
1170
15.7k
              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
15.7k
    if( ((NULL == context) && (NULL != reginfo->contextName)) ||
1179
15.7k
        ((NULL != context) && (NULL == reginfo->contextName)) ||
1180
15.7k
        ( ((NULL != context) && (NULL != reginfo->contextName)) &&
1181
15.7k
          (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
15.7k
    subtree->reginfo = reginfo;
1191
15.7k
    subtree->name_a  = snmp_duplicate_objid(mibloc, mibloclen);
1192
15.7k
    subtree->start_a = snmp_duplicate_objid(mibloc, mibloclen);
1193
15.7k
    subtree->end_a   = snmp_duplicate_objid(mibloc, mibloclen);
1194
15.7k
    subtree->label_a = strdup(moduleName);
1195
15.7k
    if (subtree->name_a == NULL || subtree->start_a == NULL || 
1196
15.7k
  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
15.7k
    subtree->namelen   = (u_char)mibloclen;
1201
15.7k
    subtree->start_len = (u_char)mibloclen;
1202
15.7k
    subtree->end_len   = (u_char)mibloclen;
1203
15.7k
    subtree->end_a[mibloclen - 1]++;
1204
1205
15.7k
    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
15.7k
    subtree->priority = priority;
1216
15.7k
    subtree->timeout = timeout;
1217
15.7k
    subtree->range_subid = range_subid;
1218
15.7k
    subtree->range_ubound = range_ubound;
1219
15.7k
    subtree->session = ss;
1220
15.7k
    subtree->flags = (u_char)flags;    /*  used to identify instance oids  */
1221
15.7k
    subtree->flags |= SUBTREE_ATTACHED;
1222
15.7k
    subtree->global_cacheid = reginfo->global_cacheid;
1223
1224
15.7k
    netsnmp_set_lookup_cache_size(0);
1225
15.7k
    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
15.7k
    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
15.7k
    } else if (res == MIB_DUPLICATE_REGISTRATION ||
1266
15.7k
               res == MIB_REGISTRATION_FAILED) {
1267
7.85k
        netsnmp_set_lookup_cache_size(old_lookup_cache_val);
1268
7.85k
        invalidate_lookup_cache(context);
1269
7.85k
        netsnmp_subtree_free(subtree);
1270
7.85k
        return res;
1271
7.85k
    }
1272
1273
    /*
1274
     * mark the MIB as detached, if there's no master agent present as of now 
1275
     */
1276
7.85k
    if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
1277
7.85k
             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
7.85k
    if (res == MIB_REGISTERED_OK && perform_callback) {
1284
7.85k
        memset(&reg_parms, 0x0, sizeof(reg_parms));
1285
7.85k
        reg_parms.name = mibloc;
1286
7.85k
        reg_parms.namelen = mibloclen;
1287
7.85k
        reg_parms.priority = priority;
1288
7.85k
        reg_parms.range_subid = range_subid;
1289
7.85k
        reg_parms.range_ubound = range_ubound;
1290
7.85k
        reg_parms.timeout = timeout;
1291
7.85k
        reg_parms.flags = (u_char) flags;
1292
7.85k
        reg_parms.session = ss;
1293
7.85k
        reg_parms.reginfo = reginfo;
1294
7.85k
        reg_parms.contextName = context;
1295
7.85k
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
1296
7.85k
                            SNMPD_CALLBACK_REGISTER_OID, &reg_parms);
1297
7.85k
    }
1298
1299
7.85k
    netsnmp_set_lookup_cache_size(old_lookup_cache_val);
1300
7.85k
    invalidate_lookup_cache(context);
1301
7.85k
    return res;
1302
15.7k
}
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
7.85k
{
1614
7.85k
    netsnmp_subtree *ptr;
1615
1616
7.85k
    DEBUGMSGTL(("register_mib", "unload("));
1617
7.85k
    if (sub != NULL) {
1618
7.85k
        DEBUGMSGOID(("register_mib", sub->start_a, sub->start_len));
1619
7.85k
    } else {
1620
0
        DEBUGMSG(("register_mib", "[NIL]"));
1621
0
        return;
1622
0
    }
1623
7.85k
    DEBUGMSG(("register_mib", ", "));
1624
7.85k
    if (prev != NULL) {
1625
0
        DEBUGMSGOID(("register_mib", prev->start_a, prev->start_len));
1626
7.85k
    } else {
1627
7.85k
        DEBUGMSG(("register_mib", "[NIL]"));
1628
7.85k
    }
1629
7.85k
    DEBUGMSG(("register_mib", ")\n"));
1630
1631
7.85k
    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
7.85k
    if (sub->children == NULL) {        /* just remove this node completely */
1641
13.0k
        for (ptr = sub->prev; ptr; ptr = ptr->children) {
1642
5.23k
            netsnmp_subtree_change_next(ptr, sub->next);
1643
5.23k
        }
1644
7.85k
        for (ptr = sub->next; ptr; ptr = ptr->children) {
1645
0
            netsnmp_subtree_change_prev(ptr, sub->prev);
1646
0
        }
1647
1648
7.85k
  if (sub->prev == NULL) {
1649
2.61k
      netsnmp_subtree_replace_first(sub->next, context);
1650
2.61k
  }
1651
1652
7.85k
    } 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
7.85k
    invalidate_lookup_cache(context);
1663
7.85k
}
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 conatins 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
7.85k
{
1702
7.85k
    netsnmp_subtree *list, *myptr = NULL;
1703
7.85k
    netsnmp_subtree *prev, *child, *next; /* loop through children */
1704
7.85k
    struct register_parameters reg_parms;
1705
7.85k
    int old_lookup_cache_val = netsnmp_get_lookup_cache_size();
1706
7.85k
    int unregistering = 1;
1707
7.85k
    int orig_subid_val = -1;
1708
1709
7.85k
    netsnmp_set_lookup_cache_size(0);
1710
1711
7.85k
    if ((range_subid > 0) &&  ((size_t)range_subid <= len))
1712
0
        orig_subid_val = name[range_subid-1];
1713
1714
15.7k
    while(unregistering){
1715
7.85k
        DEBUGMSGTL(("register_mib", "unregistering "));
1716
7.85k
        DEBUGMSGOIDRANGE(("register_mib", name, len, range_subid, range_ubound));
1717
7.85k
        DEBUGMSG(("register_mib", "\n"));
1718
1719
7.85k
        list = netsnmp_subtree_find(name, len, netsnmp_subtree_find_first(context),
1720
7.85k
                    context);
1721
7.85k
        if (list == NULL) {
1722
0
            return MIB_NO_SUCH_REGISTRATION;
1723
0
        }
1724
1725
7.85k
        for (child = list, prev = NULL; child != NULL;
1726
7.85k
            prev = child, child = child->children) {
1727
7.85k
            if (netsnmp_oid_equals(child->name_a, child->namelen, name, len) == 0 &&
1728
7.85k
                child->priority == priority) {
1729
7.85k
                break;              /* found it */
1730
7.85k
             }
1731
7.85k
        }
1732
1733
7.85k
        if (child == NULL) {
1734
0
            return MIB_NO_SUCH_REGISTRATION;
1735
0
        }
1736
1737
7.85k
        netsnmp_subtree_unload(child, prev, context);
1738
7.85k
        myptr = child;              /* remember this for later */
1739
1740
        /*
1741
        *  Now handle any occurances 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
7.85k
        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
7.85k
        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
7.85k
        else {
1775
7.85k
            unregistering=0;
1776
7.85k
        }
1777
7.85k
    }
1778
1779
7.85k
    memset(&reg_parms, 0x0, sizeof(reg_parms));
1780
7.85k
    reg_parms.name = name;
1781
7.85k
    reg_parms.namelen = len;
1782
7.85k
    reg_parms.priority = priority;
1783
7.85k
    reg_parms.range_subid = range_subid;
1784
7.85k
    reg_parms.range_ubound = range_ubound;
1785
7.85k
    reg_parms.flags = 0x00;     /*  this is okay I think  */
1786
7.85k
    reg_parms.contextName = context;
1787
7.85k
    snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
1788
7.85k
                        SNMPD_CALLBACK_UNREGISTER_OID, &reg_parms);
1789
1790
7.85k
    netsnmp_subtree_free(myptr);
1791
7.85k
    netsnmp_set_lookup_cache_size(old_lookup_cache_val);
1792
7.85k
    invalidate_lookup_cache(context);
1793
7.85k
    return MIB_UNREGISTERED_OK;
1794
7.85k
}
1795
1796
#ifndef NETSNMP_FEATURE_REMOVE_UNREGISTER_MIB_TABLE_ROW
1797
int
1798
netsnmp_unregister_mib_table_row(oid * name, size_t len, int priority,
1799
                                 int var_subid, oid range_ubound,
1800
                                 const char *context)
1801
0
{
1802
0
    netsnmp_subtree *list, *myptr, *futureptr;
1803
0
    netsnmp_subtree *prev, *child;       /* loop through children */
1804
0
    struct register_parameters reg_parms;
1805
0
    oid             range_lbound = name[var_subid - 1];
1806
1807
0
    DEBUGMSGTL(("register_mib", "unregistering "));
1808
0
    DEBUGMSGOIDRANGE(("register_mib", name, len, var_subid, range_ubound));
1809
0
    DEBUGMSG(("register_mib", "\n"));
1810
1811
0
    for (; name[var_subid - 1] <= range_ubound; name[var_subid - 1]++) {
1812
0
        list = netsnmp_subtree_find(name, len, 
1813
0
        netsnmp_subtree_find_first(context), context);
1814
1815
0
        if (list == NULL) {
1816
0
            continue;
1817
0
        }
1818
1819
0
        for (child = list, prev = NULL; child != NULL;
1820
0
             prev = child, child = child->children) {
1821
1822
0
            if (netsnmp_oid_equals(child->name_a, child->namelen, 
1823
0
         name, len) == 0 && 
1824
0
    (child->priority == priority)) {
1825
0
                break;          /* found it */
1826
0
            }
1827
0
        }
1828
1829
0
        if (child == NULL) {
1830
0
            continue;
1831
0
        }
1832
1833
0
        netsnmp_subtree_unload(child, prev, context);
1834
0
        myptr = child;          /* remember this for later */
1835
1836
0
        for (list = myptr->next; list != NULL; list = futureptr) {
1837
            /* remember the next spot in the list in case we free this node */
1838
0
            futureptr = list->next;
1839
1840
            /* check each child */
1841
0
            for (child = list, prev = NULL; child != NULL;
1842
0
                 prev = child, child = child->children) {
1843
1844
0
                if (netsnmp_oid_equals(child->name_a, child->namelen, 
1845
0
              name, len) == 0 &&
1846
0
                    (child->priority == priority)) {
1847
0
                    netsnmp_subtree_unload(child, prev, context);
1848
0
                    netsnmp_subtree_free(child);
1849
0
                    break;
1850
0
                }
1851
0
            }
1852
1853
            /* XXX: wjh: not sure why we're bailing here */
1854
0
            if (child == NULL) {        /* Didn't find the given name */
1855
0
                break;
1856
0
            }
1857
0
        }
1858
0
        netsnmp_subtree_free(myptr);
1859
0
    }
1860
1861
0
    name[var_subid - 1] = range_lbound;
1862
0
    memset(&reg_parms, 0x0, sizeof(reg_parms));
1863
0
    reg_parms.name = name;
1864
0
    reg_parms.namelen = len;
1865
0
    reg_parms.priority = priority;
1866
0
    reg_parms.range_subid = var_subid;
1867
0
    reg_parms.range_ubound = range_ubound;
1868
0
    reg_parms.flags = 0x00;     /*  this is okay I think  */
1869
0
    reg_parms.contextName = context;
1870
0
    snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
1871
0
                        SNMPD_CALLBACK_UNREGISTER_OID, &reg_parms);
1872
1873
0
    return 0;
1874
0
}
1875
#endif /* NETSNMP_FEATURE_REMOVE_UNREGISTER_MIB_TABLE_ROW */
1876
1877
/**
1878
 * Unregisters a module registered against a given OID (or range) in the default context. 
1879
 * Typically used when a module has multiple contexts defined.
1880
 * The parameters priority, range_subid, and range_ubound should
1881
 * match those used to register the module originally.
1882
 *
1883
 * @param name  the specific OID to unregister if it conatins the associated
1884
 *              context.
1885
 *
1886
 * @param len   the length of the OID, use  OID_LENGTH macro.
1887
 *
1888
 * @param priority  a value between 1 and 255, used to achieve a desired
1889
 *                  configuration when different sessions register identical or
1890
 *                  overlapping regions.  Subagents with no particular
1891
 *                  knowledge of priority should register with the default
1892
 *                  value of 127.
1893
 *
1894
 * @param range_subid  permits specifying a range in place of one of a subtree
1895
 *                     sub-identifiers.  When this value is zero, no range is
1896
 *                     being specified.
1897
 *
1898
 * @param range_ubound  the upper bound of a sub-identifier's range.
1899
 *                      This field is present only if range_subid is not 0.
1900
 *
1901
 * @return gives MIB_UNREGISTERED_OK or MIB_* error code.
1902
 * 
1903
 * @see unregister_mib()
1904
 * @see unregister_mib_priority()
1905
 * @see unregister_mib_context()
1906
 */
1907
int
1908
unregister_mib_range(oid * name, size_t len, int priority,
1909
                     int range_subid, oid range_ubound)
1910
0
{
1911
0
    return unregister_mib_context(name, len, priority, range_subid,
1912
0
                                  range_ubound, "");
1913
0
}
1914
1915
/**
1916
 * Unregisters a module registered against a given OID at the specified priority.
1917
 * The priority parameter should match that used to register the module originally.
1918
 *
1919
 * @param name  the specific OID to unregister if it conatins the associated
1920
 *              context.
1921
 *
1922
 * @param len   the length of the OID, use  OID_LENGTH macro.
1923
 *
1924
 * @param priority  a value between 1 and 255, used to achieve a desired
1925
 *                  configuration when different sessions register identical or
1926
 *                  overlapping regions.  Subagents with no particular
1927
 *                  knowledge of priority should register with the default
1928
 *                  value of 127.
1929
 *
1930
 * @return gives MIB_UNREGISTERED_OK or MIB_* error code.
1931
 * 
1932
 * @see unregister_mib()
1933
 * @see unregister_mib_range()
1934
 * @see unregister_mib_context()
1935
 */
1936
int
1937
unregister_mib_priority(oid * name, size_t len, int priority)
1938
0
{
1939
0
    return unregister_mib_range(name, len, priority, 0, 0);
1940
0
}
1941
1942
/**
1943
 * Unregisters a module registered against a given OID at the default priority.
1944
 *
1945
 * @param name  the specific OID to unregister if it conatins the associated
1946
 *              context.
1947
 *
1948
 * @param len   the length of the OID, use  OID_LENGTH macro.
1949
 *
1950
 * @return gives MIB_UNREGISTERED_OK or MIB_* error code.
1951
 * 
1952
 * @see unregister_mib_priority()
1953
 * @see unregister_mib_context()
1954
 * @see unregister_mib_range()
1955
 * @see unregister_agentx_list()
1956
 */
1957
int
1958
unregister_mib(oid * name, size_t len)
1959
0
{
1960
0
    return unregister_mib_priority(name, len, DEFAULT_MIB_PRIORITY);
1961
0
}
1962
1963
/** Unregisters subtree of OIDs bounded to given session.
1964
 *
1965
 *  @param ss Session which OIDs will be removed from tree.
1966
 *
1967
 *  @see unregister_mib()
1968
 *  @see unregister_agentx_list()
1969
 */
1970
void
1971
unregister_mibs_by_session(netsnmp_session * ss)
1972
0
{
1973
0
    netsnmp_subtree *list, *list2;
1974
0
    netsnmp_subtree *child, *prev, *next_child;
1975
0
    struct register_parameters rp;
1976
0
    subtree_context_cache *contextptr;
1977
1978
0
    DEBUGMSGTL(("register_mib", "unregister_mibs_by_session(%p) ctxt \"%s\"\n",
1979
0
    ss, (ss && ss->contextName) ? ss->contextName : "[NIL]"));
1980
1981
0
    for (contextptr = get_top_context_cache(); contextptr != NULL;
1982
0
         contextptr = contextptr->next) {
1983
0
        for (list = contextptr->first_subtree; list != NULL; list = list2) {
1984
0
            list2 = list->next;
1985
1986
0
            for (child = list, prev = NULL; child != NULL; child = next_child){
1987
0
                next_child = child->children;
1988
1989
0
                if (((!ss || ss->flags & SNMP_FLAGS_SUBSESSION) &&
1990
0
         child->session == ss) ||
1991
0
                    (!(!ss || ss->flags & SNMP_FLAGS_SUBSESSION) && child->session &&
1992
0
                     child->session->subsession == ss)) {
1993
1994
0
                    memset(&rp,0x0,sizeof(rp));
1995
0
                    rp.name = child->name_a;
1996
0
        child->name_a = NULL;
1997
0
                    rp.namelen = child->namelen;
1998
0
                    rp.priority = child->priority;
1999
0
                    rp.range_subid = child->range_subid;
2000
0
                    rp.range_ubound = child->range_ubound;
2001
0
                    rp.timeout = child->timeout;
2002
0
                    rp.flags = child->flags;
2003
0
                    if ((NULL != child->reginfo) &&
2004
0
                        (NULL != child->reginfo->contextName))
2005
0
                        rp.contextName = child->reginfo->contextName;
2006
2007
0
                    if (child->reginfo != NULL) {
2008
                        /*
2009
                         * Don't let's free the session pointer just yet!  
2010
                         */
2011
0
                        child->reginfo->handler->myvoid = NULL;
2012
0
                        netsnmp_handler_registration_free(child->reginfo);
2013
0
      child->reginfo = NULL;
2014
0
                    }
2015
2016
0
                    netsnmp_subtree_unload(child, prev, contextptr->context_name);
2017
0
                    netsnmp_subtree_free(child);
2018
2019
0
                    snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
2020
0
                                        SNMPD_CALLBACK_UNREGISTER_OID, &rp);
2021
0
        SNMP_FREE(rp.name);
2022
0
                } else {
2023
0
                    prev = child;
2024
0
                }
2025
0
            }
2026
0
        }
2027
0
        netsnmp_subtree_join(contextptr->first_subtree);
2028
0
    }
2029
0
}
2030
2031
/** Determines if given PDU is allowed to see (or update) a given OID.
2032
 *
2033
 * @param name    The OID to check access for.
2034
 *                On return, this parameter holds the OID actually matched
2035
 *
2036
 * @param namelen Number of sub-identifiers in the OID.
2037
 *                On return, this parameter holds the length of the matched OID
2038
 *
2039
 * @param pdu     PDU requesting access to the OID.
2040
 *
2041
 * @param type    ANS.1 type of the value at given OID.
2042
 *                (Used for catching SNMPv1 requests for SMIv2-only objects)
2043
 *
2044
 * @return gives VACM_SUCCESS if the OID is in the PDU, otherwise error code.
2045
 */
2046
int
2047
in_a_view(oid *name, size_t *namelen, netsnmp_pdu *pdu, int type)
2048
498
{
2049
498
    struct view_parameters view_parms;
2050
2051
498
    if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
2052
  /* Enable bypassing of view-based access control */
2053
498
        return VACM_SUCCESS;
2054
498
    }
2055
2056
    /*
2057
     * check for v1 and counter64s, since snmpv1 doesn't support it 
2058
     */
2059
0
#ifndef NETSNMP_DISABLE_SNMPV1
2060
0
    if (pdu->version == SNMP_VERSION_1 && type == ASN_COUNTER64) {
2061
0
        return VACM_NOTINVIEW;
2062
0
    }
2063
0
#endif
2064
2065
0
    view_parms.pdu = pdu;
2066
0
    view_parms.name = name;
2067
0
    if (namelen != NULL) {
2068
0
        view_parms.namelen = *namelen;
2069
0
    } else {
2070
0
        view_parms.namelen = 0;
2071
0
    }
2072
0
    view_parms.errorcode = 0;
2073
0
    view_parms.check_subtree = 0;
2074
2075
0
    switch (pdu->version) {
2076
0
#ifndef NETSNMP_DISABLE_SNMPV1
2077
0
    case SNMP_VERSION_1:
2078
0
#endif
2079
0
#ifndef NETSNMP_DISABLE_SNMPV2C
2080
0
    case SNMP_VERSION_2c:
2081
0
#endif
2082
0
   case SNMP_VERSION_3:
2083
0
        NETSNMP_RUNTIME_PROTOCOL_CHECK(pdu->version,unsupported_version);
2084
0
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
2085
0
                            SNMPD_CALLBACK_ACM_CHECK, &view_parms);
2086
0
        return view_parms.errorcode;
2087
0
    }
2088
0
  unsupported_version:
2089
0
    return VACM_NOSECNAME;
2090
0
}
2091
2092
/** Determines if the given PDU request could potentially succeed.
2093
 *  (Preliminary, OID-independent validation)
2094
 *
2095
 * @param pdu     PDU requesting access
2096
 *
2097
 * @return gives VACM_SUCCESS   if the entire MIB tree is accessible
2098
 *               VACM_NOTINVIEW if the entire MIB tree is inaccessible
2099
 *               VACM_SUBTREE_UNKNOWN if some portions are accessible
2100
 *               other codes may returned on error
2101
 */
2102
int
2103
check_access(netsnmp_pdu *pdu)
2104
9.84k
{                               /* IN - pdu being checked */
2105
9.84k
    struct view_parameters view_parms;
2106
9.84k
    view_parms.pdu = pdu;
2107
9.84k
    view_parms.name = NULL;
2108
9.84k
    view_parms.namelen = 0;
2109
9.84k
    view_parms.errorcode = 0;
2110
9.84k
    view_parms.check_subtree = 0;
2111
2112
9.84k
    if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
2113
  /* Enable bypassing of view-based access control */
2114
9.84k
        return 0;
2115
9.84k
    }
2116
2117
0
    switch (pdu->version) {
2118
0
#ifndef NETSNMP_DISABLE_SNMPV1
2119
0
    case SNMP_VERSION_1:
2120
0
#endif
2121
0
#ifndef NETSNMP_DISABLE_SNMPV2C
2122
0
    case SNMP_VERSION_2c:
2123
0
#endif
2124
0
    case SNMP_VERSION_3:
2125
0
        NETSNMP_RUNTIME_PROTOCOL_CHECK(pdu->version,unsupported_version);
2126
0
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
2127
0
                            SNMPD_CALLBACK_ACM_CHECK_INITIAL, &view_parms);
2128
0
        return view_parms.errorcode;
2129
0
    }
2130
0
  unsupported_version:
2131
0
    return 1;
2132
0
}
2133
2134
/** Determines if the given PDU request could potentially access
2135
 *   the specified MIB subtree
2136
 *
2137
 * @param pdu     PDU requesting access
2138
 *
2139
 * @param name    The OID to check access for.
2140
 *
2141
 * @param namelen Number of sub-identifiers in the OID.
2142
 *
2143
 * @return gives VACM_SUCCESS   if the entire MIB tree is accessible
2144
 *               VACM_NOTINVIEW if the entire MIB tree is inaccessible
2145
 *               VACM_SUBTREE_UNKNOWN if some portions are accessible
2146
 *               other codes may returned on error
2147
 */
2148
int
2149
netsnmp_acm_check_subtree(netsnmp_pdu *pdu, oid *name, size_t namelen)
2150
0
{                               /* IN - pdu being checked */
2151
0
    struct view_parameters view_parms;
2152
0
    view_parms.pdu = pdu;
2153
0
    view_parms.name = name;
2154
0
    view_parms.namelen = namelen;
2155
0
    view_parms.errorcode = 0;
2156
0
    view_parms.check_subtree = 1;
2157
2158
0
    if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
2159
  /* Enable bypassing of view-based access control */
2160
0
        return 0;
2161
0
    }
2162
2163
0
    switch (pdu->version) {
2164
0
#ifndef NETSNMP_DISABLE_SNMPV1
2165
0
    case SNMP_VERSION_1:
2166
0
#endif
2167
0
#ifndef NETSNMP_DISABLE_SNMPV2C
2168
0
    case SNMP_VERSION_2c:
2169
0
#endif
2170
0
    case SNMP_VERSION_3:
2171
0
        NETSNMP_RUNTIME_PROTOCOL_CHECK(pdu->version,unsupported_version);
2172
0
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
2173
0
                            SNMPD_CALLBACK_ACM_CHECK_SUBTREE, &view_parms);
2174
0
        return view_parms.errorcode;
2175
0
    }
2176
0
  unsupported_version:
2177
0
    return 1;
2178
0
}
2179
2180
netsnmp_feature_child_of(get_session_for_oid,netsnmp_unused);
2181
#ifndef NETSNMP_FEATURE_REMOVE_GET_SESSION_FOR_OID
2182
netsnmp_session *
2183
get_session_for_oid(const oid *name, size_t len, const char *context_name)
2184
0
{
2185
0
    netsnmp_subtree *myptr;
2186
2187
0
    myptr = netsnmp_subtree_find_prev(name, len, 
2188
0
              netsnmp_subtree_find_first(context_name),
2189
0
              context_name);
2190
2191
0
    while (myptr && myptr->variables == NULL) {
2192
0
        myptr = myptr->next;
2193
0
    }
2194
2195
0
    if (myptr == NULL) {
2196
0
        return NULL;
2197
0
    } else {
2198
0
        return myptr->session;
2199
0
    }
2200
0
}
2201
#endif /* NETSNMP_FEATURE_REMOVE_GET_SESSION_FOR_OID */
2202
2203
void
2204
setup_tree(void)
2205
2.61k
{
2206
2.61k
    oid ccitt[1]           = { 0 };
2207
2.61k
    oid iso[1]             = { 1 };
2208
2.61k
    oid joint_ccitt_iso[1] = { 2 };
2209
2210
2.61k
#ifdef USING_AGENTX_SUBAGENT_MODULE
2211
2.61k
    int role =  netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
2212
2.61k
               NETSNMP_DS_AGENT_ROLE);
2213
2214
2.61k
    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 
2215
2.61k
         MASTER_AGENT);
2216
2.61k
#endif
2217
2218
    /* 
2219
     * we need to have the oid's in the heap, that we can *free* it for every case, 
2220
     * thats the purpose of the duplicate_objid's
2221
     */
2222
2.61k
    netsnmp_register_null(snmp_duplicate_objid(ccitt, 1), 1);
2223
2.61k
    netsnmp_register_null(snmp_duplicate_objid(iso, 1), 1);
2224
2.61k
    netsnmp_register_null(snmp_duplicate_objid(joint_ccitt_iso, 1), 1);
2225
2226
2.61k
#ifdef USING_AGENTX_SUBAGENT_MODULE
2227
2.61k
    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 
2228
2.61k
         role);
2229
2.61k
#endif
2230
2.61k
}
2231
2232
int 
2233
7.85k
remove_tree_entry (oid *name, size_t len) {
2234
2235
7.85k
    netsnmp_subtree *sub = NULL;
2236
2237
7.85k
    if ((sub = netsnmp_subtree_find(name, len, NULL, "")) == NULL) {
2238
0
  return MIB_NO_SUCH_REGISTRATION;
2239
0
    }
2240
2241
7.85k
    return unregister_mib_context(name, len, sub->priority,
2242
7.85k
          sub->range_subid, sub->range_ubound, "");
2243
2244
7.85k
}
2245
2246
2247
void
2248
2.61k
shutdown_tree(void) {
2249
2.61k
    oid ccitt[1]           = { 0 };
2250
2.61k
    oid iso[1]             = { 1 };
2251
2.61k
    oid joint_ccitt_iso[1] = { 2 };
2252
2253
2.61k
    DEBUGMSGTL(("agent_registry", "shut down tree\n"));
2254
2255
2.61k
    remove_tree_entry(joint_ccitt_iso, 1);
2256
2.61k
    remove_tree_entry(iso, 1);
2257
2.61k
    remove_tree_entry(ccitt, 1);
2258
2259
2.61k
}
2260
2261
void
2262
dump_registry(void)
2263
0
{
2264
0
    struct variable *vp = NULL;
2265
0
    netsnmp_subtree *myptr, *myptr2;
2266
0
    u_char *s = NULL, *e = NULL, *v = NULL;
2267
0
    size_t sl = 256, el = 256, vl = 256, sl_o = 0, el_o = 0, vl_o = 0;
2268
0
    int i = 0;
2269
2270
0
    if ((s = calloc(sl, 1)) != NULL &&
2271
0
        (e = calloc(sl, 1)) != NULL &&
2272
0
        (v = calloc(sl, 1)) != NULL) {
2273
2274
0
        subtree_context_cache *ptr;
2275
0
        for (ptr = context_subtrees; ptr; ptr = ptr->next) {
2276
0
            printf("Subtrees for Context: %s\n", ptr->context_name);
2277
0
            for (myptr = ptr->first_subtree; myptr != NULL;
2278
0
                 myptr = myptr->next) {
2279
0
                sl_o = el_o = vl_o = 0;
2280
2281
0
                if (!sprint_realloc_objid(&s, &sl, &sl_o, 1,
2282
0
                                          myptr->start_a,
2283
0
                                          myptr->start_len)) {
2284
0
                    break;
2285
0
                }
2286
0
                if (!sprint_realloc_objid(&e, &el, &el_o, 1,
2287
0
                                          myptr->end_a,
2288
0
            myptr->end_len)) {
2289
0
                    break;
2290
0
                }
2291
2292
0
                if (myptr->variables) {
2293
0
                    printf("%02x ( %s - %s ) [", myptr->flags, s, e);
2294
0
                    for (i = 0, vp = myptr->variables;
2295
0
                         i < myptr->variables_len; i++) {
2296
0
                        vl_o = 0;
2297
0
                        if (!sprint_realloc_objid
2298
0
                            (&v, &vl, &vl_o, 1, vp->name, vp->namelen)) {
2299
0
                            break;
2300
0
                        }
2301
0
                        printf("%s, ", v);
2302
0
                        vp = (struct variable *) ((char *) vp +
2303
0
                                                  myptr->variables_width);
2304
0
                    }
2305
0
                    printf("]\n");
2306
0
                } else {
2307
0
                    printf("%02x   %s - %s  \n", myptr->flags, s, e);
2308
0
                }
2309
0
                for (myptr2 = myptr; myptr2 != NULL;
2310
0
                     myptr2 = myptr2->children) {
2311
0
                    if (myptr2->label_a && myptr2->label_a[0]) {
2312
0
                        if (strcmp(myptr2->label_a, "old_api") == 0) {
2313
0
                            struct variable *vp =
2314
0
                                (struct variable*)myptr2->reginfo->handler->myvoid;
2315
2316
0
                            if (!sprint_realloc_objid(&s, &sl, &sl_o, 1,
2317
0
                                                 vp->name, vp->namelen)) {
2318
0
                                continue;
2319
0
                            }
2320
0
                            printf("\t%s[%s] %p var %s\n", myptr2->label_a,
2321
0
                                   myptr2->reginfo->handlerName ?
2322
0
                                   myptr2->reginfo->handlerName : "no-name",
2323
0
                                   myptr2->reginfo, s);
2324
0
                        } else {
2325
0
                            printf("\t%s %s %p\n", myptr2->label_a,
2326
0
                                   myptr2->reginfo->handlerName ?
2327
0
                                   myptr2->reginfo->handlerName : "no-handler-name",
2328
0
                                   myptr2->reginfo);
2329
0
                        }
2330
0
                    }
2331
0
                }
2332
0
            }
2333
0
        }
2334
0
    }
2335
2336
0
    SNMP_FREE(s);
2337
0
    SNMP_FREE(e);
2338
0
    SNMP_FREE(v);
2339
2340
0
    dump_idx_registry();
2341
0
}
2342
2343
/**  @} */
2344
/* End of MIB registration code */
2345
2346
2347
netsnmp_feature_child_of(register_signal, netsnmp_unused);
2348
#ifndef NETSNMP_FEATURE_REMOVE_REGISTER_SIGNAL
2349
2350
/** @defgroup agent_signals POSIX signals support for agents.
2351
 *     Registering and unregistering signal handlers.
2352
 *   @ingroup agent_registry
2353
 *
2354
 * @{
2355
 */
2356
2357
int             external_signal_scheduled[NUM_EXTERNAL_SIGS];
2358
void            (*external_signal_handler[NUM_EXTERNAL_SIGS]) (int);
2359
2360
#ifndef WIN32
2361
2362
/*
2363
 * TODO: add agent_SIGXXX_handler functions and `case SIGXXX: ...' lines
2364
 *       below for every single that might be handled by register_signal().
2365
 */
2366
2367
RETSIGTYPE
2368
agent_SIGCHLD_handler(int sig)
2369
0
{
2370
0
    external_signal_scheduled[SIGCHLD]++;
2371
#ifndef HAVE_SIGACTION
2372
    /*
2373
     * signal() sucks. It *might* have SysV semantics, which means that
2374
     * * a signal handler is reset once it gets called. Ensure that it
2375
     * * remains active.
2376
     */
2377
    signal(SIGCHLD, agent_SIGCHLD_handler);
2378
#endif
2379
0
}
2380
2381
/** Registers a POSIX Signal handler.
2382
 *  Implements the signal registering process for POSIX and non-POSIX
2383
 *  systems. Also, unifies the way signals work.
2384
 *  Note that the signal handler should register itself again with
2385
 *  signal() call before end of execution to prevent possible problems.
2386
 *
2387
 *  @param sig POSIX Signal ID number, as defined in signal.h.
2388
 *
2389
 *  @param func New signal handler function.
2390
 *
2391
 *  @return value is SIG_REGISTERED_OK for success and
2392
 *        SIG_REGISTRATION_FAILED if the registration can't
2393
 *        be handled.
2394
 */
2395
int
2396
register_signal(int sig, void (*func) (int))
2397
0
{
2398
2399
0
    switch (sig) {
2400
0
#if defined(SIGCHLD)
2401
0
    case SIGCHLD:
2402
0
#ifdef HAVE_SIGACTION
2403
0
        {
2404
0
            static struct sigaction act;
2405
0
            act.sa_handler = agent_SIGCHLD_handler;
2406
0
            sigemptyset(&act.sa_mask);
2407
0
            act.sa_flags = 0;
2408
0
            sigaction(SIGCHLD, &act, NULL);
2409
0
        }
2410
#else
2411
        signal(SIGCHLD, agent_SIGCHLD_handler);
2412
#endif
2413
0
        break;
2414
0
#endif
2415
0
    default:
2416
0
        snmp_log(LOG_CRIT,
2417
0
                 "register_signal: signal %d cannot be handled\n", sig);
2418
0
        return SIG_REGISTRATION_FAILED;
2419
0
    }
2420
2421
0
    external_signal_handler[sig] = func;
2422
0
    external_signal_scheduled[sig] = 0;
2423
2424
0
    DEBUGMSGTL(("register_signal", "registered signal %d\n", sig));
2425
0
    return SIG_REGISTERED_OK;
2426
0
}
2427
2428
/** Unregisters a POSIX Signal handler.
2429
 *
2430
 *  @param sig POSIX Signal ID number, as defined in signal.h.
2431
 *
2432
 *  @return value is SIG_UNREGISTERED_OK for success, or error code.
2433
 */
2434
int
2435
unregister_signal(int sig)
2436
0
{
2437
0
    signal(sig, SIG_DFL);
2438
0
    DEBUGMSGTL(("unregister_signal", "unregistered signal %d\n", sig));
2439
0
    return SIG_UNREGISTERED_OK;
2440
0
}
2441
2442
#endif                          /* !WIN32 */
2443
2444
/**  @} */
2445
/* End of signals support code */
2446
2447
#endif /* NETSNMP_FEATURE_REMOVE_REGISTER_SIGNAL */
2448
2449
/**  @} */
2450