Reverse the order of const and type specifier e.g. const char * becomes char const *
[freeradius.git] / src / lib / misc.c
1 /*
2  * misc.c       Various miscellaneous functions.
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 2000,2006  The FreeRADIUS server project
21  */
22
23 RCSID("$Id$")
24
25 #include        <freeradius-devel/libradius.h>
26
27 #include        <ctype.h>
28 #include        <sys/file.h>
29 #include        <fcntl.h>
30
31 int             fr_dns_lookups = 0;
32 int             fr_debug_flag = 0;
33
34 /*
35  *      Return an IP address in standard dot notation
36  *
37  *      FIXME: DELETE THIS
38  */
39 char const *ip_ntoa(char *buffer, uint32_t ipaddr)
40 {
41         ipaddr = ntohl(ipaddr);
42
43         sprintf(buffer, "%d.%d.%d.%d",
44                 (ipaddr >> 24) & 0xff,
45                 (ipaddr >> 16) & 0xff,
46                 (ipaddr >>  8) & 0xff,
47                 (ipaddr      ) & 0xff);
48         return buffer;
49 }
50
51 /*
52  *      Internal wrapper for locking, to minimize the number of ifdef's
53  *
54  *      Use fcntl or error
55  */
56 int rad_lockfd(int fd, int lock_len)
57 {
58 #ifdef F_WRLCK
59         struct flock fl;
60         
61         fl.l_start = 0;
62         fl.l_len = lock_len;
63         fl.l_pid = getpid();
64         fl.l_type = F_WRLCK;
65         fl.l_whence = SEEK_CUR;
66         
67         return fcntl(fd, F_SETLKW, (void *)&fl);
68 #else
69 #error "missing definition for F_WRLCK, all file locks will fail"
70         
71         return -1;
72 #endif
73 }
74
75 /*
76  *      Internal wrapper for locking, to minimize the number of ifdef's
77  *
78  *      Lock an fd, prefer lockf() over flock()
79  *      Nonblocking version.
80  */
81 int rad_lockfd_nonblock(int fd, int lock_len)
82 {
83 #ifdef F_WRLCK
84         struct flock fl;
85         
86         fl.l_start = 0;
87         fl.l_len = lock_len;
88         fl.l_pid = getpid();
89         fl.l_type = F_WRLCK;
90         fl.l_whence = SEEK_CUR;
91         
92         return fcntl(fd, F_SETLK, (void *)&fl);
93 #else
94 #error "missing definition for F_WRLCK, all file locks will fail"
95
96         return -1;
97 #endif
98 }
99
100 /*
101  *      Internal wrapper for unlocking, to minimize the number of ifdef's
102  *      in the source.
103  *
104  *      Unlock an fd, prefer lockf() over flock()
105  */
106 int rad_unlockfd(int fd, int lock_len)
107 {
108 #ifdef F_WRLCK
109         struct flock fl;
110         
111         fl.l_start = 0;
112         fl.l_len = lock_len;
113         fl.l_pid = getpid();
114         fl.l_type = F_WRLCK;
115         fl.l_whence = SEEK_CUR;
116
117         return fcntl(fd, F_UNLCK, (void *)&fl);
118 #else
119 #error "missing definition for F_WRLCK, all file locks will fail"
120
121         return -1;
122 #endif
123 }
124
125 /*
126  *      Return an interface-id in standard colon notation
127  */
128 char *ifid_ntoa(char *buffer, size_t size, uint8_t const *ifid)
129 {
130         snprintf(buffer, size, "%x:%x:%x:%x",
131                  (ifid[0] << 8) + ifid[1], (ifid[2] << 8) + ifid[3],
132                  (ifid[4] << 8) + ifid[5], (ifid[6] << 8) + ifid[7]);
133         return buffer;
134 }
135
136
137 /*
138  *      Return an interface-id from
139  *      one supplied in standard colon notation.
140  */
141 uint8_t *ifid_aton(char const *ifid_str, uint8_t *ifid)
142 {
143         static char const xdigits[] = "0123456789abcdef";
144         char const *p, *pch;
145         int num_id = 0, val = 0, idx = 0;
146
147         for (p = ifid_str; ; ++p) {
148                 if (*p == ':' || *p == '\0') {
149                         if (num_id <= 0)
150                                 return NULL;
151
152                         /*
153                          *      Drop 'val' into the array.
154                          */
155                         ifid[idx] = (val >> 8) & 0xff;
156                         ifid[idx + 1] = val & 0xff;
157                         if (*p == '\0') {
158                                 /*
159                                  *      Must have all entries before
160                                  *      end of the string.
161                                  */
162                                 if (idx != 6)
163                                         return NULL;
164                                 break;
165                         }
166                         val = 0;
167                         num_id = 0;
168                         if ((idx += 2) > 6)
169                                 return NULL;
170                 } else if ((pch = strchr(xdigits, tolower(*p))) != NULL) {
171                         if (++num_id > 4)
172                                 return NULL;
173                         /*
174                          *      Dumb version of 'scanf'
175                          */
176                         val <<= 4;
177                         val |= (pch - xdigits);
178                 } else
179                         return NULL;
180         }
181         return ifid;
182 }
183
184
185 #ifndef HAVE_INET_PTON
186 static int inet_pton4(char const *src, struct in_addr *dst)
187 {
188         int octet;
189         unsigned int num;
190         char const *p, *off;
191         uint8_t tmp[4];
192         static char const digits[] = "0123456789";
193
194         octet = 0;
195         p = src;
196         while (1) {
197                 num = 0;
198                 while (*p && ((off = strchr(digits, *p)) != NULL)) {
199                         num *= 10;
200                         num += (off - digits);
201
202                         if (num > 255) return 0;
203
204                         p++;
205                 }
206                 if (!*p) break;
207
208                 /*
209                  *      Not a digit, MUST be a dot, else we
210                  *      die.
211                  */
212                 if (*p != '.') {
213                         return 0;
214                 }
215
216                 tmp[octet++] = num;
217                 p++;
218         }
219
220         /*
221          *      End of the string.  At the fourth
222          *      octet is OK, anything else is an
223          *      error.
224          */
225         if (octet != 3) {
226                 return 0;
227         }
228         tmp[3] = num;
229
230         memcpy(dst, &tmp, sizeof(tmp));
231         return 1;
232 }
233
234
235 #ifdef HAVE_STRUCT_SOCKADDR_IN6
236 /* int
237  * inet_pton6(src, dst)
238  *      convert presentation level address to network order binary form.
239  * return:
240  *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
241  * notice:
242  *      (1) does not touch `dst' unless it's returning 1.
243  *      (2) :: in a full address is silently ignored.
244  * credit:
245  *      inspired by Mark Andrews.
246  * author:
247  *      Paul Vixie, 1996.
248  */
249 static int
250 inet_pton6(char const *src, unsigned char *dst)
251 {
252         static char const xdigits_l[] = "0123456789abcdef",
253                           xdigits_u[] = "0123456789ABCDEF";
254         u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
255         char const *xdigits, *curtok;
256         int ch, saw_xdigit;
257         u_int val;
258
259         memset((tp = tmp), 0, IN6ADDRSZ);
260         endp = tp + IN6ADDRSZ;
261         colonp = NULL;
262         /* Leading :: requires some special handling. */
263         if (*src == ':')
264                 if (*++src != ':')
265                         return (0);
266         curtok = src;
267         saw_xdigit = 0;
268         val = 0;
269         while ((ch = *src++) != '\0') {
270                 char const *pch;
271
272                 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
273                         pch = strchr((xdigits = xdigits_u), ch);
274                 if (pch != NULL) {
275                         val <<= 4;
276                         val |= (pch - xdigits);
277                         if (val > 0xffff)
278                                 return (0);
279                         saw_xdigit = 1;
280                         continue;
281                 }
282                 if (ch == ':') {
283                         curtok = src;
284                         if (!saw_xdigit) {
285                                 if (colonp)
286                                         return (0);
287                                 colonp = tp;
288                                 continue;
289                         }
290                         if (tp + INT16SZ > endp)
291                                 return (0);
292                         *tp++ = (u_char) (val >> 8) & 0xff;
293                         *tp++ = (u_char) val & 0xff;
294                         saw_xdigit = 0;
295                         val = 0;
296                         continue;
297                 }
298                 if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
299                     inet_pton4(curtok, (struct in_addr *) tp) > 0) {
300                         tp += INADDRSZ;
301                         saw_xdigit = 0;
302                         break;  /* '\0' was seen by inet_pton4(). */
303                 }
304                 return (0);
305         }
306         if (saw_xdigit) {
307                 if (tp + INT16SZ > endp)
308                         return (0);
309                 *tp++ = (u_char) (val >> 8) & 0xff;
310                 *tp++ = (u_char) val & 0xff;
311         }
312         if (colonp != NULL) {
313                 /*
314                  * Since some memmove()'s erroneously fail to handle
315                  * overlapping regions, we'll do the shift by hand.
316                  */
317                 const int n = tp - colonp;
318                 int i;
319
320                 for (i = 1; i <= n; i++) {
321                         endp[- i] = colonp[n - i];
322                         colonp[n - i] = 0;
323                 }
324                 tp = endp;
325         }
326         if (tp != endp)
327                 return (0);
328         /* bcopy(tmp, dst, IN6ADDRSZ); */
329         memcpy(dst, tmp, IN6ADDRSZ);
330         return (1);
331 }
332 #endif
333
334 /*
335  *      Utility function, so that the rest of the server doesn't
336  *      have ifdef's around IPv6 support
337  */
338 int inet_pton(int af, char const *src, void *dst)
339 {
340         if (af == AF_INET) {
341                 return inet_pton4(src, dst);
342         }
343 #ifdef HAVE_STRUCT_SOCKADDR_IN6
344
345         if (af == AF_INET6) {
346                 return inet_pton6(src, dst);
347         }
348 #endif
349
350         return -1;
351 }
352 #endif
353
354
355 #ifndef HAVE_INET_NTOP
356 /*
357  *      Utility function, so that the rest of the server doesn't
358  *      have ifdef's around IPv6 support
359  */
360 char const *inet_ntop(int af, void const *src, char *dst, size_t cnt)
361 {
362         if (af == AF_INET) {
363                 const uint8_t *ipaddr = src;
364
365                 if (cnt <= INET_ADDRSTRLEN) return NULL;
366
367                 snprintf(dst, cnt, "%d.%d.%d.%d",
368                          ipaddr[0], ipaddr[1],
369                          ipaddr[2], ipaddr[3]);
370                 return dst;
371         }
372
373         /*
374          *      If the system doesn't define this, we define it
375          *      in missing.h
376          */
377         if (af == AF_INET6) {
378                 const struct in6_addr *ipaddr = src;
379
380                 if (cnt <= INET6_ADDRSTRLEN) return NULL;
381
382                 snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x",
383                          (ipaddr->s6_addr[0] << 8) | ipaddr->s6_addr[1],
384                          (ipaddr->s6_addr[2] << 8) | ipaddr->s6_addr[3],
385                          (ipaddr->s6_addr[4] << 8) | ipaddr->s6_addr[5],
386                          (ipaddr->s6_addr[6] << 8) | ipaddr->s6_addr[7],
387                          (ipaddr->s6_addr[8] << 8) | ipaddr->s6_addr[9],
388                          (ipaddr->s6_addr[10] << 8) | ipaddr->s6_addr[11],
389                          (ipaddr->s6_addr[12] << 8) | ipaddr->s6_addr[13],
390                          (ipaddr->s6_addr[14] << 8) | ipaddr->s6_addr[15]);
391                 return dst;
392         }
393
394         return NULL;            /* don't support IPv6 */
395 }
396 #endif
397
398
399 /*
400  *      Wrappers for IPv4/IPv6 host to IP address lookup.
401  *      This API returns only one IP address, of the specified
402  *      address family, or the first address (of whatever family),
403  *      if AF_UNSPEC is used.
404  */
405 int ip_hton(char const *src, int af, fr_ipaddr_t *dst)
406 {
407         int rcode;
408         struct addrinfo hints, *ai = NULL, *res = NULL;
409
410         memset(&hints, 0, sizeof(hints));
411         hints.ai_family = af;
412
413         if ((rcode = getaddrinfo(src, NULL, &hints, &res)) != 0) {
414                 fr_strerror_printf("ip_hton: %s", gai_strerror(rcode));
415                 return -1;
416         }
417
418         for (ai = res; ai; ai = ai->ai_next) {
419                 if ((af == ai->ai_family) || (af == AF_UNSPEC))
420                         break;
421         }
422
423         if (!ai) {
424                 fr_strerror_printf("ip_hton failed to find requested information for host %.100s", src);
425                 freeaddrinfo(ai);
426                 return -1;
427         }
428
429         rcode = fr_sockaddr2ipaddr((struct sockaddr_storage *)ai->ai_addr,
430                                    ai->ai_addrlen, dst, NULL);
431         freeaddrinfo(ai);
432         if (!rcode) return -1;
433
434         return 0;
435 }
436
437 /*
438  *      Look IP addresses up, and print names (depending on DNS config)
439  */
440 char const *ip_ntoh(fr_ipaddr_t const *src, char *dst, size_t cnt)
441 {
442         struct sockaddr_storage ss;
443         int error;
444         socklen_t salen;
445
446         /*
447          *      No DNS lookups
448          */
449         if (!fr_dns_lookups) {
450                 return inet_ntop(src->af, &(src->ipaddr), dst, cnt);
451         }
452
453         if (!fr_ipaddr2sockaddr(src, 0, &ss, &salen)) {
454                 return NULL;
455         }
456
457         if ((error = getnameinfo((struct sockaddr *)&ss, salen, dst, cnt, NULL, 0,
458                                  NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
459                 fr_strerror_printf("ip_ntoh: %s", gai_strerror(error));
460                 return NULL;
461         }
462         return dst;
463 }
464
465
466 static char const *hextab = "0123456789abcdef";
467
468 /** Convert hex strings to binary data
469  *
470  * @param hex input string.
471  * @param bin Buffer to write output to.
472  * @param len length of input string.
473  * @return length of data written to buffer.
474  */
475 size_t fr_hex2bin(char const *hex, uint8_t *bin, size_t len)
476 {
477         size_t i;
478         char *c1, *c2;
479
480         for (i = 0; i < len; i++) {
481                 if(!(c1 = memchr(hextab, tolower((int) hex[i << 1]), 16)) ||
482                    !(c2 = memchr(hextab, tolower((int) hex[(i << 1) + 1]), 16)))
483                         break;
484                  bin[i] = ((c1-hextab)<<4) + (c2-hextab);
485         }
486
487         return i;
488 }
489
490
491 /** Convert binary data to a hex string
492  *
493  * Ascii encoded hex string will not be prefixed with '0x'
494  *
495  * @warning If the output buffer isn't long enough, we have a buffer overflow.
496  *
497  * @param[in] bin input.
498  * @param[out] hex Buffer to write hex output.
499  * @param[in] len of bin input.
500  * @return length of data written to buffer.
501  */
502 size_t fr_bin2hex(uint8_t const *bin, char *hex, size_t len)
503 {
504         size_t i;
505
506         for (i = 0; i < len; i++) {
507                 hex[0] = hextab[((*bin) >> 4) & 0x0f];
508                 hex[1] = hextab[*bin & 0x0f];
509                 hex += 2;
510                 bin++;
511         }
512         
513         *hex = '\0';
514         return len * 2;
515 }
516
517
518 /*
519  *      So we don't have ifdef's in the rest of the code
520  */
521 #ifndef HAVE_CLOSEFROM
522 int closefrom(int fd)
523 {
524         int i;
525         int maxfd = 256;
526
527 #ifdef _SC_OPEN_MAX
528         maxfd = sysconf(_SC_OPEN_MAX);
529         if (maxfd < 0) {
530           maxfd = 256;
531         }
532 #endif
533
534         if (fd > maxfd) return 0;
535
536         /*
537          *      FIXME: return EINTR?
538          *
539          *      Use F_CLOSEM?
540          */
541         for (i = fd; i < maxfd; i++) {
542                 close(i);
543         }
544
545         return 0;
546 }
547 #endif
548
549 int fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
550 {
551         if (a->af < b->af) return -1;
552         if (a->af > b->af) return +1;
553
554         switch (a->af) {
555         case AF_INET:
556                 return memcmp(&a->ipaddr.ip4addr,
557                               &b->ipaddr.ip4addr,
558                               sizeof(a->ipaddr.ip4addr));
559                 break;
560
561 #ifdef HAVE_STRUCT_SOCKADDR_IN6
562         case AF_INET6:
563                 if (a->scope < b->scope) return -1;
564                 if (a->scope > b->scope) return +1;
565
566                 return memcmp(&a->ipaddr.ip6addr,
567                               &b->ipaddr.ip6addr,
568                               sizeof(a->ipaddr.ip6addr));
569                 break;
570 #endif
571
572         default:
573                 break;
574         }
575
576         return -1;
577 }
578
579 int fr_ipaddr2sockaddr(fr_ipaddr_t const *ipaddr, int port,
580                        struct sockaddr_storage *sa, socklen_t *salen)
581 {
582         if (ipaddr->af == AF_INET) {
583                 struct sockaddr_in s4;
584
585                 *salen = sizeof(s4);
586
587                 memset(&s4, 0, sizeof(s4));
588                 s4.sin_family = AF_INET;
589                 s4.sin_addr = ipaddr->ipaddr.ip4addr;
590                 s4.sin_port = htons(port);
591                 memset(sa, 0, sizeof(*sa));
592                 memcpy(sa, &s4, sizeof(s4));
593
594 #ifdef HAVE_STRUCT_SOCKADDR_IN6
595         } else if (ipaddr->af == AF_INET6) {
596                 struct sockaddr_in6 s6;
597
598                 *salen = sizeof(s6);
599
600                 memset(&s6, 0, sizeof(s6));
601                 s6.sin6_family = AF_INET6;
602                 s6.sin6_addr = ipaddr->ipaddr.ip6addr;
603                 s6.sin6_port = htons(port);
604                 s6.sin6_scope_id = ipaddr->scope;
605                 memset(sa, 0, sizeof(*sa));
606                 memcpy(sa, &s6, sizeof(s6));
607 #endif
608         } else {
609                 return 0;
610         }
611
612         return 1;
613 }
614
615
616 int fr_sockaddr2ipaddr(struct sockaddr_storage const *sa, socklen_t salen,
617                        fr_ipaddr_t *ipaddr, int *port)
618 {
619         if (sa->ss_family == AF_INET) {
620                 struct sockaddr_in      s4;
621
622                 if (salen < sizeof(s4)) {
623                         fr_strerror_printf("IPv4 address is too small");
624                         return 0;
625                 }
626                 
627                 memcpy(&s4, sa, sizeof(s4));
628                 ipaddr->af = AF_INET;
629                 ipaddr->ipaddr.ip4addr = s4.sin_addr;
630                 if (port) *port = ntohs(s4.sin_port);
631                 
632 #ifdef HAVE_STRUCT_SOCKADDR_IN6
633         } else if (sa->ss_family == AF_INET6) {
634                 struct sockaddr_in6     s6;
635                 
636                 if (salen < sizeof(s6)) {
637                         fr_strerror_printf("IPv6 address is too small");
638                         return 0;
639                 }
640                 
641                 memcpy(&s6, sa, sizeof(s6));
642                 ipaddr->af = AF_INET6;
643                 ipaddr->ipaddr.ip6addr = s6.sin6_addr;
644                 if (port) *port = ntohs(s6.sin6_port);
645                 ipaddr->scope = s6.sin6_scope_id;
646 #endif
647
648         } else {
649                 fr_strerror_printf("Unsupported address famility %d",
650                                    sa->ss_family);
651                 return 0;
652         }
653
654         return 1;
655 }