~ubuntu-branches/ubuntu/trusty/net-snmp/trusty

« back to all changes in this revision

Viewing changes to agent/agent_registry.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2004-09-13 12:06:21 UTC
  • Revision ID: james.westby@ubuntu.com-20040913120621-g952ntonlleihcvm
Tags: upstream-5.1.1
ImportĀ upstreamĀ versionĀ 5.1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
/** @defgroup agent_registry Maintain a registry of MIB subtrees, together with related information regarding mibmodule, sessions, etc
 
15
 *   @ingroup agent
 
16
 *
 
17
 * @{
 
18
 */
 
19
 
 
20
#define IN_SNMP_VARS_C
 
21
 
 
22
#include <net-snmp/net-snmp-config.h>
 
23
#include <signal.h>
 
24
#if HAVE_STRING_H
 
25
#include <string.h>
 
26
#endif
 
27
#if HAVE_STDLIB_H
 
28
#include <stdlib.h>
 
29
#endif
 
30
#include <sys/types.h>
 
31
#include <stdio.h>
 
32
#include <fcntl.h>
 
33
#if HAVE_WINSOCK_H
 
34
#include <winsock.h>
 
35
#endif
 
36
#if TIME_WITH_SYS_TIME
 
37
# ifdef WIN32
 
38
#  include <sys/timeb.h>
 
39
# else
 
40
#  include <sys/time.h>
 
41
# endif
 
42
# include <time.h>
 
43
#else
 
44
# if HAVE_SYS_TIME_H
 
45
#  include <sys/time.h>
 
46
# else
 
47
#  include <time.h>
 
48
# endif
 
49
#endif
 
50
#if HAVE_NETINET_IN_H
 
51
#include <netinet/in.h>
 
52
#endif
 
53
 
 
54
#if HAVE_DMALLOC_H
 
55
#include <dmalloc.h>
 
56
#endif
 
57
 
 
58
#include <net-snmp/net-snmp-includes.h>
 
59
#include <net-snmp/agent/net-snmp-agent-includes.h>
 
60
#include <net-snmp/agent/agent_callbacks.h>
 
61
 
 
62
#include "snmpd.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_registry.h>
 
69
#include "mib_module_includes.h"
 
70
 
 
71
#ifdef USING_AGENTX_SUBAGENT_MODULE
 
72
#include "agentx/subagent.h"
 
73
#include "agentx/client.h"
 
74
#endif
 
75
 
 
76
static void register_mib_detach_node(netsnmp_subtree *s);
 
77
NETSNMP_STATIC_INLINE void invalidate_lookup_cache(const char *context);
 
78
void netsnmp_set_lookup_cache_size(int newsize);
 
79
int netsnmp_get_lookup_cache_size(void);
 
80
 
 
81
subtree_context_cache *context_subtrees = NULL;
 
82
 
 
83
void
 
84
netsnmp_subtree_free(netsnmp_subtree *a)
 
85
{
 
86
  if (a != NULL) {
 
87
    if (a->variables != NULL && netsnmp_oid_equals(a->name_a, a->namelen, 
 
88
                                             a->start_a, a->start_len) == 0) {
 
89
      SNMP_FREE(a->variables);
 
90
    }
 
91
    SNMP_FREE(a->name_a);
 
92
    SNMP_FREE(a->start_a);
 
93
    SNMP_FREE(a->end_a);
 
94
    SNMP_FREE(a->label_a);
 
95
    netsnmp_handler_registration_free(a->reginfo);
 
96
    SNMP_FREE(a);
 
97
  }
 
98
}
 
99
 
 
100
netsnmp_subtree *
 
101
netsnmp_subtree_deepcopy(netsnmp_subtree *a)
 
102
{
 
103
  netsnmp_subtree *b = (netsnmp_subtree *)calloc(1, sizeof(netsnmp_subtree));
 
104
 
 
105
  if (b != NULL) {
 
106
    memcpy(b, a, sizeof(netsnmp_subtree));
 
107
    b->name_a  = snmp_duplicate_objid(a->name_a,  a->namelen);
 
108
    b->start_a = snmp_duplicate_objid(a->start_a, a->start_len);
 
109
    b->end_a   = snmp_duplicate_objid(a->end_a,   a->end_len);
 
110
    b->label_a = strdup(a->label_a);
 
111
    
 
112
    if (b->name_a == NULL || b->start_a == NULL || 
 
113
        b->end_a  == NULL || b->label_a == NULL) {
 
114
      netsnmp_subtree_free(b);
 
115
      return NULL;
 
116
    }
 
117
 
 
118
    if (a->variables != NULL) {
 
119
      b->variables = (struct variable *)malloc(a->variables_len * 
 
120
                                               a->variables_width);
 
121
      if (b->variables != NULL) {
 
122
        memcpy(b->variables, a->variables,a->variables_len*a->variables_width);
 
123
      } else {
 
124
        netsnmp_subtree_free(b);
 
125
        return NULL;
 
126
      }
 
127
    }
 
128
 
 
129
    if (a->reginfo != NULL) {
 
130
      b->reginfo = netsnmp_handler_registration_dup(a->reginfo);
 
131
      if (b->reginfo == NULL) {
 
132
        netsnmp_subtree_free(b);
 
133
        return NULL;
 
134
      }
 
135
    }
 
136
  }
 
137
  return b;
 
138
}
 
139
 
 
140
subtree_context_cache *
 
141
get_top_context_cache(void)
 
142
{
 
143
    return context_subtrees;
 
144
}
 
145
 
 
146
netsnmp_subtree *
 
147
netsnmp_subtree_find_first(const char *context_name)
 
148
{
 
149
    subtree_context_cache *ptr;
 
150
 
 
151
    if (!context_name) {
 
152
        context_name = "";
 
153
    }
 
154
 
 
155
    DEBUGMSGTL(("subtree", "looking for subtree for context: \"%s\"\n", 
 
156
                context_name));
 
157
    for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) {
 
158
        if (ptr->context_name != NULL && 
 
159
            strcmp(ptr->context_name, context_name) == 0) {
 
160
            DEBUGMSGTL(("subtree", "found one for: \"%s\"\n", context_name));
 
161
            return ptr->first_subtree;
 
162
        }
 
163
    }
 
164
    DEBUGMSGTL(("subtree", "didn't find a subtree for context: \"%s\"\n", 
 
165
                context_name));
 
166
    return NULL;
 
167
}
 
168
 
 
169
netsnmp_subtree *
 
170
add_subtree(netsnmp_subtree *new_tree, const char *context_name)
 
171
{
 
172
    subtree_context_cache *ptr = SNMP_MALLOC_TYPEDEF(subtree_context_cache);
 
173
    if (!context_name) {
 
174
        context_name = "";
 
175
    }
 
176
 
 
177
    if (!ptr) {
 
178
        return NULL;
 
179
    }
 
180
 
 
181
    DEBUGMSGTL(("subtree", "adding subtree for context: \"%s\"\n",      
 
182
                context_name));
 
183
    ptr->next = context_subtrees;
 
184
    ptr->first_subtree = new_tree;
 
185
    ptr->context_name = strdup(context_name);
 
186
    context_subtrees = ptr;
 
187
    return ptr->first_subtree;
 
188
}
 
189
 
 
190
netsnmp_subtree *
 
191
netsnmp_subtree_replace_first(netsnmp_subtree *new_tree, 
 
192
                              const char *context_name)
 
193
{
 
194
    subtree_context_cache *ptr;
 
195
    if (!context_name) {
 
196
        context_name = "";
 
197
    }
 
198
    for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) {
 
199
        if (ptr->context_name != NULL &&
 
200
            strcmp(ptr->context_name, context_name) == 0) {
 
201
            ptr->first_subtree = new_tree;
 
202
            return ptr->first_subtree;
 
203
        }
 
204
    }
 
205
    return add_subtree(new_tree, context_name);
 
206
}
 
207
 
 
208
 
 
209
 
 
210
int
 
211
netsnmp_subtree_compare(const netsnmp_subtree *ap, const netsnmp_subtree *bp)
 
212
{
 
213
    return snmp_oid_compare(ap->name_a, ap->namelen, bp->name_a, bp->namelen);
 
214
}
 
215
 
 
216
void
 
217
netsnmp_subtree_join(netsnmp_subtree *root)
 
218
{
 
219
    netsnmp_subtree *s, *tmp, *c, *d;
 
220
 
 
221
    while (root != NULL) {
 
222
        s = root->next;
 
223
        while (s != NULL && root->reginfo == s->reginfo) {
 
224
            tmp = s->next;
 
225
            DEBUGMSGTL(("subtree", "root start "));
 
226
            DEBUGMSGOID(("subtree", root->start_a, root->start_len));
 
227
            DEBUGMSG(("subtree", " (original end "));
 
228
            DEBUGMSGOID(("subtree", root->end_a, root->end_len));
 
229
            DEBUGMSG(("subtree", ")\n"));
 
230
            DEBUGMSGTL(("subtree", "  JOINING to "));
 
231
            DEBUGMSGOID(("subtree", s->start_a, s->start_len));
 
232
 
 
233
            SNMP_FREE(root->end_a);
 
234
            root->end_a   = s->end_a;
 
235
            root->end_len = s->end_len;
 
236
            s->end_a      = NULL;
 
237
 
 
238
            for (c = root; c != NULL; c = c->children) {
 
239
                c->next = s->next;
 
240
            }
 
241
            for (c = s; c != NULL; c = c->children) {
 
242
                c->prev = root;
 
243
            }
 
244
            DEBUGMSG(("subtree", " so new end "));
 
245
            DEBUGMSGOID(("subtree", root->end_a, root->end_len));
 
246
            DEBUGMSG(("subtree", "\n"));
 
247
            /*
 
248
             * Probably need to free children too?  
 
249
             */
 
250
            for (c = s->children; c != NULL; c = d) {
 
251
                d = c->children;
 
252
                netsnmp_subtree_free(c);
 
253
            }
 
254
            netsnmp_subtree_free(s);
 
255
            s = tmp;
 
256
        }
 
257
        root = root->next;
 
258
    }
 
259
}
 
