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