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