260
 
 
261
 
 
262
        /*
 
263
         *  Split the subtree into two at the specified point,
 
264
         *    returning the new (second) subtree
 
265
         */
 
266
netsnmp_subtree *
 
267
netsnmp_subtree_split(netsnmp_subtree *current, oid name[], int name_len)
 
268
{
 
269
    struct variable *vp = NULL;
 
270
    netsnmp_subtree *new_sub, *ptr;
 
271
    int i = 0, rc = 0, rc2 = 0;
 
272
    size_t common_len = 0;
 
273
    char *cp;
 
274
    oid *tmp_a, *tmp_b;
 
275
 
 
276
    if (snmp_oid_compare(name, name_len, current->end_a, current->end_len)>0) {
 
277
        /* Split comes after the end of this subtree */
 
278
        return NULL;
 
279
    }
 
280
 
 
281
    new_sub = netsnmp_subtree_deepcopy(current);
 
282
    if (new_sub == NULL) {
 
283
        return NULL;
 
284
    }
 
285
 
 
286
    /*  Set up the point of division.  */
 
287
    tmp_a = snmp_duplicate_objid(name, name_len);
 
288
    if (tmp_a == NULL) {
 
289
        netsnmp_subtree_free(new_sub);
 
290
        return NULL;
 
291
    }
 
292
    tmp_b = snmp_duplicate_objid(name, name_len);
 
293
    if (tmp_b == NULL) {
 
294
        netsnmp_subtree_free(new_sub);
 
295
        SNMP_FREE(tmp_a);
 
296
        return NULL;
 
297
    }
 
298
 
 
299
    if (current->end_a != NULL) {
 
300
        SNMP_FREE(current->end_a);
 
301
    }
 
302
    current->end_a = tmp_a;
 
303
    current->end_len = name_len;
 
304
    if (new_sub->start_a != NULL) {
 
305
        SNMP_FREE(new_sub->start_a);
 
306
    }
 
307
    new_sub->start_a = tmp_b;
 
308
    new_sub->start_len = name_len;
 
309
 
 
310
    /*  Split the variables between the two new subtrees.  */
 
311
    i = current->variables_len;
 
312
    current->variables_len = 0;
 
313
 
 
314
    for (vp = current->variables; i > 0; i--) {
 
315
        /*  Note that the variable "name" field omits the prefix common to the
 
316
            whole registration, hence the strange comparison here.  */
 
317
 
 
318
        rc = snmp_oid_compare(vp->name, vp->namelen,
 
319
                              name     + current->namelen, 
 
320
                              name_len - current->namelen);
 
321
 
 
322
        if (name_len - current->namelen > vp->namelen) {
 
323
            common_len = vp->namelen;
 
324
        } else {
 
325
            common_len = name_len - current->namelen;
 
326
        }
 
327
 
 
328
        rc2 = snmp_oid_compare(vp->name, common_len,
 
329
                               name + current->namelen, common_len);
 
330
 
 
331
        if (rc >= 0) {
 
332
            break;  /* All following variables belong to the second subtree */
 
333
        }
 
334
 
 
335
        current->variables_len++;
 
336
        if (rc2 < 0) {
 
337
            new_sub->variables_len--;
 
338
            cp = (char *) new_sub->variables;
 
339
            new_sub->variables = (struct variable *)(cp + 
 
340
                                                     new_sub->variables_width);
 
341
        }
 
342
        vp = (struct variable *) ((char *) vp + current->variables_width);
 
343
    }
 
344
 
 
345
    /* Delegated trees should retain their variables regardless */
 
346
    if (current->variables_len > 0 &&
 
347
        IS_DELEGATED((u_char) current->variables[0].type)) {
 
348
        new_sub->variables_len = 1;
 
349
        new_sub->variables = current->variables;
 
350
    }
 
351
 
 
352
    /* Propogate this split down through any children */
 
353
    if (current->children) {
 
354
        new_sub->children = netsnmp_subtree_split(current->children, 
 
355
                                                  name, name_len);
 
356
    }
 
357
 
 
358
    /* Retain the correct linking of the list */
 
359
    for (ptr = current; ptr != NULL; ptr = ptr->children) {
 
360
      ptr->next = new_sub;
 
361
    }
 
362
    for (ptr = new_sub; ptr != NULL; ptr = ptr->children) {
 
363
      ptr->prev = current;
 
364
    }
 
365
    for (ptr = new_sub->next; ptr != NULL; ptr=ptr->children) {
 
366
      ptr->prev = new_sub;
 
367
    }
 
368
 
 
369
    return new_sub;
 
370
}
 
371
 
 
372
int
 
373
netsnmp_subtree_load(netsnmp_subtree *new_sub, const char *context_name)
 
374
{
 
375
    netsnmp_subtree *tree1, *tree2, *new2;
 
376
    netsnmp_subtree *prev, *next;
 
377
    int             res, rc = 0;
 
378
 
 
379
    if (new_sub == NULL) {
 
380
        return MIB_REGISTERED_OK;       /* Degenerate case */
 
381
    }
 
382
 
 
383
    /*  Find the subtree that contains the start of the new subtree (if
 
384
        any)...*/
 
385
 
 
386
    tree1 = netsnmp_subtree_find(new_sub->start_a, new_sub->start_len, 
 
387
                                 NULL, context_name);
 
388
 
 
389
    /*  ... and the subtree that follows the new one (NULL implies this is the
 
390
        final region covered).  */
 
391
 
 
392
    if (tree1 == NULL) {
 
393
        tree2 = netsnmp_subtree_find_next(new_sub->start_a, new_sub->start_len,
 
394
                                          NULL, context_name);
 
395
    } else {
 
396
        tree2 = tree1->next;
 
397
    }
 
398
 
 
399
    /*  Handle new subtrees that start in virgin territory.  */
 
400
 
 
401
    if (tree1 == NULL) {
 
402
        new2 = NULL;
 
403
        /*  Is there any overlap with later subtrees?  */
 
404
        if (tree2 && snmp_oid_compare(new_sub->end_a, new_sub->end_len,
 
405
                                      tree2->start_a, tree2->start_len) > 0) {
 
406
            new2 = netsnmp_subtree_split(new_sub, 
 
407
                                         tree2->start_a, tree2->start_len);
 
408
        }
 
409
 
 
410
        /*  Link the new subtree (less any overlapping region) with the list of
 
411
            existing registrations.  */
 
412
 
 
413
        if (tree2) {
 
414
            new_sub->prev = tree2->prev;
 
415
            tree2->prev   = new_sub;
 
416
        } else {
 
417
            new_sub->prev = netsnmp_subtree_find_prev(new_sub->start_a,
 
418
                                      new_sub->start_len, NULL, context_name);
 
419
 
 
420
            if (new_sub->prev) {
 
421
                new_sub->prev->next = new_sub;
 
422
            } else {
 
423
                netsnmp_subtree_replace_first(new_sub, context_name);
 
424
            }
 
425
 
 
426
            new_sub->next = tree2;
 
427
 
 
428
            /* If there was any overlap, recurse to merge in the overlapping
 
429
               region (including anything that may follow the overlap).  */
 
430
            if (new2) {
 
431
                return netsnmp_subtree_load(new2, context_name);
 
432
            }
 
433
        }
 
434
    } else {
 
435
        /*  If the new subtree starts *within* an existing registration
 
436
            (rather than at the same point as it), then split the existing
 
437
            subtree at this point.  */
 
438
 
 
439
        if (netsnmp_oid_equals(new_sub->start_a, new_sub->start_len, 
 
440
                             tree1->start_a,   tree1->start_len) != 0) {
 
441
            tree1 = netsnmp_subtree_split(tree1, new_sub->start_a, 
 
442
                                          new_sub->start_len);
 
443
        }
 
444
 
 
445
        if (tree1 == NULL) {
 
446
            return MIB_REGISTRATION_FAILED;
 
447
        }
 
448
 
 
449
        /*  Now consider the end of this existing subtree:
 
450
            
 
451
            If it matches the new subtree precisely,
 
452
                    simply merge the new one into the list of children
 
453
 
 
454
            If it includes the whole of the new subtree,
 
455
                    split it at the appropriate point, and merge again
 
456
     
 
457
            If the new subtree extends beyond this existing region,
 
458
                    split it, and recurse to merge the two parts.  */
 
459
 
 
460
        rc = snmp_oid_compare(new_sub->end_a, new_sub->end_len, 
 
461
                              tree1->end_a, tree1->end_len);
 
462
 
 
463
        switch (rc) {
 
464
 
 
465
        case -1:
 
466
            /*  Existing subtree contains new one.  */
 
467
            netsnmp_subtree_split(tree1, new_sub->end_a, new_sub->end_len);
 
468
            /* Fall Through */
 
469
 
 
470
        case  0:
 
471
            /*  The two trees match precisely.  */
 
472
 
 
473
            /*  Note: This is the only point where the original registration
 
474
                OID ("name") is used.  */
 
475
 
 
476
            prev = NULL;
 
477
            next = tree1;
 
478
        
 
479
            while (next && next->namelen > new_sub->namelen) {
 
480
                prev = next;
 
481
                next = next->children;
 
482
            }
 
483
 
 
484
            while (next && next->namelen == new_sub->namelen &&
 
485
                   next->priority < new_sub->priority ) {
 
486
                prev = next;
 
487
                next = next->children;
 
488
            }
 
489
        
 
490
            if (next && (next->namelen  == new_sub->namelen) &&
 
491
                (next->priority == new_sub->priority)) {
 
492
                return MIB_DUPLICATE_REGISTRATION;
 
493
            }
 
494
 
 
495
            if (prev) {
 
496
                prev->children    = new_sub;
 
497
                new_sub->children = next;
 
498
                new_sub->prev = prev->prev;
 
499
                new_sub->next = prev->next;
 
500
            } else {
 
501
                new_sub->children = next;
 
502
                new_sub->prev = next->prev;
 
503
                new_sub->next = next->next;
 
504
        
 
505
                for (next = new_sub->next; next != NULL;next = next->children){
 
506
                    next->prev = new_sub;
 
507
                }
 
508
 
 
509
                for (prev = new_sub->prev; prev != NULL;prev = prev->children){
 
510
                    prev->next = new_sub;
 
511
                }
 
512
            }
 
513
            break;
 
514
 
 
515
        case  1:
 
516
            /*  New subtree contains the existing one.  */
 
517
            new2 = netsnmp_subtree_split(new_sub, tree1->end_a,tree1->end_len);
 
518
            res = netsnmp_subtree_load(new_sub, context_name);
 
519
            if (res != MIB_REGISTERED_OK) {
 
520
                netsnmp_subtree_free(new2);
 
521
                return res;
 
522
            }
 
523
            return netsnmp_subtree_load(new2, context_name);
 
524
        }
 
525
    }
 
526
    return 0;
 
527
}
 
