Coverage Report

Created: 2026-09-04 09:22

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