511655d8a09d1224384977d13b1b7206a4a0717e
[freeradius.git] / src / lib / radius.c
1 /*
2  * radius.c     Functions to send/receive radius packets.
3  *
4  * Version:     $Id$
5  *
6  */
7
8 static const char rcsid[] = "$Id$";
9
10 #include        "autoconf.h"
11
12 #include        <stdlib.h>
13 #include        <unistd.h>
14 #include        <fcntl.h>
15 #include        <string.h>
16 #include        <ctype.h>
17
18 #include        "libradius.h"
19
20 #if HAVE_NETINET_IN_H
21 #include        <netinet/in.h>
22 #endif
23
24 #include        <sys/socket.h>
25
26 #if HAVE_ARPA_INET_H
27 #include        <arpa/inet.h>
28 #endif
29
30 #if HAVE_MALLOC_H
31 #include        <malloc.h>
32 #endif
33
34 #ifdef WIN32
35 #include        <process.h>
36 #endif
37
38 /*
39  *  The RFC says 4096 octets max, and most packets are less than 256.
40  *  However, this number is just larger than the maximum MTU of just
41  *  most types of networks, except maybe for gigabit ethernet.
42  */
43 #define PACKET_DATA_LEN 1600
44
45 typedef struct radius_packet_t {
46   uint8_t       code;
47   uint8_t       id;
48   uint8_t       length[2];
49   uint8_t       vector[16];
50   uint8_t       data[1];
51 } radius_packet_t;
52
53 static uint8_t random_vector_pool[AUTH_VECTOR_LEN*2];
54
55 static const char *packet_codes[] = {
56   "",
57   "Access-Request",
58   "Access-Accept",
59   "Access-Reject",
60   "Accounting-Request",
61   "Accounting-Response",
62   "Accounting-Status",
63   "Password-Request",
64   "Password-Accept",
65   "Password-Reject",
66   "Accounting-Message",
67   "Access-Challenge",
68   "Status-Server",
69   "Status-Client"
70 };
71
72 /*
73  *      Reply to the request.  Also attach
74  *      reply attribute value pairs and any user message provided.
75  */
76 int rad_send(RADIUS_PACKET *packet, const char *secret)
77 {
78         VALUE_PAIR              *reply;
79         struct  sockaddr        saremote;
80         struct  sockaddr_in     *sa;
81         const char              *what;
82         uint8_t                 ip_buffer[16];
83
84         reply = packet->vps;
85         
86         if ((packet->code > 0) && (packet->code < 14)) {
87           what = packet_codes[packet->code];
88         } else {
89           what = "Reply";
90         }
91
92         /*
93          *  First time through, allocate room for the packet
94          */
95         if (!packet->data) {
96                   radius_packet_t       *hdr;
97                   int32_t               lvalue;
98                   uint8_t               *ptr, *length_ptr;
99                   uint8_t               digest[16];
100                   int                   secretlen;
101                   int                   vendorcode, vendorpec;
102                   u_short               total_length, tmp;
103                   int                   len;
104                   
105                   hdr = (radius_packet_t *) malloc(PACKET_DATA_LEN);
106                   if (!hdr) {
107                     librad_log("Out of memory");
108                     return -1;
109                   }
110                   packet->data = (uint8_t *) hdr;
111                   
112                   /*
113                    *    Build standard header
114                    */
115                   hdr->code = packet->code;
116                   hdr->id = packet->id;
117                   if (packet->code == PW_ACCOUNTING_REQUEST)
118                     memset(hdr->vector, 0, AUTH_VECTOR_LEN);
119                   else
120                     memcpy(hdr->vector, packet->vector, AUTH_VECTOR_LEN);
121                   
122                   DEBUG("Sending %s of id %d to %s:%d\n",
123                         what, packet->id,
124                         ip_ntoa((char *)ip_buffer, packet->dst_ipaddr),
125                         packet->dst_port);
126                   
127                   total_length = AUTH_HDR_LEN;
128                   
129                   /*
130                    *    Load up the configuration values for the user
131                    */
132                   ptr = hdr->data;
133                   while (reply != NULL) {
134                     /*
135                      *  This could be a vendor-specific attribute.
136                      */
137                     length_ptr = NULL;
138                     if ((vendorcode = VENDOR(reply->attribute)) > 0 &&
139                         (vendorpec  = dict_vendorpec(vendorcode)) > 0) {
140                       *ptr++ = PW_VENDOR_SPECIFIC;
141                       length_ptr = ptr;
142                       *ptr++ = 6;
143                       lvalue = htonl(vendorpec);
144                       memcpy(ptr, &lvalue, 4);
145                       ptr += 4;
146                       total_length += 6;
147                     } else if (reply->attribute > 0xff) {
148                       /*
149                        *        Ignore attributes > 0xff
150                        */
151
152                       if (librad_debug) {
153                         printf("\t  ");
154                         vp_print(stdout, reply);
155                         printf("\n");
156                       }
157                       reply = reply->next;
158                       continue;
159                     } else
160                       vendorpec = 0;
161                     
162 #ifdef ATTRIB_NMC
163                     if (vendorpec == VENDORPEC_USR) {
164                       lvalue = htonl(reply->attribute & 0xFFFF);
165                       memcpy(ptr, &lvalue, 4);
166                       total_length += 2;
167                       *length_ptr  += 2;
168                       ptr          += 4;
169                     } else
170 #endif
171                       *ptr++ = (reply->attribute & 0xFF);
172                     
173                     switch(reply->type) {
174                       
175                     case PW_TYPE_STRING:
176                       /*
177                        *        If it's a password, encode it.
178                        */
179                       if (!vendorpec) {
180                         if (reply->attribute == PW_PASSWORD) {
181                           rad_pwencode((char *)reply->strvalue,
182                                        &(reply->length),
183                                        secret, (char *)packet->vector);
184
185                           /*
186                            *    If there's a CHAP password, assume it's
187                            *    currently in clear text, and encode it
188                            *    in place.
189                            *
190                            *    The ID is taken from pseudo-random
191                            *    numbers somehow...
192                            */
193                         } else if (reply->attribute == PW_CHAP_PASSWORD) {
194                           rad_chap_encode(packet, (char *)reply->strvalue,
195                                           packet->id, reply);
196                           reply->length = 1 + CHAP_VALUE_LENGTH;
197                         } 
198                       }
199                       
200 #ifndef ASCEND_BINARY
201                     case PW_TYPE_ABINARY:
202 #endif
203                     case PW_TYPE_OCTETS:
204                       len = reply->length;
205                       
206                       if (len >= MAX_STRING_LEN) {
207                         len = MAX_STRING_LEN - 1;
208                       }
209 #ifdef ATTRIB_NMC
210                       if (vendorpec != VENDORPEC_USR)
211 #endif
212                         *ptr++ = len + 2;
213                       if (length_ptr) *length_ptr += len + 2;
214                       memcpy(ptr, reply->strvalue,len);
215                       ptr += len;
216                       total_length += len + 2;
217                       break;
218                       
219                     case PW_TYPE_INTEGER:
220                     case PW_TYPE_IPADDR:
221 #ifdef ATTRIB_NMC
222                       if (vendorpec != VENDORPEC_USR)
223 #endif
224                         *ptr++ = sizeof(uint32_t) + 2;
225                       if (length_ptr) *length_ptr += sizeof(uint32_t)+ 2;
226                       if (reply->type != PW_TYPE_IPADDR)
227                         lvalue = htonl(reply->lvalue);
228                       else
229                         lvalue = reply->lvalue;
230                       memcpy(ptr, &lvalue, sizeof(uint32_t));
231                       ptr += sizeof(uint32_t);
232                       total_length += sizeof(uint32_t) + 2;
233                       break;
234 #ifdef ASCEND_BINARY
235                     case PW_TYPE_ABINARY:
236                       len = reply->length;
237                       if (len >= MAX_STRING_LEN) {
238                         len = MAX_STRING_LEN - 1;
239                       }
240 #ifdef ATTRIB_NMC
241                       if (vendorpec != VENDORPEC_USR)
242 #endif
243                         *ptr++ = len + 2;
244                       if (length_ptr) *length_ptr += len + 2;
245                       memcpy(ptr, reply->strvalue,len);
246                       ptr += len;
247                       total_length += len + 2;
248                       break;
249 #endif
250
251                     default:
252                       break;
253                     }
254                     
255                     /*
256                      *  Print out ONLY the attributes which we're
257                      *  sending over the wire.  Also, pick up any hacked
258                      *  password attributes.
259                      */
260                     debug_pair(reply);
261                     reply = reply->next;
262                   }
263                   
264                   tmp = htons(total_length);
265                   memcpy(hdr->length, &tmp, sizeof(u_short));
266                   packet->data_len = total_length;
267
268                   /*
269                    *    If this is not an authentication request, we
270                    *    need to calculate the md5 hash over the entire packet
271                    *    and put it in the vector.
272                    */
273                   if (packet->code != PW_AUTHENTICATION_REQUEST) {
274                         secretlen = strlen(secret);
275                         memcpy((char *)hdr + total_length, secret, secretlen);
276                         librad_md5_calc(digest, (unsigned char *)hdr,
277                                         total_length + secretlen);
278                         memcpy(hdr->vector, digest, AUTH_VECTOR_LEN);
279                         memset((char *)hdr + total_length, 0, secretlen);
280                   }
281
282                   /*
283                    *    If packet->data points to data, then we print out
284                    *    the VP list again only for debugging.
285                    */
286         } else if (librad_debug) {
287                 DEBUG("Sending %s of id %d to %s\n", what, packet->id,
288                       ip_ntoa((char *)ip_buffer, packet->dst_ipaddr));
289                 while (reply) {
290                   /* FIXME: ignore attributes > 0xff */
291                   debug_pair(reply);
292                   reply = reply->next;
293                 }
294         }
295
296         /*
297          *      And send it on it's way.
298          */
299         sa = (struct sockaddr_in *) &saremote;
300         memset ((char *) sa, '\0', sizeof (saremote));
301         sa->sin_family = AF_INET;
302         sa->sin_addr.s_addr = packet->dst_ipaddr;
303         sa->sin_port = htons(packet->dst_port);
304
305         return sendto(packet->sockfd, packet->data, (int)packet->data_len, 0,
306                       &saremote, sizeof(struct sockaddr_in));
307 }
308
309
310 /*
311  *      Validates the requesting client NAS.  Calculates the
312  *      signature based on the clients private key.
313  */
314 int calc_acctdigest(RADIUS_PACKET *packet, const char *secret, char *recvbuf, int len)
315 {
316         int             secretlen;
317         u_char          digest[AUTH_VECTOR_LEN];
318
319         /*
320          *      Older clients have the authentication vector set to
321          *      all zeros. Return `1' in that case.
322          */
323         memset(digest, 0, sizeof(digest));
324         if (memcmp(packet->vector, digest, AUTH_VECTOR_LEN) == 0) {
325                 packet->verified = 1;
326                 return 1;
327         }
328
329         /*
330          *      Zero out the auth_vector in the received packet.
331          *      Then append the shared secret to the received packet,
332          *      and calculate the MD5 sum. This must be the same
333          *      as the original MD5 sum (packet->vector).
334          */
335         secretlen = strlen(secret);
336         memset(recvbuf + 4, 0, AUTH_VECTOR_LEN);
337         memcpy(recvbuf + len, secret, secretlen);
338         librad_md5_calc(digest, (u_char *)recvbuf, len + secretlen);
339
340         /*
341          *      Return 0 if OK, 2 if not OK.
342          */
343         packet->verified =
344         memcmp(digest, packet->vector, AUTH_VECTOR_LEN) ? 2 : 0;
345
346         return packet->verified;
347 }
348
349 /*
350  *      Validates the requesting client NAS.  Calculates the
351  *      signature based on the clients private key.
352  */
353 static int calc_replydigest(RADIUS_PACKET *packet, RADIUS_PACKET *original, const char *secret, char *recvbuf, int len)
354 {
355         int             secretlen;
356         uint8_t         calc_digest[AUTH_VECTOR_LEN];
357
358         memcpy(recvbuf + 4, original->vector, sizeof(original->vector));
359         secretlen = strlen(secret);
360         memcpy(recvbuf + len, secret, secretlen);
361         librad_md5_calc(calc_digest, (u_char *)recvbuf, len + secretlen);
362
363         /*
364          *      Return 0 if OK, 2 if not OK.
365          */
366         packet->verified =
367                 memcmp(packet->vector, calc_digest, sizeof(packet->vector)) ? 2 : 0;
368         return packet->verified;
369 }
370
371 /*
372  *      Receive UDP client requests, and fill in
373  *      the basics of a RADIUS_PACKET structure.
374  */
375 RADIUS_PACKET *rad_recv(int fd)
376 {
377         RADIUS_PACKET           *packet;
378         struct sockaddr_in      saremote;
379         int                     totallen;
380         socklen_t               salen;
381         u_short                 len;
382         uint8_t                 *attr;
383         int                     count;
384         radius_packet_t         *hdr;
385         char                    host_ipaddr[16];
386
387         /*
388          *      Allocate the new request data structure
389          */
390         if ((packet = malloc(sizeof(RADIUS_PACKET))) == NULL) {
391                 librad_log("out of memory");
392                 errno = ENOMEM;
393                 return NULL;
394         }
395         memset(packet, 0, sizeof(RADIUS_PACKET));
396         if ((packet->data = malloc(PACKET_DATA_LEN)) == NULL) {
397                 free(packet);
398                 librad_log("out of memory");
399                 errno = ENOMEM;
400                 return NULL;
401         }
402
403         /*
404          *      Receive the packet.
405          */
406         salen = sizeof(saremote);
407         memset(&saremote, 0, sizeof(saremote));
408         packet->data_len = recvfrom(fd, packet->data, PACKET_DATA_LEN,
409                 0, (struct sockaddr *)&saremote, &salen);
410
411         /*
412          *      Fill IP header fields
413          */
414         packet->sockfd = fd;
415         packet->src_ipaddr = saremote.sin_addr.s_addr;
416         packet->src_port = ntohs(saremote.sin_port);
417
418         /*
419          *      Explicitely set the VP list to empty.
420          */
421         packet->vps = NULL;
422
423         /*
424          *      Check for socket errors.
425          */
426         if (packet->data_len < 0) {
427                 librad_log("Error receiving packet from host %s: %s",
428                            ip_ntoa(host_ipaddr, packet->src_ipaddr),
429                            strerror(errno));
430                 free(packet->data);
431                 free(packet);
432                 return NULL;
433         }
434
435         /*
436          *      Check for packets smaller than the packet header.
437          */
438         if (packet->data_len < AUTH_HDR_LEN) {
439                 librad_log("Malformed RADIUS packet from host %s: too short",
440                            ip_ntoa(host_ipaddr, packet->src_ipaddr));
441                 free(packet->data);
442                 free(packet);
443                 return NULL;
444         }
445
446         /*
447          *      Check for packets with mismatched size.
448          *      i.e. We've received 128 bytes, and the packet header
449          *      says it's 256 bytes long.
450          */
451         hdr = (radius_packet_t *)packet->data;
452         memcpy(&len, hdr->length, sizeof(u_short));
453         totallen = ntohs(len);
454         if (packet->data_len != totallen) {
455                 librad_log("Malformed RADIUS packet from host %s: received %d octets, packet size says %d",
456                            ip_ntoa(host_ipaddr, packet->src_ipaddr),
457                            packet->data_len, totallen);
458                 free(packet->data);
459                 free(packet);
460                 return NULL;
461         }
462
463         /*
464          *      Walk through the packet's attributes, ensuring that
465          *      they add up EXACTLY to the size of the packet.
466          *
467          *      If they don't, then the attributes either under-fill
468          *      or over-fill the packet.  Any parsing of the packet
469          *      is impossible, and will result in unknown side effects.
470          *
471          *      This would ONLY happen with buggy RADIUS implementations,
472          *      or with an intentional attack.  Either way, we do NOT want
473          *      to be vulnerable to this problem.
474          */
475         attr = hdr->data;
476         count = totallen - AUTH_HDR_LEN;
477         while (count > 0) {
478                 /*
479                  *      Attribute number zero is NOT defined.
480                  */
481                 if (attr[0] == 0) {
482                         librad_log("Malformed RADIUS packet from host %s: Invalid attribute 0",
483                                    ip_ntoa(host_ipaddr, packet->src_ipaddr));
484                         free(packet->data);
485                         free(packet);
486                         return NULL;
487                 }
488                 
489                 /*
490                  *      Attributes are at LEAST as long as the ID & length
491                  *      fields.  Anything shorter is an invalid attribute.
492                  */
493                 if (attr[1] < 2) {
494                         librad_log("Malformed RADIUS packet from host %s: attribute %d too short",
495                                    ip_ntoa(host_ipaddr, packet->src_ipaddr),
496                                    attr[0]);
497                         free(packet->data);
498                         free(packet);
499                         return NULL;
500                 }
501                 count -= attr[1];       /* grab the attribute length */
502                 attr += attr[1];
503         }
504
505         /*
506          *      If the attributes add up to a packet, it's allowed.
507          *
508          *      If not, we complain, and throw the packet away.
509          */
510         if (count != 0) {
511                 librad_log("Malformed RADIUS packet from host %s: packet attributes do NOT exactly fill the packet",
512                            ip_ntoa(host_ipaddr, packet->src_ipaddr));
513                 free(packet->data);
514                 free(packet);
515                 return NULL;
516         }
517
518         if (librad_debug) {
519           if ((hdr->code > 0) && (hdr->code < 14)) {
520             printf("rad_recv: %s packet from host %s:%d",
521                    packet_codes[hdr->code],
522                    ip_ntoa(host_ipaddr, packet->src_ipaddr), packet->src_port);
523           } else {
524             printf("rad_recv: Packet from host %s:%d code=%d",  
525                    ip_ntoa(host_ipaddr, packet->src_ipaddr), packet->src_port,
526                    hdr->code);
527           }
528           printf(", id=%d, length=%d\n", hdr->id, totallen);
529         }
530
531         /*
532          *      Fill RADIUS header fields
533          */
534         packet->code = hdr->code;
535         packet->id = hdr->id;
536         memcpy(packet->vector, hdr->vector, AUTH_VECTOR_LEN);
537
538         return packet;
539 }
540
541 /*
542  *      Calculate/check digest, and decode radius attributes.
543  */
544 int rad_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original, const char *secret)
545 {
546         DICT_ATTR               *attr;
547         uint32_t                lvalue;
548         uint32_t                vendorcode;
549         uint32_t                vendorpec;
550         VALUE_PAIR              *first_pair;
551         VALUE_PAIR              *prev;
552         VALUE_PAIR              *pair;
553         uint8_t                 *ptr;
554         int                     length;
555         int                     attribute;
556         int                     attrlen;
557         int                     vendorlen;
558         radius_packet_t         *hdr;
559
560         hdr = (radius_packet_t *)packet->data;
561         length = packet->data_len;
562
563         /*
564          *      Calculate and/or verify digest.
565          */
566         switch(packet->code) {
567                 case PW_AUTHENTICATION_REQUEST:
568                         break;
569                 case PW_ACCOUNTING_REQUEST:
570                         if (calc_acctdigest(packet, secret,
571                             (char *)packet->data, length) > 1) {
572                                 char buffer[32];
573                                 librad_log("Received accounting packet "
574                                     "from %s with invalid signature!",
575                                     ip_ntoa(buffer, packet->src_ipaddr));
576                                 return 1;
577                         }
578                         break;
579
580                         /* Verify the reply digest */
581                 case PW_AUTHENTICATION_ACK:
582                 case PW_AUTHENTICATION_REJECT:
583                         if (calc_replydigest(packet, original, secret,
584                                              (char *)packet->data,
585                                              length) > 1) {
586                                 char buffer[32];
587                                 librad_log("Received authentication reply packet "
588                                            "from %s with invalid signature!",
589                                            ip_ntoa(buffer, packet->src_ipaddr));
590                                 return 1;
591                         }
592                   break;
593
594                 case PW_ACCOUNTING_RESPONSE:
595                         break;  /* ??? */
596         }
597
598         /*
599          *      Extract attribute-value pairs
600          */
601         ptr = hdr->data;
602         length -= AUTH_HDR_LEN;
603         first_pair = NULL;
604         prev = NULL;
605
606         vendorcode = 0;
607         vendorlen  = 0;
608
609         while(length > 0) {
610
611                 if (vendorlen > 0) {
612                         attribute = *ptr++ | (vendorcode << 16);
613                         attrlen   = *ptr++;
614                 } else {
615                         attribute = *ptr++;
616                         attrlen   = *ptr++;
617                 }
618                 if (attrlen < 2) { /* rad_recv() now handles this check */
619                         length = 0;
620                         continue;
621                 }
622                 attrlen -= 2;
623                 length  -= 2;
624
625                 /*
626                  *      This could be a Vendor-Specific attribute.
627                  *
628                  */
629                 if (vendorlen <= 0 &&
630                     attribute == PW_VENDOR_SPECIFIC && attrlen > 6) {
631                         memcpy(&lvalue, ptr, 4);
632                         vendorpec = ntohl(lvalue);
633                         if ((vendorcode = dict_vendorcode(vendorpec))
634                             != 0) {
635 #ifdef ATTRIB_NMC
636                                 if (vendorpec == VENDORPEC_USR) {
637                                         ptr += 4;
638                                         memcpy(&lvalue, ptr, 4);
639                                         /*printf("received USR %04x\n", ntohl(lvalue));*/
640                                         attribute = (ntohl(lvalue) & 0xFFFF) |
641                                                         (vendorcode << 16);
642                                         ptr += 4;
643                                         attrlen -= 8;
644                                         length -= 8;
645                                 } else
646 #endif
647                                 {
648                                         ptr += 4;
649                                         vendorlen = attrlen - 4;
650                                         attribute = *ptr++ | (vendorcode << 16);
651                                         attrlen   = *ptr++;
652                                         attrlen -= 2;
653                                         length -= 6;
654                                 }
655                         }
656                 }
657
658                 if ( attrlen >= MAX_STRING_LEN ) {
659                         DEBUG("attribute %d too long, %d >= %d\n", attribute,
660                                 attrlen, MAX_STRING_LEN);
661                 }
662                 /* rad_recv() now handles this check */
663                 else if ( attrlen > length ) {
664                         DEBUG("attribute %d longer than buffer left, %d > %d\n",
665                                 attribute, attrlen, length);
666                 }
667                 else {
668                         /*
669                          *      FIXME: should we us paircreate() ?
670                          */
671                         if ((pair = malloc(sizeof(VALUE_PAIR))) == NULL) {
672                                 pairfree(first_pair);
673                                 librad_log("out of memory");
674                                 errno = ENOMEM;
675                                 return -1;
676                         }
677
678                         memset(pair, 0, sizeof(VALUE_PAIR));
679                         if ((attr = dict_attrbyvalue(attribute)) == NULL) {
680                                 sprintf(pair->name, "Attr-%d", attribute);
681                                 pair->type = PW_TYPE_STRING;
682                         } else {
683                                 strcpy(pair->name, attr->name);
684                                 pair->type = attr->type;
685                         }
686                         pair->attribute = attribute;
687                         pair->length = attrlen;
688                         pair->next = NULL;
689
690                         switch (pair->type) {
691
692                         case PW_TYPE_OCTETS:
693                         case PW_TYPE_ABINARY:
694                         case PW_TYPE_STRING:
695                                 /* attrlen always < MAX_STRING_LEN */
696                                 memcpy(pair->strvalue, ptr, attrlen);
697                                 break;
698                         
699                         case PW_TYPE_INTEGER:
700                         case PW_TYPE_DATE:
701                         case PW_TYPE_IPADDR:
702                                 /*
703                                  *      Check for RFC compliance.
704                                  *      If the attribute isn't compliant,
705                                  *      turn it into a string of raw octets.
706                                  *
707                                  *      Also set the lvalue to something
708                                  *      which should never match anything.
709                                  */
710                                 if (attrlen != 4) {
711                                         pair->type = PW_TYPE_OCTETS;
712                                         memcpy(pair->strvalue, ptr, attrlen);
713                                         pair->lvalue = 0xbaddbadd;
714                                         break;
715                                 }
716                                 memcpy(&lvalue, ptr, 4);
717                                 if (attr->type != PW_TYPE_IPADDR)
718                                         pair->lvalue = ntohl(lvalue);
719                                 else
720                                         pair->lvalue = lvalue;
721                                 break;
722                         
723                         default:
724                                 DEBUG("    %s (Unknown Type %d)\n",
725                                         attr->name,attr->type);
726                                 free(pair);
727                                 pair = NULL;
728                                 break;
729                         }
730
731                         if (pair) {
732                                 debug_pair(pair);
733                                 if (first_pair == NULL)
734                                         first_pair = pair;
735                                 else
736                                         prev->next = pair;
737                                 prev = pair;
738                         }
739                 }
740                 ptr += attrlen;
741                 length -= attrlen;
742                 if (vendorlen > 0) vendorlen -= (attrlen + 2);
743         }
744
745         packet->vps = first_pair;
746
747         /*
748          *      Merge information from the outside world into our
749          *      random vector pool.  The MD5 is expensive, but it's
750          *      amortized over *legal* packets from *known* clients,
751          *      so the problem isn't too bad.
752          *
753          *      The MD5 helps to make sure that the random pool uses
754          *      information from outside to increase entropy, without
755          *      being contaminated by that information.
756          *
757          *      Both AUTH_VECTOR_LEN and the MD5 output are 16 octets
758          *      long, so we copy the user's vector to the end of our
759          *      pool, and make the pool out of the hash of the two.
760          *
761          *      However, doing this for *every* packet can be time
762          *      consuming.  Instead, we do it (on average) once every
763          *      32 packets, and do less work the rest of the time.
764          */
765         if ((random_vector_pool[0] & 0x1f) == 0x00) {
766                 memcpy((char *) random_vector_pool + AUTH_VECTOR_LEN,
767                        (char *) packet->vector, AUTH_VECTOR_LEN);
768                 librad_md5_calc((u_char *)random_vector_pool,
769                                 (u_char *)random_vector_pool,
770                                 sizeof(random_vector_pool));
771
772         } else for (length = 0; length < AUTH_VECTOR_LEN; length++) {
773                 random_vector_pool[length] += packet->vector[length];
774         }
775
776         return 0;
777 }
778
779
780 /*
781  *      Encode password.
782  *
783  *      We assume that the passwd buffer passed is big enough.
784  *      RFC2138 says the password is max 128 chars, so the size
785  *      of the passwd buffer must be at least 129 characters.
786  *      Preferably it's just MAX_STRING_LEN.
787  *
788  *      int *pwlen is updated to the new length of the encrypted
789  *      password - a multiple of 16 bytes.
790  */
791 int rad_pwencode(char *passwd, int *pwlen, const char *secret, const char *vector)
792 {
793         uint8_t buffer[AUTH_VECTOR_LEN + MAX_STRING_LEN + 1];
794         char    digest[AUTH_VECTOR_LEN];
795         int     i, n, secretlen;
796         int     len;
797
798         /*
799          *      Padd password to multiple of 16 bytes.
800          */
801         len = strlen(passwd);
802         if (len > 128) len = 128;
803         *pwlen = len;
804         if (len % 16 != 0) {
805                 n = 16 - (len % 16);
806                 for (i = len; n > 0; n--, i++)
807                         passwd[i] = 0;
808                 len = *pwlen = i;
809         }
810
811         /*
812          *      Use the secret to setup the decryption digest
813          */
814         secretlen = strlen(secret);
815         strcpy(buffer, secret);
816         memcpy(buffer + secretlen, vector, AUTH_VECTOR_LEN);
817         librad_md5_calc((u_char *)digest, buffer, secretlen + AUTH_VECTOR_LEN);
818
819         /*
820          *      Now we can encode the password *in place*
821          */
822         for (i = 0; i < 16; i++)
823                 passwd[i] ^= digest[i];
824
825         if (len <= 16) return 0;
826
827         /*
828          *      Length > 16, so we need to use the extended
829          *      algorithm.
830          */
831         for (n = 0; n < 128 && n <= (len - 16); n += 16) { 
832                 memcpy(buffer + secretlen, passwd + n, 16);
833                 librad_md5_calc((u_char *)digest, buffer, secretlen + 16);
834                 for (i = 0; i < 16; i++)
835                         passwd[i + n + 16] ^= digest[i];
836         }
837
838         return 0;
839 }
840
841 /*
842  *      Decode password.
843  */
844 int rad_pwdecode(char *passwd, int pwlen, const char *secret, const char *vector)
845 {
846         uint8_t buffer[AUTH_VECTOR_LEN + MAX_STRING_LEN + 1];
847         char    digest[AUTH_VECTOR_LEN];
848         char    r[AUTH_VECTOR_LEN];
849         char    *s;
850         int     i, n, secretlen;
851         int     rlen;
852
853         /*
854          *      Use the secret to setup the decryption digest
855          */
856         secretlen = strlen(secret);
857         strcpy(buffer, secret);
858         memcpy(buffer + secretlen, vector, AUTH_VECTOR_LEN);
859         librad_md5_calc((u_char *)digest, buffer, secretlen + AUTH_VECTOR_LEN);
860
861         /*
862          *      Now we can decode the password *in place*
863          */
864         memcpy(r, passwd, 16);
865         for (i = 0; i < 16 && i < pwlen; i++)
866                 passwd[i] ^= digest[i];
867
868         if (pwlen <= 16) {
869                 passwd[pwlen+1] = 0;
870                 return pwlen;
871         }
872
873         /*
874          *      Length > 16, so we need to use the extended
875          *      algorithm.
876          */
877         rlen = ((pwlen - 1) / 16) * 16;
878
879         for (n = rlen; n > 0; n -= 16 ) { 
880                 s = (n == 16) ? r : (passwd + n - 16);
881                 memcpy(buffer + secretlen, s, 16);
882                 librad_md5_calc((u_char *)digest, buffer, secretlen + 16);
883                 for (i = 0; i < 16 && (i + n) < pwlen; i++)
884                         passwd[i + n] ^= digest[i];
885         }
886         passwd[pwlen] = 0;
887
888         return pwlen;
889 }
890
891 /*
892  *      Encode a CHAP password
893  *
894  *      FIXME: might not work with Ascend because
895  *      we use vp->length, and Ascend gear likes
896  *      to send an extra '\0' in the string!
897  */
898 int rad_chap_encode(RADIUS_PACKET *packet, char *output, int id, VALUE_PAIR *password)
899 {
900         int             i;
901         char            *ptr;
902         char            string[MAX_STRING_LEN];
903         VALUE_PAIR      *challenge;
904
905         /*
906          *      Sanity check the input parameters
907          */
908         if ((packet == NULL) || (password == NULL)) {
909                 return -1;
910         }
911
912         /*
913          *      Note that the password VP can be EITHER
914          *      a Password attribute (from a check-item list),
915          *      or a CHAP-Password attribute (the client asking
916          *      the library to encode it).
917          */
918
919         i = 0;
920         ptr = string;
921         *ptr++ = id;
922
923         i++;
924         memcpy(ptr, password->strvalue, password->length);
925         ptr += password->length;
926         i += password->length;
927
928         /*
929          *      Use Chap-Challenge pair if present,
930          *      Request-Authenticator otherwise.
931          */
932         challenge = pairfind(packet->vps, PW_CHAP_CHALLENGE);
933         if (challenge) {
934                 memcpy(ptr, challenge->strvalue, challenge->length);
935                 i += challenge->length;
936         } else {
937                 memcpy(ptr, packet->vector, AUTH_VECTOR_LEN);
938                 i += AUTH_VECTOR_LEN; 
939         }
940
941         *output = id;
942         librad_md5_calc((u_char *)output + 1, (u_char *)string, i);
943
944         return 0;
945 }
946
947 /*
948  *      Create a random vector of AUTH_VECTOR_LEN bytes.
949  */
950 static void random_vector(uint8_t *vector)
951 {
952         int             i;
953         static int      did_srand = 0;
954         static int      counter = 0;
955 #ifdef __linux__
956         static int      urandom_fd = -1;
957
958         /*
959          *      Use /dev/urandom if available.
960          */
961         if (urandom_fd > -2) {
962                 /*
963                  *      Open urandom fd if not yet opened.
964                  */
965                 if (urandom_fd < 0)
966                         urandom_fd = open("/dev/urandom", O_RDONLY);
967                 if (urandom_fd < 0) {
968                         /*
969                          *      It's not there, don't try
970                          *      it again.
971                          */
972                         DEBUG("Cannot open /dev/urandom, using rand()\n");
973                         urandom_fd = -2;
974                 } else {
975
976                         fcntl(urandom_fd, F_SETFD, 1);
977
978                         /*
979                          *      Read 16 bytes.
980                          */
981                         if (read(urandom_fd, (char *) vector, AUTH_VECTOR_LEN)
982                             == AUTH_VECTOR_LEN)
983                                 return;
984                         /*
985                          *      We didn't get 16 bytes - fall
986                          *      back on rand) and don't try again.
987                          */
988                 DEBUG("Read short packet from /dev/urandom, using rand()\n");
989                         urandom_fd = -2;
990                 }
991         }
992 #endif
993
994         if (!did_srand) {
995                 srand(time(NULL) + getpid());
996
997                 /*
998                  *      Now that we have a bad random seed, let's
999                  *      make it a little better by MD5'ing it.
1000                  */
1001                 for (i = 0; i < (int)sizeof(random_vector_pool); i++) {
1002                         random_vector_pool[i] += rand() & 0xff;
1003                 }
1004
1005                 librad_md5_calc((u_char *) random_vector_pool,
1006                                 (u_char *) random_vector_pool,
1007                                 sizeof(random_vector_pool));
1008
1009                 did_srand = 1;
1010         }
1011
1012         /*
1013          *      Modify our random pool, based on the counter,
1014          *      and put the resulting information through MD5,
1015          *      so it's all mashed together.
1016          */
1017         counter++;
1018         random_vector_pool[AUTH_VECTOR_LEN] += (counter & 0xff);
1019         librad_md5_calc((u_char *) random_vector_pool,
1020                         (u_char *) random_vector_pool,
1021                         sizeof(random_vector_pool));
1022
1023         /*
1024          *      And do another MD5 hash of the result, to give
1025          *      the user a random vector.  This ensures that the
1026          *      user has a random vector, without giving them
1027          *      an exact image of what's in the random pool.
1028          */
1029         librad_md5_calc((u_char *) vector,
1030                         (u_char *) random_vector_pool,
1031                         sizeof(random_vector_pool));
1032 }
1033
1034
1035 /*
1036  *      Allocate a new RADIUS_PACKET
1037  */
1038 RADIUS_PACKET *rad_alloc(int newvector)
1039 {
1040         RADIUS_PACKET   *rp;
1041
1042         if ((rp = malloc(sizeof(RADIUS_PACKET))) == NULL)
1043                 return NULL;
1044         memset(rp, 0, sizeof(RADIUS_PACKET));
1045         if (newvector)
1046                 random_vector(rp->vector);
1047
1048         return rp;
1049 }
1050
1051 /*
1052  *      Free a RADIUS_PACKET
1053  */
1054 void rad_free(RADIUS_PACKET *rp)
1055 {
1056         if (rp->data) free(rp->data);
1057         if (rp->vps) pairfree(rp->vps);
1058         free(rp);
1059 }