528
 
 
529
int
 
530
netsnmp_register_mib(const char *moduleName,
 
531
                     struct variable *var,
 
532
                     size_t varsize,
 
533
                     size_t numvars,
 
534
                     oid * mibloc,
 
535
                     size_t mibloclen,
 
536
                     int priority,
 
537
                     int range_subid,
 
538
                     oid range_ubound,
 
539
                     netsnmp_session * ss,
 
540
                     const char *context,
 
541
                     int timeout,
 
542
                     int flags,
 
543
                     netsnmp_handler_registration *reginfo,
 
544
                     int perform_callback)
 
545
{
 
546
    netsnmp_subtree *subtree, *sub2;
 
547
    int             res, i;
 
548
    struct register_parameters reg_parms;
 
549
    int old_lookup_cache_val = netsnmp_get_lookup_cache_size();
 
550
 
 
551
    subtree = (netsnmp_subtree *)calloc(1, sizeof(netsnmp_subtree));
 
552
    if (subtree == NULL) {
 
553
        return MIB_REGISTRATION_FAILED;
 
554
    }
 
555
 
 
556
    DEBUGMSGTL(("register_mib", "registering \"%s\" at ", moduleName));
 
557
    DEBUGMSGOIDRANGE(("register_mib", mibloc, mibloclen, range_subid,
 
558
                      range_ubound));
 
559
    DEBUGMSG(("register_mib", "\n"));
 
560
 
 
561
    /*  Create the new subtree node being registered.  */
 
562
 
 
563
    subtree->name_a  = snmp_duplicate_objid(mibloc, mibloclen);
 
564
    subtree->start_a = snmp_duplicate_objid(mibloc, mibloclen);
 
565
    subtree->end_a   = snmp_duplicate_objid(mibloc, mibloclen);
 
566
    subtree->label_a = strdup(moduleName);
 
567
    if (subtree->name_a == NULL || subtree->start_a == NULL || 
 
568
        subtree->end_a  == NULL || subtree->label_a == NULL) {
 
569
        netsnmp_subtree_free(subtree);
 
570
        return MIB_REGISTRATION_FAILED;
 
571
    }
 
572
    subtree->namelen   = (u_char)mibloclen;
 
573
    subtree->start_len = (u_char)mibloclen;
 
574
    subtree->end_len   = (u_char)mibloclen;
 
575
    subtree->end_a[mibloclen - 1]++;
 
576
 
 
577
    if (var != NULL) {
 
578
        subtree->variables = (struct variable *)malloc(varsize*numvars);
 
579
        if (subtree->variables == NULL) {
 
580
            netsnmp_subtree_free(subtree);
 
581
            return MIB_REGISTRATION_FAILED;
 
582
        }
 
583
        memcpy(subtree->variables, var, numvars*varsize);
 
584
        subtree->variables_len = numvars;
 
585
        subtree->variables_width = varsize;
 
586
    }
 
587
    subtree->priority = priority;
 
588
    subtree->timeout = timeout;
 
589
    subtree->range_subid = range_subid;
 
590
    subtree->range_ubound = range_ubound;
 
591
    subtree->session = ss;
 
592
    subtree->reginfo = reginfo;
 
593
    subtree->flags = (u_char)flags;    /*  used to identify instance oids  */
 
594
    subtree->flags |= SUBTREE_ATTACHED;
 
595
    subtree->global_cacheid = reginfo->global_cacheid;
 
596
 
 
597
    netsnmp_set_lookup_cache_size(0);
 
598
    res = netsnmp_subtree_load(subtree, context);
 
599
 
 
600
    /*  If registering a range, use the first subtree as a template for the
 
601
        rest of the range.  */
 
602
 
 
603
    if (res == MIB_REGISTERED_OK && range_subid != 0) {
 
604
        for (i = mibloc[range_subid - 1] + 1; i <= (int)range_ubound; i++) {
 
605
            sub2 = netsnmp_subtree_deepcopy(subtree);
 
606
 
 
607
            if (sub2 == NULL) {
 
608
                unregister_mib_context(mibloc, mibloclen, priority,
 
609
                                       range_subid, range_ubound, context);
 
610
                netsnmp_set_lookup_cache_size(old_lookup_cache_val);
 
611
                invalidate_lookup_cache(context);
 
612
                return MIB_REGISTRATION_FAILED;
 
613
            }
 
614
 
 
615
            sub2->name_a[range_subid - 1]  = i;
 
616
            sub2->start_a[range_subid - 1] = i;
 
617
            sub2->end_a[range_subid - 1]   = i;     /* XXX - ???? */
 
618
            res = netsnmp_subtree_load(sub2, context);
 
619
            sub2->flags |= SUBTREE_ATTACHED;
 
620
            if (res != MIB_REGISTERED_OK) {
 
621
                unregister_mib_context(mibloc, mibloclen, priority,
 
622
                                       range_subid, range_ubound, context);
 
623
                netsnmp_subtree_free(sub2);
 
624
                netsnmp_set_lookup_cache_size(old_lookup_cache_val);
 
625
                invalidate_lookup_cache(context);
 
626
                return res;
 
627
            }
 
628
        }
 
629
    } else if (res == MIB_DUPLICATE_REGISTRATION ||
 
630
               res == MIB_REGISTRATION_FAILED) {
 
631
        netsnmp_subtree_free(subtree);
 
632
    }
 
633
 
 
634
    /*
 
635
     * mark the MIB as detached, if there's no master agent present as of now 
 
636
     */
 
637
    if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
 
638
                               NETSNMP_DS_AGENT_ROLE) != MASTER_AGENT) {
 
639
        extern struct snmp_session *main_session;
 
640
        if (main_session == NULL) {
 
641
            register_mib_detach_node(subtree);
 
642
        }
 
643
    }
 
644
 
 
645
    if (perform_callback) {
 
646
        reg_parms.name = mibloc;
 
647
        reg_parms.namelen = mibloclen;
 
648
        reg_parms.priority = priority;
 
649
        reg_parms.range_subid = range_subid;
 
650
        reg_parms.range_ubound = range_ubound;
 
651
        reg_parms.timeout = timeout;
 
652
        reg_parms.flags = (u_char) flags;
 
653
 
 
654
        /*
 
655
         * Should this really be called if the registration hasn't actually 
 
656
         * succeeded?  
 
657
         */
 
658
 
 
659
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
 
660
                            SNMPD_CALLBACK_REGISTER_OID, &reg_parms);
 
661
    }
 
662
 
 
663
    netsnmp_set_lookup_cache_size(old_lookup_cache_val);
 
664
    invalidate_lookup_cache(context);
 
665
    return res;
 
666
}
 
667
 
 
668
/*
 
669
 * Reattach a particular node.  
 
670
 */
 
671
 
 
672
static void
 
673
register_mib_reattach_node(netsnmp_subtree *s)
 
674
{
 
675
    if ((s != NULL) && (s->namelen > 1) && !(s->flags & SUBTREE_ATTACHED)) {
 
676
        struct register_parameters reg_parms;
 
677
        /*
 
678
         * only do registrations that are not the top level nodes 
 
679
         */
 
680
        /*
 
681
         * XXX: do this better 
 
682
         */
 
683
        reg_parms.name = s->name_a;
 
684
        reg_parms.namelen = s->namelen;
 
685
        reg_parms.priority = s->priority;
 
686
        reg_parms.range_subid = s->range_subid;
 
687
        reg_parms.range_ubound = s->range_ubound;
 
688
        reg_parms.timeout = s->timeout;
 
689
        reg_parms.flags = s->flags;
 
690
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
 
691
                            SNMPD_CALLBACK_REGISTER_OID, &reg_parms);
 
692
        s->flags |= SUBTREE_ATTACHED;
 
693
    }
 
694
}
 
695
 
 
696
/*
 
697
 * Call callbacks to reattach all our nodes.  
 
698
 */
 
699
 
 
700
void
 
701
register_mib_reattach(void)
 
702
{
 
703
    netsnmp_subtree *s, *t;
 
704
    subtree_context_cache *ptr;
 
705
 
 
706
    for (ptr = context_subtrees; ptr; ptr = ptr->next) {
 
707
        for (s = ptr->first_subtree; s != NULL; s = s->next) {
 
708
            register_mib_reattach_node(s);
 
709
            for (t = s->children; t != NULL; t = t->children) {
 
710
                register_mib_reattach_node(t);
 
711
            }
 
712
        }
 
713
    }
 
714
}
 
715
 
 
716
/*
 
717
 * Mark a node as detached.  
 
718
 */
 
