~ubuntu-branches/ubuntu/gutsy/net-snmp/gutsy-security

« back to all changes in this revision

Viewing changes to agent/mibgroup/smux/smux.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
 * Smux module authored by Rohit Dube.
 
3
 * Rewritten by Nick Amato <naamato@merit.net>.
 
4
 */
 
5
 
 
6
#include <net-snmp/net-snmp-config.h>
 
7
#include <sys/types.h>
 
8
#include <ctype.h>
 
9
 
 
10
#if HAVE_IO_H                   /* win32 */
 
11
#include <io.h>
 
12
#endif
 
13
#include <stdio.h>
 
14
#if HAVE_STDLIB_H
 
15
#include <stdlib.h>
 
16
#endif
 
17
#if HAVE_STRING_H
 
18
#include <string.h>
 
19
#else
 
20
#include <strings.h>
 
21
#endif
 
22
#if HAVE_UNISTD_H
 
23
#include <unistd.h>
 
24
#endif
 
25
#if HAVE_ERR_H
 
26
#include <err.h>
 
27
#endif
 
28
#if TIME_WITH_SYS_TIME
 
29
# ifdef WIN32
 
30
#  include <sys/timeb.h>
 
31
# else
 
32
#  include <sys/time.h>
 
33
# endif
 
34
# include <time.h>
 
35
#else
 
36
# if HAVE_SYS_TIME_H
 
37
#  include <sys/time.h>
 
38
# else
 
39
#  include <time.h>
 
40
# endif
 
41
#endif
 
42
#include <errno.h>
 
43
#if HAVE_NETDB_H
 
44
#include <netdb.h>
 
45
#endif
 
46
 
 
47
#include <sys/stat.h>
 
48
#if HAVE_SYS_SOCKET_H
 
49
#include <sys/socket.h>
 
50
#elif HAVE_WINSOCK_H
 
51
#include <winsock.h>
 
52
#endif
 
53
#if HAVE_SYS_FILIO_H
 
54
#include <sys/filio.h>
 
55
#endif
 
56
 
 
57
#if HAVE_NETINET_IN_H
 
58
#include <netinet/in.h>
 
59
#endif
 
60
 
 
61
#if HAVE_ARPA_INET_H
 
62
#include <arpa/inet.h>
 
63
#endif
 
64
 
 
65
#if HAVE_SYS_IOCTL_H
 
66
#include <sys/ioctl.h>
 
67
#endif
 
68
 
 
69
#include <net-snmp/net-snmp-includes.h>
 
70
#include <net-snmp/agent/net-snmp-agent-includes.h>
 
71
 
 
72
#include "smux.h"
 
73
#include "util_funcs.h"
 
74
#include "mibdefs.h"
 
75
#include "snmpd.h"
 
76
 
 
77
long            smux_long;
 
78
u_long          smux_ulong;
 
79
struct sockaddr_in smux_sa;
 
80
struct counter64 smux_counter64;
 
81
oid             smux_objid[MAX_OID_LEN];
 
82
u_char          smux_str[SMUXMAXSTRLEN];
 
83
int             smux_listen_sd = -1;
 
84
 
 
85
static struct timeval smux_rcv_timeout;
 
86
static u_long   smux_reqid;
 
87
 
 
88
void            init_smux(void);
 
89
static u_char  *smux_open_process(int, u_char *, size_t *, int *);
 
90
static u_char  *smux_rreq_process(int, u_char *, size_t *);
 
91
static u_char  *smux_close_process(int, u_char *, size_t *);
 
92
static u_char  *smux_trap_process(u_char *, size_t *);
 
93
static u_char  *smux_parse(u_char *, oid *, size_t *, size_t *, u_char *);
 
94
static u_char  *smux_parse_var(u_char *, size_t *, oid *, size_t *,
 
95
                               size_t *, u_char *);
 
96
static void     smux_send_close(int, int);
 
97
static void     smux_list_detach(smux_reg **, smux_reg **);
 
98
static void     smux_replace_active(smux_reg *, smux_reg *);
 
99
static void     smux_peer_cleanup(int);
 
100
static int      smux_auth_peer(oid *, size_t, char *, int);
 
101
static int      smux_build(u_char, u_long, oid *,
 
102
                           size_t *, u_char, u_char *, size_t, u_char *,
 
103
                           size_t *);
 
104
static int      smux_list_add(smux_reg **, smux_reg *);
 
105
static int      smux_pdu_process(int, u_char *, size_t);
 
106
static int      smux_send_rrsp(int, int);
 
107
static smux_reg *smux_find_match(smux_reg *, int, oid *, size_t, long);
 
108
static smux_reg *smux_find_replacement(oid *, size_t);
 
109
u_char         *var_smux(struct variable *, oid *, size_t *, int, size_t *,
 
110
                         WriteMethod ** write_method);
 
111
int             var_smux_write(int, u_char *, u_char, size_t, u_char *,
 
112
                               oid *, size_t);
 
113
 
 
114
static smux_reg *ActiveRegs;    /* Active registrations                 */
 
115
static smux_reg *PassiveRegs;   /* Currently unused registrations       */
 
116
 
 
117
static smux_peer_auth *Auths[SMUX_MAX_PEERS];   /* Configured peers */
 
118
static int      nauths, npeers = 0;
 
119
 
 
120
struct variable2 smux_variables[] = {
 
121
    /*
 
122
     * bogus entry, as in pass.c 
 
123
     */
 
124
    {MIBINDEX, ASN_INTEGER, RWRITE, var_smux, 0, {MIBINDEX}},
 
125
};
 
126
 
 
127
 
 
128
 
 
129
void
 
130
smux_parse_smux_socket(const char *token, char *cptr)
 
131
{
 
132
    DEBUGMSGTL(("smux", "port spec: %s\n", cptr));
 
133
    netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_SMUX_SOCKET, cptr);
 
134
}
 
135
 
 
136
void
 
137
smux_parse_peer_auth(const char *token, char *cptr)
 
138
{
 
139
    smux_peer_auth *aptr;
 
140
 
 
141
    if ((aptr =
 
142
         (smux_peer_auth *) calloc(1, sizeof(smux_peer_auth))) == NULL) {
 
143
        snmp_log_perror("smux_parse_peer_auth: malloc");
 
144
        return;
 
145
    }
 
146
    aptr->sa_active_fd = -1;
 
147
    if (!cptr) {
 
148
        /*
 
149
         * null passwords OK 
 
150
         */
 
151
        Auths[nauths++] = aptr;
 
152
        DEBUGMSGTL(("smux_conf", "null password\n"));
 
153
        return;
 
154
    }
 
155
 
 
156
    if (*cptr == '.')
 
157
        cptr++;
 
158
 
 
159
    if (!isdigit(*cptr)) {
 
160
        config_perror("second token is not an OID");
 
161
        free((char *) aptr);
 
162
        return;
 
163
    }
 
164
    /*
 
165
     * oid 
 
166
     */
 
167
    aptr->sa_oid_len = parse_miboid(cptr, aptr->sa_oid);
 
168
 
 
169
    DEBUGMSGTL(("smux_conf", "parsing registration for: %s\n", cptr));
 
170
 
 
171
    while (isdigit(*cptr) || *cptr == '.')
 
172
        cptr++;
 
173
    cptr = skip_white(cptr);
 
174
 
 
175
    /*
 
176
     * password 
 
177
     */
 
178
    if (cptr)
 
179
        strcpy(aptr->sa_passwd, cptr);
 
180
 
 
181
    Auths[nauths++] = aptr;
 
182
}
 
183
 
 
184
void
 
185
smux_free_peer_auth(void)
 
186
{
 
187
    int             i;
 
188
 
 
189
    for (i = 0; i < nauths; i++) {
 
190
        free(Auths[i]);
 
191
        Auths[i] = NULL;
 
192
    }
 
193
    nauths = 0;
 
194
}
 
195
 
 
196
void
 
197
init_smux(void)
 
198
{
 
199
    snmpd_register_config_handler("smuxpeer", smux_parse_peer_auth,
 
200
                                  smux_free_peer_auth,
 
201
                                  "OID-IDENTITY PASSWORD");
 
202
    snmpd_register_config_handler("smuxsocket",
 
203
                                  smux_parse_smux_socket, NULL,
 
204
                                  "SMUX bind address");
 
205
}
 
206
 
 
207
void
 
208
real_init_smux(void)
 
209
{
 
210
    struct sockaddr_in lo_socket;
 
211
    char           *smux_socket;
 
212
    int             one = 1;
 
213
 
 
214
    if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE) == SUB_AGENT) {
 
215
        smux_listen_sd = -1;
 
216
        return;
 
217
    }
 
218
 
 
219
    /*
 
220
     * Reqid 
 
221
     */
 
222
    smux_reqid = 0;
 
223
    smux_listen_sd = -1;
 
224
 
 
225
    /*
 
226
     * Receive timeout 
 
227
     */
 
228
    smux_rcv_timeout.tv_sec = 0;
 
229
    smux_rcv_timeout.tv_usec = 500000;
 
230
 
 
231
    /*
 
232
     * Get ready to listen on the SMUX port
 
233
     */
 
234
    memset(&lo_socket, (0), sizeof(lo_socket));
 
235
    lo_socket.sin_family = AF_INET;
 
236
 
 
237
    smux_socket = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, 
 
238
                                        NETSNMP_DS_SMUX_SOCKET);
 
239
#ifdef LOCAL_SMUX
 
240
    if (!smux_socket)
 
241
        smux_socket = "127.0.0.1";   /* By default, listen on localhost only */
 
242
#endif
 
243
    netsnmp_sockaddr_in( &lo_socket, smux_socket, SMUXPORT );
 
