diff options
Diffstat (limited to 'src/lib/missing.c')
-rw-r--r-- | src/lib/missing.c | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/src/lib/missing.c b/src/lib/missing.c new file mode 100644 index 0000000..95b8c54 --- /dev/null +++ b/src/lib/missing.c @@ -0,0 +1,443 @@ +/* + * missing.c Replacements for functions that are or can be + * missing on some platforms. + * + * Version: $Id$ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * Copyright 2000,2006 The FreeRADIUS server project + */ + +RCSID("$Id$") + +#include <freeradius-devel/libradius.h> + +#include <ctype.h> + +#ifndef HAVE_CRYPT +char *crypt(UNUSED char *key, char *salt) +{ + /*log(L_ERR, "crypt() called but not implemented");*/ + return salt; +} +#endif + +#ifndef HAVE_STRNCASECMP +int strncasecmp(char *s1, char *s2, int n) +{ + int dif; + unsigned char *p1, *p2; + int c1, c2; + + p1 = (unsigned char *)s1; + p2 = (unsigned char *)s2; + dif = 0; + + while (n != 0) { + if (*p1 == 0 && *p2 == 0) + break; + c1 = *p1; + c2 = *p2; + + if (islower(c1)) c1 = toupper(c1); + if (islower(c2)) c2 = toupper(c2); + + if ((dif = c1 - c2) != 0) + break; + p1++; + p2++; + n--; + } + return dif; +} +#endif + +#ifndef HAVE_STRCASECMP +int strcasecmp(char *s1, char *s2) +{ + int l1, l2; + + l1 = strlen(s1); + l2 = strlen(s2); + if (l2 > l1) l1 = l2; + + return strncasecmp(s1, s2, l1); +} +#endif + +#ifndef HAVE_INET_ATON +int inet_aton(char const *cp, struct in_addr *inp) +{ + int a1, a2, a3, a4; + + if (sscanf(cp, "%d.%d.%d.%d", &a1, &a2, &a3, &a4) != 4) + return 0; + + inp->s_addr = htonl((a1 << 24) + (a2 << 16) + (a3 << 8) + a4); + return 1; +} +#endif + +#ifndef HAVE_STRSEP +/* + * Get next token from string *stringp, where tokens are + * possibly-empty strings separated by characters from delim. + * + * Writes NULs into the string at *stringp to end tokens. + * delim need not remain constant from call to call. On + * return, *stringp points past the last NUL written (if there + * might be further tokens), or is NULL (if there are + * definitely no more tokens). + * + * If *stringp is NULL, strsep returns NULL. + */ +char * +strsep(char **stringp, char const *delim) +{ + char *s; + char const *spanp; + int c, sc; + char *tok; + + if ((s = *stringp) == NULL) + return (NULL); + + for (tok = s;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *stringp = s; + return (tok); + } + } while (sc != 0); + } + + return NULL; /* NOTREACHED, but the compiler complains */ +} +#endif + +#ifndef HAVE_LOCALTIME_R +/* + * We use localtime_r() by default in the server. + * + * For systems which do NOT have localtime_r(), we make the + * assumption that localtime() is re-entrant, and returns a + * per-thread data structure. + * + * Even if localtime is NOT re-entrant, this function will + * lower the possibility of race conditions. + */ +struct tm *localtime_r(time_t const *l_clock, struct tm *result) +{ + memcpy(result, localtime(l_clock), sizeof(*result)); + + return result; +} +#endif + +#ifndef HAVE_CTIME_R +/* + * We use ctime_r() by default in the server. + * + * For systems which do NOT have ctime_r(), we make the + * assumption that ctime() is re-entrant, and returns a + * per-thread data structure. + * + * Even if ctime is NOT re-entrant, this function will + * lower the possibility of race conditions. + */ +char *ctime_r(time_t const *l_clock, char *l_buf) +{ + strcpy(l_buf, ctime(l_clock)); + + return l_buf; +} +#endif + +#ifndef HAVE_GMTIME_R +/* + * We use gmtime_r() by default in the server. + * + * For systems which do NOT have gmtime_r(), we make the + * assumption that gmtime() is re-entrant, and returns a + * per-thread data structure. + * + * Even if gmtime is NOT re-entrant, this function will + * lower the possibility of race conditions. + */ +struct tm *gmtime_r(time_t const *l_clock, struct tm *result) +{ + memcpy(result, gmtime(l_clock), sizeof(*result)); + + return result; +} +#endif + +#ifndef HAVE_VDPRINTF +int vdprintf (int fd, char const *format, va_list args) +{ + int ret; + FILE *fp; + int dup_fd; + + dup_fd = dup(fd); + if (dup_fd < 0) return -1; + + fp = fdopen(fd, "w"); + if (!fp) { + close(dup_fd); + return -1; + } + + ret = vfprintf(fp, format, args); + fclose(fp); /* Also closes dup_fd */ + + return ret; +} +#endif + +#ifndef HAVE_GETTIMEOFDAY +#ifdef WIN32 +/* + * Number of micro-seconds between the beginning of the Windows epoch + * (Jan. 1, 1601) and the Unix epoch (Jan. 1, 1970). + * + * This assumes all Win32 compilers have 64-bit support. + */ +#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) || defined(__WATCOMC__) +#define DELTA_EPOCH_IN_USEC 11644473600000000Ui64 +#else +#define DELTA_EPOCH_IN_USEC 11644473600000000ULL +#endif + +static uint64_t filetime_to_unix_epoch (FILETIME const *ft) +{ + uint64_t res = (uint64_t) ft->dwHighDateTime << 32; + + res |= ft->dwLowDateTime; + res /= 10; /* from 100 nano-sec periods to usec */ + res -= DELTA_EPOCH_IN_USEC; /* from Win epoch to Unix epoch */ + return (res); +} + +int gettimeofday (struct timeval *tv, UNUSED void *tz) +{ + FILETIME ft; + uint64_t tim; + + if (!tv) { + errno = EINVAL; + return (-1); + } + GetSystemTimeAsFileTime (&ft); + tim = filetime_to_unix_epoch (&ft); + tv->tv_sec = (long) (tim / 1000000L); + tv->tv_usec = (long) (tim % 1000000L); + return (0); +} +#endif +#endif + +#define NTP_EPOCH_OFFSET 2208988800ULL + +/* + * Convert 'struct timeval' into NTP format (32-bit integer + * of seconds, 32-bit integer of fractional seconds) + */ +void +timeval2ntp(struct timeval const *tv, uint8_t *ntp) +{ + uint32_t sec, usec; + + sec = tv->tv_sec + NTP_EPOCH_OFFSET; + usec = tv->tv_usec * 4295; /* close enough to 2^32 / USEC */ + usec -= ((tv->tv_usec * 2143) >> 16); /* */ + + sec = htonl(sec); + usec = htonl(usec); + + memcpy(ntp, &sec, sizeof(sec)); + memcpy(ntp + sizeof(sec), &usec, sizeof(usec)); +} + +/* + * Inverse of timeval2ntp + */ +void +ntp2timeval(struct timeval *tv, char const *ntp) +{ + uint32_t sec, usec; + + memcpy(&sec, ntp, sizeof(sec)); + memcpy(&usec, ntp + sizeof(sec), sizeof(usec)); + + sec = ntohl(sec); + usec = ntohl(usec); + + tv->tv_sec = sec - NTP_EPOCH_OFFSET; + tv->tv_usec = usec / 4295; /* close enough */ +} + +#if !defined(HAVE_128BIT_INTEGERS) && defined(FR_LITTLE_ENDIAN) +/** Swap byte order of 128 bit integer + * + * @param num 128bit integer to swap. + * @return 128bit integer reversed. + */ +uint128_t ntohlll(uint128_t const num) +{ + uint64_t const *p = (uint64_t const *) # + uint64_t ret[2]; + + /* swapsies */ + ret[1] = ntohll(p[0]); + ret[0] = ntohll(p[1]); + + return *(uint128_t *)ret; +} +#endif + +#ifdef HAVE_OPENSSL_HMAC_H +# ifndef HAVE_HMAC_CTX_NEW +HMAC_CTX *HMAC_CTX_new(void) +{ + HMAC_CTX *ctx; + ctx = OPENSSL_malloc(sizeof(*ctx)); + if (!ctx) return NULL; + + memset(ctx, 0, sizeof(*ctx)); + HMAC_CTX_init(ctx); + return ctx; +} +# endif +# ifndef HAVE_HMAC_CTX_FREE +void HMAC_CTX_free(HMAC_CTX *ctx) +{ + if (ctx == NULL) { + return; + } + HMAC_CTX_cleanup(ctx); + OPENSSL_free(ctx); +} +# endif +#endif + +#ifdef HAVE_OPENSSL_SSL_H +# ifndef HAVE_SSL_GET_CLIENT_RANDOM +size_t SSL_get_client_random(const SSL *s, unsigned char *out, size_t outlen) +{ + if (!outlen) return sizeof(s->s3->client_random); + + if (outlen > sizeof(s->s3->client_random)) outlen = sizeof(s->s3->client_random); + + memcpy(out, s->s3->client_random, outlen); + return outlen; +} +# endif +# ifndef HAVE_SSL_GET_SERVER_RANDOM +size_t SSL_get_server_random(const SSL *s, unsigned char *out, size_t outlen) +{ + if (!outlen) return sizeof(s->s3->server_random); + + if (outlen > sizeof(s->s3->server_random)) outlen = sizeof(s->s3->server_random); + + memcpy(out, s->s3->server_random, outlen); + return outlen; +} +# endif +# ifndef HAVE_SSL_SESSION_GET_MASTER_KEY +size_t SSL_SESSION_get_master_key(const SSL_SESSION *s, + unsigned char *out, size_t outlen) +{ + if (!outlen) return s->master_key_length; + + if (outlen > (size_t)s->master_key_length) outlen = (size_t)s->master_key_length; + + memcpy(out, s->master_key, outlen); + return outlen; +} +# endif +#endif + +/** Call talloc strdup, setting the type on the new chunk correctly + * + * For some bizarre reason the talloc string functions don't set the + * memory chunk type to char, which causes all kinds of issues with + * verifying VALUE_PAIRs. + * + * @param[in] t The talloc context to hang the result off. + * @param[in] p The string you want to duplicate. + * @return The duplicated string, NULL on error. + */ +char *talloc_typed_strdup(void const *t, char const *p) +{ + char *n; + + n = talloc_strdup(t, p); + if (!n) return NULL; + talloc_set_type(n, char); + + return n; +} + +/** Call talloc vasprintf, setting the type on the new chunk correctly + * + * For some bizarre reason the talloc string functions don't set the + * memory chunk type to char, which causes all kinds of issues with + * verifying VALUE_PAIRs. + * + * @param[in] t The talloc context to hang the result off. + * @param[in] fmt The format string. + * @return The formatted string, NULL on error. + */ +char *talloc_typed_asprintf(void const *t, char const *fmt, ...) +{ + char *n; + va_list ap; + + va_start(ap, fmt); + n = talloc_vasprintf(t, fmt, ap); + va_end(ap); + if (!n) return NULL; + talloc_set_type(n, char); + + return n; +} + +/** Binary safe strndup function + * + * @param[in] t The talloc context o allocate new buffer in. + * @param[in] in String to dup, may contain embedded '\0'. + * @param[in] inlen Number of bytes to dup. + * @return duped string. + */ +char *talloc_bstrndup(void const *t, char const *in, size_t inlen) +{ + char *p; + + p = talloc_array(t, char, inlen + 1); + if (!p) return NULL; + memcpy(p, in, inlen); + p[inlen] = '\0'; + + return p; +} + |