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