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