newvector should be a bool
[freeradius.git] / src / modules / proto_vmps / vqp.c
1 /*
2  * vqp.c        Functions to send/receive VQP packets.
3  *
4  * Version:     $Id$
5  *
6  *   This library is free software; you can redistribute it and/or
7  *   modify it under the terms of the GNU Lesser General Public
8  *   License as published by the Free Software Foundation; either
9  *   version 2.1 of the License, or (at your option) any later version.
10  *
11  *   This library 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 GNU
14  *   Lesser General Public License for more details.
15  *
16  *   You should have received a copy of the GNU Lesser General Public
17  *   License along with this library; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2007 Alan DeKok <aland@deployingradius.com>
21  */
22
23 RCSID("$Id$");
24
25 #include        <freeradius-devel/libradius.h>
26 #include        <freeradius-devel/udpfromto.h>
27
28 #include        "vqp.h"
29
30 #define MAX_VMPS_LEN (MAX_STRING_LEN - 1)
31
32 /* @todo: this is a hack */
33 #  define DEBUG                 if (fr_debug_flag && fr_log_fp) fr_printf_log
34 #  define debug_pair(vp)        do { if (fr_debug_flag && fr_log_fp) { \
35                                         vp_print(fr_log_fp, vp); \
36                                      } \
37                                 } while(0)
38 /*
39  *  http://www.openbsd.org/cgi-bin/cvsweb/src/usr.sbin/tcpdump/print-vqp.c
40  *
41  *  Some of how it works:
42  *
43  *  http://www.hackingciscoexposed.com/pdf/chapter12.pdf
44  *
45  * VLAN Query Protocol (VQP)
46  *
47  *    0            1               2               3
48  *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
49  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50  *   |    Version    |    Opcode     | Response Code |  Data Count   |
51  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52  *   |                   Transaction ID                 |
53  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
54  *   |                      Type (1)                       |
55  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
56  *   |       Length         |       Data               /
57  *   /                                                         /
58  *   /                                                         /
59  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
60  *   |                      Type (n)                       |
61  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
62  *   |       Length         |       Data               /
63  *   /                                                         /
64  *   /                                                         /
65  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
66  *
67  * VQP is layered over UDP.  The default destination port is 1589.
68  *
69  */
70 #define VQP_HDR_LEN (8)
71 #define VQP_VERSION (1)
72 #define VQP_MAX_ATTRIBUTES (12)
73
74
75 /*
76  *      Wrapper for sendto which handles sendfromto, IPv6, and all
77  *      possible combinations.
78  *
79  *      FIXME:  This is just a copy of rad_sendto().
80  *      Duplicate code is bad.
81  */
82 static int vqp_sendto(int sockfd, void *data, size_t data_len, int flags,
83 #ifdef WITH_UDPFROMTO
84                       fr_ipaddr_t *src_ipaddr,
85 #else
86                       UNUSED fr_ipaddr_t *src_ipaddr,
87 #endif
88                       fr_ipaddr_t *dst_ipaddr,
89                       uint16_t dst_port)
90 {
91         struct sockaddr_storage dst;
92         socklen_t               sizeof_dst;
93
94 #ifdef WITH_UDPFROMTO
95         struct sockaddr_storage src;
96         socklen_t               sizeof_src;
97
98         if (!fr_ipaddr2sockaddr(src_ipaddr, 0, &src, &sizeof_src)) {
99                 return -1;   /* Unknown address family, Die Die Die! */
100         }
101 #endif
102
103         if (!fr_ipaddr2sockaddr(dst_ipaddr, dst_port, &dst, &sizeof_dst)) {
104                 return -1;   /* Unknown address family, Die Die Die! */
105         }
106
107 #ifdef WITH_UDPFROMTO
108         /*
109          *      Only IPv4 is supported for udpfromto.
110          *
111          *      And if they don't specify a source IP address, don't
112          *      use udpfromto.
113          */
114         if ((dst_ipaddr->af == AF_INET) &&
115             (src_ipaddr->af != AF_UNSPEC)) {
116                 return sendfromto(sockfd, data, data_len, flags,
117                                   (struct sockaddr *)&src, sizeof_src,
118                                   (struct sockaddr *)&dst, sizeof_dst);
119         }
120 #endif
121
122         /*
123          *      No udpfromto, OR an IPv6 socket, fail gracefully.
124          */
125         return sendto(sockfd, data, data_len, flags,
126                       (struct sockaddr *)&dst, sizeof_dst);
127 }
128
129 /*
130  *      Wrapper for recvfrom, which handles recvfromto, IPv6, and all
131  *      possible combinations.
132  *
133  *      FIXME:  This is copied from rad_recvfrom, with minor edits.
134  */
135 static ssize_t vqp_recvfrom(int sockfd, RADIUS_PACKET *packet, int flags,
136                             fr_ipaddr_t *src_ipaddr, uint16_t *src_port,
137                             fr_ipaddr_t *dst_ipaddr, uint16_t *dst_port)
138 {
139         struct sockaddr_storage src;
140         struct sockaddr_storage dst;
141         socklen_t               sizeof_src = sizeof(src);
142         socklen_t               sizeof_dst = sizeof(dst);
143         ssize_t                 data_len;
144         uint8_t                 header[4];
145         size_t                  len;
146         uint16_t                port;
147
148         memset(&src, 0, sizeof_src);
149         memset(&dst, 0, sizeof_dst);
150
151         /*
152          *      Get address family, etc. first, so we know if we
153          *      need to do udpfromto.
154          *
155          *      FIXME: udpfromto also does this, but it's not
156          *      a critical problem.
157          */
158         if (getsockname(sockfd, (struct sockaddr *)&dst,
159                         &sizeof_dst) < 0) return -1;
160
161         /*
162          *      Read the length of the packet, from the packet.
163          *      This lets us allocate the buffer to use for
164          *      reading the rest of the packet.
165          */
166         data_len = recvfrom(sockfd, header, sizeof(header), MSG_PEEK,
167                             (struct sockaddr *)&src, &sizeof_src);
168         if (data_len < 0) return -1;
169
170         /*
171          *      Too little data is available, discard the packet.
172          */
173         if (data_len < 4) {
174                 rad_recv_discard(sockfd);
175
176                 return 0;
177
178         /*
179          *      Invalid version, packet type, or too many
180          *      attributes.  Die.
181          */
182         } else if ((header[0] != VQP_VERSION) ||
183                    (header[1] < 1) ||
184                    (header[1] > 4) ||
185                    (header[3] > VQP_MAX_ATTRIBUTES)) {
186                 rad_recv_discard(sockfd);
187
188                 return 0;
189
190         } else {                /* we got 4 bytes of data. */
191                 /*
192                  *      We don't care about the contents for now...
193                  */
194 #if 0
195                 /*
196                  *      How many attributes are in the packet.
197                  */
198                 len = header[3];
199
200                 if ((header[1] == 1) || (header[1] == 3)) {
201                         if (len != VQP_MAX_ATTRIBUTES) {
202                                 rad_recv_discard(sockfd);
203
204                                 return 0;
205                         }
206                         /*
207                          *      Maximum length we support.
208                          */
209                         len = (12 * (4 + 4 + MAX_VMPS_LEN));
210
211                 } else {
212                         if (len != 2) {
213                                 rad_recv_discard(sockfd);
214
215                                 return 0;
216                         }
217                         /*
218                          *      Maximum length we support.
219                          */
220                         len = (12 * (4 + 4 + MAX_VMPS_LEN));
221                 }
222 #endif
223         }
224
225         /*
226          *      For now, be generous.
227          */
228         len = (12 * (4 + 4 + MAX_VMPS_LEN));
229
230         packet->data = talloc_array(packet, uint8_t, len);
231         if (!packet->data) return -1;
232
233         /*
234          *      Receive the packet.  The OS will discard any data in the
235          *      packet after "len" bytes.
236          */
237 #ifdef WITH_UDPFROMTO
238         if (dst.ss_family == AF_INET) {
239                 data_len = recvfromto(sockfd, packet->data, len, flags,
240                                       (struct sockaddr *)&src, &sizeof_src,
241                                       (struct sockaddr *)&dst, &sizeof_dst);
242         } else
243 #endif
244                 /*
245                  *      No udpfromto, OR an IPv6 socket.  Fail gracefully.
246                  */
247                 data_len = recvfrom(sockfd, packet->data, len, flags,
248                                     (struct sockaddr *)&src, &sizeof_src);
249         if (data_len < 0) {
250                 return data_len;
251         }
252
253         if (!fr_sockaddr2ipaddr(&src, sizeof_src, src_ipaddr, &port)) {
254                 return -1;      /* Unknown address family, Die Die Die! */
255         }
256         *src_port = port;
257
258         fr_sockaddr2ipaddr(&dst, sizeof_dst, dst_ipaddr, &port);
259         *dst_port = port;
260
261         /*
262          *      Different address families should never happen.
263          */
264         if (src.ss_family != dst.ss_family) {
265                 return -1;
266         }
267
268         return data_len;
269 }
270
271 RADIUS_PACKET *vqp_recv(int sockfd)
272 {
273         uint8_t *ptr;
274         ssize_t length;
275         uint32_t id;
276         RADIUS_PACKET *packet;
277
278         /*
279          *      Allocate the new request data structure
280          */
281         packet = rad_alloc(NULL, false);
282         if (!packet) {
283                 fr_strerror_printf("out of memory");
284                 return NULL;
285         }
286
287         length = vqp_recvfrom(sockfd, packet, 0,
288                               &packet->src_ipaddr, &packet->src_port,
289                               &packet->dst_ipaddr, &packet->dst_port);
290
291         /*
292          *      Check for socket errors.
293          */
294         if (length < 0) {
295                 fr_strerror_printf("Error receiving packet: %s", fr_syserror(errno));
296                 /* packet->data is NULL */
297                 rad_free(&packet);
298                 return NULL;
299         }
300         packet->data_len = length; /* unsigned vs signed */
301
302         /*
303          *      We can only receive packets formatted in a way we
304          *      expect.  However, we accept MORE attributes in a
305          *      packet than normal implementations may send.
306          */
307         if (packet->data_len < VQP_HDR_LEN) {
308                 fr_strerror_printf("VQP packet is too short");
309                 rad_free(&packet);
310                 return NULL;
311         }
312
313         ptr = packet->data;
314
315         if (0) {
316                 size_t i;
317                 for (i = 0; i < packet->data_len; i++) {
318                   if ((i & 0x0f) == 0) fprintf(stderr, "%02x: ", (int) i);
319                         fprintf(stderr, "%02x ", ptr[i]);
320                         if ((i & 0x0f) == 0x0f) fprintf(stderr, "\n");
321                 }
322
323         }
324
325         if (ptr[3] > VQP_MAX_ATTRIBUTES) {
326                 fr_strerror_printf("Too many VQP attributes");
327                 rad_free(&packet);
328                 return NULL;
329         }
330
331         if (packet->data_len > VQP_HDR_LEN) {
332                 int attrlen;
333
334                 /*
335                  *      Skip the header.
336                  */
337                 ptr += VQP_HDR_LEN;
338                 length = packet->data_len - VQP_HDR_LEN;
339
340                 while (length > 0) {
341                         if (length < 7) {
342                                 fr_strerror_printf("Packet contains malformed attribute");
343                                 rad_free(&packet);
344                                 return NULL;
345                         }
346
347                         /*
348                          *      Attributes are 4 bytes
349                          *      0x00000c01 ... 0x00000c08
350                          */
351                         if ((ptr[0] != 0) || (ptr[1] != 0) ||
352                             (ptr[2] != 0x0c) || (ptr[3] < 1) || (ptr[3] > 8)) {
353                                 fr_strerror_printf("Packet contains invalid attribute");
354                                 rad_free(&packet);
355                                 return NULL;
356                         }
357
358                         /*
359                          *      Length is 2 bytes
360                          *
361                          *      We support lengths 1..253, for internal
362                          *      server reasons.  Also, there's no reason
363                          *      for bigger lengths to exist... admins
364                          *      won't be typing in a 32K vlan name.
365                          *
366                          *      Except for received ethernet frames...
367                          *      they get chopped to 253 internally.
368                          */
369                         if ((ptr[3] != 5) &&
370                             ((ptr[4] != 0) || (ptr[5] > MAX_VMPS_LEN))) {
371                                 fr_strerror_printf("Packet contains attribute with invalid length %02x %02x", ptr[4], ptr[5]);
372                                 rad_free(&packet);
373                                 return NULL;
374                         }
375                         attrlen = (ptr[4] << 8) | ptr[5];
376                         ptr += 6 + attrlen;
377                         length -= (6 + attrlen);
378                 }
379         }
380
381         packet->sockfd = sockfd;
382         packet->vps = NULL;
383
384         /*
385          *      This is more than a bit of a hack.
386          */
387         packet->code = PW_CODE_ACCESS_REQUEST;
388
389         memcpy(&id, packet->data + 4, 4);
390         packet->id = ntohl(id);
391
392         /*
393          *      FIXME: Create a fake "request authenticator", to
394          *      avoid duplicates?  Or is the VQP sequence number
395          *      adequate for this purpose?
396          */
397
398         return packet;
399 }
400
401 /*
402  *      We do NOT  mirror the old-style RADIUS code  that does encode,
403  *      sign && send in one function.  For VQP, the caller MUST perform
404  *      each task manually, and separately.
405  */
406 int vqp_send(RADIUS_PACKET *packet)
407 {
408         if (!packet || !packet->data || (packet->data_len < 8)) return -1;
409
410         /*
411          *      Don't print out the attributes, they were printed out
412          *      when it was encoded.
413          */
414
415         /*
416          *      And send it on it's way.
417          */
418         return vqp_sendto(packet->sockfd, packet->data, packet->data_len, 0,
419                           &packet->src_ipaddr, &packet->dst_ipaddr,
420                           packet->dst_port);
421 }
422
423
424 int vqp_decode(RADIUS_PACKET *packet)
425 {
426         uint8_t *ptr, *end;
427         int attribute, length;
428         vp_cursor_t cursor;
429         VALUE_PAIR *vp;
430
431         if (!packet || !packet->data) return -1;
432
433         if (packet->data_len < VQP_HDR_LEN) return -1;
434
435         fr_cursor_init(&cursor, &packet->vps);
436         vp = paircreate(packet, PW_VQP_PACKET_TYPE, 0);
437         if (!vp) {
438                 fr_strerror_printf("No memory");
439                 return -1;
440         }
441         vp->vp_integer = packet->data[1];
442         debug_pair(vp);
443         fr_cursor_insert(&cursor, vp);
444
445         vp = paircreate(packet, PW_VQP_ERROR_CODE, 0);
446         if (!vp) {
447                 fr_strerror_printf("No memory");
448                 return -1;
449         }
450         vp->vp_integer = packet->data[2];
451         debug_pair(vp);
452         fr_cursor_insert(&cursor, vp);
453
454         vp = paircreate(packet, PW_VQP_SEQUENCE_NUMBER, 0);
455         if (!vp) {
456                 fr_strerror_printf("No memory");
457                 return -1;
458         }
459         vp->vp_integer = packet->id; /* already set by vqp_recv */
460         debug_pair(vp);
461         fr_cursor_insert(&cursor, vp);
462
463         ptr = packet->data + VQP_HDR_LEN;
464         end = packet->data + packet->data_len;
465
466         /*
467          *      Note that vqp_recv() MUST ensure that the packet is
468          *      formatted in a way we expect, and that vqp_recv() MUST
469          *      be called before vqp_decode().
470          */
471         while (ptr < end) {
472                 char *p;
473
474                 attribute = (ptr[2] << 8) | ptr[3];
475                 length = (ptr[4] << 8) | ptr[5];
476                 ptr += 6;
477
478                 /*
479                  *      Hack to get the dictionaries to work correctly.
480                  */
481                 attribute |= 0x2000;
482                 vp = paircreate(packet, attribute, 0);
483                 if (!vp) {
484                         pairfree(&packet->vps);
485
486                         fr_strerror_printf("No memory");
487                         return -1;
488                 }
489
490                 switch (vp->da->type) {
491                 case PW_TYPE_IPV4_ADDR:
492                         if (length == 4) {
493                                 memcpy(&vp->vp_ipaddr, ptr, 4);
494                                 vp->length = 4;
495                                 break;
496                         }
497
498                         /*
499                          *      Value doesn't match the type we have for the
500                          *      valuepair so we must change it's da to an
501                          *      unknown attr.
502                          */
503                         vp->da = dict_attrunknown(vp->da->attr, vp->da->vendor,
504                                                   true);
505                         /* FALL-THROUGH */
506
507                 default:
508                 case PW_TYPE_OCTETS:
509                         if (length < 1024) {
510                                 pairmemcpy(vp, ptr, length);
511                         } else {
512                                 pairmemcpy(vp, ptr, 1024);
513                         }
514                         break;
515
516                 case PW_TYPE_STRING:
517                         if (length < 1024) {
518                                 vp->length = length;
519                                 vp->vp_strvalue = p = talloc_array(vp, char, vp->length + 1);
520                                 vp->type = VT_DATA;
521                                 memcpy(p, ptr, vp->length);
522                                 p[vp->length] = '\0';
523                         } else {
524                                 vp->length = 1024;
525                                 vp->vp_strvalue = p = talloc_array(vp, char, 1025);
526                                 vp->type = VT_DATA;
527                                 memcpy(p, ptr, vp->length);
528                                 p[vp->length] = '\0';
529                         }
530                         break;
531                 }
532                 ptr += length;
533                 debug_pair(vp);
534                 fr_cursor_insert(&cursor, vp);
535         }
536
537         /*
538          *      FIXME: Map attributes to Calling-Station-Id, etc...
539          */
540
541         return 0;
542 }
543
544 /*
545  *      These are the MUST HAVE contents for a VQP packet.
546  *
547  *      We don't allow the caller to give less than these, because
548  *      it won't work.  We don't encode more than these, because the
549  *      clients will ignore it.
550  *
551  *      FIXME: Be more generous?  Look for CISCO + VQP attributes?
552  */
553 static int contents[5][VQP_MAX_ATTRIBUTES] = {
554         { 0,      0,      0,      0,      0,      0 },
555         { 0x0c01, 0x0c02, 0x0c03, 0x0c04, 0x0c07, 0x0c05 }, /* Join request */
556         { 0x0c03, 0x0c08, 0,      0,      0,      0 },  /* Join Response */
557         { 0x0c01, 0x0c02, 0x0c03, 0x0c04, 0x0c07, 0x0c08 }, /* Reconfirm */
558         { 0x0c03, 0x0c08, 0,      0,      0,      0 }
559 };
560
561 int vqp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
562 {
563         int i, code, length;
564         VALUE_PAIR *vp;
565         uint8_t *ptr;
566         VALUE_PAIR      *vps[VQP_MAX_ATTRIBUTES];
567
568         if (!packet) {
569                 fr_strerror_printf("Failed encoding VQP");
570                 return -1;
571         }
572
573         if (packet->data) return 0;
574
575         vp = pairfind(packet->vps, PW_VQP_PACKET_TYPE, 0, TAG_ANY);
576         if (!vp) {
577                 fr_strerror_printf("Failed to find VQP-Packet-Type in response packet");
578                 return -1;
579         }
580
581         code = vp->vp_integer;
582         if ((code < 1) || (code > 4)) {
583                 fr_strerror_printf("Invalid value %d for VQP-Packet-Type", code);
584                 return -1;
585         }
586
587         length = VQP_HDR_LEN;
588         memset(vps, 0, sizeof(vps));
589
590         vp = pairfind(packet->vps, PW_VQP_ERROR_CODE, 0, TAG_ANY);
591
592         /*
593          *      FIXME: Map attributes from calling-station-Id, etc.
594          *
595          *      Maybe do this via rlm_vqp?  That's probably the
596          *      best place to add the code...
597          */
598
599         /*
600          *      No error: encode attributes.
601          */
602         if (!vp) for (i = 0; i < VQP_MAX_ATTRIBUTES; i++) {
603                 if (!contents[code][i]) break;
604
605                 vps[i] = pairfind(packet->vps, contents[code][i] | 0x2000, 0, TAG_ANY);
606
607                 /*
608                  *      FIXME: Print the name...
609                  */
610                 if (!vps[i]) {
611                         fr_strerror_printf("Failed to find VQP attribute %02x",
612                                    contents[code][i]);
613                         return -1;
614                 }
615
616                 length += 6;
617                 length += vps[i]->length;
618         }
619
620         packet->data = talloc_array(packet, uint8_t, length);
621         if (!packet->data) {
622                 fr_strerror_printf("No memory");
623                 return -1;
624         }
625         packet->data_len = length;
626
627         ptr = packet->data;
628
629         ptr[0] = VQP_VERSION;
630         ptr[1] = code;
631
632         if (!vp) {
633                 ptr[2] = 0;
634         } else {
635                 ptr[2] = vp->vp_integer & 0xff;
636                 return 0;
637         }
638
639         /*
640          *      The number of attributes is hard-coded.
641          */
642         if ((code == 1) || (code == 3)) {
643                 uint32_t sequence;
644
645                 ptr[3] = VQP_MAX_ATTRIBUTES;
646
647                 sequence = htonl(packet->id);
648                 memcpy(ptr + 4, &sequence, 4);
649         } else {
650                 if (!original) {
651                         fr_strerror_printf("Cannot send VQP response without request");
652                         return -1;
653                 }
654
655                 /*
656                  *      Packet Sequence Number
657                  */
658                 memcpy(ptr + 4, original->data + 4, 4);
659
660                 ptr[3] = 2;
661         }
662
663         ptr += 8;
664
665         /*
666          *      Encode the VP's.
667          */
668         for (i = 0; i < VQP_MAX_ATTRIBUTES; i++) {
669                 if (!vps[i]) break;
670                 if (ptr >= (packet->data + packet->data_len)) break;
671
672                 vp = vps[i];
673
674                 debug_pair(vp);
675
676                 /*
677                  *      Type.  Note that we look at only the lower 8
678                  *      bits, as the upper 8 bits have been hacked.
679                  *      See also dictionary.vqp
680                  */
681                 ptr[0] = 0;
682                 ptr[1] = 0;
683                 ptr[2] = 0x0c;
684                 ptr[3] = vp->da->attr & 0xff;
685
686                 /* Length */
687                 ptr[4] = 0;
688                 ptr[5] = vp->length & 0xff;
689
690                 ptr += 6;
691
692                 /* Data */
693                 switch (vp->da->type) {
694                 case PW_TYPE_IPV4_ADDR:
695                         memcpy(ptr, &vp->vp_ipaddr, 4);
696                         break;
697
698                 default:
699                 case PW_TYPE_OCTETS:
700                 case PW_TYPE_STRING:
701                         memcpy(ptr, vp->vp_octets, vp->length);
702                         break;
703                 }
704                 ptr += vp->length;
705         }
706
707         return 0;
708 }