719
 
 
720
static void
 
721
register_mib_detach_node(netsnmp_subtree *s)
 
722
{
 
723
    if (s != NULL) {
 
724
        s->flags = s->flags & ~SUBTREE_ATTACHED;
 
725
    }
 
726
}
 
727
 
 
728
/*
 
729
 * Mark all our registered OIDs as detached.  This is only really
 
730
 * useful for subagent protocols, when a connection is lost or
 
731
 * something.  
 
732
 */
 
733
 
 
734
void
 
735
register_mib_detach(void)
 
736
{
 
737
    netsnmp_subtree *s, *t;
 
738
    subtree_context_cache *ptr;
 
739
    for (ptr = context_subtrees; ptr; ptr = ptr->next) {
 
740
        for (s = ptr->first_subtree; s != NULL; s = s->next) {
 
741
            register_mib_detach_node(s);
 
742
            for (t = s->children; t != NULL; t = t->children) {
 
743
                register_mib_detach_node(t);
 
744
            }
 
745
        }
 
746
    }
 
747
}
 
748
 
 
749
int
 
750
register_mib_context(const char *moduleName,
 
751
                     struct variable *var,
 
752
                     size_t varsize,
 
753
                     size_t numvars,
 
754
                     oid * mibloc,
 
755
                     size_t mibloclen,
 
756
                     int priority,
 
757
                     int range_subid,
 
758
                     oid range_ubound,
 
759
                     netsnmp_session * ss,
 
760
                     const char *context, int timeout, int flags)
 
761
{
 
762
    return netsnmp_register_old_api(moduleName, var, varsize, numvars,
 
763
                                    mibloc, mibloclen, priority,
 
764
                                    range_subid, range_ubound, ss, context,
 
765
                                    timeout, flags);
 
766
}
 
767
 
 
768
int
 
769
register_mib_range(const char *moduleName,
 
770
                   struct variable *var,
 
771
                   size_t varsize,
 
772
                   size_t numvars,
 
773
                   oid * mibloc,
 
774
                   size_t mibloclen,
 
775
                   int priority,
 
776
                   int range_subid, oid range_ubound, netsnmp_session * ss)
 
777
{
 
778
    return register_mib_context(moduleName, var, varsize, numvars,
 
779
                                mibloc, mibloclen, priority,
 
780
                                range_subid, range_ubound, ss, "", -1, 0);
 
781
}
 
782
 
 
783
int
 
784
register_mib_priority(const char *moduleName,
 
785
                      struct variable *var,
 
786
                      size_t varsize,
 
787
                      size_t numvars,
 
788
                      oid * mibloc, size_t mibloclen, int priority)
 
789
{
 
790
    return register_mib_range(moduleName, var, varsize, numvars,
 
791
                              mibloc, mibloclen, priority, 0, 0, NULL);
 
792
}
 
793
 
 
794
int
 
795
register_mib(const char *moduleName,
 
796
             struct variable *var,
 
797
             size_t varsize,
 
798
             size_t numvars, oid * mibloc, size_t mibloclen)
 
799
{
 
800
    return register_mib_priority(moduleName, var, varsize, numvars,
 
801
                                 mibloc, mibloclen, DEFAULT_MIB_PRIORITY);
 
802
}
 
803
 
 
804
void
 
805
netsnmp_subtree_unload(netsnmp_subtree *sub, netsnmp_subtree *prev, const char *context)
 
806
{
 
807
    netsnmp_subtree *ptr;
 
808
 
 
809
    DEBUGMSGTL(("register_mib", "unload("));
 
810
    if (sub != NULL) {
 
811
        DEBUGMSGOID(("register_mib", sub->start_a, sub->start_len));
 
812
    } else {
 
813
        DEBUGMSG(("register_mib", "[NIL]"));
 
814
    }
 
815
    DEBUGMSG(("register_mib", ", "));
 
816
    if (prev != NULL) {
 
817
        DEBUGMSGOID(("register_mib", prev->start_a, prev->start_len));
 
818
    } else {
 
819
        DEBUGMSG(("register_mib", "[NIL]"));
 
820
    }
 
821
    DEBUGMSG(("register_mib", ")\n"));
 
822
 
 
823
    if (prev != NULL) {         /* non-leading entries are easy */
 
824
        prev->children = sub->children;
 
825
        invalidate_lookup_cache(context);
 
826
        return;
 
827
    }
 
828
    /*
 
829
     * otherwise, we need to amend our neighbours as well 
 
830
     */
 
831
 
 
832
    if (sub->children == NULL) {        /* just remove this node completely */
 
833
        for (ptr = sub->prev; ptr; ptr = ptr->children)
 
834
            ptr->next = sub->next;
 
835
        for (ptr = sub->next; ptr; ptr = ptr->children)
 
836
            ptr->prev = sub->prev;
 
837
 
 
838
        if (sub->prev == NULL) {
 
839
            netsnmp_subtree_replace_first(sub->next, context);
 
840
        }
 
841
 
 
842
    } else {
 
843
        for (ptr = sub->prev; ptr; ptr = ptr->children)
 
844
            ptr->next = sub->children;
 
845
        for (ptr = sub->next; ptr; ptr = ptr->children)
 
846
            ptr->prev = sub->children;
 
847
 
 
848
        if (sub->prev == NULL) {
 
849
            netsnmp_subtree_replace_first(sub->children, context);
 
850
        }
 
851
    }
 
852
    invalidate_lookup_cache(context);
 
853
}
 
854
 
 
855
/**
 
856
 * Unregisters an OID that has an associated context name value. 
 
857
 * Typically used when a module has multiple contexts defined.  The parameters
 
858
 * priority, range_subid, and range_ubound should be used in conjunction with
 
859
 * agentx, see RFC 2741, otherwise these values should always be 0.
 
860
 *
 
861
 * @param name  the specific OID to unregister if it conatins the associated
 
862
 *              context.
 
863
 *
 
864
 * @param len   the length of the OID, use  OID_LENGTH macro.
 
865
 *
 
866
 * @param priority  a value between 1 and 255, used to achieve a desired
 
867
 *                  configuration when different sessions register identical or
 
868
 *                  overlapping regions.  Subagents with no particular
 
869
 *                  knowledge of priority should register with the default
 
870
 *                  value of 127.
 
871
 *
 
872
 * @param range_subid  permits specifying a range in place of one of a subtree
 
873
 *                     sub-identifiers.  When this value is zero, no range is
 
874
 *                     being specified.
 
875
 *
 
876
 * @param range_ubound  the upper bound of a sub-identifier's range.
 
877
 *                      This field is present only if range_subid is not 0.
 
878
 *
 
879
 * @param context  a context name that has been created
 
880
 *
 
881
 * @return 
 
882
 * 
 
883
 */
 
884
int
 
885
unregister_mib_context(oid * name, size_t len, int priority,
 
886
                       int range_subid, oid range_ubound,
 
887
                       const char *context)
 
888
{
 
889
    netsnmp_subtree *list, *myptr;
 
890
    netsnmp_subtree *prev, *child;       /* loop through children */
 
891
    struct register_parameters reg_parms;
 
892
    int old_lookup_cache_val = netsnmp_get_lookup_cache_size();
 
893
    netsnmp_set_lookup_cache_size(0);
 
894
 
 
895
    DEBUGMSGTL(("register_mib", "unregistering "));
 
896
    DEBUGMSGOIDRANGE(("register_mib", name, len, range_subid, range_ubound));
 
897
    DEBUGMSG(("register_mib", "\n"));
 
898
 
 
899
    list = netsnmp_subtree_find(name, len, netsnmp_subtree_find_first(context),
 
900
                                context);
 
901
    if (list == NULL) {
 
902
        return MIB_NO_SUCH_REGISTRATION;
 
903
    }
 
904
 
 
905
    for (child = list, prev = NULL; child != NULL;
 
906
         prev = child, child = child->children) {
 
907
        if (netsnmp_oid_equals(child->name_a, child->namelen, name, len) == 0 &&
 
908
            child->priority == priority) {
 
909
            break;              /* found it */
 
910
        }
 
911
    }
 
912
 
 
913
    if (child == NULL) {
 
914
        return MIB_NO_SUCH_REGISTRATION;
 
915
    }
 
916
 
 
917
    netsnmp_subtree_unload(child, prev, context);
 
918
    myptr = child;              /* remember this for later */
 
919
 
 
920
    /*
 
921
     *  Now handle any occurances in the following subtrees,
 
922
     *      as a result of splitting this range.  Due to the
 
923
     *      nature of the way such splits work, the first
 
924
     *      subtree 'slice' that doesn't refer to the given
 
925
     *      name marks the end of the original region.
 
926
     *
 
927
     *  This should also serve to register ranges.
 
928
     */
 
929
 
 
930
    for (list = myptr->next; list != NULL; list = list->next) {
 
931
        for (child = list, prev = NULL; child != NULL;
 
932
             prev = child, child = child->children) {
 
933
            if ((netsnmp_oid_equals(child->name_a, child->namelen,
 
934
                                  name, len) == 0) &&
 
935
                (child->priority == priority)) {
 
936
                netsnmp_subtree_unload(child, prev, context);
 
937
                netsnmp_subtree_free(child);
 
938
                break;
 
939
            }
 
940
        }
 
941
        if (child == NULL)      /* Didn't find the given name */
 
942
            break;
 
943
    }
 
944
    netsnmp_subtree_free(myptr);
 
945
 
 
946
    reg_parms.name = name;
 
947
    reg_parms.namelen = len;
 
948
    reg_parms.priority = priority;
 
949
    reg_parms.range_subid = range_subid;
 
950
    reg_parms.range_ubound = range_ubound;
 
951
    reg_parms.flags = 0x00;     /*  this is okay I think  */
 
952
    snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
 
953
                        SNMPD_CALLBACK_UNREGISTER_OID, &reg_parms);
 
