pull fixes from branch_1_1
[freeradius.git] / src / main / smux.c
1 /*
2  * smux.c       SNMP support
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000,2006  The FreeRADIUS server project
21  * Copyright 1999  Jochen Friedrich <jochen@scram.de>
22  * Copyright 1999  Kunihiro Ishiguro <kunihiro@zebra.org>
23  */
24
25 #ifdef WITH_SNMP
26
27 #include <freeradius-devel/ident.h>
28 RCSID("$Id$")
29
30 #include <freeradius-devel/autoconf.h>
31
32
33 #include <sys/socket.h>
34 #include <sys/file.h>
35
36 #ifdef HAVE_NETINET_IN_H
37 #include <netinet/in.h>
38 #endif
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <netdb.h>
44 #include <fcntl.h>
45 #include <ctype.h>
46
47 #include <freeradius-devel/radiusd.h>
48 #include <freeradius-devel/radius_snmp.h>
49 #include <freeradius-devel/smux.h>
50
51 #define min(A,B) ((A) < (B) ? (A) : (B))
52
53
54
55 /* internal prototypes */
56 static int oid_compare (oid *, int, oid *, int);
57
58 /* SMUX subtree vector. */
59 static struct list *treelist = NULL;
60
61 /* SMUX oid. */
62 static oid *smux_oid;
63 static size_t smux_oid_len;
64
65 static void *
66 oid_copy (void *dest, void *src, size_t size)
67 {
68   return memcpy (dest, src, size * sizeof (oid));
69 }
70
71 #if 0
72 static void
73 oid2in_addr (oid my_oid[], int len, struct in_addr *addr)
74 {
75         int i;
76         u_char *pnt;
77
78         if (len == 0)
79                 return;
80
81         pnt = (u_char *) addr;
82
83         for (i = 0; i < len; i++)
84                 *pnt++ = my_oid[i];
85 }
86
87 static void
88 oid_copy_addr (oid my_oid[], struct in_addr *addr, int len)
89 {
90         int i;
91         u_char *pnt;
92
93         if (len == 0)
94                 return;
95
96         pnt = (u_char *) addr;
97
98         for (i = 0; i < len; i++)
99                 my_oid[i] = *pnt++;
100 }
101 #endif /* NOT USED */
102
103 static int
104 oid_compare (oid *o1, int o1_len, oid *o2, int o2_len)
105 {
106         int i;
107
108         for (i = 0; i < min (o1_len, o2_len); i++) {
109                         if (o1[i] < o2[i])
110                                 return -1;
111                         else if (o1[i] > o2[i])
112                                 return 1;
113         }
114         if (o1_len < o2_len)
115                 return -1;
116         if (o1_len > o2_len)
117                 return 1;
118
119         return 0;
120 }
121
122 static int
123 oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len)
124 {
125         int i;
126
127         for (i = 0; i < min (o1_len, o2_len); i++) {
128                         if (o1[i] < o2[i])
129                                 return -1;
130                         else if (o1[i] > o2[i])
131                                 return 1;
132         }
133         if (o1_len < o2_len)
134                 return -1;
135
136         return 0;
137 }
138 \f
139 static void
140 smux_oid_dump(const char *prefix, oid *my_oid, size_t oid_len)
141 {
142         int i;
143         int first = 1;
144         char buf[MAX_OID_LEN * 3];
145
146         buf[0] = '\0';
147
148         for (i = 0; i < oid_len; i++) {
149                         sprintf (buf + strlen (buf), "%s%d", first ? "" : ".", (int) my_oid[i]);
150                         first = 0;
151         }
152         DEBUG2 ("%s: %s", prefix, buf);
153 }
154
155 static int
156 smux_sock (void)
157 {
158         int ret;
159         int on = 1;
160 #ifdef HAVE_IPV6
161         struct addrinfo hints, *res0, *res;
162         int gai;
163 #else
164         struct sockaddr_in serv;
165         struct servent *sp;
166 #endif
167         int fd;
168
169 #ifdef HAVE_IPV6
170         memset(&hints, 0, sizeof(hints));
171         hints.ai_family = PF_UNSPEC;
172         hints.ai_socktype = SOCK_STREAM;
173         gai = getaddrinfo(NULL, "smux", &hints, &res0);
174         if (gai == EAI_SERVICE) {
175                 char servbuf[NI_MAXSERV];
176                 sprintf(servbuf,"%d",SMUX_PORT_DEFAULT);
177                 gai = getaddrinfo(NULL, servbuf, &hints, &res0);
178         }
179         if (gai) {
180                 DEBUG("Cannot locate loopback service smux");
181                 return -1;
182         }
183         for(res=res0; res; res=res->ai_next) {
184                 fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
185                 if (fd < 0)
186                         continue;
187                 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof (on));
188 #ifdef SO_REUSEPORT
189                 setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof (on));
190 #endif
191                 ret = connect (fd, res->ai_addr, res->ai_addrlen);
192                 if (ret < 0) {
193                         close(fd);
194                         fd = -1;
195                         continue;
196                 }
197                 break;
198         }
199         freeaddrinfo(res0);
200         if (fd < 0)
201                 DEBUG ("Can't connect to SNMP agent with SMUX");
202 #else
203         fd = socket (AF_INET, SOCK_STREAM, 0);
204         if (fd < 0) {
205                 DEBUG ("Can't make socket for SNMP");
206                 return -1;
207         }
208
209         memset (&serv, 0, sizeof (struct sockaddr_in));
210         serv.sin_family = AF_INET;
211 #ifdef HAVE_SIN_LEN
212         serv.sin_len = sizeof (struct sockaddr_in);
213 #endif /* HAVE_SIN_LEN */
214
215         sp = getservbyname ("smux", "tcp");
216         if (sp != NULL)
217                 serv.sin_port = sp->s_port;
218         else
219                 serv.sin_port = htons (SMUX_PORT_DEFAULT);
220
221         serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
222
223         setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof (on));
224 #ifdef SO_REUSEPORT
225         setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof (on));
226 #endif
227
228         ret = connect (fd, (struct sockaddr *) &serv, sizeof (struct sockaddr_in));
229         if (ret < 0) {
230                 close (fd);
231                 DEBUG ("Can't connect to SNMP agent with SMUX: %s", strerror(errno));
232                 fd = -1;
233         }
234 #endif
235         return fd;
236 }
237
238 static void
239 smux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat,
240                 long errindex, u_char val_type, const void *arg, size_t arg_len)
241 {
242         int ret;
243         u_char buf[BUFSIZ];
244         u_char *ptr, *h1, *h1e, *h2, *h2e;
245         int len, length;
246
247         ptr = buf;
248         len = BUFSIZ;
249         length = len;
250
251         DEBUG2("SMUX GETRSP send");
252         DEBUG2("SMUX GETRSP reqid: %ld", reqid);
253
254         h1 = ptr;
255         /* Place holder h1 for complete sequence */
256         ptr = asn_build_sequence (ptr, &len, (u_char) SMUX_GETRSP, 0);
257         h1e = ptr;
258
259         ptr = asn_build_int (ptr, &len,
260                         (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
261                         &reqid, sizeof (reqid));
262
263         DEBUG2("SMUX GETRSP errstat: %ld", errstat);
264
265         ptr = asn_build_int (ptr, &len,
266                         (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
267                         &errstat, sizeof (errstat));
268         DEBUG2("SMUX GETRSP errindex: %ld", errindex);
269
270         ptr = asn_build_int (ptr, &len,
271                         (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
272                         &errindex, sizeof (errindex));
273
274         h2 = ptr;
275         /* Place holder h2 for one variable */
276         ptr = asn_build_sequence (ptr, &len,
277                         (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
278                         0);
279         h2e = ptr;
280
281         ptr = snmp_build_var_op (ptr, objid, &objid_len,
282                         val_type, arg_len, arg, &len);
283
284         /* Now variable size is known, fill in size */
285         asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e);
286
287         /* Fill in size of whole sequence */
288         asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e);
289
290         DEBUG2("SMUX getresp send: %d", ptr - buf);
291
292         ret = send (rad_snmp.smux_fd, buf, (ptr - buf), 0);
293 }
294
295 static char *
296 smux_var (char *ptr, int len, oid objid[], size_t *objid_len,
297                 size_t *var_val_len,
298                 u_char *var_val_type,
299                 void **var_value)
300 {
301         u_char type;
302         u_char val_type;
303         size_t val_len;
304         u_char *val;
305
306         DEBUG2("SMUX var parse: len %d", len);
307
308         /* Parse header. */
309         ptr = asn_parse_header (ptr, &len, &type);
310
311         DEBUG2("SMUX var parse: type %d len %d", type, len);
312         DEBUG2("SMUX var parse: type must be %d", (ASN_SEQUENCE | ASN_CONSTRUCTOR));
313
314         /* Parse var option. */
315         *objid_len = MAX_OID_LEN;
316         ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type,
317                                 &val_len, &val, &len);
318
319         if (var_val_len)
320                 *var_val_len = val_len;
321
322         if (var_value)
323                 *var_value = (void*) val;
324
325         if (var_val_type)
326                 *var_val_type = val_type;
327
328         /* Requested object id length is objid_len. */
329         smux_oid_dump ("Request OID", objid, *objid_len);
330
331         DEBUG2 ("SMUX val_type: %d", val_type);
332
333         /* Check request value type. */
334         switch (val_type) {
335                 case ASN_NULL:
336                         /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
337                                  ASN_NULL. */
338                         DEBUG2 ("ASN_NULL");
339                         break;
340
341                 case ASN_INTEGER:
342                         DEBUG2 ("ASN_INTEGER");
343                         break;
344                 case ASN_COUNTER:
345                 case ASN_GAUGE:
346                 case ASN_TIMETICKS:
347                 case ASN_UINTEGER:
348                         DEBUG2 ("ASN_COUNTER");
349                         break;
350                 case ASN_COUNTER64:
351                         DEBUG2 ("ASN_COUNTER64");
352                         break;
353                 case ASN_IPADDRESS:
354                         DEBUG2 ("ASN_IPADDRESS");
355                         break;
356                 case ASN_OCTET_STR:
357                         DEBUG2 ("ASN_OCTET_STR");
358                         break;
359                 case ASN_OPAQUE:
360                 case ASN_NSAP:
361                 case ASN_OBJECT_ID:
362                         DEBUG2 ("ASN_OPAQUE");
363                         break;
364                 case SNMP_NOSUCHOBJECT:
365                         DEBUG2 ("SNMP_NOSUCHOBJECT");
366                         break;
367                 case SNMP_NOSUCHINSTANCE:
368                         DEBUG2 ("SNMP_NOSUCHINSTANCE");
369                         break;
370                 case SNMP_ENDOFMIBVIEW:
371                         DEBUG2 ("SNMP_ENDOFMIBVIEW");
372                         break;
373                 case ASN_BIT_STR:
374                         DEBUG2 ("ASN_BIT_STR");
375                         break;
376                 default:
377                         DEBUG2 ("Unknown type");
378                         break;
379         }
380         return ptr;
381 }
382
383 /* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
384          ucd-snmp smux and as such suppose, that the peer receives in the message
385          only one variable. Fortunately, IBM seems to do the same in AIX. */
386
387 static int
388 smux_set (oid *reqid, size_t *reqid_len,
389                 u_char val_type, void *val, size_t val_len, int action)
390 {
391         int j;
392         struct subtree *subtree;
393         struct variable *v;
394         struct list *l;
395         int subresult;
396         oid *suffix;
397         int suffix_len;
398         int result;
399         const unsigned char *statP = NULL;
400         WriteMethod *write_method = NULL;
401
402         if (!rad_snmp.snmp_write_access)
403                 return SNMP_ERR_NOSUCHNAME;
404
405         /* Check */
406         for (l = treelist; l; l=l->next) {
407                 subtree = l->data;
408                 subresult = oid_compare_part (reqid, *reqid_len,
409                                 subtree->name, subtree->name_len);
410
411                 /* Subtree matched. */
412                 if (subresult == 0) {
413                         /* Prepare suffix. */
414                         suffix = reqid + subtree->name_len;
415                         suffix_len = *reqid_len - subtree->name_len;
416                         result = subresult;
417
418                         /* Check variables. */
419                         for (j = 0; j < subtree->variables_num; j++) {
420                                 v = &subtree->variables[j];
421
422                                 /* Always check suffix */
423                                 result = oid_compare_part (suffix, suffix_len,
424                                                 v->name, v->namelen);
425
426                                 /* This is exact match so result must be zero. */
427                                 if (result == 0) {
428                                         DEBUG2 ("SMUX function call index is %d", v->magic);
429
430                                         statP = (*v->findVar) (v, suffix, &suffix_len, 1,
431                                         &val_len, &write_method);
432
433                                         if (write_method) {
434                                                 return (*write_method)(action, val, val_type, val_len, statP, suffix, suffix_len);
435
436                                         } else {
437                                                 return SNMP_ERR_READONLY;
438                                         }
439                                 }
440
441                                 /* If above execution is failed or oid is small (so
442                                    there is no further match). */
443                                 if (result < 0)
444                                         return SNMP_ERR_NOSUCHNAME;
445                         }
446                 }
447         }
448         return SNMP_ERR_NOSUCHNAME;
449 }
450
451 static int
452 smux_get (oid *reqid, size_t *reqid_len, int exact,
453                 u_char *val_type,const void **val, size_t *val_len)
454 {
455         int j;
456         struct subtree *subtree;
457         struct variable *v;
458         struct list *l;
459         int subresult;
460         oid *suffix;
461         int suffix_len;
462         int result;
463         WriteMethod *write_method=NULL;
464
465         /* Check */
466         for (l = treelist; l; l=l->next) {
467                 subtree = l->data;
468                 subresult = oid_compare_part (reqid, *reqid_len,
469                                 subtree->name, subtree->name_len);
470
471                 /* Subtree matched. */
472                 if (subresult == 0) {
473                         /* Prepare suffix. */
474                         suffix = reqid + subtree->name_len;
475                         suffix_len = *reqid_len - subtree->name_len;
476                         result = subresult;
477
478                         /* Check variables. */
479                         for (j = 0; j < subtree->variables_num; j++) {
480                                 v = &subtree->variables[j];
481
482                                 /* Always check suffix */
483                                 result = oid_compare_part (suffix, suffix_len,
484                                                 v->name, v->namelen);
485
486                                 /* This is exact match so result must be zero. */
487                                 if (result == 0) {
488                                         DEBUG2 ("SMUX function call index is %d", v->magic);
489
490                                         *val = (*v->findVar) (v, suffix, &suffix_len, exact,
491                                                         val_len, &write_method);
492
493                                         /* There is no instance. */
494                                         if (*val == NULL)
495                                                 return SNMP_ERR_NOSUCHNAME;
496
497                                         /* Call is suceed. */
498                                         *val_type = v->type;
499
500                                         return 0;
501                                 }
502
503                                 /* If above execution is failed or oid is small (so
504                                    there is no further match). */
505                                 if (result < 0)
506                                         return SNMP_ERR_NOSUCHNAME;
507                         }
508                 }
509         }
510         return SNMP_ERR_NOSUCHNAME;
511 }
512
513 static int
514 smux_getnext (oid *reqid, size_t *reqid_len, int exact,
515                 u_char *val_type, const void **val, size_t *val_len)
516 {
517         int j;
518         oid save[MAX_OID_LEN];
519         int savelen = 0;
520         struct subtree *subtree;
521         struct variable *v;
522         struct list *l;
523         int subresult;
524         oid *suffix;
525         int suffix_len;
526         int result;
527         WriteMethod *write_method=NULL;
528
529         /* Save incoming request. */
530         oid_copy (save, reqid, *reqid_len);
531         savelen = *reqid_len;
532
533         /* Check for best matching subtree */
534
535         for (l = treelist; l; l=l->next) {
536                 subtree = l->data;
537
538                 subresult = oid_compare_part (reqid, *reqid_len,
539                                 subtree->name, subtree->name_len);
540
541                  /* If request is in the tree. The agent has to make sure we
542                     only receive requests we have registered for. */
543                  /* Unfortunately, that's not true. In fact, a SMUX subagent has to
544                     behave as if it manages the whole SNMP MIB tree itself. It's the
545                     duty of the master agent to collect the best answer and return it
546                     to the manager. See RFC 1227 chapter 3.1.6 for the glory details
547                     :-). ucd-snmp really behaves bad here as it actually might ask
548                     multiple times for the same GETNEXT request as it throws away the
549                     answer when it expects it in a different subtree and might come
550                     back later with the very same request. --jochen */
551
552                 if (subresult <= 0) {
553                                 /* Prepare suffix. */
554                                 suffix = reqid + subtree->name_len;
555                                 suffix_len = *reqid_len - subtree->name_len;
556                                 if (subresult < 0) {
557                                         oid_copy(reqid, subtree->name, subtree->name_len);
558                                         *reqid_len = subtree->name_len;
559                                 }
560                         for (j = 0; j < subtree->variables_num; j++) {
561                                 result = subresult;
562                                 v = &subtree->variables[j];
563
564                                 /* Next then check result >= 0. */
565                                 if (result == 0)
566                                         result = oid_compare_part (suffix, suffix_len,
567                                                         v->name, v->namelen);
568
569                                 if (result <= 0) {
570                                         DEBUG2 ("SMUX function call index is %d", v->magic);
571                                         if(result<0) {
572                                                 oid_copy(suffix, v->name, v->namelen);
573                                                 suffix_len = v->namelen;
574                                         }
575                                         *val = (*v->findVar) (v, suffix, &suffix_len, exact,
576                                         val_len, &write_method);
577                                         *reqid_len = suffix_len + subtree->name_len;
578                                         if (*val) {
579                                                 *val_type = v->type;
580                                                 return 0;
581                                         }
582                                 }
583                         }
584                 }
585         }
586         memcpy (reqid, save, savelen * sizeof(oid));
587         *reqid_len = savelen;
588
589         return SNMP_ERR_NOSUCHNAME;
590 }
591
592 /* GET message header. */
593 static char *
594 smux_parse_get_header (char *ptr, size_t *len, long *reqid)
595 {
596         u_char type;
597         long errstat;
598         long errindex;
599
600         /* Request ID. */
601         ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid));
602
603         DEBUG2 ("SMUX GET reqid: %ld len: %d", *reqid, (int) *len);
604
605         /* Error status. */
606         ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat));
607
608         DEBUG2 ("SMUX GET errstat %ld len: %d", errstat, *len);
609
610         /* Error index. */
611         ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex));
612
613         DEBUG2 ("SMUX GET errindex %ld len: %d", errindex, *len);
614
615         return ptr;
616 }
617
618 static void
619 smux_parse_set (char *ptr, size_t len, int action)
620 {
621         long reqid;
622         oid my_oid[MAX_OID_LEN];
623         size_t oid_len;
624         u_char val_type;
625         void *val;
626         size_t val_len;
627         int ret;
628
629         DEBUG2 ("SMUX SET(%s) message parse: len %d",
630                         (RESERVE1 == action) ? "RESERVE1" : ((FREE == action) ? "FREE" : "COMMIT"),
631                         len);
632
633         /* Parse SET message header. */
634         ptr = smux_parse_get_header (ptr, &len, &reqid);
635
636         /* Parse SET message object ID. */
637         ptr = smux_var (ptr, len, my_oid, &oid_len, &val_len, &val_type, &val);
638
639         ret = smux_set (my_oid, &oid_len, val_type, val, val_len, action);
640         DEBUG2 ("SMUX SET ret %d", ret);
641
642         /* Return result. */
643         if (RESERVE1 == action)
644                 smux_getresp_send (my_oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
645 }
646
647 static void
648 smux_parse_get (char *ptr, size_t len, int exact)
649 {
650         long reqid;
651         oid my_oid[MAX_OID_LEN];
652         size_t oid_len;
653         u_char val_type;
654         const void *val;
655         size_t val_len;
656         int ret;
657
658         DEBUG2 ("SMUX GET message parse: len %d", len);
659
660         /* Parse GET message header. */
661         ptr = smux_parse_get_header (ptr, &len, &reqid);
662
663         /* Parse GET message object ID. We needn't the value come */
664         ptr = smux_var (ptr, len, my_oid, &oid_len, NULL, NULL, NULL);
665
666         /* Traditional getstatptr. */
667         if (exact)
668                 ret = smux_get (my_oid, &oid_len, exact, &val_type, &val, &val_len);
669         else
670                 ret = smux_getnext (my_oid, &oid_len, exact, &val_type, &val, &val_len);
671
672         /* Return result. */
673         if (ret == 0)
674                 smux_getresp_send (my_oid, oid_len, reqid, 0, 0, val_type, val, val_len);
675         else
676                 smux_getresp_send (my_oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
677 }
678
679 /* Parse SMUX_CLOSE message. */
680 static void
681 smux_parse_close (char *ptr, int len)
682 {
683         long reason = 0;
684
685         while (len--) {
686                 reason = (reason << 8) | (long) *ptr;
687                 ptr++;
688         }
689         DEBUG ("SMUX_CLOSE with reason: %ld", reason);
690 }
691
692 /* SMUX_RRSP message. */
693 static void
694 smux_parse_rrsp (char *ptr, int len)
695 {
696         char val;
697         long errstat;
698
699         ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat));
700
701         DEBUG2 ("SMUX_RRSP value: %d errstat: %ld", val, errstat);
702 }
703
704 /* Parse SMUX message. */
705 static int
706 smux_parse (char *ptr, int len)
707 {
708         /* this buffer we'll use for SOUT message. We could allocate it with malloc and
709                  save only static pointer/lenght, but IMHO static buffer is a faster solusion */
710         static u_char sout_save_buff[SMUXMAXPKTSIZE];
711         static int sout_save_len = 0;
712
713         int len_income = len; /* see note below: YYY */
714         u_char type;
715         u_char rollback;
716
717         rollback = ptr[2]; /* important only for SMUX_SOUT */
718
719 process_rest: /* see note below: YYY */
720
721         /* Parse SMUX message type and subsequent length. */
722         ptr = asn_parse_header (ptr, &len, &type);
723
724         DEBUG2 ("SMUX message received type: %d rest len: %d", type, len);
725
726         switch (type) {
727                 case SMUX_OPEN:
728                         /* Open must be not send from SNMP agent. */
729                         DEBUG ("SMUX_OPEN received: resetting connection.");
730                         return -1;
731                         break;
732                 case SMUX_RREQ:
733                         /* SMUX_RREQ message is invalid for us. */
734                         DEBUG ("SMUX_RREQ received: resetting connection.");
735                         return -1;
736                         break;
737                 case SMUX_SOUT:
738                         /* SMUX_SOUT message is now valied for us. */
739                         DEBUG2 ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit");
740
741                         if (sout_save_len > 0) {
742                                 smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT);
743                                 sout_save_len = 0;
744                         } else
745                                 DEBUG ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len);
746
747                         if (len_income > 3) {
748                                 /* YYY: this strange code has to solve the "slow peer"
749                                    problem: When agent sends SMUX_SOUT message it doesn't
750                                    wait any responce and may send some next message to
751                                    subagent. Then the peer in 'smux_read()' will recieve
752                                    from socket the 'concatenated' buffer, contaning both
753                                    SMUX_SOUT message and the next one
754                                    (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
755                                    the buffer is longer than 3 ( length of SMUX_SOUT ), we
756                                    must process the rest of it. This effect may be observed
757                                    if DEBUG is set to >1 */
758                                         ptr++;
759                                         len = len_income - 3;
760                                         goto process_rest;
761                                 }
762                         break;
763                 case SMUX_GETRSP:
764                         /* SMUX_GETRSP message is invalid for us. */
765                         DEBUG ("SMUX_GETRSP received: resetting connection.");
766                         return -1;
767                         break;
768                 case SMUX_CLOSE:
769                         /* Close SMUX connection. */
770                         DEBUG2 ("SMUX_CLOSE");
771                         smux_parse_close (ptr, len);
772                         return -1;
773                         break;
774                 case SMUX_RRSP:
775                         /* This is response for register message. */
776                         DEBUG2 ("SMUX_RRSP");
777                         smux_parse_rrsp (ptr, len);
778                         break;
779                 case SMUX_GET:
780                         /* Exact request for object id. */
781                         DEBUG2 ("SMUX_GET");
782                         smux_parse_get (ptr, len, 1);
783                         break;
784                 case SMUX_GETNEXT:
785                         /* Next request for object id. */
786                         DEBUG2 ("SMUX_GETNEXT");
787                         smux_parse_get (ptr, len, 0);
788                         break;
789                 case SMUX_SET:
790                         /* SMUX_SET is supported with some limitations. */
791                         DEBUG2 ("SMUX_SET");
792                         /* save the data for future SMUX_SOUT */
793                         memcpy (sout_save_buff, ptr, len);
794                         sout_save_len = len;
795                         smux_parse_set (ptr, len, RESERVE1);
796                         break;
797                 default:
798                         DEBUG ("Unknown type: %d", type);
799                         break;
800         }
801         return 0;
802 }
803
804 /* SMUX message read function. */
805 int
806 smux_read ()
807 {
808         int len;
809         u_char buf[SMUXMAXPKTSIZE];
810         int ret;
811
812         rad_snmp.smux_event=SMUX_NONE;
813         DEBUG2 ("SMUX read start");
814
815         /* Read message from SMUX socket. */
816         len = recv (rad_snmp.smux_fd, buf, SMUXMAXPKTSIZE, 0);
817
818         if (len < 0) {
819                 DEBUG ("Can't read all SMUX packet: %s", strerror (errno));
820                 close (rad_snmp.smux_fd);
821                 rad_snmp.smux_fd = -1;
822                 rad_snmp.smux_event=SMUX_CONNECT;
823                 return -1;
824         }
825
826         if (len == 0) {
827                 DEBUG ("SMUX connection closed: %d", rad_snmp.smux_fd);
828                 close (rad_snmp.smux_fd);
829                 rad_snmp.smux_fd = -1;
830                 rad_snmp.smux_event=SMUX_CONNECT;
831                 return -1;
832         }
833
834         DEBUG2 ("SMUX read len: %d", len);
835
836         /* Parse the message. */
837         ret = smux_parse (buf, len);
838
839         if (ret < 0) {
840                 close (rad_snmp.smux_fd);
841                 rad_snmp.smux_fd = -1;
842                 rad_snmp.smux_event=SMUX_CONNECT;
843                 return -1;
844         }
845
846         rad_snmp.smux_event=SMUX_READ;
847
848         return 0;
849 }
850
851 int
852 smux_open(void)
853 {
854         u_char buf[BUFSIZ];
855         u_char *ptr;
856         int len;
857         u_long smux_proto_version;
858         u_char rad_progname[] = "radiusd";
859
860         smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len);
861         DEBUG2 ("SMUX open progname: %s", rad_progname);
862         DEBUG2 ("SMUX open password: %s", rad_snmp.smux_password);
863
864         ptr = buf;
865         len = BUFSIZ;
866
867         /* SMUX Header. As placeholder. */
868         ptr = asn_build_header (ptr, &len, (u_char) SMUX_OPEN, 0);
869
870         /* SMUX Open. */
871         smux_proto_version = 0;
872         ptr = asn_build_int (ptr, &len,
873                         (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
874                         &smux_proto_version, sizeof (u_long));
875
876         /* SMUX connection oid. */
877         ptr = asn_build_objid (ptr, &len,
878                         (u_char)
879                         (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
880                         smux_oid, smux_oid_len);
881
882         /* SMUX connection description. */
883         ptr = asn_build_string (ptr, &len,
884                         (u_char)
885                         (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
886                         rad_progname, strlen (rad_progname));
887
888         /* SMUX connection password. */
889         ptr = asn_build_string (ptr, &len,
890                         (u_char)
891                         (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
892                         rad_snmp.smux_password, strlen(rad_snmp.smux_password));
893
894         /* Fill in real SMUX header.    We exclude ASN header size (2). */
895         len = BUFSIZ;
896         asn_build_header (buf, &len, (u_char) SMUX_OPEN, (ptr - buf) - 2);
897
898         return send (rad_snmp.smux_fd, buf, (ptr - buf), 0);
899 }
900
901 int
902 smux_register(void)
903 {
904         u_char buf[BUFSIZ];
905         u_char *ptr;
906         int len, ret;
907         long priority;
908         long operation;
909         struct subtree *subtree;
910         struct list *l;
911
912         ret = 0;
913
914         for (l = treelist; l; l=l->next) {
915                 subtree = l->data;
916
917                 ptr = buf;
918                 len = BUFSIZ;
919
920                 /* SMUX RReq Header. */
921                 ptr = asn_build_header (ptr, &len, (u_char) SMUX_RREQ, 0);
922
923                 /* Register MIB tree. */
924                 ptr = asn_build_objid (ptr, &len,
925                                 (u_char)
926                                 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
927                                 subtree->name, subtree->name_len);
928
929                 /* Priority. */
930                 priority = -1;
931                 ptr = asn_build_int (ptr, &len,
932                                 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
933                                 &priority, sizeof (u_long));
934
935                 /* Operation. */
936                 operation = rad_snmp.snmp_write_access ? 2 : 1; /* Register R/O or R/W */
937                 ptr = asn_build_int (ptr, &len,
938                                 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
939                                 &operation, sizeof (u_long));
940
941                 smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len);
942                 DEBUG2 ("SMUX register priority: %ld", priority);
943                 DEBUG2 ("SMUX register operation: %ld", operation);
944
945                 len = BUFSIZ;
946                 asn_build_header (buf, &len, (u_char) SMUX_RREQ, (ptr - buf) - 2);
947                 ret = send (rad_snmp.smux_fd, buf, (ptr - buf), 0);
948                 if (ret < 0)
949                         return ret;
950                 }
951         return ret;
952 }
953
954 /* Try to connect to SNMP agent. */
955 int
956 smux_connect ()
957 {
958         int ret;
959
960         rad_snmp.smux_event=SMUX_NONE;
961         DEBUG2 ("SMUX connect try %d", rad_snmp.smux_failures + 1);
962
963         /* Make socket. Try to connect. */
964         rad_snmp.smux_fd = smux_sock ();
965         if (rad_snmp.smux_fd < 0) {
966                 if (++rad_snmp.smux_failures < rad_snmp.smux_max_failures)
967                         rad_snmp.smux_event=SMUX_CONNECT;
968                 return 0;
969         }
970
971         /* Send OPEN PDU. */
972         ret = smux_open ();
973         if (ret < 0) {
974                 DEBUG ("SMUX open message send failed: %s", strerror (errno));
975                 close (rad_snmp.smux_fd);
976                 rad_snmp.smux_fd = -1;
977                 rad_snmp.smux_event=SMUX_CONNECT;
978                 return -1;
979         }
980
981         /* Send any outstanding register PDUs. */
982         ret = smux_register ();
983         if (ret < 0) {
984                 DEBUG ("SMUX register message send failed: %s", strerror (errno));
985                 close (rad_snmp.smux_fd);
986                 rad_snmp.smux_fd = -1;
987                 rad_snmp.smux_event=SMUX_CONNECT;
988                 return -1;
989         }
990
991         /* Everything goes fine. */
992         rad_snmp.smux_event=SMUX_READ;
993
994         return 0;
995 }
996
997 /* Clear all SMUX related resources. */
998 void
999 smux_stop(void)
1000 {
1001         rad_snmp.smux_event=SMUX_NONE;
1002         if (rad_snmp.smux_fd >= 0)
1003                 close (rad_snmp.smux_fd);
1004         rad_snmp.smux_fd = -1;
1005 }
1006
1007 int
1008 smux_str2oid (char *str, oid *my_oid, size_t *oid_len)
1009 {
1010         int len;
1011         int val;
1012
1013         len = 0;
1014         val = 0;
1015         *oid_len = 0;
1016
1017         if (*str == '.')
1018                 str++;
1019         if (*str == '\0')
1020                 return 0;
1021
1022         while (1) {
1023                 if (! isdigit ((int) *str))
1024                         return -1;
1025
1026                 while (isdigit ((int) *str)) {
1027                         val *= 10;
1028                         val += (*str - '0');
1029                         str++;
1030                 }
1031
1032                 if (*str == '\0')
1033                         break;
1034                 if (*str != '.')
1035                         return -1;
1036
1037                 my_oid[len++] = val;
1038                 val = 0;
1039                 str++;
1040         }
1041
1042         my_oid[len++] = val;
1043         *oid_len = len;
1044
1045         return 0;
1046 }
1047
1048 oid *
1049 smux_oid_dup (oid *objid, size_t objid_len)
1050 {
1051         oid *new;
1052
1053         new = (oid *)rad_malloc(sizeof (oid) * objid_len);
1054         oid_copy (new, objid, objid_len);
1055
1056         return new;
1057 }
1058
1059 int
1060 smux_header_generic (struct variable *v, oid *name, size_t *length, int exact,
1061                 size_t *var_len, WriteMethod **write_method)
1062 {
1063         oid fulloid[MAX_OID_LEN];
1064         int ret;
1065
1066         oid_copy (fulloid, v->name, v->namelen);
1067         fulloid[v->namelen] = 0;
1068         /* Check against full instance. */
1069         ret = oid_compare (name, *length, fulloid, v->namelen + 1);
1070
1071         /* Check single instance. */
1072         if ((exact && (ret != 0)) || (!exact && (ret >= 0)))
1073         return MATCH_FAILED;
1074
1075         /* In case of getnext, fill in full instance. */
1076         memcpy (name, fulloid, (v->namelen + 1) * sizeof (oid));
1077         *length = v->namelen + 1;
1078
1079         *write_method = 0;
1080         *var_len = sizeof(long);                /* default to 'long' results */
1081
1082         return MATCH_SUCCEEDED;
1083 }
1084
1085 /* Initialize some values then schedule first SMUX connection. */
1086 void
1087 smux_init (oid defoid[], size_t defoid_len)
1088 {
1089         smux_oid = defoid;
1090         smux_oid_len = defoid_len;
1091 }
1092
1093 /* Register subtree to smux master tree. */
1094 void
1095 smux_register_mib(UNUSED const char *descr, struct variable *var, size_t width,
1096                 int num, oid name[], size_t namelen)
1097 {
1098         struct subtree *tree, *tt;
1099         struct list *l, *ll;
1100
1101         tree = (struct subtree *)rad_malloc(sizeof(struct subtree));
1102         oid_copy (tree->name, name, namelen);
1103         tree->name_len = namelen;
1104         tree->variables = var;
1105         tree->variables_num = num;
1106         tree->variables_width = width;
1107         tree->registered = 0;
1108         l = (struct list *)rad_malloc(sizeof(struct list));
1109         l->data = tree;
1110         l->next = NULL;
1111 /* Build a treelist sorted by the name. This makes GETNEXT simpler */
1112         if (treelist == NULL) {
1113                 treelist = l;
1114                 return;
1115         }
1116         tt = (struct subtree*) treelist->data;
1117         if (oid_compare(name, namelen, tt->name, tt->name_len) < 0) {
1118                 l->next = treelist;
1119                 treelist = l;
1120                 return;
1121         }
1122         for (ll = treelist; ll->next; ll=ll->next) {
1123                 tt = (struct subtree*) ll->next->data;
1124                 if (oid_compare(name, namelen, tt->name, tt->name_len) < 0) {
1125                         l->next = ll->next;
1126                         ll->next = l;
1127                         return;
1128                 }
1129         }
1130         ll->next = l;
1131 }
1132
1133 void
1134 smux_start(void)
1135 {
1136         rad_snmp.smux_event=SMUX_CONNECT;
1137         smux_connect();
1138 }
1139 #endif /* WITH_SNMP */