244
 
 
245
    if ((smux_listen_sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
 
246
        snmp_log_perror("[init_smux] socket failed");
 
247
        return;
 
248
    }
 
249
#ifdef SO_REUSEADDR
 
250
    /*
 
251
     * At least on Linux, when the master agent terminates, any
 
252
     * TCP connections for SMUX peers are put in the TIME_WAIT
 
253
     * state for about 60 seconds. If the master agent is started
 
254
     * during this time, the bind for the listening socket will
 
255
     * fail because the SMUX port is in use.
 
256
     */
 
257
    if (setsockopt(smux_listen_sd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
 
258
                   sizeof(one)) < 0) {
 
259
        snmp_log_perror("[init_smux] setsockopt(SO_REUSEADDR) failed");
 
260
    }
 
261
#endif                          /* SO_REUSEADDR */
 
262
 
 
263
    if (bind(smux_listen_sd, (struct sockaddr *) &lo_socket,
 
264
             sizeof(lo_socket)) < 0) {
 
265
        snmp_log_perror("[init_smux] bind failed");
 
266
        close(smux_listen_sd);
 
267
        smux_listen_sd = -1;
 
268
        return;
 
269
    }
 
270
#ifdef  SO_KEEPALIVE
 
271
    if (setsockopt(smux_listen_sd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one,
 
272
                   sizeof(one)) < 0) {
 
273
        snmp_log_perror("[init_smux] setsockopt(SO_KEEPALIVE) failed");
 
274
        close(smux_listen_sd);
 
275
        smux_listen_sd = -1;
 
276
        return;
 
277
    }
 
278
#endif                          /* SO_KEEPALIVE */
 
279
 
 
280
    if (listen(smux_listen_sd, SOMAXCONN) == -1) {
 
281
        snmp_log_perror("[init_smux] listen failed");
 
282
        close(smux_listen_sd);
 
283
        smux_listen_sd = -1;
 
284
        return;
 
285
    }
 
286
 
 
287
    DEBUGMSGTL(("smux_init",
 
288
                "[smux_init] done; smux listen sd is %d, smux port is %d\n",
 
289
                smux_listen_sd, ntohs(lo_socket.sin_port)));
 
290
}
 
291
 
 
292
u_char         *
 
293
var_smux(struct variable * vp,
 
294
         oid * name,
 
295
         size_t * length,
 
296
         int exact, size_t * var_len, WriteMethod ** write_method)
 
297
{
 
298
    u_char         *valptr, val_type;
 
299
    smux_reg       *rptr;
 
300
 
 
301
    *write_method = var_smux_write;
 
302
    /*
 
303
     * search the active registration list 
 
304
     */
 
305
    for (rptr = ActiveRegs; rptr; rptr = rptr->sr_next) {
 
306
        if (0 >= snmp_oidtree_compare(vp->name, vp->namelen, rptr->sr_name,
 
307
                                      rptr->sr_name_len))
 
308
            break;
 
309
    }
 
310
    if (rptr == NULL)
 
311
        return NULL;
 
312
    else if (exact && (*length < rptr->sr_name_len))
 
313
        return NULL;
 
314
 
 
315
    valptr = smux_snmp_process(exact, name, length,
 
316
                               var_len, &val_type, rptr->sr_fd);
 
317
 
 
318
    if (valptr == NULL)
 
319
        return NULL;
 
320
 
 
321
    if ((snmp_oidtree_compare(name, *length, rptr->sr_name,
 
322
                              rptr->sr_name_len)) != 0) {
 
323
        /*
 
324
         * the peer has returned a value outside
 
325
         * * of the registered tree
 
326
         */
 
327
        return NULL;
 
328
    } else {
 
329
        /*
 
330
         * set the type and return the value 
 
331
         */
 
332
        vp->type = val_type;
 
333
        return valptr;
 
334
    }
 
335
}
 
336
 
 
337
int
 
338
var_smux_write(int action,
 
339
               u_char * var_val,
 
340
               u_char var_val_type,
 
341
               size_t var_val_len,
 
342
               u_char * statP, oid * name, size_t name_len)
 
343
{
 
344
    smux_reg       *rptr;
 
345
    u_char          buf[SMUXMAXPKTSIZE], *ptr, sout[3], type;
 
346
    int             reterr;
 
347
    size_t          var_len, datalen, name_length, packet_len;
 
348
    ssize_t         len;
 
349
    long            reqid, errsts, erridx;
 
350
    u_char          var_type, *dataptr;
 
351
 
 
352
    DEBUGMSGTL(("smux", "[var_smux_write] entering var_smux_write\n"));
 
353
 
 
354
    len = SMUXMAXPKTSIZE;
 
355
    reterr = SNMP_ERR_NOERROR;
 
356
    var_len = var_val_len;
 
357
    var_type = var_val_type;
 
358
    name_length = name_len;
 
359
 
 
360
    /*
 
361
     * XXX find the descriptor again 
 
362
     */
 
363
    for (rptr = ActiveRegs; rptr; rptr = rptr->sr_next) {
 
364
        if (!snmp_oidtree_compare(name, name_len, rptr->sr_name,
 
365
                                  rptr->sr_name_len))
 
366
            break;
 
367
    }
 
368
 
 
369
    switch (action) {
 
370
    case RESERVE1:
 
371
        DEBUGMSGTL(("smux", "[var_smux_write] entering RESERVE1\n"));
 
372
 
 
373
        /*
 
374
         * length might be long 
 
375
         */
 
376
        var_len += (*(var_val + 1) & ASN_LONG_LEN) ?
 
377
            var_len + ((*(var_val + 1) & 0x7F) + 2) : 2;
 
378
 
 
379
        switch (var_val_type) {
 
380
        case ASN_INTEGER:
 
381
        case ASN_OCTET_STR:
 
382
        case ASN_COUNTER:
 
383
        case ASN_GAUGE:
 
384
        case ASN_TIMETICKS:
 
385
        case ASN_UINTEGER:
 
386
        case ASN_COUNTER64:
 
387
        case ASN_IPADDRESS:
 
388
        case ASN_OPAQUE:
 
389
        case ASN_NSAP:
 
390
        case ASN_OBJECT_ID:
 
391
        case ASN_BIT_STR:
 
392
            datalen = var_val_len;
 
393
            dataptr = var_val;
 
394
            break;
 
395
        case SNMP_NOSUCHOBJECT:
 
396
        case SNMP_NOSUCHINSTANCE:
 
397
        case SNMP_ENDOFMIBVIEW:
 
398
        case ASN_NULL:
 
399
        default:
 
400
            DEBUGMSGTL(("smux",
 
401
                        "[var_smux_write] variable not supported\n"));
 
402
            return SNMP_ERR_GENERR;
 
403
            break;
 
404
        }
 
405
 
 
406
        if ((smux_build((u_char) SMUX_SET, smux_reqid,
 
407
                        name, &name_length, var_val_type, dataptr,
 
408
                        datalen, buf, &len)) < 0) {
 
409
            DEBUGMSGTL(("smux", "[var_smux_write] smux build failed\n"));
 
410
            return SNMP_ERR_GENERR;
 
411
        }
 
412
 
 
413
        if (send(rptr->sr_fd, buf, len, 0) < 0) {
 
414
            DEBUGMSGTL(("smux", "[var_smux_write] send failed\n"));
 
415
            return SNMP_ERR_GENERR;
 
416
        }
 
417
 
 
418
        while (1) {
 
419
            /*
 
420
             * peek at what's received 
 
421
             */
 
422
            if ((len = recv(rptr->sr_fd, buf,
 
423
                            SMUXMAXPKTSIZE, MSG_PEEK)) <= 0) {
 
424
                DEBUGMSGTL(("smux",
 
425
                            "[var_smux_write] peek failed or timed out\n"));
 
426
                /*
 
427
                 * do we need to do a peer cleanup in this case?? 
 
428
                 */
 
429
                smux_peer_cleanup(rptr->sr_fd);
 
430
                return SNMP_ERR_GENERR;
 
431
            }
 
432
 
 
433
            DEBUGMSGTL(("smux", "[var_smux_write] Peeked at %d bytes\n",
 
434
                        len));
 
435
            DEBUGDUMPSETUP("var_smux_write", buf, len);
 
436
 
 
437
            /*
 
438
             * determine if we received more than one packet 
 
439
             */
 
440
            packet_len = len;
 
441
            ptr = asn_parse_header(buf, &packet_len, &type);
 
442
            packet_len += (ptr - buf);
 
443
            if (len > (ssize_t)packet_len) {
 
444
                /*
 
445
                 * set length to receive only the first packet 
 
446
                 */
 
447
                len = packet_len;
 
448
            }
 
449
 
 
450
            /*
 
451
             * receive the first packet 
 
452
             */
 
453
            if ((len = recv(rptr->sr_fd, buf, len, 0)) <= 0) {
 
454
                DEBUGMSGTL(("smux",
 
455
                            "[var_smux_write] recv failed or timed out\n"));
 
456
                /*
 
457
                 * do we need to do a peer cleanup in this case?? 
 
458
                 */
 
459
                smux_peer_cleanup(rptr->sr_fd);
 
460
                return SNMP_ERR_GENERR;
 
461
            }
 
462
 
 
463
            DEBUGMSGTL(("smux", "[var_smux_write] Received %d bytes\n",
 
464
                        len));
 
465
 
 
466
            if (buf[0] == SMUX_TRAP) {
 
467
                DEBUGMSGTL(("smux", "[var_smux_write] Received trap\n"));
 
468
                snmp_log(LOG_INFO, "Got trap from peer on fd %d\n",
 
469
                         rptr->sr_fd);
 
470
                ptr = asn_parse_header(buf, &len, &type);
 
471
                smux_trap_process(ptr, &len);
 
472
 
 
473
 
 
474
                /*
 
475
                 * go and peek at received data again 
 
476
                 */
 
477
                /*
 
478
                 * we could receive the reply or another trap 
 
479
                 */
 
480
            } else {
 
481
                ptr = buf;
 
482
                ptr = asn_parse_header(ptr, &len, &type);
 
483
                if ((ptr == NULL) || type != SNMP_MSG_RESPONSE)
 
484
                    return SNMP_ERR_GENERR;
 
485
 
 
486
                ptr =
 
487
                    asn_parse_int(ptr, &len, &type, &reqid, sizeof(reqid));
 
488
                if ((ptr == NULL) || type != ASN_INTEGER)
 
489
                    return SNMP_ERR_GENERR;
 
490
 
 
491
                ptr =
 
492
                    asn_parse_int(ptr, &len, &type, &errsts,
 
493
                                  sizeof(errsts));
 
494
                if ((ptr == NULL) || type != ASN_INTEGER)
 
495
                    return SNMP_ERR_GENERR;
 
496
 
 
497
                if (errsts) {
 
498
                    DEBUGMSGTL(("smux",
 
499
                                "[var_smux_write] errsts returned\n"));
 
500
                    return (errsts);
 
501
                }
 
502
 
 
503
                ptr =
 
504
                    asn_parse_int(ptr, &len, &type, &erridx,
 
505
                                  sizeof(erridx));
 
506
                if ((ptr == NULL) || type != ASN_INTEGER)
 
507
                    return SNMP_ERR_GENERR;
 
508
 
 
509
                reterr = SNMP_ERR_NOERROR;
 
510
                break;
 
511
            }
 
512
        }                       /* while (1) */
 
513
        break;                  /* case Action == RESERVE1 */
 
514
 
 
515
    case RESERVE2:
 
516
        DEBUGMSGTL(("smux", "[var_smux_write] entering RESERVE2\n"));
 
517
        reterr = SNMP_ERR_NOERROR;
 
518
        break;                  /* case Action == RESERVE2 */
 
519
 
 
520
    case FREE:
 
521
    case COMMIT:
 
522
        ptr = sout;
 
523
        *(ptr++) = (u_char) SMUX_SOUT;
 
524
        *(ptr++) = (u_char) 1;
 
525
        if (action == FREE) {
 
526
            *ptr = (u_char) 1;  /* rollback */
 
527
            DEBUGMSGTL(("smux",
 
528
                        "[var_smux_write] entering FREE - sending RollBack \n"));
 
529
        } else {
 
530
            *ptr = (u_char) 0;  /* commit */
 
531
            DEBUGMSGTL(("smux",
 
532
                        "[var_smux_write] entering FREE - sending Commit \n"));
 
533
        }
 
534
 
 
535
        if ((send(rptr->sr_fd, sout, 3, 0)) < 0) {
 
536
            DEBUGMSGTL(("smux",
 
537
                        "[var_smux_write] send rollback/commit failed\n"));
 
538
            return SNMP_ERR_GENERR;
 
539
        }
 
540
 
 
541
        reterr = SNMP_ERR_NOERROR;
 
542
        break;                  /* case Action == COMMIT */
 
543
 
 
544
    default:
 
545
        break;
 
546
    }
 
547
    return reterr;
 
548
}
 