954
 
 
955
    netsnmp_set_lookup_cache_size(old_lookup_cache_val);
 
956
    invalidate_lookup_cache(context);
 
957
    return MIB_UNREGISTERED_OK;
 
958
}
 
959
 
 
960
int
 
961
netsnmp_unregister_mib_table_row(oid * name, size_t len, int priority,
 
962
                                 int var_subid, oid range_ubound,
 
963
                                 const char *context)
 
964
{
 
965
    netsnmp_subtree *list, *myptr;
 
966
    netsnmp_subtree *prev, *child;       /* loop through children */
 
967
    struct register_parameters reg_parms;
 
968
    oid             range_lbound = name[var_subid - 1];
 
969
 
 
970
    DEBUGMSGTL(("register_mib", "unregistering "));
 
971
    DEBUGMSGOIDRANGE(("register_mib", name, len, var_subid, range_ubound));
 
972
    DEBUGMSG(("register_mib", "\n"));
 
973
 
 
974
    for (; name[var_subid - 1] <= range_ubound; name[var_subid - 1]++) {
 
975
        list = netsnmp_subtree_find(name, len, 
 
976
                                netsnmp_subtree_find_first(context), context);
 
977
 
 
978
        if (list == NULL) {
 
979
            continue;
 
980
        }
 
981
 
 
982
        for (child = list, prev = NULL; child != NULL;
 
983
             prev = child, child = child->children) {
 
984
 
 
985
            if (netsnmp_oid_equals(child->name_a, child->namelen, 
 
986
                                 name, len) == 0 && 
 
987
                (child->priority == priority)) {
 
988
                break;          /* found it */
 
989
            }
 
990
        }
 
991
 
 
992
        if (child == NULL) {
 
993
            continue;
 
994
        }
 
995
 
 
996
        netsnmp_subtree_unload(child, prev, context);
 
997
        myptr = child;          /* remember this for later */
 
998
 
 
999
        for (list = myptr->next; list != NULL; list = list->next) {
 
1000
            for (child = list, prev = NULL; child != NULL;
 
1001
                 prev = child, child = child->children) {
 
1002
 
 
1003
                if (netsnmp_oid_equals(child->name_a, child->namelen, 
 
1004
                                      name, len) == 0 &&
 
1005
                    (child->priority == priority)) {
 
1006
                    netsnmp_subtree_unload(child, prev, context);
 
1007
                    netsnmp_subtree_free(child);
 
1008
                    break;
 
1009
                }
 
1010
            }
 
1011
            if (child == NULL) {        /* Didn't find the given name */
 
1012
                break;
 
1013
            }
 
1014
        }
 
1015
        netsnmp_subtree_free(myptr);
 
1016
    }
 
1017
 
 
1018
    name[var_subid - 1] = range_lbound;
 
1019
    reg_parms.name = name;
 
1020
    reg_parms.namelen = len;
 
1021
    reg_parms.priority = priority;
 
1022
    reg_parms.range_subid = var_subid;
 
1023
    reg_parms.range_ubound = range_ubound;
 
1024
    reg_parms.flags = 0x00;     /*  this is okay I think  */
 
1025
    snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
 
1026
                        SNMPD_CALLBACK_UNREGISTER_OID, &reg_parms);
 
1027
 
 
1028
    return 0;
 
1029
}
 
1030
 
 
1031
int
 
1032
unregister_mib_range(oid * name, size_t len, int priority,
 
1033
                     int range_subid, oid range_ubound)
 
1034
{
 
1035
    return unregister_mib_context(name, len, priority, range_subid,
 
1036
                                  range_ubound, "");
 
1037
}
 
1038
 
 
1039
int
 
1040
unregister_mib_priority(oid * name, size_t len, int priority)
 
1041
{
 
1042
    return unregister_mib_range(name, len, priority, 0, 0);
 
1043
}
 
1044
 
 
1045
int
 
1046
unregister_mib(oid * name, size_t len)
 
1047
{
 
1048
    return unregister_mib_priority(name, len, DEFAULT_MIB_PRIORITY);
 
1049
}
 
1050
 
 
1051
void
 
1052
unregister_mibs_by_session(netsnmp_session * ss)
 
1053
{
 
1054
    netsnmp_subtree *list, *list2;
 
1055
    netsnmp_subtree *child, *prev, *next_child;
 
1056
    struct register_parameters rp;
 
1057
    subtree_context_cache *contextptr;
 
1058
 
 
1059
    DEBUGMSGTL(("register_mib", "unregister_mibs_by_session(%p) ctxt \"%s\"\n",
 
1060
                ss, (ss && ss->contextName) ? ss->contextName : "[NIL]"));
 
1061
 
 
1062
    for (contextptr = get_top_context_cache(); contextptr != NULL;
 
1063
         contextptr = contextptr->next) {
 
1064
        for (list = contextptr->first_subtree; list != NULL; list = list2) {
 
1065
            list2 = list->next;
 
1066
 
 
1067
            for (child = list, prev = NULL; child != NULL; child = next_child){
 
1068
                next_child = child->children;
 
1069
 
 
1070
                if (((!ss || ss->flags & SNMP_FLAGS_SUBSESSION) &&
 
1071
                     child->session == ss) ||
 
1072
                    (!(!ss || ss->flags & SNMP_FLAGS_SUBSESSION) && child->session &&
 
1073
                     child->session->subsession == ss)) {
 
1074
 
 
1075
                    rp.name = child->name_a;
 
1076
                    child->name_a = NULL;
 
1077
                    rp.namelen = child->namelen;
 
1078
                    rp.priority = child->priority;
 
1079
                    rp.range_subid = child->range_subid;
 
1080
                    rp.range_ubound = child->range_ubound;
 
1081
                    rp.timeout = child->timeout;
 
1082
                    rp.flags = child->flags;
 
1083
 
 
1084
                    if (child->reginfo != NULL) {
 
1085
                        /*
 
1086
                         * Don't let's free the session pointer just yet!  
 
1087
                         */
 
1088
                        child->reginfo->handler->myvoid = NULL;
 
1089
                        netsnmp_handler_registration_free(child->reginfo);
 
1090
                        child->reginfo = NULL;
 
1091
                    }
 
1092
 
 
1093
                    netsnmp_subtree_unload(child, prev, contextptr->context_name);
 
1094
                    netsnmp_subtree_free(child);
 
1095
 
 
1096
                    snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
 
1097
                                        SNMPD_CALLBACK_UNREGISTER_OID, &rp);
 
1098
                    SNMP_FREE(rp.name);
 
1099
                } else {
 
1100
                    prev = child;
 
1101
                }
 
1102
            }
 
1103
        }
 
1104
        netsnmp_subtree_join(contextptr->first_subtree);
 
1105
    }
 
1106
}
 
1107
 
 
1108
/*
 
1109
 * in_a_view: determines if a given snmp_pdu is allowed to see a
 
1110
 * given name/namelen OID pointer
 
1111
 * name         IN - name of var, OUT - name matched
 
1112
 * nameLen      IN -number of sub-ids in name, OUT - subid-is in matched name
 
1113
 * pi           IN - relevant auth info re PDU 
 
1114
 * cvp          IN - relevant auth info re mib module
 
1115
 */
 
1116
 
 
1117
int
 
1118
in_a_view(oid *name, size_t *namelen, netsnmp_pdu *pdu, int type)
 
1119
{
 
1120
    struct view_parameters view_parms;
 
1121
 
 
1122
    if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
 
1123
        /* Enable bypassing of view-based access control */
 
1124
        return VACM_SUCCESS;
 
1125
    }
 
1126
 
 
1127
    /*
 
1128
     * check for v1 and counter64s, since snmpv1 doesn't support it 
 
1129
     */
 
1130
    if (pdu->version == SNMP_VERSION_1 && type == ASN_COUNTER64) {
 
1131
        return VACM_NOTINVIEW;
 
1132
    }
 
1133
 
 
1134
    view_parms.pdu = pdu;
 
1135
    view_parms.name = name;
 
1136
    if (namelen != NULL) {
 
1137
        view_parms.namelen = *namelen;
 
1138
    } else {
 
1139
        view_parms.namelen = 0;
 
1140
    }
 
1141
    view_parms.errorcode = 0;
 
1142
    view_parms.check_subtree = 0;
 
1143
 
 
1144
    switch (pdu->version) {
 
1145
    case SNMP_VERSION_1:
 
1146
    case SNMP_VERSION_2c:
 
1147
    case SNMP_VERSION_3:
 
1148
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
 
1149
                            SNMPD_CALLBACK_ACM_CHECK, &view_parms);
 
1150
        return view_parms.errorcode;
 
1151
    }
 
1152
    return VACM_NOSECNAME;
 
1153
}
 
1154
 
 
1155
/*
 
1156
 * check_acces: determines if a given snmp_pdu is ever going to be
 
1157
 * allowed to do anynthing or if it's not going to ever be
 
1158
 * authenticated.
 
1159
 */
 
1160
int
 
1161
check_access(netsnmp_pdu *pdu)
 
1162
{                               /* IN - pdu being checked */
 
1163
    struct view_parameters view_parms;
 
1164
    view_parms.pdu = pdu;
 
1165
    view_parms.name = 0;
 
1166
    view_parms.namelen = 0;
 
1167
    view_parms.errorcode = 0;
 
1168
    view_parms.check_subtree = 0;
 
1169
 
 
1170
    if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
 
1171
        /* Enable bypassing of view-based access control */
 
1172
        return 0;
 
1173
    }
 
1174
 
 
1175
    switch (pdu->version) {
 
1176
    case SNMP_VERSION_1:
 
1177
    case SNMP_VERSION_2c:
 
1178
    case SNMP_VERSION_3:
 
1179
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
 
1180
                            SNMPD_CALLBACK_ACM_CHECK_INITIAL, &view_parms);
 
