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