549
 
 
550
 
 
551
int
 
552
smux_accept(int sd)
 
553
{
 
554
    u_char          data[SMUXMAXPKTSIZE], *ptr, type;
 
555
    struct sockaddr_in in_socket;
 
556
    struct timeval  tv;
 
557
    int             fail, fd, alen;
 
558
    int             length;
 
559
    ssize_t         len;
 
560
 
 
561
    alen = sizeof(struct sockaddr_in);
 
562
    /*
 
563
     * this may be too high 
 
564
     */
 
565
    tv.tv_sec = 5;
 
566
    tv.tv_usec = 0;
 
567
 
 
568
    /*
 
569
     * connection request 
 
570
     */
 
571
    DEBUGMSGTL(("smux", "[smux_accept] Calling accept()\n"));
 
572
    errno = 0;
 
573
    if ((fd = accept(sd, (struct sockaddr *) &in_socket, &alen)) < 0) {
 
574
        snmp_log_perror("[smux_accept] accept failed");
 
575
        return -1;
 
576
    } else {
 
577
        snmp_log(LOG_INFO, "[smux_accept] accepted fd %d from %s:%d\n",
 
578
                 fd, inet_ntoa(in_socket.sin_addr),
 
579
                 ntohs(in_socket.sin_port));
 
580
        if (npeers + 1 == SMUXMAXPEERS) {
 
581
            snmp_log(LOG_ERR,
 
582
                     "[smux_accept] denied peer on fd %d, limit %d reached",
 
583
                     fd, SMUXMAXPEERS);
 
584
            close(sd);
 
585
            return -1;
 
586
        }
 
587
 
 
588
        /*
 
589
         * now block for an OpenPDU 
 
590
         */
 
591
        if ((length = recv(fd, (char *) data, SMUXMAXPKTSIZE, 0)) <= 0) {
 
592
            DEBUGMSGTL(("smux",
 
593
                        "[smux_accept] peer on fd %d died or timed out\n",
 
594
                        fd));
 
595
            close(fd);
 
596
            return -1;
 
597
        }
 
598
        /*
 
599
         * try to authorize him 
 
600
         */
 
601
        ptr = data;
 
602
        len = length;
 
603
        if ((ptr = asn_parse_header(ptr, &len, &type)) == NULL) {
 
604
            smux_send_close(fd, SMUXC_PACKETFORMAT);
 
605
            close(fd);
 
606
            DEBUGMSGTL(("smux", "[smux_accept] peer on %d sent bad open"));
 
607
            return -1;
 
608
        } else if (type != (u_char) SMUX_OPEN) {
 
609
            smux_send_close(fd, SMUXC_PROTOCOLERROR);
 
610
            close(fd);
 
611
            DEBUGMSGTL(("smux",
 
612
                        "[smux_accept] peer on %d did not send open: (%d)\n",
 
613
                        type));
 
614
            return -1;
 
615
        }
 
616
        ptr = smux_open_process(fd, ptr, &len, &fail);
 
617
        if (fail) {
 
618
            smux_send_close(fd, SMUXC_AUTHENTICATIONFAILURE);
 
619
            close(fd);
 
620
            DEBUGMSGTL(("smux",
 
621
                        "[smux_accept] peer on %d failed authentication\n",
 
622
                        fd));
 
623
            return -1;
 
624
        }
 
625
 
 
626
        /*
 
627
         * he's OK 
 
628
         */
 
629
#ifdef SO_RCVTIMEO
 
630
        if (setsockopt
 
631
            (fd, SOL_SOCKET, SO_RCVTIMEO, (void *) &tv, sizeof(tv)) < 0) {
 
632
            DEBUGMSGTL(("smux",
 
633
                        "[smux_accept] setsockopt(SO_RCVTIMEO) failed fd %d\n",
 
634
                        fd));
 
635
            snmp_log_perror("smux_accept: setsockopt SO_RCVTIMEO");
 
636
        }
 
637
#endif
 
638
        npeers++;
 
639
        DEBUGMSGTL(("smux", "[smux_accept] fd %d\n", fd));
 
640
 
 
641
        /*
 
642
         * Process other PDUs already read, e.g. a registerRequest. 
 
643
         */
 
644
        len = length - (ptr - data);
 
645
        if (smux_pdu_process(fd, ptr, len) < 0) {
 
646
            /*
 
647
             * Easy come, easy go.  Clean-up is already done. 
 
648
             */
 
649
            return -1;
 
650
        }
 
651
    }
 
652
    return fd;
 
653
}
 
654
 
 
655
int
 
656
smux_process(int fd)
 
657
{
 
658
    int             length;
 
659
    u_char          data[SMUXMAXPKTSIZE];
 
660
 
 
661
    length = recv(fd, (char *) data, SMUXMAXPKTSIZE, 0);
 
662
    if (length <= 0) {
 
663
        /*
 
664
         * the peer went away, close this descriptor 
 
665
         * * and delete it from the list
 
666
         */
 
667
        DEBUGMSGTL(("smux",
 
668
                    "[smux_process] peer on fd %d died or timed out\n",
 
669
                    fd));
 
670
        smux_peer_cleanup(fd);
 
671
        return -1;
 
672
    }
 
673
 
 
674
    return smux_pdu_process(fd, data, length);
 
675
}
 
676
 
 
677
static int
 
678
smux_pdu_process(int fd, u_char * data, size_t length)
 
679
{
 
680
    int             error;
 
681
    size_t          len;
 
682
    u_char         *ptr, type;
 
683
 
 
684
    DEBUGMSGTL(("smux", "[smux_pdu_process] Processing %d bytes\n",
 
685
                length));
 
686
 
 
687
    error = 0;
 
688
    ptr = data;
 
689
    while (error == 0 && ptr != NULL && ptr < data + length) {
 
690
        len = length - (ptr - data);
 
691
        ptr = asn_parse_header(ptr, &len, &type);
 
692
        DEBUGMSGTL(("smux", "[smux_pdu_process] type is %d\n",
 
693
                    (int) type));
 
694
        switch (type) {
 
695
        case SMUX_OPEN:
 
696
            smux_send_close(fd, SMUXC_PROTOCOLERROR);
 
697
            DEBUGMSGTL(("smux",
 
698
                        "[smux_pdu_process] peer on fd %d sent duplicate open?\n",
 
699
                        fd));
 
700
            smux_peer_cleanup(fd);
 
701
            error = -1;
 
702
            break;
 
703
        case SMUX_CLOSE:
 
704
            ptr = smux_close_process(fd, ptr, &len);
 
705
            smux_peer_cleanup(fd);
 
706
            error = -1;
 
707
            break;
 
708
        case SMUX_RREQ:
 
709
            ptr = smux_rreq_process(fd, ptr, &len);
 
710
            break;
 
711
        case SMUX_RRSP:
 
712
            error = -1;
 
713
            smux_send_close(fd, SMUXC_PROTOCOLERROR);
 
714
            smux_peer_cleanup(fd);
 
715
            DEBUGMSGTL(("smux",
 
716
                        "[smux_pdu_process] peer on fd %d sent RRSP!\n",
 
717
                        fd));
 
718
            break;
 
719
        case SMUX_SOUT:
 
720
            error = -1;
 
721
            smux_send_close(fd, SMUXC_PROTOCOLERROR);
 
722
            smux_peer_cleanup(fd);
 
723
            DEBUGMSGTL(("smux", "This shouldn't have happened!\n"));
 
724
            break;
 
725
        case SMUX_TRAP:
 
726
            snmp_log(LOG_INFO, "Got trap from peer on fd %d\n", fd);
 
727
            ptr = smux_trap_process(ptr, &len);
 
728
            /*
 
729
             * watch out for close on top of this...should return correct end 
 
730
             */
 
731
            /*
 
732
             * debug this... 
 
733
             */
 
734
            ptr = NULL;
 
735
            break;
 
736
        default:
 
737
            smux_send_close(fd, SMUXC_PACKETFORMAT);
 
738
            smux_peer_cleanup(fd);
 
739
            DEBUGMSGTL(("smux", "[smux_pdu_process] Wrong type %d\n",
 
740
                        (int) type));
 
741
            error = -1;
 
742
            break;
 
743
        }
 
744
    }
 
745
    return error;
 
746
}
 
747
 
 
748
static u_char  *
 
749
smux_open_process(int fd, u_char * ptr, size_t * len, int *fail)
 