1181
        return view_parms.errorcode;
 
1182
    }
 
1183
    return 1;
 
1184
}
 
1185
 
 
1186
/** checks to see if everything within a
 
1187
 *  given subtree is either: in view, not in view, or possibly both.
 
1188
 *  If the entire subtree is not-in-view we can use this information to
 
1189
 *  skip calling the sub-handlers entirely.
 
1190
 *  @returns 0 if entire subtree is accessible, 5 if not and 7 if
 
1191
 *  portions are both.  1 on error (illegal pdu version).
 
1192
 */
 
1193
int
 
1194
netsnmp_acm_check_subtree(netsnmp_pdu *pdu, oid *name, size_t namelen)
 
1195
{                               /* IN - pdu being checked */
 
1196
    struct view_parameters view_parms;
 
1197
    view_parms.pdu = pdu;
 
1198
    view_parms.name = name;
 
1199
    view_parms.namelen = namelen;
 
1200
    view_parms.errorcode = 0;
 
1201
    view_parms.check_subtree = 1;
 
1202
 
 
1203
    if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
 
1204
        /* Enable bypassing of view-based access control */
 
1205
        return 0;
 
1206
    }
 
1207
 
 
1208
    switch (pdu->version) {
 
1209
    case SNMP_VERSION_1:
 
1210
    case SNMP_VERSION_2c:
 
1211
    case SNMP_VERSION_3:
 
1212
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
 
1213
                            SNMPD_CALLBACK_ACM_CHECK_SUBTREE, &view_parms);
 
1214
        return view_parms.errorcode;
 
1215
    }
 
1216
    return 1;
 
1217
}
 
1218
 
 
1219
#define SUBTREE_DEFAULT_CACHE_SIZE 8
 
1220
#define SUBTREE_MAX_CACHE_SIZE     32
 
1221
int lookup_cache_size = 0; /*enabled later after registrations are loaded */
 
1222
 
 
1223
typedef struct lookup_cache_s {
 
1224
   netsnmp_subtree *next;
 
1225
   netsnmp_subtree *previous;
 
1226
} lookup_cache;
 
1227
 
 
1228
typedef struct lookup_cache_context_s {
 
1229
   char *context;
 
1230
   struct lookup_cache_context_s *next;
 
1231
   int thecachecount;
 
1232
   int currentpos;
 
1233
   lookup_cache cache[SUBTREE_MAX_CACHE_SIZE];
 
1234
} lookup_cache_context;
 
1235
 
 
1236
static lookup_cache_context *thecontextcache = NULL;
 
1237
 
 
1238
/** set the lookup cache size for optimized agent registration performance.
 
1239
 * @param newsize set to the maximum size of a cache for a given
 
1240
 * context.  Set to 0 to completely disable caching, or to -1 to set
 
1241
 * to the default cache size (8), or to a number of your chosing.  The
 
1242
 * rough guide is that it should be equal to the maximum number of
 
1243
 * simultanious managers you expect to talk to the agent (M) times 80%
 
1244
 * (or so, he says randomly) the average number (N) of varbinds you
 
1245
 * expect to receive in a given request for a manager.  ie, M times N.
 
1246
 * Bigger does NOT necessarily mean better.  Certainly 16 should be an
 
1247
 * upper limit.  32 is the hard coded limit.
 
1248
 */
 
1249
void
 
1250
netsnmp_set_lookup_cache_size(int newsize) {
 
1251
    if (newsize < 0)
 
1252
        lookup_cache_size = SUBTREE_DEFAULT_CACHE_SIZE;
 
1253
    else if (newsize < SUBTREE_MAX_CACHE_SIZE)
 
1254
        lookup_cache_size = newsize;
 
1255
    else
 
1256
        lookup_cache_size = SUBTREE_MAX_CACHE_SIZE;
 
1257
}
 
1258
 
 
1259
/** retrieves the current value of the lookup cache size
 
1260
 *  @return the current lookup cache size
 
1261
 */
 
1262
int
 
1263
netsnmp_get_lookup_cache_size(void) {
 
1264
    return lookup_cache_size;
 
1265
}
 
1266
 
 
1267
NETSNMP_STATIC_INLINE lookup_cache_context *
 
1268
get_context_lookup_cache(const char *context) {
 
1269
    lookup_cache_context *ptr;
 
1270
    if (!context)
 
1271
        context = "";
 
1272
 
 
1273
    for(ptr = thecontextcache; ptr; ptr = ptr->next) {
 
1274
        if (strcmp(ptr->context, context) == 0)
 
1275
            break;
 
1276
    }
 
1277
    if (!ptr) {
 
1278
        if (netsnmp_subtree_find_first(context)) {
 
1279
            ptr = SNMP_MALLOC_TYPEDEF(lookup_cache_context);
 
1280
            ptr->next = thecontextcache;
 
1281
            ptr->context = strdup(context);
 
1282
            thecontextcache = ptr;
 
1283
        } else {
 
1284
            return NULL;
 
1285
        }
 
1286
    }
 
1287
    return ptr;
 
1288
}
 
1289
 
 
1290
NETSNMP_STATIC_INLINE void
 
1291
lookup_cache_add(const char *context,
 
1292
                 netsnmp_subtree *next, netsnmp_subtree *previous) {
 
1293
    lookup_cache_context *cptr;
 
1294
 
 
1295
    if ((cptr = get_context_lookup_cache(context)) == NULL)
 
1296
        return;
 
1297
    
 
1298
    if (cptr->thecachecount < lookup_cache_size)
 
1299
        cptr->thecachecount++;
 
1300
 
 
1301
    cptr->cache[cptr->currentpos].next = next;
 
1302
    cptr->cache[cptr->currentpos].previous = previous;
 
1303
 
 
1304
    if (++cptr->currentpos >= lookup_cache_size)
 
1305
        cptr->currentpos = 0;
 
1306
}
 
1307
 
 
1308
NETSNMP_STATIC_INLINE void
 
1309
lookup_cache_replace(lookup_cache *ptr,
 
1310
                     netsnmp_subtree *next, netsnmp_subtree *previous) {
 
1311
 
 
1312
    ptr->next = next;
 
1313
    ptr->previous = previous;
 
1314
}
 
1315
 
 
1316
NETSNMP_STATIC_INLINE lookup_cache *
 
1317
lookup_cache_find(const char *context, oid *name, size_t name_len,
 
1318
                  int *retcmp) {
 
1319
    lookup_cache_context *cptr;
 
1320
    lookup_cache *ret = NULL;
 
1321
    int cmp;
 
1322
    int i;
 
1323
 
 
1324
    if ((cptr = get_context_lookup_cache(context)) == NULL)
 
1325
        return NULL;
 
1326
 
 
1327
    for(i = 0; i < cptr->thecachecount && i < lookup_cache_size; i++) {
 
1328
        if (cptr->cache[i].previous->start_a)
 
1329
            cmp = snmp_oid_compare(name, name_len,
 
1330
                                   cptr->cache[i].previous->start_a,
 
1331
                                   cptr->cache[i].previous->start_len);
 
1332
        else
 
1333
            cmp = 1;
 
1334
        if (cmp >= 0) {
 
1335
            *retcmp = cmp;
 
1336
            ret = &(cptr->cache[i]);
 
1337
        }
 
1338
    }
 
1339
    return ret;
 
1340
}
 
1341
 
 
1342
NETSNMP_STATIC_INLINE void
 
1343
invalidate_lookup_cache(const char *context) {
 
1344
    lookup_cache_context *cptr;
 
1345
    if ((cptr = get_context_lookup_cache(context)) != NULL) {
 
1346
        cptr->thecachecount = 0;
 
1347
        cptr->currentpos = 0;
 
1348
    }
 
1349
}
 
1350
 
 
1351
netsnmp_subtree *
 
1352
netsnmp_subtree_find_prev(oid *name, size_t len, netsnmp_subtree *subtree,
 
1353
                          const char *context_name)
 
1354
{
 
1355
    lookup_cache *lookup_cache = NULL;
 
1356
    netsnmp_subtree *myptr = NULL, *previous = NULL;
 
1357
    int cmp = 1;
 
1358
 
 
1359
    if (subtree) {
 
1360
        myptr = subtree;
 
1361
    } else {
 
1362
        /* look through everything */
 
1363
        if (lookup_cache_size) {
 
1364
            lookup_cache = lookup_cache_find(context_name, name, len, &cmp);
 
1365
            if (lookup_cache) {
 
1366
                myptr = lookup_cache->next;
 
1367
                previous = lookup_cache->previous;
 
1368
            }
 
1369
            if (!myptr)
 
1370
                myptr = netsnmp_subtree_find_first(context_name);
 
1371
        } else {
 
1372
            myptr = netsnmp_subtree_find_first(context_name);
 
1373
        }
 
1374
    }
 
1375
 
 
1376
    for (; myptr != NULL; previous = myptr, myptr = myptr->next) {
 
1377
        if (snmp_oid_compare(name, len, myptr->start_a, myptr->start_len) < 0) {
 
1378
            if (lookup_cache_size && previous && cmp) {
 
1379
                if (lookup_cache) {
 
1380
                    lookup_cache_replace(lookup_cache, myptr, previous);
 
1381
                } else {
 
1382
                    lookup_cache_add(context_name, myptr, previous);
 
1383
                }
 
1384
            }
 
1385
            return previous;
 
1386
        }
 
1387
    }
 
1388
    return previous;
 
1389
}
 
1390
 
 
1391
netsnmp_subtree *
 
1392
netsnmp_subtree_find_next(oid *name, size_t len,
 
1393
                          netsnmp_subtree *subtree, const char *context_name)
 
1394
{
 
1395
    netsnmp_subtree *myptr = NULL;
 
1396
 
 
1397
    myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name);
 
