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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
20 * Copyright 2000 The FreeRADIUS server project
23 static const char rcsid[] =
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
42 #include "libradius.h"
50 * Return a printable host name (or IP address in dot notation)
51 * for the supplied IP address.
53 char *ip_hostname(char *buf, size_t buflen, uint32_t ipaddr)
56 #ifdef GETHOSTBYADDRRSTYLE
57 #if (GETHOSTBYADDRRSTYLE == SYSVSTYLE) || (GETHOSTBYADDRRSTYLE == GNUSTYLE)
59 struct hostent result;
65 * No DNS: don't look up host names
67 if (librad_dodns == 0) {
72 #ifdef GETHOSTBYADDRRSTYLE
73 #if GETHOSTBYADDRRSTYLE == SYSVSTYLE
74 hp = gethostbyaddr_r((char *)&ipaddr, sizeof(struct in_addr), AF_INET, &result, buffer, sizeof(buffer), &error);
75 #elif GETHOSTBYADDRRSTYLE == GNUSTYLE
76 if (gethostbyaddr_r((char *)&ipaddr, sizeof(struct in_addr),
77 AF_INET, &result, buffer, sizeof(buffer),
82 hp = gethostbyaddr((char *)&ipaddr, sizeof(struct in_addr), AF_INET);
85 hp = gethostbyaddr((char *)&ipaddr, sizeof(struct in_addr), AF_INET);
88 (strlen((char *)hp->h_name) >= buflen)) {
93 strNcpy(buf, (char *)hp->h_name, buflen);
99 * Return an IP address from a host
100 * name or address in dot notation.
102 uint32_t ip_getaddr(const char *host)
106 #ifdef GETHOSTBYNAMERSTYLE
107 #if (GETHOSTBYNAMERSTYLE == SYSVSTYLE) || (GETHOSTBYNAMERSTYLE == GNUSTYLE)
108 struct hostent result;
114 if ((a = ip_addr(host)) != htonl(INADDR_NONE))
117 #ifdef GETHOSTBYNAMERSTYLE
118 #if GETHOSTBYNAMERSTYLE == SYSVSTYLE
119 hp = gethostbyname_r(host, &result, buffer, sizeof(buffer), &error);
120 #elif GETHOSTBYNAMERSTYLE == GNUSTYLE
121 if (gethostbyname_r(host, &result, buffer, sizeof(buffer),
123 return htonl(INADDR_NONE);
126 hp = gethostbyname(host);
129 hp = gethostbyname(host);
132 return htonl(INADDR_NONE);
136 * Paranoia from a Bind vulnerability. An attacker
137 * can manipulate DNS entries to change the length of the
138 * address. If the length isn't 4, something's wrong.
140 if (hp->h_length != 4) {
141 return htonl(INADDR_NONE);
144 memcpy(&a, hp->h_addr, sizeof(uint32_t));
150 * Return an IP address in standard dot notation
154 const char *ip_ntoa(char *buffer, uint32_t ipaddr)
156 ipaddr = ntohl(ipaddr);
158 sprintf(buffer, "%d.%d.%d.%d",
159 (ipaddr >> 24) & 0xff,
160 (ipaddr >> 16) & 0xff,
161 (ipaddr >> 8) & 0xff,
168 * Return an IP address from
169 * one supplied in standard dot notation.
173 uint32_t ip_addr(const char *ip_str)
177 if (inet_aton(ip_str, &in) == 0)
178 return htonl(INADDR_NONE);
184 * Like strncpy, but always adds \0
186 char *strNcpy(char *dest, const char *src, int n)
190 while ((n > 1) && (*src)) {
203 void rad_lowercase(char *str) {
207 if (isupper((int) *s)) *s = tolower((int) *s);
211 * Remove spaces from a string
213 void rad_rmspace(char *str) {
217 while(ptr && *ptr!='\0') {
218 while(isspace((int) *ptr))
228 * Internal wrapper for locking, to minimize the number of ifdef's
230 * Lock an fd, prefer lockf() over flock()
232 int rad_lockfd(int fd, int lock_len)
234 #if defined(F_LOCK) && !defined(BSD)
235 return lockf(fd, F_LOCK, lock_len);
236 #elif defined(LOCK_EX)
237 return flock(fd, LOCK_EX);
244 fl.l_whence = SEEK_CUR;
245 return fcntl(fd, F_SETLKW, (void *)&fl);
250 * Internal wrapper for locking, to minimize the number of ifdef's
252 * Lock an fd, prefer lockf() over flock()
253 * Nonblocking version.
255 int rad_lockfd_nonblock(int fd, int lock_len)
257 #if defined(F_LOCK) && !defined(BSD)
258 return lockf(fd, F_TLOCK, lock_len);
259 #elif defined(LOCK_EX)
260 return flock(fd, LOCK_EX | LOCK_NB);
267 fl.l_whence = SEEK_CUR;
268 return fcntl(fd, F_SETLK, (void *)&fl);
273 * Internal wrapper for unlocking, to minimize the number of ifdef's
276 * Unlock an fd, prefer lockf() over flock()
278 int rad_unlockfd(int fd, int lock_len)
280 #if defined(F_LOCK) && !defined(BSD)
281 return lockf(fd, F_ULOCK, lock_len);
282 #elif defined(LOCK_EX)
283 return flock(fd, LOCK_UN);
290 fl.l_whence = SEEK_CUR;
291 return fcntl(fd, F_UNLCK, (void *)&fl);
296 * Return an interface-id in standard colon notation
298 char *ifid_ntoa(char *buffer, size_t size, uint8_t *ifid)
300 snprintf(buffer, size, "%x:%x:%x:%x",
301 (ifid[0] << 8) + ifid[1], (ifid[2] << 8) + ifid[3],
302 (ifid[4] << 8) + ifid[5], (ifid[6] << 8) + ifid[7]);
308 * Return an interface-id from
309 * one supplied in standard colon notation.
311 uint8_t *ifid_aton(const char *ifid_str, uint8_t *ifid)
313 static const char xdigits[] = "0123456789abcdef";
315 int num_id = 0, val = 0, idx = 0;
317 for (p = ifid_str; ; ++p) {
318 if (*p == ':' || *p == '\0') {
323 * Drop 'val' into the array.
325 ifid[idx] = (val >> 8) & 0xff;
326 ifid[idx + 1] = val & 0xff;
329 * Must have all entries before
340 } else if ((pch = strchr(xdigits, tolower(*p))) != NULL) {
344 * Dumb version of 'scanf'
347 val |= (pch - xdigits);
355 #ifndef HAVE_INET_PTON
357 * Utility function, so that the rest of the server doesn't
358 * have ifdef's around IPv6 support
360 int inet_pton(int af, const char *src, void *dst)
362 if (af != AF_INET) return -1; /* unsupported */
364 return inet_aton(src, dst);
369 #ifndef HAVE_INET_NTOP
371 * Utility function, so that the rest of the server doesn't
372 * have ifdef's around IPv6 support
374 const char *inet_ntop(int af, const void *src, char *dst, size_t cnt)
379 if (cnt <= 15) return NULL;
381 ipaddr = *(uint32_t *) src;
382 ipaddr = ntohl(ipaddr);
384 snprintf(dst, cnt, "%d.%d.%d.%d",
385 (ipaddr >> 24) & 0xff,
386 (ipaddr >> 16) & 0xff,
387 (ipaddr >> 8) & 0xff,
392 return NULL; /* don't support IPv6 */
398 * Wrappers for IPv4/IPv6 host to IP address lookup.
399 * This API returns only one IP address, of the specified
402 int ip_hton(const char *src, int af, lrad_ipaddr_t *dst)
405 #ifdef GETHOSTBYNAMERSTYLE
406 #if (GETHOSTBYNAMERSTYLE == SYSVSTYLE) || (GETHOSTBYNAMERSTYLE == GNUSTYLE)
407 struct hostent result;
413 if (af != AF_INET) return -1; /* only IPv4 for now */
418 * No DNS lookups, assume it's an IP address.
421 return inet_pton(af, src, &dst->ipaddr.ip4addr);
424 #ifdef GETHOSTBYNAMERSTYLE
425 #if GETHOSTBYNAMERSTYLE == SYSVSTYLE
426 hp = gethostbyname_r(src, &result, buffer, sizeof(buffer), &error);
427 #elif GETHOSTBYNAMERSTYLE == GNUSTYLE
428 if (gethostbyname_r(src, &result, buffer, sizeof(buffer),
430 return htonl(INADDR_NONE);
433 hp = gethostbyname(src);
436 hp = gethostbyname(src);
440 if (hp->h_addrtype != af) return -1; /* not the right address family */
443 * Paranoia from a Bind vulnerability. An attacker
444 * can manipulate DNS entries to change the length of the
445 * address. If the length isn't 4, something's wrong.
447 if (hp->h_length != 4) {
451 memcpy(&dst->ipaddr.ip4addr.s_addr, hp->h_addr,
452 sizeof(dst->ipaddr.ip4addr.s_addr));
458 * Look IP addreses up, and print names (depending on DNS config)
460 const char *ip_ntoh(const lrad_ipaddr_t *src, char *dst, size_t cnt)
463 #ifdef GETHOSTBYADDRRSTYLE
464 #if (GETHOSTBYADDRRSTYLE == SYSVSTYLE) || (GETHOSTBYADDRRSTYLE == GNUSTYLE)
466 struct hostent result;
472 * No DNS: don't look up host names
475 return inet_ntop(src->af, &src->ipaddr, dst, cnt);
478 if (src->af != AF_INET) return NULL; /* invalid */
480 #ifdef GETHOSTBYADDRRSTYLE
481 #if GETHOSTBYADDRRSTYLE == SYSVSTYLE
482 hp = gethostbyaddr_r((const char *)&src->ipaddr.ip4addr.s_addr,
483 sizeof(src->ipaddr.ip4addr.s_addr),
484 src->af, &result, buffer, sizeof(buffer), &error);
485 #elif GETHOSTBYADDRRSTYLE == GNUSTYLE
486 if (gethostbyaddr_r((const char *)&src->ipaddr.ip4addr.s_addr,
487 sizeof(src->ipaddr.ip4addr.s_addr),
488 src->af, &result, buffer, sizeof(buffer),
493 hp = gethostbyaddr((const char *)&src->ipaddr.ip4addr.s_addr,
494 sizeof(src->ipaddr.ip4addr.s_addr), src->af);
497 hp = gethostbyaddr((const char *)&src->ipaddr.ip4addr.s_addr,
498 sizeof(src->ipaddr.ip4addr.s_addr), src->af);
501 (strlen((char *)hp->h_name) >= cnt)) {
502 return inet_ntop(src->af, &src->ipaddr, dst, cnt);
505 strNcpy(dst, (char *)hp->h_name, cnt);
509 static const char *hextab = "0123456789abcdef";
514 * We allow: hex == bin
516 int lrad_hex2bin(const unsigned char *hex, unsigned char *bin, int len)
521 for (i = 0; i < len; i++) {
522 if(!(c1 = memchr(hextab, tolower((int) hex[i << 1]), 16)) ||
523 !(c2 = memchr(hextab, tolower((int) hex[(i << 1) + 1]), 16)))
525 bin[i] = ((c1-hextab)<<4) + (c2-hextab);
535 * If the output buffer isn't long enough, we have a buffer overflow.
537 void lrad_bin2hex(const unsigned char *bin, unsigned char *hex, int len)
541 for (i = 0; i < len; i++) {
542 hex[0] = hextab[((*bin) >> 4) & 0x0f];
543 hex[1] = hextab[*bin & 0x0f];