750
{
 
751
    u_char          type;
 
752
    long            version;
 
753
    oid             oid_name[MAX_OID_LEN];
 
754
    char            passwd[SMUXMAXSTRLEN];
 
755
    char            descr[SMUXMAXSTRLEN];
 
756
    char            oid_print[SMUXMAXSTRLEN];
 
757
    int             i;
 
758
    size_t          oid_name_len, string_len;
 
759
 
 
760
    if (!(ptr = asn_parse_int(ptr, len, &type, &version, sizeof(version)))) {
 
761
        DEBUGMSGTL(("smux", "[smux_open_process] version parse failed\n"));
 
762
        *fail = TRUE;
 
763
        return ((ptr += *len));
 
764
    }
 
765
    DEBUGMSGTL(("smux",
 
766
                "[smux_open_process] version %d, len %d, type %d\n",
 
767
                version, *len, (int) type));
 
768
 
 
769
    oid_name_len = MAX_OID_LEN;
 
770
    if ((ptr = asn_parse_objid(ptr, len, &type, oid_name,
 
771
                               &oid_name_len)) == NULL) {
 
772
        DEBUGMSGTL(("smux", "[smux_open_process] oid parse failed\n"));
 
773
        *fail = TRUE;
 
774
        return ((ptr += *len));
 
775
    }
 
776
    snprint_objid(oid_print, sizeof(oid_print), oid_name, oid_name_len);
 
777
 
 
778
    if (snmp_get_do_debugging()) {
 
779
        DEBUGMSGTL(("smux", "[smux_open_process] smux peer: %s\n",
 
780
                    oid_print));
 
781
        DEBUGMSGTL(("smux", "[smux_open_process] len %d, type %d\n", *len,
 
782
                    (int) type));
 
783
    }
 
784
 
 
785
    string_len = SMUXMAXSTRLEN;
 
786
    if ((ptr = asn_parse_string(ptr, len, &type, (u_char *) descr,
 
787
                                &string_len)) == NULL) {
 
788
        DEBUGMSGTL(("smux", "[smux_open_process] descr parse failed\n"));
 
789
        *fail = TRUE;
 
790
        return ((ptr += *len));
 
791
    }
 
792
 
 
793
    if (snmp_get_do_debugging()) {
 
794
        DEBUGMSGTL(("smux", "[smux_open_process] smux peer descr: "));
 
795
        for (i = 0; i < (int) string_len; i++)
 
796
            DEBUGMSG(("smux", "%c", descr[i]));
 
797
        DEBUGMSG(("smux", "\n"));
 
798
        DEBUGMSGTL(("smux", "[smux_open_process] len %d, type %d\n", *len,
 
799
                    (int) type));
 
800
    }
 
801
    descr[string_len] = 0;
 
802
 
 
803
    string_len = SMUXMAXSTRLEN;
 
804
    if ((ptr = asn_parse_string(ptr, len, &type, (u_char *) passwd,
 
805
                                &string_len)) == NULL) {
 
806
        DEBUGMSGTL(("smux", "[smux_open_process] passwd parse failed\n"));
 
807
        *fail = TRUE;
 
808
        return ((ptr += *len));
 
809
    }
 
810
 
 
811
    if (snmp_get_do_debugging()) {
 
812
        DEBUGMSGTL(("smux", "[smux_open_process] smux peer passwd: "));
 
813
        for (i = 0; i < (int) string_len; i++)
 
814
            DEBUGMSG(("smux", "%c", passwd[i]));
 
815
        DEBUGMSG(("smux", "\n"));
 
816
        DEBUGMSGTL(("smux", "[smux_open_process] len %d, type %d\n", *len,
 
817
                    (int) type));
 
818
    }
 
819
    passwd[string_len] = '\0';
 
820
    if (!smux_auth_peer(oid_name, oid_name_len, passwd, fd)) {
 
821
        snmp_log(LOG_WARNING,
 
822
                 "refused smux peer: oid %s, password %s, descr %s\n",
 
823
                 oid_print, passwd, descr);
 
824
        *fail = TRUE;
 
825
        return ptr;
 
826
    }
 
827
    snmp_log(LOG_INFO,
 
828
             "accepted smux peer: oid %s, password %s, descr %s\n",
 
829
             oid_print, passwd, descr);
 
830
    *fail = FALSE;
 
831
    return ptr;
 
832
}
 
833
 
 
834
static void
 
835
smux_send_close(int fd, int reason)
 
836
{
 
837
    u_char          outpacket[3], *ptr;
 
838
 
 
839
    ptr = outpacket;
 
840
 
 
841
    *(ptr++) = (u_char) SMUX_CLOSE;
 
842
    *(ptr++) = (u_char) 1;
 
843
    *ptr = (u_char) (reason & 0xFF);
 
844
 
 
845
    if (snmp_get_do_debugging())
 
846
        DEBUGMSGTL(("smux",
 
847
                    "[smux_close] sending close to fd %d, reason %d\n", fd,
 
848
                    reason));
 
849
 
 
850
    /*
 
851
     * send a response back 
 
852
     */
 
853
    if (send(fd, (char *) outpacket, 3, 0) < 0) {
 
854
        snmp_log_perror("[smux_snmp_close] send failed");
 
855
    }
 
856
}
 
857
 
 
858
 
 
859
static int
 
860
smux_auth_peer(oid * name, size_t namelen, char *passwd, int fd)
 
861
{
 
862
    int             i;
 
863
 
 
864
    for (i = 0; i < nauths; i++) {
 
865
        if (snmp_oid_compare(Auths[i]->sa_oid, Auths[i]->sa_oid_len,
 
866
                             name, namelen) == 0) {
 
867
            if (!(strcmp(Auths[i]->sa_passwd, passwd)) &&
 
868
                (Auths[i]->sa_active_fd == -1)) {
 
869
                /*
 
870
                 * matched, mark the auth 
 
871
                 */
 
872
                Auths[i]->sa_active_fd = fd;
 
873
                return 1;
 
874
            }
 
875
        }
 
876
    }
 
877
    /*
 
878
     * did not match oid and passwd 
 
879
     */
 
880
    return 0;
 
881
}
 
882
 
 
883
 
 
884
/*
 
885
 * XXX - Bells and Whistles:
 
886
 * Need to catch signal when snmpd goes down and send close pdu to gated 
 
887
 */
 
888
static u_char  *
 
889
smux_close_process(int fd, u_char * ptr, size_t * len)
 
890
{
 
891
    long            down = 0;
 
892
    int             length = *len;
 
893
 
 
894
    /*
 
895
     * This is the integer part of the close pdu 
 
896
     */
 
897
    while (length--) {
 
898
        down = (down << 8) | (long) *ptr;
 
899
        ptr++;
 
900
    }
 
901
 
 
902
    DEBUGMSGTL(("smux",
 
903
                "[smux_close_process] close from peer on fd %d reason %d\n",
 
904
                fd, down));
 
905
    smux_peer_cleanup(fd);
 
906
 
 
907
    return NULL;
 
908
}
 
909
 
 
910
static u_char  *
 
911
smux_rreq_process(int sd, u_char * ptr, size_t * len)
 