1398
 
 
1399
    if (myptr != NULL) {
 
1400
        myptr = myptr->next;
 
1401
        while (myptr != NULL && (myptr->variables == NULL || 
 
1402
                                 myptr->variables_len == 0)) {
 
1403
            myptr = myptr->next;
 
1404
        }
 
1405
        return myptr;
 
1406
    } else if (subtree != NULL && snmp_oid_compare(name, len, 
 
1407
                                   subtree->start_a, subtree->start_len) < 0) {
 
1408
        return subtree;
 
1409
    } else {
 
1410
        return NULL;
 
1411
    }
 
1412
}
 
1413
 
 
1414
netsnmp_subtree *
 
1415
netsnmp_subtree_find(oid *name, size_t len, netsnmp_subtree *subtree, 
 
1416
                     const char *context_name)
 
1417
{
 
1418
    netsnmp_subtree *myptr;
 
1419
 
 
1420
    myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name);
 
1421
    if (myptr && myptr->end_a &&
 
1422
        snmp_oid_compare(name, len, myptr->end_a, myptr->end_len)<0) {
 
1423
        return myptr;
 
1424
    }
 
1425
 
 
1426
    return NULL;
 
1427
}
 
1428
 
 
1429
netsnmp_session *
 
1430
get_session_for_oid(oid *name, size_t len, const char *context_name)
 
1431
{
 
1432
    netsnmp_subtree *myptr;
 
1433
 
 
1434
    myptr = netsnmp_subtree_find_prev(name, len, 
 
1435
                                      netsnmp_subtree_find_first(context_name),
 
1436
                                      context_name);
 
1437
 
 
1438
    while (myptr && myptr->variables == NULL) {
 
1439
        myptr = myptr->next;
 
1440
    }
 
1441
 
 
1442
    if (myptr == NULL) {
 
1443
        return NULL;
 
1444
    } else {
 
1445
        return myptr->session;
 
1446
    }
 
1447
}
 
1448
 
 
1449
void
 
1450
setup_tree(void)
 
1451
{
 
1452
    oid ccitt[1]           = { 0 };
 
1453
    oid iso[1]             = { 1 };
 
1454
    oid joint_ccitt_iso[1] = { 2 };
 
1455
 
 
1456
#ifdef USING_AGENTX_SUBAGENT_MODULE
 
1457
    int role =  netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
 
1458
                                       NETSNMP_DS_AGENT_ROLE);
 
1459
 
 
1460
    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 
 
1461
                           MASTER_AGENT);
 
1462
#endif
 
1463
 
 
1464
    /* 
 
1465
     * we need to have the oid's in the heap, that we can *free* it for every case, 
 
1466
     * thats the purpose of the duplicate_objid's
 
1467
     */
 
1468
    netsnmp_register_null(snmp_duplicate_objid(ccitt, 1), 1);
 
1469
    netsnmp_register_null(snmp_duplicate_objid(iso, 1), 1);
 
1470
    netsnmp_register_null(snmp_duplicate_objid(joint_ccitt_iso, 1), 1);
 
1471
 
 
1472
#ifdef USING_AGENTX_SUBAGENT_MODULE
 
1473
    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 
 
1474
                           role);
 
1475
#endif
 
1476
}
 
1477
 
 
1478
int 
 
1479
remove_tree_entry (oid *name, size_t len) {
 
1480
 
 
1481
    netsnmp_subtree *sub = NULL;
 
1482
 
 
1483
    if ((sub = netsnmp_subtree_find(name, len, NULL, "")) == NULL) {
 
1484
        return MIB_NO_SUCH_REGISTRATION;
 
1485
    }
 
1486
 
 
1487
    return unregister_mib_context(name, len, sub->priority,
 
1488
                                  sub->range_subid, sub->range_ubound, "");
 
1489
 
 
1490
}
 
1491
 
 
1492
 
 
1493
void
 
1494
shutdown_tree(void) {
 
1495
    oid ccitt[1]           = { 0 };
 
1496
    oid iso[1]             = { 1 };
 
1497
    oid joint_ccitt_iso[1] = { 2 };
 
1498
 
 
1499
    DEBUGMSGTL(("agent_registry", "shut down tree\n"));
 
1500
 
 
1501
    remove_tree_entry(joint_ccitt_iso, 1);
 
1502
    remove_tree_entry(iso, 1);
 
1503
    remove_tree_entry(ccitt, 1);
 
1504
 
 
1505
}
 
1506
 
 
1507
void
 
1508
clear_subtree (netsnmp_subtree *sub) {
 
1509
 
 
1510
    netsnmp_subtree *nxt;
 
1511
    
 
1512
    if (sub == NULL)
 
1513
        return;
 
1514
 
 
1515
    for(nxt = sub; nxt;) {
 
1516
        if (nxt->children != NULL) {
 
1517
            clear_subtree(nxt->children);
 
1518
        }
 
1519
        sub = nxt;
 
1520
        nxt = nxt->next;
 
1521
        netsnmp_subtree_free(sub);
 
1522
    }
 
1523
 
 
1524
}
 
1525
 
 
1526
void
 
1527
clear_lookup_cache(void) {
 
1528
 
 
1529
    lookup_cache_context *ptr = NULL, *next = NULL;
 
1530
 
 
1531
    ptr = thecontextcache;
 
1532
    while (ptr) {
 
1533
        next = ptr->next;
 
1534
        SNMP_FREE(ptr->context);
 
1535
        SNMP_FREE(ptr);
 
1536
        ptr = next;
 
1537
    }
 
1538
    thecontextcache = NULL; /* !!! */
 
1539
}
 
1540
 
 
1541
void
 
1542
clear_context(void) {
 
1543
 
 
1544
    subtree_context_cache *ptr = NULL, *next = NULL;
 
1545
 
 
1546
    DEBUGMSGTL(("agent_registry", "clear context\n"));
 
1547
 
 
1548
    ptr = get_top_context_cache(); 
 
1549
    while (ptr) {
 
1550
        next = ptr->next;
 
1551
 
 
1552
        if (ptr->first_subtree) {
 
1553
            clear_subtree(ptr->first_subtree);
 
1554
        }
 
1555
 
 
1556
        SNMP_FREE(ptr->context_name);
 
1557
        SNMP_FREE(ptr);
 
1558
 
 
1559
        ptr = next;
 
1560
    }
 
1561
    context_subtrees = NULL; /* !!! */
 
1562
    clear_lookup_cache();
 
1563
}
 
1564
 
 
1565
extern void     dump_idx_registry(void);
 
1566
void
 
1567
dump_registry(void)
 
1568
{
 
1569
    struct variable *vp = NULL;
 
1570
    netsnmp_subtree *myptr, *myptr2;
 
1571
    u_char *s = NULL, *e = NULL, *v = NULL;
 
1572
    size_t sl = 256, el = 256, vl = 256, sl_o = 0, el_o = 0, vl_o = 0;
 
1573
    int i = 0;
 
1574
 
 
1575
    if ((s = (u_char *) calloc(sl, 1)) != NULL &&
 
1576
        (e = (u_char *) calloc(sl, 1)) != NULL &&
 
1577
        (v = (u_char *) calloc(sl, 1)) != NULL) {
 
1578
 
 
1579
        subtree_context_cache *ptr;
 
1580
        for (ptr = context_subtrees; ptr; ptr = ptr->next) {
 
1581
            printf("Subtrees for Context: %s\n", ptr->context_name);
 
1582
            for (myptr = ptr->first_subtree; myptr != NULL;
 
1583
                 myptr = myptr->next) {
 
1584
                sl_o = el_o = vl_o = 0;
 
1585
 
 
1586
                if (!sprint_realloc_objid(&s, &sl, &sl_o, 1,
 
1587
                                          myptr->start_a,
 
1588
                                          myptr->start_len)) {
 
1589
                    break;
 
1590
                }
 
1591
                if (!sprint_realloc_objid(&e, &el, &el_o, 1,
 
1592
                                          myptr->end_a,
 
1593
                                          myptr->end_len)) {
 
1594
                    break;
 
1595
                }
 
1596
 
 
1597
                if (myptr->variables) {
 
1598
                    printf("%02x ( %s - %s ) [", myptr->flags, s, e);
 
1599
                    for (i = 0, vp = myptr->variables;
 
1600
                         i < myptr->variables_len; i++) {
 
1601
                        vl_o = 0;
 
1602
                        if (!sprint_realloc_objid
 
1603
                            (&v, &vl, &vl_o, 1, vp->name, vp->namelen)) {
 
1604
                            break;
 
1605
                        }
 
1606
                        printf("%s, ", v);
 
1607
                        vp = (struct variable *) ((char *) vp +
 
1608
                                                  myptr->variables_width);
 
1609
                    }
 
1610
                    printf("]\n");
 
1611
                } else {
 
1612
                    printf("%02x   %s - %s  \n", myptr->flags, s, e);
 
1613
                }
 
1614
                for (myptr2 = myptr; myptr2 != NULL;
 
1615
                     myptr2 = myptr2->children) {
 
1616
                    if (myptr2->label_a && myptr2->label_a[0]) {
 
1617
                        if (strcmp(myptr2->label_a, "old_api") == 0) {
 
1618
                            struct variable *vp =
 
1619
                                myptr2->reginfo->handler->myvoid;
 
1620
 
 
1621
                            sprint_realloc_objid(&s, &sl, &sl_o, 1,
 
1622
                                                 vp->name, vp->namelen);
 
1623
                            printf("\t%s[%s] %p var %s\n", myptr2->label_a,
 
1624
                                   myptr2->reginfo->handlerName ? myptr2->
 
1625
                                   reginfo->handlerName : "no-name",
 
1626
                                   myptr2->reginfo, s);
 
1627
                        } else {
 
1628
                            printf("\t%s %s %p\n", myptr2->label_a,
 
1629
                                   myptr2->reginfo->handlerName ? myptr2->
 
1630
                                   reginfo->
 
1631
                                   handlerName : "no-handler-name",
 
1632
                                   myptr2->reginfo);
 
1633
                        }
 
1634
                    }
 
1635
                }
 
1636
            }
 
1637
        }
 
1638
    }
 
1639
 
 
1640
    if (s != NULL) {
 
1641
        SNMP_FREE(s);
 
1642
    }
 
1643
    if (e != NULL) {
 
1644
        SNMP_FREE(e);
 
1645
    }
 
1646
    if (v != NULL) {
 
1647
        SNMP_FREE(v);
 
1648
    }
 
1649
 
 
1650
    dump_idx_registry();
 
1651
}
 
