Coverage Report

Created: 2025-08-11 06:35

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