912
{
 
913
    long            priority, rpriority;
 
914
    long            operation;
 
915
    oid             oid_name[MAX_OID_LEN];
 
916
    size_t          oid_name_len;
 
917
    int             i, result;
 
918
    u_char          type;
 
919
    smux_reg       *rptr, *nrptr;
 
920
 
 
921
    oid_name_len = MAX_OID_LEN;
 
922
    ptr = asn_parse_objid(ptr, len, &type, oid_name, &oid_name_len);
 
923
 
 
924
    DEBUGMSGTL(("smux", "[smux_rreq_process] smux subtree: "));
 
925
    DEBUGMSGOID(("smux", oid_name, oid_name_len));
 
926
    DEBUGMSG(("smux", "\n"));
 
927
 
 
928
    if ((ptr = asn_parse_int(ptr, len, &type, &priority,
 
929
                             sizeof(priority))) == NULL) {
 
930
        DEBUGMSGTL(("smux",
 
931
                    "[smux_rreq_process] priority parse failed\n"));
 
932
        smux_send_rrsp(sd, -1);
 
933
        return NULL;
 
934
    }
 
935
    DEBUGMSGTL(("smux", "[smux_rreq_process] priority %d\n", priority));
 
936
 
 
937
    if ((ptr = asn_parse_int(ptr, len, &type, &operation,
 
938
                             sizeof(operation))) == NULL) {
 
939
        DEBUGMSGTL(("smux",
 
940
                    "[smux_rreq_process] operation parse failed\n"));
 
941
        smux_send_rrsp(sd, -1);
 
942
        return NULL;
 
943
    }
 
944
    DEBUGMSGTL(("smux", "[smux_rreq_process] operation %d\n", operation));
 
945
 
 
946
    if (operation == SMUX_REGOP_DELETE) {
 
947
        /*
 
948
         * search the active list for this registration 
 
949
         */
 
950
        rptr =
 
951
            smux_find_match(ActiveRegs, sd, oid_name, oid_name_len,
 
952
                            priority);
 
953
        if (rptr) {
 
954
            rpriority = rptr->sr_priority;
 
955
            /*
 
956
             * unregister the mib 
 
957
             */
 
958
            unregister_mib(rptr->sr_name, rptr->sr_name_len);
 
959
            /*
 
960
             * find a replacement 
 
961
             */
 
962
            nrptr =
 
963
                smux_find_replacement(rptr->sr_name, rptr->sr_name_len);
 
964
            if (nrptr) {
 
965
                /*
 
966
                 * found one 
 
967
                 */
 
968
                smux_replace_active(rptr, nrptr);
 
969
            } else {
 
970
                /*
 
971
                 * no replacement found 
 
972
                 */
 
973
                smux_list_detach(&ActiveRegs, &rptr);
 
974
                free(rptr);
 
975
            }
 
976
            smux_send_rrsp(sd, rpriority);
 
977
            return ptr;
 
978
        }
 
979
        /*
 
980
         * search the passive list for this registration 
 
981
         */
 
982
        rptr =
 
983
            smux_find_match(PassiveRegs, sd, oid_name, oid_name_len,
 
984
                            priority);
 
985
        if (rptr) {
 
986
            rpriority = rptr->sr_priority;
 
987
            smux_list_detach(&PassiveRegs, &rptr);
 
988
            free(rptr);
 
989
            smux_send_rrsp(sd, rpriority);
 
990
            return ptr;
 
991
        }
 
992
        /*
 
993
         * This peer cannot unregister the tree, it does not
 
994
         * * belong to him.  Send him an error.
 
995
         */
 
996
        smux_send_rrsp(sd, -1);
 
997
        return ptr;
 
998
 
 
999
    } else if ((operation == SMUX_REGOP_REGISTER_RO) ||
 
1000
               (operation == SMUX_REGOP_REGISTER_RW)) {
 
1001
        if (priority < -1) {
 
1002
            DEBUGMSGTL(("smux",
 
1003
                        "[smux_rreq_process] peer fd %d invalid priority",
 
1004
                        sd, priority));
 
1005
            smux_send_rrsp(sd, -1);
 
1006
            return NULL;
 
1007
        }
 
1008
        if ((nrptr = malloc(sizeof(smux_reg))) == NULL) {
 
1009
            snmp_log_perror("[smux_rreq_process] malloc");
 
1010
            smux_send_rrsp(sd, -1);
 
1011
            return NULL;
 
1012
        }
 
1013
        nrptr->sr_priority = priority;
 
1014
        nrptr->sr_name_len = oid_name_len;
 
1015
        nrptr->sr_fd = sd;
 
1016
        for (i = 0; i < (int) oid_name_len; i++)
 
1017
            nrptr->sr_name[i] = oid_name[i];
 
1018
 
 
1019
        /*
 
1020
         * See if this tree matches or scopes any of the
 
1021
         * * active trees.
 
1022
         */
 
1023
        for (rptr = ActiveRegs; rptr; rptr = rptr->sr_next) {
 
1024
            result =
 
1025
                snmp_oid_compare(oid_name, oid_name_len, rptr->sr_name,
 
1026
                                 rptr->sr_name_len);
 
1027
            if (result == 0) {
 
1028
                if ((oid_name_len == rptr->sr_name_len)) {
 
1029
                    if ((nrptr->sr_priority == -1)) {
 
1030
                        nrptr->sr_priority = rptr->sr_priority;
 
1031
                        do {
 
1032
                            nrptr->sr_priority++;
 
1033
                        } while (smux_list_add(&PassiveRegs, nrptr));
 
1034
                        goto done;
 
1035
                    } else if (nrptr->sr_priority < rptr->sr_priority) {
 
1036
                        /*
 
1037
                         * Better priority.  There are no better
 
1038
                         * * priorities for this tree in the passive list,
 
1039
                         * * so replace the current active tree.
 
1040
                         */
 
1041
                        smux_replace_active(rptr, nrptr);
 
1042
                        goto done;
 
1043
                    } else {
 
1044
                        /*
 
1045
                         * Equal or worse priority 
 
1046
                         */
 
1047
                        do {
 
1048
                            nrptr->sr_priority++;
 
1049
                        } while (smux_list_add(&PassiveRegs, nrptr) == -1);
 
1050
                        goto done;
 
1051
                    }
 
1052
                } else if (oid_name_len < rptr->sr_name_len) {
 
1053
                    /*
 
1054
                     * This tree scopes a current active
 
1055
                     * * tree.  Replace the current active tree.
 
1056
                     */
 
1057
                    smux_replace_active(rptr, nrptr);
 
1058
                    goto done;
 
1059
                } else {        /* oid_name_len > rptr->sr_name_len */
 
1060
                    /*
 
1061
                     * This tree is scoped by a current
 
1062
                     * * active tree.  
 
1063
                     */
 
1064
                    do {
 
1065
                        nrptr->sr_priority++;
 
1066
                    } while (smux_list_add(&PassiveRegs, nrptr) == -1);
 
1067
                    goto done;
 
1068
                }
 
1069
            }
 
1070
        }
 
1071
        /*
 
1072
         * We didn't find it in the active list.  Add it at
 
1073
         * * the requested priority.
 
1074
         */
 
1075
        if (nrptr->sr_priority == -1)
 
1076
            nrptr->sr_priority = 0;
 
1077
        smux_list_add(&ActiveRegs, nrptr);
 
1078
        register_mib("smux", (struct variable *)
 
1079
                     smux_variables, sizeof(struct variable2),
 
1080
                     1, nrptr->sr_name, nrptr->sr_name_len);
 
1081
      done:
 
1082
        smux_send_rrsp(sd, nrptr->sr_priority);
 
1083
        return ptr;
 
1084
    } else {
 
1085
        DEBUGMSGTL(("smux", "[smux_rreq_process] unknown operation\n"));
 
1086
        smux_send_rrsp(sd, -1);
 
1087
        return NULL;
 
1088
    }
 
1089
}
 
1090
 
 
1091
/*
 
1092
 * Find the registration with a matching descriptor, OID and priority.  If
 
1093
 * the priority is -1 then find a registration with a matching descriptor,
 
1094
 * a matching OID, and the highest priority.
 
1095
 */
 
1096
static smux_reg *
 
1097
smux_find_match(smux_reg * regs, int sd, oid * oid_name,
 
1098
                size_t oid_name_len, long priority)
 
1099
{
 
1100
    smux_reg       *rptr, *bestrptr;
 
1101
 
 
1102
    bestrptr = NULL;
 
1103
    for (rptr = regs; rptr; rptr = rptr->sr_next) {
 
1104
        if (rptr->sr_fd != sd)
 
1105
            continue;
 
1106
        if (snmp_oid_compare
 
1107
            (rptr->sr_name, rptr->sr_name_len, oid_name, oid_name_len))
 
1108
            continue;
 
1109
        if (rptr->sr_priority == priority)
 
1110
            return rptr;
 
1111
        if (priority != -1)
 
1112
            continue;
 
1113
        if (bestrptr) {
 
1114
            if (bestrptr->sr_priority > rptr->sr_priority)
 
1115
                bestrptr = rptr;
 
1116
        } else {
 
1117
            bestrptr = rptr;
 
1118
        }
 
1119
    }
 
1120
    return bestrptr;
 
1121
}
 
1122
 
 
1123
static void
 
1124
smux_replace_active(smux_reg * actptr, smux_reg * pasptr)
 
1125
{
 
1126
    smux_list_detach(&ActiveRegs, &actptr);
 
1127
    unregister_mib(actptr->sr_name, actptr->sr_name_len);
 
1128
 
 
1129
    smux_list_detach(&PassiveRegs, &pasptr);
 
1130
    (void) smux_list_add(&ActiveRegs, pasptr);
 
1131
 
 
1132
    register_mib("smux", (struct variable *) smux_variables,
 
1133
                 sizeof(struct variable2), 1, pasptr->sr_name,
 
1134
                 pasptr->sr_name_len);
 
1135
    free(actptr);
 
1136
}
 
1137
 
 
1138
static void
 
1139
smux_list_detach(smux_reg ** head, smux_reg ** m_remove)
 
1140
{
 
1141
    smux_reg       *rptr, *rptr2;
 
1142
 
 
1143
    if (*head == NULL) {
 
1144
        DEBUGMSGTL(("smux", "[smux_list_detach] Ouch!"));
 
1145
        return;
 
1146
    }
 
1147
    if (*head == *m_remove) {
 
1148
        *m_remove = *head;
 
1149
        *head = (*head)->sr_next;
 
1150
        return;
 
1151
    }
 
1152
    for (rptr = *head, rptr2 = rptr->sr_next; rptr2;
 
1153
         rptr2 = rptr2->sr_next, rptr = rptr->sr_next) {
 
1154
        if (rptr2 == *m_remove) {
 
1155
            *m_remove = rptr2;
 
1156
            rptr->sr_next = rptr2->sr_next;
 
1157
            return;
 
1158
        }
 
1159
    }
 
1160
}
 
1161
 
 
1162
/*
 
1163
 * Attempt to add a registration (in order) to a list.  If the
 
1164
 * add fails (because of an existing registration with equal
 
1165
 * priority) return -1.
 
1166
 */
 
1167
static int
 
1168
smux_list_add(smux_reg ** head, smux_reg * add)
 
1169
{
 
1170
    smux_reg       *rptr;
 
1171
    int             result;
 
1172
 
 
1173
    if (*head == NULL) {
 
1174
        *head = add;
 
1175
        (*head)->sr_next = NULL;
 
1176
        return 0;
 
1177
    }
 
1178
    for (rptr = *head; rptr->sr_next; rptr = rptr->sr_next) {
 
1179
        result = snmp_oid_compare(add->sr_name, add->sr_name_len,
 
1180
                                  rptr->sr_name, rptr->sr_name_len);
 
1181
        if ((result == 0) && (add->sr_priority == rptr->sr_priority)) {
 
1182
            /*
 
1183
             * same tree, same pri, nope 
 
1184
             */
 
1185
            return -1;
 
1186
        } else if (result < 0) {
 
1187
            /*
 
1188
             * this can only happen if we go before the head 
 
1189
             */
 
1190
            add->sr_next = *head;
 
1191
            *head = add;
 
1192
            return 0;
 
1193
        } else if ((snmp_oid_compare(add->sr_name, add->sr_name_len,
 
1194
                                     rptr->sr_next->sr_name,
 
1195
                                     rptr->sr_next->sr_name_len)) < 0) {
 
1196
            /*
 
1197
             * insert here 
 
1198
             */
 
1199
            add->sr_next = rptr->sr_next;
 
1200
            rptr->sr_next = add;
 
1201
            return 0;
 
1202
        }
 
1203
    }
 
1204
    /*
 
1205
     * compare the last one 
 
1206
     */
 
1207
    if ((snmp_oid_compare(add->sr_name, add->sr_name_len, rptr->sr_name,
 
1208
                          rptr->sr_name_len) == 0)
 
1209
        && add->sr_priority == rptr->sr_priority)
 
1210
        return -1;
 
1211
    else {
 
1212
        rptr->sr_next = add;
 
1213
        add->sr_next = NULL;
 
1214
    }
 
1215
    return 0;
 
1216
}
 
1217
 
 
1218
/*
 
1219
 * Find a replacement for this registration.  In order
 
1220
 * of preference:
 
1221
 *
 
1222
 *      - Least difference in subtree length
 
1223
 *      - Best (lowest) priority
 
1224
 *
 
1225
 * For example, if we need to replace .1.3.6.1.69, 
 
1226
 * we would pick .1.3.6.1.69.1 instead of .1.3.6.69.1.1
 
1227
 *
 
1228
 */
 
1229
static smux_reg *
 
