2 * misc.c Various miscellaneous functions.
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.
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.
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
20 * Copyright 2000,2006 The FreeRADIUS server project
25 #include <freeradius-devel/libradius.h>
32 #define FR_PUT_LE16(a, val)\
34 a[1] = ((uint16_t) (val)) >> 8;\
35 a[0] = ((uint16_t) (val)) & 0xff;\
38 static int fr_debugger_present = -1;
40 int fr_dns_lookups = 0;
41 int fr_debug_flag = 0;
43 /** Allocates a new talloc context from the root autofree context
45 * @param signum signal raised.
47 static void _sigtrap_handler(UNUSED int signum)
49 fr_debugger_present = 0;
50 signal(SIGTRAP, SIG_DFL);
53 /** Break in GDB (if were running under GDB)
55 * If the server is running under GDB this will raise a SIGTRAP which
56 * will pause the running process.
58 * If the server is not running under GDB then this will do nothing.
60 void fr_debug_break(void)
62 if (fr_debugger_present == -1) {
63 fr_debugger_present = 0;
64 signal(SIGTRAP, _sigtrap_handler);
66 } else if (fr_debugger_present == 1) {
72 * Return an IP address in standard dot notation
76 char const *ip_ntoa(char *buffer, uint32_t ipaddr)
78 ipaddr = ntohl(ipaddr);
80 sprintf(buffer, "%d.%d.%d.%d",
81 (ipaddr >> 24) & 0xff,
82 (ipaddr >> 16) & 0xff,
89 * Internal wrapper for locking, to minimize the number of ifdef's
93 int rad_lockfd(int fd, int lock_len)
102 fl.l_whence = SEEK_CUR;
104 return fcntl(fd, F_SETLKW, (void *)&fl);
106 #error "missing definition for F_WRLCK, all file locks will fail"
113 * Internal wrapper for locking, to minimize the number of ifdef's
115 * Lock an fd, prefer lockf() over flock()
116 * Nonblocking version.
118 int rad_lockfd_nonblock(int fd, int lock_len)
127 fl.l_whence = SEEK_CUR;
129 return fcntl(fd, F_SETLK, (void *)&fl);
131 #error "missing definition for F_WRLCK, all file locks will fail"
138 * Internal wrapper for unlocking, to minimize the number of ifdef's
141 * Unlock an fd, prefer lockf() over flock()
143 int rad_unlockfd(int fd, int lock_len)
152 fl.l_whence = SEEK_CUR;
154 return fcntl(fd, F_UNLCK, (void *)&fl);
156 #error "missing definition for F_WRLCK, all file locks will fail"
163 * Return an interface-id in standard colon notation
165 char *ifid_ntoa(char *buffer, size_t size, uint8_t const *ifid)
167 snprintf(buffer, size, "%x:%x:%x:%x",
168 (ifid[0] << 8) + ifid[1], (ifid[2] << 8) + ifid[3],
169 (ifid[4] << 8) + ifid[5], (ifid[6] << 8) + ifid[7]);
175 * Return an interface-id from
176 * one supplied in standard colon notation.
178 uint8_t *ifid_aton(char const *ifid_str, uint8_t *ifid)
180 static char const xdigits[] = "0123456789abcdef";
182 int num_id = 0, val = 0, idx = 0;
184 for (p = ifid_str; ; ++p) {
185 if (*p == ':' || *p == '\0') {
190 * Drop 'val' into the array.
192 ifid[idx] = (val >> 8) & 0xff;
193 ifid[idx + 1] = val & 0xff;
196 * Must have all entries before
207 } else if ((pch = strchr(xdigits, tolower(*p))) != NULL) {
211 * Dumb version of 'scanf'
214 val |= (pch - xdigits);
222 #ifndef HAVE_INET_PTON
223 static int inet_pton4(char const *src, struct in_addr *dst)
229 static char const digits[] = "0123456789";
235 while (*p && ((off = strchr(digits, *p)) != NULL)) {
237 num += (off - digits);
239 if (num > 255) return 0;
246 * Not a digit, MUST be a dot, else we
258 * End of the string. At the fourth
259 * octet is OK, anything else is an
267 memcpy(dst, &tmp, sizeof(tmp));
272 #ifdef HAVE_STRUCT_SOCKADDR_IN6
274 * inet_pton6(src, dst)
275 * convert presentation level address to network order binary form.
277 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
279 * (1) does not touch `dst' unless it's returning 1.
280 * (2) :: in a full address is silently ignored.
282 * inspired by Mark Andrews.
287 inet_pton6(char const *src, unsigned char *dst)
289 static char const xdigits_l[] = "0123456789abcdef",
290 xdigits_u[] = "0123456789ABCDEF";
291 u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
292 char const *xdigits, *curtok;
296 memset((tp = tmp), 0, IN6ADDRSZ);
297 endp = tp + IN6ADDRSZ;
299 /* Leading :: requires some special handling. */
306 while ((ch = *src++) != '\0') {
309 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
310 pch = strchr((xdigits = xdigits_u), ch);
313 val |= (pch - xdigits);
327 if (tp + INT16SZ > endp)
329 *tp++ = (u_char) (val >> 8) & 0xff;
330 *tp++ = (u_char) val & 0xff;
335 if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
336 inet_pton4(curtok, (struct in_addr *) tp) > 0) {
339 break; /* '\0' was seen by inet_pton4(). */
344 if (tp + INT16SZ > endp)
346 *tp++ = (u_char) (val >> 8) & 0xff;
347 *tp++ = (u_char) val & 0xff;
349 if (colonp != NULL) {
351 * Since some memmove()'s erroneously fail to handle
352 * overlapping regions, we'll do the shift by hand.
354 int const n = tp - colonp;
357 for (i = 1; i <= n; i++) {
358 endp[- i] = colonp[n - i];
365 /* bcopy(tmp, dst, IN6ADDRSZ); */
366 memcpy(dst, tmp, IN6ADDRSZ);
372 * Utility function, so that the rest of the server doesn't
373 * have ifdef's around IPv6 support
375 int inet_pton(int af, char const *src, void *dst)
378 return inet_pton4(src, dst);
380 #ifdef HAVE_STRUCT_SOCKADDR_IN6
382 if (af == AF_INET6) {
383 return inet_pton6(src, dst);
392 #ifndef HAVE_INET_NTOP
394 * Utility function, so that the rest of the server doesn't
395 * have ifdef's around IPv6 support
397 char const *inet_ntop(int af, void const *src, char *dst, size_t cnt)
400 uint8_t const *ipaddr = src;
402 if (cnt <= INET_ADDRSTRLEN) return NULL;
404 snprintf(dst, cnt, "%d.%d.%d.%d",
405 ipaddr[0], ipaddr[1],
406 ipaddr[2], ipaddr[3]);
411 * If the system doesn't define this, we define it
414 if (af == AF_INET6) {
415 struct const in6_addr *ipaddr = src;
417 if (cnt <= INET6_ADDRSTRLEN) return NULL;
419 snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x",
420 (ipaddr->s6_addr[0] << 8) | ipaddr->s6_addr[1],
421 (ipaddr->s6_addr[2] << 8) | ipaddr->s6_addr[3],
422 (ipaddr->s6_addr[4] << 8) | ipaddr->s6_addr[5],
423 (ipaddr->s6_addr[6] << 8) | ipaddr->s6_addr[7],
424 (ipaddr->s6_addr[8] << 8) | ipaddr->s6_addr[9],
425 (ipaddr->s6_addr[10] << 8) | ipaddr->s6_addr[11],
426 (ipaddr->s6_addr[12] << 8) | ipaddr->s6_addr[13],
427 (ipaddr->s6_addr[14] << 8) | ipaddr->s6_addr[15]);
431 return NULL; /* don't support IPv6 */
437 * Wrappers for IPv4/IPv6 host to IP address lookup.
438 * This API returns only one IP address, of the specified
439 * address family, or the first address (of whatever family),
440 * if AF_UNSPEC is used.
442 int ip_hton(char const *src, int af, fr_ipaddr_t *dst)
445 struct addrinfo hints, *ai = NULL, *res = NULL;
447 memset(&hints, 0, sizeof(hints));
448 hints.ai_family = af;
450 if ((rcode = getaddrinfo(src, NULL, &hints, &res)) != 0) {
451 fr_strerror_printf("ip_hton: %s", gai_strerror(rcode));
455 for (ai = res; ai; ai = ai->ai_next) {
456 if ((af == ai->ai_family) || (af == AF_UNSPEC))
461 fr_strerror_printf("ip_hton failed to find requested information for host %.100s", src);
466 rcode = fr_sockaddr2ipaddr((struct sockaddr_storage *)ai->ai_addr,
467 ai->ai_addrlen, dst, NULL);
469 if (!rcode) return -1;
475 * Look IP addresses up, and print names (depending on DNS config)
477 char const *ip_ntoh(fr_ipaddr_t const *src, char *dst, size_t cnt)
479 struct sockaddr_storage ss;
486 if (!fr_dns_lookups) {
487 return inet_ntop(src->af, &(src->ipaddr), dst, cnt);
490 if (!fr_ipaddr2sockaddr(src, 0, &ss, &salen)) {
494 if ((error = getnameinfo((struct sockaddr *)&ss, salen, dst, cnt, NULL, 0,
495 NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
496 fr_strerror_printf("ip_ntoh: %s", gai_strerror(error));
503 static char const *hextab = "0123456789abcdef";
505 /** Convert hex strings to binary data
507 * @param bin Buffer to write output to.
508 * @param hex input string.
509 * @param outlen length of output buffer (or length of input string / 2).
510 * @return length of data written to buffer.
512 size_t fr_hex2bin(uint8_t *bin, char const *hex, size_t outlen)
517 for (i = 0; i < outlen; i++) {
518 if(!(c1 = memchr(hextab, tolower((int) hex[i << 1]), 16)) ||
519 !(c2 = memchr(hextab, tolower((int) hex[(i << 1) + 1]), 16)))
521 bin[i] = ((c1-hextab)<<4) + (c2-hextab);
528 /** Convert binary data to a hex string
530 * Ascii encoded hex string will not be prefixed with '0x'
532 * @warning If the output buffer isn't long enough, we have a buffer overflow.
534 * @param[out] hex Buffer to write hex output.
535 * @param[in] bin input.
536 * @param[in] inlen of bin input.
537 * @return length of data written to buffer.
539 size_t fr_bin2hex(char *hex, uint8_t const *bin, size_t inlen)
543 for (i = 0; i < inlen; i++) {
544 hex[0] = hextab[((*bin) >> 4) & 0x0f];
545 hex[1] = hextab[*bin & 0x0f];
556 * So we don't have ifdef's in the rest of the code
558 #ifndef HAVE_CLOSEFROM
559 int closefrom(int fd)
565 maxfd = sysconf(_SC_OPEN_MAX);
571 if (fd > maxfd) return 0;
574 * FIXME: return EINTR?
578 for (i = fd; i < maxfd; i++) {
586 int fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
588 if (a->af < b->af) return -1;
589 if (a->af > b->af) return +1;
593 return memcmp(&a->ipaddr.ip4addr,
595 sizeof(a->ipaddr.ip4addr));
598 #ifdef HAVE_STRUCT_SOCKADDR_IN6
600 if (a->scope < b->scope) return -1;
601 if (a->scope > b->scope) return +1;
603 return memcmp(&a->ipaddr.ip6addr,
605 sizeof(a->ipaddr.ip6addr));
616 int fr_ipaddr2sockaddr(fr_ipaddr_t const *ipaddr, int port,
617 struct sockaddr_storage *sa, socklen_t *salen)
619 if (ipaddr->af == AF_INET) {
620 struct sockaddr_in s4;
624 memset(&s4, 0, sizeof(s4));
625 s4.sin_family = AF_INET;
626 s4.sin_addr = ipaddr->ipaddr.ip4addr;
627 s4.sin_port = htons(port);
628 memset(sa, 0, sizeof(*sa));
629 memcpy(sa, &s4, sizeof(s4));
631 #ifdef HAVE_STRUCT_SOCKADDR_IN6
632 } else if (ipaddr->af == AF_INET6) {
633 struct sockaddr_in6 s6;
637 memset(&s6, 0, sizeof(s6));
638 s6.sin6_family = AF_INET6;
639 s6.sin6_addr = ipaddr->ipaddr.ip6addr;
640 s6.sin6_port = htons(port);
641 s6.sin6_scope_id = ipaddr->scope;
642 memset(sa, 0, sizeof(*sa));
643 memcpy(sa, &s6, sizeof(s6));
653 int fr_sockaddr2ipaddr(struct sockaddr_storage const *sa, socklen_t salen,
654 fr_ipaddr_t *ipaddr, int *port)
656 if (sa->ss_family == AF_INET) {
657 struct sockaddr_in s4;
659 if (salen < sizeof(s4)) {
660 fr_strerror_printf("IPv4 address is too small");
664 memcpy(&s4, sa, sizeof(s4));
665 ipaddr->af = AF_INET;
666 ipaddr->ipaddr.ip4addr = s4.sin_addr;
667 if (port) *port = ntohs(s4.sin_port);
669 #ifdef HAVE_STRUCT_SOCKADDR_IN6
670 } else if (sa->ss_family == AF_INET6) {
671 struct sockaddr_in6 s6;
673 if (salen < sizeof(s6)) {
674 fr_strerror_printf("IPv6 address is too small");
678 memcpy(&s6, sa, sizeof(s6));
679 ipaddr->af = AF_INET6;
680 ipaddr->ipaddr.ip6addr = s6.sin6_addr;
681 if (port) *port = ntohs(s6.sin6_port);
682 ipaddr->scope = s6.sin6_scope_id;
686 fr_strerror_printf("Unsupported address famility %d",
694 /** Convert UTF8 string to UCS2 encoding
696 * @note Borrowed from src/crypto/ms_funcs.c of wpa_supplicant project (http://hostap.epitest.fi/wpa_supplicant/)
698 * @param[out] out Where to write the ucs2 string.
699 * @param[in] outlen Size of output buffer.
700 * @param[in] in UTF8 string to convert.
701 * @param[in] inlen length of UTF8 string.
702 * @return the size of the UCS2 string written to the output buffer (in bytes).
704 ssize_t fr_utf8_to_ucs2(uint8_t *out, size_t outlen, char const *in, size_t inlen)
707 uint8_t *start = out;
709 for (i = 0; i < inlen; i++) {
713 if ((size_t)(out - start) >= outlen) {
718 /* One-byte encoding */
723 } else if ((i == (inlen - 1)) || ((size_t)(out - start) >= (outlen - 1))) {
724 /* Incomplete surrogate */
729 /* Two-byte encoding */
730 if ((c & 0xe0) == 0xc0) {
731 FR_PUT_LE16(out, ((c & 0x1f) << 6) | (c2 & 0x3f));
735 if ((i == inlen) || ((size_t)(out - start) >= (outlen - 1))) {
736 /* Incomplete surrogate */
740 /* Three-byte encoding */
742 FR_PUT_LE16(out, ((c & 0xf) << 12) | ((c2 & 0x3f) << 6) | (c3 & 0x3f));