1652
 
 
1653
 
 
1654
int     external_readfd[NUM_EXTERNAL_FDS],   external_readfdlen   = 0;
 
1655
int     external_writefd[NUM_EXTERNAL_FDS],  external_writefdlen  = 0;
 
1656
int     external_exceptfd[NUM_EXTERNAL_FDS], external_exceptfdlen = 0;
 
1657
void  (*external_readfdfunc[NUM_EXTERNAL_FDS]) (int, void *);
 
1658
void  (*external_writefdfunc[NUM_EXTERNAL_FDS]) (int, void *);
 
1659
void  (*external_exceptfdfunc[NUM_EXTERNAL_FDS]) (int, void *);
 
1660
void   *external_readfd_data[NUM_EXTERNAL_FDS];
 
1661
void   *external_writefd_data[NUM_EXTERNAL_FDS];
 
1662
void   *external_exceptfd_data[NUM_EXTERNAL_FDS];
 
1663
 
 
1664
int
 
1665
register_readfd(int fd, void (*func) (int, void *), void *data)
 
1666
{
 
1667
    if (external_readfdlen < NUM_EXTERNAL_FDS) {
 
1668
        external_readfd[external_readfdlen] = fd;
 
1669
        external_readfdfunc[external_readfdlen] = func;
 
1670
        external_readfd_data[external_readfdlen] = data;
 
1671
        external_readfdlen++;
 
1672
        DEBUGMSGTL(("register_readfd", "registered fd %d\n", fd));
 
1673
        return FD_REGISTERED_OK;
 
1674
    } else {
 
1675
        snmp_log(LOG_CRIT, "register_readfd: too many file descriptors\n");
 
1676
        return FD_REGISTRATION_FAILED;
 
1677
    }
 
1678
}
 
1679
 
 
1680
int
 
1681
register_writefd(int fd, void (*func) (int, void *), void *data)
 
1682
{
 
1683
    if (external_writefdlen < NUM_EXTERNAL_FDS) {
 
1684
        external_writefd[external_writefdlen] = fd;
 
1685
        external_writefdfunc[external_writefdlen] = func;
 
1686
        external_writefd_data[external_writefdlen] = data;
 
1687
        external_writefdlen++;
 
1688
        DEBUGMSGTL(("register_writefd", "registered fd %d\n", fd));
 
1689
        return FD_REGISTERED_OK;
 
1690
    } else {
 
1691
        snmp_log(LOG_CRIT,
 
1692
                 "register_writefd: too many file descriptors\n");
 
1693
        return FD_REGISTRATION_FAILED;
 
1694
    }
 
1695
}
 
1696
 
 
1697
int
 
1698
register_exceptfd(int fd, void (*func) (int, void *), void *data)
 
1699
{
 
1700
    if (external_exceptfdlen < NUM_EXTERNAL_FDS) {
 
1701
        external_exceptfd[external_exceptfdlen] = fd;
 
1702
        external_exceptfdfunc[external_exceptfdlen] = func;
 
1703
        external_exceptfd_data[external_exceptfdlen] = data;
 
1704
        external_exceptfdlen++;
 
1705
        DEBUGMSGTL(("register_exceptfd", "registered fd %d\n", fd));
 
1706
        return FD_REGISTERED_OK;
 
1707
    } else {
 
1708
        snmp_log(LOG_CRIT,
 
1709
                 "register_exceptfd: too many file descriptors\n");
 
1710
        return FD_REGISTRATION_FAILED;
 
1711
    }
 
1712
}
 
1713
 
 
1714
int
 
1715
unregister_readfd(int fd)
 
1716
{
 
1717
    int             i, j;
 
1718
 
 
1719
    for (i = 0; i < external_readfdlen; i++) {
 
1720
        if (external_readfd[i] == fd) {
 
1721
            external_readfdlen--;
 
1722
            for (j = i; j < external_readfdlen; j++) {
 
1723
                external_readfd[j] = external_readfd[j + 1];
 
1724
                external_readfdfunc[j] = external_readfdfunc[j + 1];
 
1725
                external_readfd_data[j] = external_readfd_data[j + 1];
 
1726
            }
 
1727
            DEBUGMSGTL(("unregister_readfd", "unregistered fd %d\n", fd));
 
1728
            return FD_UNREGISTERED_OK;
 
1729
        }
 
1730
    }
 
1731
    return FD_NO_SUCH_REGISTRATION;
 
1732
}
 
1733
 
 
1734
int
 
1735
unregister_writefd(int fd)
 
1736
{
 
1737
    int             i, j;
 
1738
 
 
1739
    for (i = 0; i < external_writefdlen; i++) {
 
1740
        if (external_writefd[i] == fd) {
 
1741
            external_writefdlen--;
 
1742
            for (j = i; j < external_writefdlen; j++) {
 
1743
                external_writefd[j] = external_writefd[j + 1];
 
1744
                external_writefdfunc[j] = external_writefdfunc[j + 1];
 
1745
                external_writefd_data[j] = external_writefd_data[j + 1];
 
1746
            }
 
1747
            DEBUGMSGTL(("unregister_writefd", "unregistered fd %d\n", fd));
 
1748
            return FD_UNREGISTERED_OK;
 
1749
        }
 
1750
    }
 
1751
    return FD_NO_SUCH_REGISTRATION;
 
1752
}
 
1753
 
 
1754
int
 
1755
unregister_exceptfd(int fd)
 
1756
{
 
1757
    int             i, j;
 
1758
 
 
1759
    for (i = 0; i < external_exceptfdlen; i++) {
 
1760
        if (external_exceptfd[i] == fd) {
 
1761
            external_exceptfdlen--;
 
1762
            for (j = i; j < external_exceptfdlen; j++) {
 
1763
                external_exceptfd[j] = external_exceptfd[j + 1];
 
1764
                external_exceptfdfunc[j] = external_exceptfdfunc[j + 1];
 
1765
                external_exceptfd_data[j] = external_exceptfd_data[j + 1];
 
1766
            }
 
1767
            DEBUGMSGTL(("unregister_exceptfd", "unregistered fd %d\n",
 
1768
                        fd));
 
1769
            return FD_UNREGISTERED_OK;
 
1770
        }
 
1771
    }
 
1772
    return FD_NO_SUCH_REGISTRATION;
 
1773
}
 
1774
 
 
1775
int             external_signal_scheduled[NUM_EXTERNAL_SIGS];
 
1776
void            (*external_signal_handler[NUM_EXTERNAL_SIGS]) (int);
 
1777
 
 
1778
#ifndef WIN32
 
1779
 
 
1780
/*
 
1781
 * TODO: add agent_SIGXXX_handler functions and `case SIGXXX: ...' lines
 
1782
 *       below for every single that might be handled by register_signal().
 
1783
 */
 
1784
 
 
1785
RETSIGTYPE
 
1786
agent_SIGCHLD_handler(int sig)
 
1787
{
 
1788
    external_signal_scheduled[SIGCHLD]++;
 
1789
#ifndef HAVE_SIGACTION
 
1790
    /*
 
1791
     * signal() sucks. It *might* have SysV semantics, which means that
 
1792
     * * a signal handler is reset once it gets called. Ensure that it
 
1793
     * * remains active.
 
1794
     */
 
1795
    signal(SIGCHLD, agent_SIGCHLD_handler);
 
1796
#endif
 
1797
}
 
1798
 
 
1799
int
 
1800
register_signal(int sig, void (*func) (int))
 
1801
{
 
1802
 
 
1803
    switch (sig) {
 
1804
#if defined(SIGCHLD)
 
1805
    case SIGCHLD:
 
1806
#ifdef HAVE_SIGACTION
 
1807
        {
 
1808
            static struct sigaction act;
 
1809
            act.sa_handler = agent_SIGCHLD_handler;
 
1810
            sigemptyset(&act.sa_mask);
 
1811
            act.sa_flags = 0;
 
1812
            sigaction(SIGCHLD, &act, NULL);
 
1813
        }
 
1814
#else
 
1815
        signal(SIGCHLD, agent_SIGCHLD_handler);
 
1816
#endif
 
1817
        break;
 
1818
#endif
 
1819
    default:
 
1820
        snmp_log(LOG_CRIT,
 
1821
                 "register_signal: signal %d cannot be handled\n", sig);
 
1822
        return SIG_REGISTRATION_FAILED;
 
1823
    }
 
1824
 
 
1825
    external_signal_handler[sig] = func;
 
1826
    external_signal_scheduled[sig] = 0;
 
1827
 
 
1828
    DEBUGMSGTL(("register_signal", "registered signal %d\n", sig));
 
1829
    return SIG_REGISTERED_OK;
 
1830
}
 
1831
 
 
1832
int
 
1833
unregister_signal(int sig)
 
1834
{
 
1835
    signal(sig, SIG_DFL);
 
1836
    DEBUGMSGTL(("unregister_signal", "unregistered signal %d\n", sig));
 
1837
    return SIG_UNREGISTERED_OK;
 
1838
}
 
1839
 
 
1840
#endif                          /* !WIN32 */
 
1841
 
 
1842
/**  }@ */