1230
smux_find_replacement(oid * name, size_t name_len)
 
1231
{
 
1232
    smux_reg       *rptr, *bestptr;
 
1233
    int             bestlen, difflen;
 
1234
 
 
1235
    bestlen = SMUX_MAX_PRIORITY;
 
1236
    bestptr = NULL;
 
1237
 
 
1238
    for (rptr = PassiveRegs; rptr; rptr = rptr->sr_next) {
 
1239
        if (!snmp_oidtree_compare(rptr->sr_name, rptr->sr_name_len,
 
1240
                                  name, name_len)) {
 
1241
            if ((difflen = rptr->sr_name_len - name_len)
 
1242
                < bestlen) {
 
1243
                bestlen = difflen;
 
1244
                bestptr = rptr;
 
1245
            } else if ((difflen == bestlen) &&
 
1246
                       (rptr->sr_priority < bestptr->sr_priority))
 
1247
                bestptr = rptr;
 
1248
        }
 
1249
    }
 
1250
    return bestptr;
 
1251
}
 
1252
 
 
1253
u_char         *
 
1254
smux_snmp_process(int exact,
 
1255
                  oid * objid,
 
1256
                  size_t * len,
 
1257
                  size_t * return_len, u_char * return_type, int sd)
 
1258
{
 
1259
    u_char          packet[SMUXMAXPKTSIZE], *ptr, result[SMUXMAXPKTSIZE];
 
1260
    size_t          length = SMUXMAXPKTSIZE;
 
1261
    u_char          type;
 
1262
    size_t          packet_len;
 
1263
 
 
1264
    /*
 
1265
     * Send the query to the peer
 
1266
     */
 
1267
    smux_reqid++;
 
1268
 
 
1269
    if (exact)
 
1270
        type = SMUX_GET;
 
1271
    else
 
1272
        type = SMUX_GETNEXT;
 
1273
 
 
1274
    if (smux_build(type, smux_reqid, objid, len, 0, NULL,
 
1275
                   *len, packet, &length) < 0) {
 
1276
        snmp_log(LOG_ERR, "[smux_snmp_process]: smux_build failed\n");
 
1277
        return NULL;
 
1278
    }
 
1279
    DEBUGMSGTL(("smux", "[smux_snmp_process] oid from build: "));
 
1280
    DEBUGMSGOID(("smux", objid, *len));
 
1281
    DEBUGMSG(("smux", "\n"));
 
1282
 
 
1283
    if (send(sd, (char *) packet, length, 0) < 0) {
 
1284
        snmp_log_perror("[smux_snmp_process] send failed");
 
1285
    }
 
1286
 
 
1287
    DEBUGMSGTL(("smux",
 
1288
                "[smux_snmp_process] Sent %d request to peer; %d bytes\n",
 
1289
                (int) type, length));
 
1290
 
 
1291
    while (1) {
 
1292
        /*
 
1293
         * peek at what's received 
 
1294
         */
 
1295
        length = recv(sd, (char *) result, SMUXMAXPKTSIZE, MSG_PEEK);
 
1296
        if (length < 0) {
 
1297
            snmp_log_perror("[smux_snmp_process] peek failed");
 
1298
            smux_peer_cleanup(sd);
 
1299
            return NULL;
 
1300
        }
 
1301
 
 
1302
        DEBUGMSGTL(("smux", "[smux_snmp_process] Peeked at %d bytes\n",
 
1303
                    length));
 
1304
        DEBUGDUMPSETUP("smux_snmp_process", result, length);
 
1305
 
 
1306
        /*
 
1307
         * determine if we received more than one packet 
 
1308
         */
 
1309
        packet_len = length;
 
1310
        ptr = asn_parse_header(result, &packet_len, &type);
 
1311
        packet_len += (ptr - result);
 
1312
        if (length > packet_len) {
 
1313
            /*
 
1314
             * set length to receive only the first packet 
 
1315
             */
 
1316
            length = packet_len;
 
1317
        }
 
1318
 
 
1319
        /*
 
1320
         * receive the first packet 
 
1321
         */
 
1322
        length = recv(sd, (char *) result, length, 0);
 
1323
        if (length < 0) {
 
1324
            snmp_log_perror("[smux_snmp_process] recv failed");
 
1325
            smux_peer_cleanup(sd);
 
1326
            return NULL;
 
1327
        }
 
1328
 
 
1329
        DEBUGMSGTL(("smux", "[smux_snmp_process] Received %d bytes\n",
 
1330
                    length));
 
1331
 
 
1332
        if (result[0] == SMUX_TRAP) {
 
1333
            DEBUGMSGTL(("smux", "[smux_snmp_process] Received trap\n"));
 
1334
            snmp_log(LOG_INFO, "Got trap from peer on fd %d\n", sd);
 
1335
            ptr = asn_parse_header(result, &length, &type);
 
1336
            smux_trap_process(ptr, &length);
 
1337
 
 
1338
            /*
 
1339
             * go and peek at received data again 
 
1340
             */
 
1341
            /*
 
1342
             * we could receive the reply or another trap 
 
1343
             */
 
1344
        } else {
 
1345
            /*
 
1346
             * Interpret reply 
 
1347
             */
 
1348
            ptr = smux_parse(result, objid, len, return_len, return_type);
 
1349
            /*
 
1350
             * ptr will point to query result or NULL if error 
 
1351
             */
 
1352
            break;
 
1353
        }
 
1354
    }                           /* while (1) */
 
1355
 
 
1356
    return ptr;
 
1357
}
 
1358
 
 
1359
static u_char  *
 
1360
smux_parse(u_char * rsp,
 
1361
           oid * objid,
 
1362
           size_t * oidlen, size_t * return_len, u_char * return_type)
 
1363
{
 
1364
    size_t          length = SMUXMAXPKTSIZE;
 
1365
    u_char         *ptr, type;
 
1366
    long            reqid, errstat, errindex;
 
1367
 
 
1368
    ptr = rsp;
 
1369
 
 
1370
    /*
 
1371
     * Return pointer to the snmp/smux return value.
 
1372
     * return_len should contain the number of bytes in the value
 
1373
     * returned above.
 
1374
     * objid is the next object, with len for GETNEXT.
 
1375
     * objid and len are not changed for GET
 
1376
     */
 
1377
    ptr = asn_parse_header(ptr, &length, &type);
 
1378
    if (ptr == NULL || type != SNMP_MSG_RESPONSE)
 
1379
        return NULL;
 
1380
 
 
1381
    if ((ptr = asn_parse_int(ptr, &length, &type, &reqid,
 
1382
                             sizeof(reqid))) == NULL) {
 
1383
        DEBUGMSGTL(("smux", "[smux_parse] parse of reqid failed\n"));
 
1384
        return NULL;
 
1385
    }
 
1386
    if ((ptr = asn_parse_int(ptr, &length, &type, &errstat,
 
1387
                             sizeof(errstat))) == NULL) {
 
1388
        DEBUGMSGTL(("smux",
 
1389
                    "[smux_parse] parse of error status failed\n"));
 
1390
        return NULL;
 
1391
    }
 
1392
    if ((ptr = asn_parse_int(ptr, &length, &type, &errindex,
 
1393
                             sizeof(errindex))) == NULL) {
 
1394
        DEBUGMSGTL(("smux", "[smux_parse] parse of error index failed\n"));
 
1395
        return NULL;
 
1396
    }
 
1397
 
 
1398
    /*
 
1399
     * XXX How to send something intelligent back in case of an error 
 
1400
     */
 
1401
    DEBUGMSGTL(("smux",
 
1402
                "[smux_parse] Message type %d, reqid %d, errstat %d, \n\terrindex %d\n",
 
1403
                (int) type, reqid, errstat, errindex));
 
1404
    if (ptr == NULL || errstat != SNMP_ERR_NOERROR)
 
1405
        return NULL;
 
1406
 
 
1407
    /*
 
1408
     * stuff to return 
 
1409
     */
 
1410
    return (smux_parse_var
 
1411
            (ptr, &length, objid, oidlen, return_len, return_type));
 
1412
}
 
1413
 
 
1414
 
 
1415
static u_char  *
 
1416
smux_parse_var(u_char * varbind,
 
1417
               size_t * varbindlength,
 
1418
               oid * objid,
 
1419
               size_t * oidlen, size_t * varlength, u_char * vartype)
 
1420
{
 
1421
    oid             var_name[MAX_OID_LEN];
 
1422
    size_t          var_name_len;
 
1423
    size_t          var_val_len;
 
1424
    u_char         *var_val;
 
1425
    size_t          str_len, objid_len;
 
1426
    size_t          len;
 
1427
    u_char         *ptr;
 
1428
    u_char          type;
 
1429
 
 
1430
    ptr = varbind;
 
1431
    len = *varbindlength;
 
1432
 
 
1433
    DEBUGMSGTL(("smux", "[smux_parse_var] before any processing: "));
 
1434
    DEBUGMSGOID(("smux", objid, *oidlen));
 
1435
    DEBUGMSG(("smux", "\n"));
 
1436
 
 
1437
    ptr = asn_parse_header(ptr, &len, &type);
 
1438
    if (ptr == NULL || type != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
 
1439
        snmp_log(LOG_NOTICE, "[smux_parse_var] Panic: type %d\n",
 
1440
                 (int) type);
 
1441
        return NULL;
 
1442
    }
 
1443
 
 
1444
    /*
 
1445
     * get hold of the objid and the asn1 coded value 
 
1446
     */
 
1447
    var_name_len = MAX_OID_LEN;
 
1448
    ptr = snmp_parse_var_op(ptr, var_name, &var_name_len, vartype,
 
1449
                            &var_val_len, &var_val, &len);
 
1450
 
 
1451
    *oidlen = var_name_len;
 
1452
    memcpy(objid, var_name, var_name_len * sizeof(oid));
 
1453
 
 
1454
    DEBUGMSGTL(("smux", "[smux_parse_var] returning oid : "));
 
1455
    DEBUGMSGOID(("smux", objid, *oidlen));
 
1456
    DEBUGMSG(("smux", "\n"));
 
1457
    /*
 
1458
     * XXX 
 
1459
     */
 
1460
    len = SMUXMAXPKTSIZE;
 
1461
    DEBUGMSGTL(("smux",
 
1462
                "[smux_parse_var] Asn coded len of var %d, type %d\n",
 
1463
                var_val_len, (int) *vartype));
 
1464
 
 
1465
    switch ((short) *vartype) {
 
1466
    case ASN_INTEGER:
 
1467
        *varlength = sizeof(long);
 
1468
        asn_parse_int(var_val, &len, vartype,
 
1469
                      (long *) &smux_long, *varlength);
 
1470
        return (u_char *) & smux_long;
 
1471
        break;
 
1472
    case ASN_COUNTER:
 
1473
    case ASN_GAUGE:
 
1474
    case ASN_TIMETICKS:
 
1475
    case ASN_UINTEGER:
 
1476
        *varlength = sizeof(u_long);
 
1477
        asn_parse_unsigned_int(var_val, &len, vartype,
 
1478
                               (u_long *) & smux_ulong, *varlength);
 
1479
        return (u_char *) & smux_ulong;
 
1480
        break;
 
1481
    case ASN_COUNTER64:
 
1482
        *varlength = sizeof(smux_counter64);
 
1483
        asn_parse_unsigned_int64(var_val, &len, vartype,
 
1484
                                 (struct counter64 *) &smux_counter64,
 
1485
                                 *varlength);
 
1486
        return (u_char *) & smux_counter64;
 
1487
        break;
 
1488
    case ASN_IPADDRESS:
 
1489
        *varlength = 4;
 
1490
        /*
 
1491
         * consume the tag and length, but just copy here
 
1492
         * because we know it is an ip address
 
1493
         */
 
1494
        if ((var_val = asn_parse_header(var_val, &len, &type)) == NULL)
 
1495
            return NULL;
 
1496
        memcpy((u_char *) & (smux_sa.sin_addr.s_addr), var_val,
 
1497
               *varlength);
 
1498
        return (u_char *) & (smux_sa.sin_addr.s_addr);
 
1499
        break;
 
1500
    case ASN_OCTET_STR:
 
1501
        /*
 
1502
         * XXX 
 
1503
         */
 
1504
        if (len == 0)
 
1505
            return NULL;
 
1506
        str_len = SMUXMAXSTRLEN;
 
1507
        asn_parse_string(var_val, &len, vartype, smux_str, &str_len);
 
1508
        *varlength = str_len;
 
1509
        return smux_str;
 
1510
        break;
 
1511
    case ASN_OPAQUE:
 
1512
    case ASN_NSAP:
 
1513
    case ASN_OBJECT_ID:
 
1514
        objid_len = MAX_OID_LEN;
 
1515
        asn_parse_objid(var_val, &len, vartype, smux_objid, &objid_len);
 
1516
        *varlength = objid_len * sizeof(oid);
 
1517
        return (u_char *) smux_objid;
 
1518
        break;
 
1519
    case SNMP_NOSUCHOBJECT:
 
1520
    case SNMP_NOSUCHINSTANCE:
 
1521
    case SNMP_ENDOFMIBVIEW:
 
1522
    case ASN_NULL:
 
1523
        return NULL;
 
1524
        break;
 
1525
    case ASN_BIT_STR:
 
1526
        /*
 
1527
         * XXX 
 
1528
         */
 
1529
        if (len == 0)
 
1530
            return NULL;
 
1531
        str_len = SMUXMAXSTRLEN;
 
1532
        asn_parse_bitstring(var_val, &len, vartype, smux_str, &str_len);
 
1533
        *varlength = str_len;
 
1534
        return (u_char *) smux_str;
 
1535
        break;
 
1536
    default:
 
1537
        snmp_log(LOG_ERR, "bad type returned (%x)\n", *vartype);
 
1538
        return NULL;
 
1539
        break;
 
1540
    }
 
1541
}
 
1542
 
 
1543
/*
 
1544
 * XXX This is a bad hack - do not want to muck with ucd code 
 
1545
 */
 
1546
static int
 
1547
smux_build(u_char type,
 
1548
           u_long reqid,
 
1549
           oid * objid,
 
1550
           size_t * oidlen,
 
1551
           u_char val_type,
 
1552
           u_char * val, size_t val_len, u_char * packet, size_t * length)
 
1553
{
 
1554
    u_char         *ptr, *save1, *save2;
 
1555
    size_t          len;
 
1556
    long            errstat = 0;
 
1557
    long            errindex = 0;
 
1558
 
 
1559
    /*
 
1560
     * leave space for Seq and length 
 
1561
     */
 
1562
    save1 = packet;
 
1563
    ptr = packet + 4;
 
1564
    len = *length - 4;
 
1565
 
 
1566
    /*
 
1567
     * build reqid 
 
1568
     */
 
1569
    ptr = asn_build_unsigned_int(ptr, &len,
 
1570
                                 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
 
1571
                                           ASN_INTEGER), &reqid,
 
1572
                                 sizeof(reqid));
 
1573
    if (ptr == NULL) {
 
1574
        return -1;
 
1575
    }
 
1576
 
 
1577
    /*
 
1578
     * build err stat 
 
1579
     */
 
1580
    ptr = asn_build_int(ptr, &len,
 
1581
                        (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
 
1582
                                  ASN_INTEGER), &errstat, sizeof(errstat));
 
1583
    if (ptr == NULL) {
 
1584
        return -1;
 
1585
    }
 
1586
 
 
1587
    /*
 
1588
     * build err index 
 
1589
     */
 
1590
    ptr = asn_build_int(ptr, &len,
 
1591
                        (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
 
1592
                                  ASN_INTEGER), &errindex,
 
1593
                        sizeof(errindex));
 
1594
    if (ptr == NULL) {
 
1595
        return -1;
 
1596
    }
 
1597
 
 
1598
    save2 = ptr;
 
1599
    ptr += 4;
 
1600
    len -= 4;
 
1601
 
 
1602
    if (type != SMUX_SET) {
 
1603
        val_type = ASN_NULL;
 
1604
        val_len = 0;
 
1605
    }
 
1606
 
 
1607
    /*
 
1608
     * build var list : snmp_build_var_op not liked by gated XXX 
 
1609
     */
 
1610
    ptr = snmp_build_var_op(ptr, objid, oidlen, val_type, val_len,
 
1611
                            val, &len);
 
1612
    if (ptr == NULL) {
 
1613
        return -1;
 
1614
    }
 
1615
 
 
1616
    len = ptr - save1;
 
1617
    asn_build_sequence(save1, &len, type, (ptr - save1 - 4));
 
1618
 
 
1619
    len = ptr - save2;
 
1620
    asn_build_sequence(save2, &len,
 
1621
                       (ASN_SEQUENCE | ASN_CONSTRUCTOR),
 
1622
                       (ptr - save2 - 4));
 
1623
 
 
1624
    *length = ptr - packet;
 
1625
 
 
1626
    return 0;
 
1627
}
 
1628
 
 
1629
static void
 
1630
smux_peer_cleanup(int sd)
 
1631
{
 
1632
    smux_reg       *nrptr, *rptr, *rptr2;
 
1633
    int             nfound, i;
 
1634
 
 
1635
    nfound = 0;
 
1636
 
 
1637
    /*
 
1638
     * close the descriptor 
 
1639
     */
 
1640
    close(sd);
 
1641
 
 
1642
    /*
 
1643
     * delete all of the passive registrations that this peer owns 
 
1644
     */
 
1645
    for (rptr = PassiveRegs; rptr; rptr = nrptr) {
 
1646
        nrptr = rptr->sr_next;
 
1647
        if (rptr->sr_fd == sd) {
 
1648
            smux_list_detach(&PassiveRegs, &rptr);
 
1649
            free(rptr);
 
1650
        }
 
1651
        rptr = nrptr;
 
1652
    }
 
1653
    /*
 
1654
     * find replacements for all of the active registrations found 
 
1655
     */
 
1656
    for (rptr = ActiveRegs; rptr; rptr = rptr2) {
 
1657
        rptr2 = rptr->sr_next;
 
1658
        if (rptr->sr_fd == sd) {
 
1659
            smux_list_detach(&ActiveRegs, &rptr);
 
1660
            unregister_mib(rptr->sr_name, rptr->sr_name_len);
 
1661
            if ((nrptr = smux_find_replacement(rptr->sr_name,
 
1662
                                               rptr->sr_name_len)) !=
 
1663
                NULL) {
 
1664
                smux_list_detach(&PassiveRegs, &nrptr);
 
1665
                smux_list_add(&ActiveRegs, nrptr);
 
1666
                register_mib("smux", (struct variable *)
 
1667
                             smux_variables, sizeof(struct variable2),
 
1668
                             1, nrptr->sr_name, nrptr->sr_name_len);
 
1669
            }
 
1670
            free(rptr);
 
1671
        }
 
1672
    }
 
1673
 
 
1674
    /*
 
1675
     * decrement the peer count 
 
1676
     */
 
1677
    npeers--;
 
1678
 
 
1679
    /*
 
1680
     * make his auth available again 
 
1681
     */
 
1682
    for (i = 0; i < nauths; i++) {
 
1683
        if (Auths[i]->sa_active_fd == sd) {
 
1684
            char            oid_name[128];
 
1685
            Auths[i]->sa_active_fd = -1;
 
1686
            snprint_objid(oid_name, sizeof(oid_name), Auths[i]->sa_oid,
 
1687
                          Auths[i]->sa_oid_len);
 
1688
            snmp_log(LOG_INFO, "peer disconnected: %s\n", oid_name);
 
1689
        }
 
1690
    }
 
1691
}
 
1692
 
 
1693
int
 
1694
smux_send_rrsp(int sd, int pri)
 
1695
{
 
1696
    u_char          outdata[2 + sizeof(int)];
 
1697
    u_char         *ptr = outdata;
 
1698
    int             intsize = sizeof(int);
 
1699
    u_int           mask = ((u_int) 0xFF) << (8 * (sizeof(int) - 1));
 
1700
    /*
 
1701
     * e.g. mask is 0xFF000000 on a 32-bit machine 
 
1702
     */
 
1703
    int             sent;
 
1704
 
 
1705
    /*
 
1706
     * This is kind of like calling asn_build_int(), but the
 
1707
     * encoding will always be the size of an integer on this
 
1708
     * machine, never shorter.
 
1709
     */
 
1710
    *ptr++ = (u_char) SMUX_RRSP;
 
1711
    *ptr++ = (u_char) intsize;
 
1712
 
 
1713
    /*
 
1714
     * Copy each byte, most significant first. 
 
1715
     */
 
1716
    while (intsize--) {
 
1717
        *ptr++ = (u_char) ((pri & mask) >> (8 * (sizeof(int) - 1)));
 
1718
        pri <<= 8;
 
1719
    }
 
1720
 
 
1721
    sent = send(sd, (char *) outdata, sizeof outdata, 0);
 
1722
    if (sent < 0) {
 
1723
        DEBUGMSGTL(("smux", "[smux_send_rrsp] send failed\n"));
 
1724
    }
 
1725
    return (sent);
 
1726
}
 
1727
 
 
1728
static u_char  *
 
1729
smux_trap_process(u_char * rsp, size_t * len)
 
1730
{
 
1731
    oid             sa_enterpriseoid[MAX_OID_LEN], var_name[MAX_OID_LEN];
 
1732
    size_t          datalen, var_name_len, var_val_len, maxlen;
 
1733
    size_t          sa_enterpriseoid_len;
 
1734
    u_char          vartype, *ptr, *var_val;
 
1735
 
 
1736
    long            trap, specific;
 
1737
    u_long          timestamp;
 
1738
 
 
1739
    netsnmp_variable_list *snmptrap_head, *snmptrap_ptr, *snmptrap_tmp;
 
1740
    snmptrap_head = NULL;
 
1741
    snmptrap_ptr = NULL;
 
1742
 
 
1743
    ptr = rsp;
 
1744
 
 
1745
    /*
 
1746
     * parse the sub-agent enterprise oid 
 
1747
     */
 
1748
    datalen = MAX_OID_LEN;
 
1749
    if ((ptr = asn_parse_objid(ptr, len,
 
1750
                               &vartype, (oid *) & sa_enterpriseoid,
 
1751
                               &sa_enterpriseoid_len)) == NULL) {
 
1752
        DEBUGMSGTL(("smux",
 
1753
                    "[smux_trap_process] asn_parse_objid failed\n"));
 
1754
        return NULL;
 
1755
    }
 
1756
 
 
1757
    /*
 
1758
     * parse the agent-addr ipAddress 
 
1759
     */
 
1760
    datalen = SMUXMAXSTRLEN;
 
1761
    if (((ptr = asn_parse_string(ptr, len,
 
1762
                                 &vartype, smux_str,
 
1763
                                 &datalen)) == NULL) ||
 
1764
        (vartype != (u_char) ASN_IPADDRESS)) {
 
1765
        DEBUGMSGTL(("smux",
 
1766
                    "[smux_trap_process] asn_parse_string failed\n"));
 
1767
        return NULL;
 
1768
    }
 
1769
 
 
1770
    /*
 
1771
     * parse the generic trap int 
 
1772
     */
 
1773
    datalen = sizeof(long);
 
1774
    if ((ptr = asn_parse_int(ptr, len, &vartype, &trap, datalen)) == NULL) {
 
1775
        DEBUGMSGTL(("smux",
 
1776
                    "[smux_trap_process] asn_parse_int generic failed\n"));
 
1777
        return NULL;
 
1778
    }
 
1779
 
 
1780
    /*
 
1781
     * parse the specific trap int 
 
1782
     */
 
1783
    datalen = sizeof(long);
 
1784
    if ((ptr = asn_parse_int(ptr, len,
 
1785
                             &vartype, &specific, datalen)) == NULL) {
 
1786
        DEBUGMSGTL(("smux",
 
1787
                    "[smux_trap_process] asn_parse_int specific failed\n"));
 
1788
        return NULL;
 
1789
    }
 
1790
 
 
1791
    /*
 
1792
     * parse the timeticks timestamp 
 
1793
     */
 
1794
    datalen = sizeof(u_long);
 
1795
    if (((ptr = asn_parse_unsigned_int(ptr, len,
 
1796
                                       &vartype, (u_long *) & timestamp,
 
1797
                                       datalen)) == NULL) ||
 
1798
        (vartype != (u_char) ASN_TIMETICKS)) {
 
1799
        DEBUGMSGTL(("smux",
 
1800
                    "[smux_trap_process] asn_parse_unsigned_int (timestamp) failed\n"));
 
1801
        return NULL;
 
1802
    }
 
1803
 
 
1804
    /*
 
1805
     * parse out the overall sequence 
 
1806
     */
 
1807
    ptr = asn_parse_header(ptr, len, &vartype);
 
1808
    if (ptr == NULL || vartype != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
 
1809
        return NULL;
 
1810
    }
 
1811
 
 
1812
    /*
 
1813
     * parse the variable bindings 
 
1814
     */
 
1815
    while (ptr && *len) {
 
1816
 
 
1817
        /*
 
1818
         * get the objid and the asn1 coded value 
 
1819
         */
 
1820
        var_name_len = MAX_OID_LEN;
 
1821
        ptr = snmp_parse_var_op(ptr, var_name, &var_name_len, &vartype,
 
1822
                                &var_val_len, (u_char **) & var_val, len);
 
1823
 
 
1824
        if (ptr == NULL) {
 
1825
            return NULL;
 
1826
        }
 
1827
 
 
1828
        maxlen = SMUXMAXPKTSIZE;
 
1829
        switch ((short) vartype) {
 
1830
        case ASN_INTEGER:
 
1831
            var_val_len = sizeof(long);
 
1832
            asn_parse_int(var_val, &maxlen, &vartype,
 
1833
                          (long *) &smux_long, var_val_len);
 
1834
            var_val = (u_char *) & smux_long;
 
1835
            break;
 
1836
        case ASN_COUNTER:
 
1837
        case ASN_GAUGE:
 
1838
        case ASN_TIMETICKS:
 
1839
        case ASN_UINTEGER:
 
1840
            var_val_len = sizeof(u_long);
 
1841
            asn_parse_unsigned_int(var_val, &maxlen, &vartype,
 
1842
                                   (u_long *) & smux_ulong, var_val_len);
 
1843
            var_val = (u_char *) & smux_ulong;
 
1844
            break;
 
1845
        case ASN_COUNTER64:
 
1846
            var_val_len = sizeof(smux_counter64);
 
1847
            asn_parse_unsigned_int64(var_val, &maxlen, &vartype,
 
1848
                                     (struct counter64 *) &smux_counter64,
 
1849
                                     var_val_len);
 
1850
            var_val = (u_char *) & smux_counter64;
 
1851
            break;
 
1852
        case ASN_IPADDRESS:
 
1853
            var_val_len = 4;
 
1854
            /*
 
1855
             * consume the tag and length, but just copy here
 
1856
             * because we know it is an ip address
 
1857
             */
 
1858
            if ((var_val =
 
1859
                 asn_parse_header(var_val, &maxlen, &vartype)) == NULL)
 
1860
                return NULL;
 
1861
            memcpy((u_char *) & (smux_sa.sin_addr.s_addr), var_val,
 
1862
                   var_val_len);
 
1863
            var_val = (u_char *) & (smux_sa.sin_addr.s_addr);
 
1864
            break;
 
1865
        case ASN_OPAQUE:
 
1866
        case ASN_OCTET_STR:
 
1867
            /*
 
1868
             * XXX 
 
1869
             */
 
1870
            if (len == 0)
 
1871
                return NULL;
 
1872
            var_val_len = SMUXMAXSTRLEN;
 
1873
            asn_parse_string(var_val, &maxlen, &vartype,
 
1874
                             smux_str, &var_val_len);
 
1875
            var_val = smux_str;
 
1876
            break;
 
1877
        case ASN_OBJECT_ID:
 
1878
            var_val_len = MAX_OID_LEN;
 
1879
            asn_parse_objid(var_val, &maxlen, &vartype,
 
1880
                            smux_objid, &var_val_len);
 
1881
            var_val_len *= sizeof(oid);
 
1882
            var_val = (u_char *) smux_objid;
 
1883
            break;
 
1884
        case SNMP_NOSUCHOBJECT:
 
1885
        case SNMP_NOSUCHINSTANCE:
 
1886
        case SNMP_ENDOFMIBVIEW:
 
1887
        case ASN_NULL:
 
1888
            var_val = NULL;
 
1889
            break;
 
1890
        case ASN_BIT_STR:
 
1891
            /*
 
1892
             * XXX 
 
1893
             */
 
1894
            if (len == 0)
 
1895
                return NULL;
 
1896
            var_val_len = SMUXMAXSTRLEN;
 
1897
            asn_parse_bitstring(var_val, &maxlen, &vartype,
 
1898
                                smux_str, &var_val_len);
 
1899
            var_val = (u_char *) smux_str;
 
1900
            break;
 
1901
        case ASN_NSAP:
 
1902
        default:
 
1903
            snmp_log(LOG_ERR, "bad type returned (%x)\n", vartype);
 
1904
            var_val = NULL;
 
1905
            break;
 
1906
        }
 
1907
 
 
1908
        snmptrap_tmp =
 
1909
            (netsnmp_variable_list *)
 
1910
            malloc(sizeof(netsnmp_variable_list));
 
1911
        if (snmptrap_tmp == NULL)
 
1912
            return NULL;
 
1913
        memset(snmptrap_tmp, 0, sizeof(netsnmp_variable_list));
 
1914
        if (snmptrap_head == NULL) {
 
1915
            snmptrap_head = snmptrap_tmp;
 
1916
            snmptrap_ptr = snmptrap_head;
 
1917
        } else {
 
1918
            snmptrap_ptr->next_variable = snmptrap_tmp;
 
1919
            snmptrap_ptr = snmptrap_ptr->next_variable;
 
1920
        }
 
1921
 
 
1922
        snmp_set_var_objid(snmptrap_ptr, var_name, var_name_len);
 
1923
        snmp_set_var_value(snmptrap_ptr, (char *) var_val, var_val_len);
 
1924
        snmptrap_ptr->type = vartype;
 
1925
        snmptrap_ptr->next_variable = NULL;
 
1926
 
 
1927
    }
 
1928
 
 
1929
    /*
 
1930
     * send the traps 
 
1931
     */
 
1932
    send_enterprise_trap_vars(trap, specific, (oid *) & sa_enterpriseoid,
 
1933
                              sa_enterpriseoid_len, snmptrap_head);
 
1934
 
 
1935
    /*
 
1936
     * free trap variables 
 
1937
     */
 
1938
    snmp_free_varbind(snmptrap_head);
 
1939
 
 
1940
    return ptr;
 
1941
 
 
1942
}
 
1943