From 9b4d748b44e2c3456d462369fa5670982855ece2 Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Wed, 31 Dec 2014 18:27:14 -0600 Subject: [PATCH] initial OS X support Well, support may be too concrete of a term. There is a lot that is missing in OS X, and not everything can be implemented with portability shims. The time APIs in OS X seem to have frozen with NeXTSTEP and never advanced with POSIX. --- Makefile.am | 18 ++++++++++ bsd-adjfreq.c | 19 +++++++++++ compat/bsd-setresgid.c | 38 +++++++++++++++++++++ compat/bsd-setresuid.c | 67 +++++++++++++++++++++++++++++++++++++ compat/clock_getres.c | 47 ++++++++++++++++++++++++++ compat/mach-clock_gettime.c | 44 ++++++++++++++++++++++++ configure.ac | 21 +++++++++--- include/time.h | 25 ++++++++++++++ include/unistd.h | 8 +++++ 9 files changed, 283 insertions(+), 4 deletions(-) create mode 100644 compat/bsd-setresgid.c create mode 100644 compat/bsd-setresuid.c create mode 100644 compat/clock_getres.c create mode 100644 compat/mach-clock_gettime.c create mode 100644 include/time.h diff --git a/Makefile.am b/Makefile.am index 54d9a67..862a22b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -94,6 +94,24 @@ libcompat_la_SOURCES += compat/imsg.c libcompat_la_SOURCES += compat/imsg-buffer.c endif +if !HAVE_CLOCK_GETRES +libcompat_la_SOURCES += compat/clock_getres.c +endif + +if !HAVE_SETRESGID +libcompat_la_SOURCES += compat/bsd-setresgid.c +endif + +if !HAVE_SETRESUID +libcompat_la_SOURCES += compat/bsd-setresuid.c +endif + +if !HAVE_CLOCK_GETTIME +if HOST_DARWIN +libcompat_la_SOURCES += compat/mach-clock_gettime.c +endif +endif + if !HAVE_ARC4RANDOM libcompat_la_SOURCES += compat/arc4random.c diff --git a/bsd-adjfreq.c b/bsd-adjfreq.c index dd1eae0..b2f5d1f 100644 --- a/bsd-adjfreq.c +++ b/bsd-adjfreq.c @@ -30,6 +30,23 @@ #include "ntp.h" #include "ntpd.h" +#ifndef NTP_ADJTIME + +#include + +/* + * Some sad but very popular platforms do not appear to provide a mechanism to + * adjust the time frequency at all! + */ +int +adjfreq(const int64_t *freq, int64_t *oldfreq) +{ + errno = ENOSYS; + return -1; +} + +#else + /* * adjfreq (old)freq = nanosec. per seconds shifted left 32 bits * timex.freq is ppm / left shifted by SHIFT_USEC (16 bits), defined in timex.h @@ -69,3 +86,5 @@ adjfreq(const int64_t *freq, int64_t *oldfreq) return 0; } + +#endif diff --git a/compat/bsd-setresgid.c b/compat/bsd-setresgid.c new file mode 100644 index 0000000..320e8f0 --- /dev/null +++ b/compat/bsd-setresgid.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2004, 2005 Darren Tucker (dtucker at zip com au). + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +int +setresgid(gid_t rgid, gid_t egid, gid_t sgid) +{ + /* this is the only configuration tested */ + if (rgid != egid || egid != sgid) + return -1; + + # if defined(HAVE_SETREGID) && !defined(BROKEN_SETREGID) + if (setregid(rgid, egid) == -1) + return -1; + # else + if (setegid(egid) == -1) + return -1; + if (setgid(rgid)) == -1) + return -1; + # endif + + return 0; +} diff --git a/compat/bsd-setresuid.c b/compat/bsd-setresuid.c new file mode 100644 index 0000000..546ce89 --- /dev/null +++ b/compat/bsd-setresuid.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2004, 2005 Darren Tucker (dtucker at zip com au). + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include + +int +setresuid(uid_t ruid, uid_t euid, uid_t suid) +{ + uid_t ouid; + int ret = -1; + + /* Allow only the tested configuration. */ + if (ruid != euid || euid != suid) { + errno = ENOSYS; + return -1; + } + ouid = getuid(); + +# if defined(HAVE_SETREUID) && !defined(BROKEN_SETREUID) + if ((ret = setreuid(euid, euid)) == -1) + return -1; +# else +# ifndef SETEUID_BREAKS_SETUID + if (seteuid(euid) == -1) + return -1; +# endif + if ((ret = setuid(ruid)) == -1) + return -1; +# endif + + /* + * When real, effective and saved uids are the same and we have + * changed uids, sanity check that we cannot restore the old uid. + */ + if (ruid == euid && euid == suid && ouid != ruid && + setuid(ouid) != -1 && seteuid(ouid) != -1) { + errno = EINVAL; + return -1; + } + + /* + * Finally, check that the real and effective uids are what we + * expect. + */ + if (getuid() != ruid || geteuid() != euid) { + errno = EACCES; + return -1; + } + + return ret; +} diff --git a/compat/clock_getres.c b/compat/clock_getres.c new file mode 100644 index 0000000..bdf11e9 --- /dev/null +++ b/compat/clock_getres.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 1999-2004 Damien Miller + * Copyright (c) 2004 Darren Tucker + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#ifdef HAVE_ADJTIMEX +#include +#endif + +int +clock_getres(clockid_t clk_id, struct timespec *tp) +{ +# ifdef HAVE_ADJTIMEX + struct timex tmx; +# endif + + if (clk_id != CLOCK_REALTIME) + return -1; /* not implemented */ + + tp->tv_sec = 0; + +# ifdef HAVE_ADJTIMEX + tmx.modes = 0; + if (adjtimex(&tmx) == -1) + return -1; + else + tp->tv_nsec = tmx.precision * 1000; /* usec -> nsec */ +# else + /* assume default 10ms tick */ + tp->tv_nsec = 10000000; +# endif + return 0; +} diff --git a/compat/mach-clock_gettime.c b/compat/mach-clock_gettime.c new file mode 100644 index 0000000..0441a49 --- /dev/null +++ b/compat/mach-clock_gettime.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 1999-2004 Damien Miller + * Copyright (c) 2014 Brent Cook + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include +#include + +int +clock_gettime(clockid_t clk_id, struct timespec *ts) +{ + static uint64_t timebase_factor = 0; + mach_timebase_info_data_t timebase_info; + uint64_t nsec; + + if (clk_id != CLOCK_REALTIME) + return -1; /* not implemented */ + + if (timebase_factor == 0) { + mach_timebase_info(&timebase_info); + timebase_factor = timebase_info.numer / timebase_info.denom; + } + + nsec = mach_absolute_time() * timebase_factor; + ts->tv_sec = nsec / 1000000000UL; + ts->tv_nsec = nsec % 1000000000UL; + + return 0; +} diff --git a/configure.ac b/configure.ac index 9adc9fa..d4e62d8 100644 --- a/configure.ac +++ b/configure.ac @@ -12,6 +12,10 @@ CFLAGS="$CFLAGS -Wall -std=gnu99 -g" case $host_os in *darwin*) HOST_OS=darwin + AC_DEFINE(SETEUID_BREAKS_SETUID,[],[setuid after seteuid doesn't work]) + AC_DEFINE(BROKEN_SETREUID,[], [Broken setreuid]) + AC_DEFINE(BROKEN_SETREGID,[], [Broken setregid]) + AC_DEFINE(YYSTYPE_IS_DECLARED,[], [Broken bison]) ;; *freebsd*) HOST_OS=freebsd @@ -41,6 +45,9 @@ AM_CONDITIONAL([HOST_SOLARIS], [test x$HOST_OS = xsolaris]) AC_CHECK_FUNC([clock_gettime],, [AC_SEARCH_LIBS([clock_gettime],[rt posix4])]) +AC_CHECK_FUNC([clock_getres],, + [AC_SEARCH_LIBS([clock_getres],[rt posix4])]) + AC_CHECK_FUNC([dl_iterate_phdr],, [AC_SEARCH_LIBS([dl_iterate_phdr],[dl])]) @@ -74,9 +81,11 @@ CFLAGS="$CFLAGS $CLANG_CFLAGS" LDFLAGS="$LDFLAGS $CLANG_FLAGS" # check functions that are expected to be in libc -AC_CHECK_FUNCS([adjfreq arc4random_uniform asprintf explicit_bzero]) +AC_CHECK_FUNCS([adjfreq ntp_adjtime adjtimex]) +AC_CHECK_FUNCS([arc4random_uniform asprintf explicit_bzero]) AC_CHECK_FUNCS([getentropy memmem poll reallocarray]) AC_CHECK_FUNCS([setproctitle setgroups]) +AC_CHECK_FUNCS([setregid setresgid setreuid setresuid]) AC_CHECK_FUNCS([strlcat strlcpy strndup strnlen strtonum]) # check auxiliary libraries that might contain other functions @@ -92,21 +101,25 @@ AM_CONDITIONAL([HAVE_ADJFREQ], [test "x$ac_cv_func_adjfreq" = xyes]) AM_CONDITIONAL([HAVE_ARC4RANDOM], [test "x$ac_cv_func_arc4random" = xyes]) AM_CONDITIONAL([HAVE_ARC4RANDOM_UNIFORM], [test "x$ac_cv_func_arc4random_uniform" = xyes]) AM_CONDITIONAL([HAVE_ASPRINTF], [test "x$ac_cv_func_asprintf" = xyes]) +AM_CONDITIONAL([HAVE_CLOCK_GETRES], [test "x$ac_cv_func_clock_getres" = xyes]) +AM_CONDITIONAL([HAVE_CLOCK_GETTIME], [test "x$ac_cv_func_clock_gettime" = xyes]) AM_CONDITIONAL([HAVE_EXPLICIT_BZERO], [test "x$ac_cv_func_explicit_bzero" = xyes]) AM_CONDITIONAL([HAVE_GETENTROPY], [test "x$ac_cv_func_getentropy" = xyes]) +AM_CONDITIONAL([HAVE_IMSG], [test "x$ac_cv_func_ibuf_open" = xyes]) +AM_CONDITIONAL([HAVE_MD5], [test "x$ac_cv_func_MD5Init" = xyes]) AM_CONDITIONAL([HAVE_MEMMEM], [test "x$ac_cv_func_memmem" = xyes]) AM_CONDITIONAL([HAVE_POLL], [test "x$ac_cv_func_poll" = xyes]) AM_CONDITIONAL([HAVE_REALLOCARRAY], [test "x$ac_cv_func_reallocarray" = xyes]) AM_CONDITIONAL([HAVE_SETGROUPS], [test "x$ac_cv_func_setgroups" = xyes]) +AM_CONDITIONAL([HAVE_SETRESGID], [test "x$ac_cv_func_setresgid" = xyes]) +AM_CONDITIONAL([HAVE_SETRESUID], [test "x$ac_cv_func_setresuid" = xyes]) AM_CONDITIONAL([HAVE_SETPROCTITLE], [test "x$ac_cv_func_setproctitle" = xyes]) +AM_CONDITIONAL([HAVE_SHA512], [test "x$ac_cv_func_SHA512Init" = xyes]) AM_CONDITIONAL([HAVE_STRLCAT], [test "x$ac_cv_func_strlcat" = xyes]) AM_CONDITIONAL([HAVE_STRLCPY], [test "x$ac_cv_func_strlcpy" = xyes]) AM_CONDITIONAL([HAVE_STRNDUP], [test "x$ac_cv_func_strndup" = xyes]) AM_CONDITIONAL([HAVE_STRNLEN], [test "x$ac_cv_func_strnlen" = xyes]) AM_CONDITIONAL([HAVE_STRTONUM], [test "x$ac_cv_func_strtonum" = xyes]) -AM_CONDITIONAL([HAVE_MD5], [test "x$ac_cv_func_MD5Init" = xyes]) -AM_CONDITIONAL([HAVE_SHA512], [test "x$ac_cv_func_SHA512Init" = xyes]) -AM_CONDITIONAL([HAVE_IMSG], [test "x$ac_cv_func_ibuf_open" = xyes]) # overrides for arc4random_buf implementations with known issues AM_CONDITIONAL([HAVE_ARC4RANDOM], diff --git a/include/time.h b/include/time.h new file mode 100644 index 0000000..1eb844b --- /dev/null +++ b/include/time.h @@ -0,0 +1,25 @@ +/* + * Public domain + * time.h compatibility shim + */ + +#include_next + +#ifndef LIBCOMPAT_TIME_H +#define LIBCOMPAT_TIME_H + +#ifndef CLOCK_REALTIME +typedef int clockid_t; +#define CLOCK_REALTIME 1 +#define CLOCK_MONOTONIC 2 +#endif + +#ifndef HAVE_CLOCK_GETRES +int clock_getres(clockid_t clk_id, struct timespec *res); +#endif + +#ifndef HAVE_CLOCK_GETTIME +int clock_gettime(clockid_t clk_id, struct timespec *ts); +#endif + +#endif diff --git a/include/unistd.h b/include/unistd.h index 6b8199a..31c1c67 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -18,4 +18,12 @@ int getentropy(void *buf, size_t buflen); int setgroups(int ngroups, const gid_t *gidset); #endif +#ifndef HAVE_SETRESGID +int setresgid(gid_t rgid, gid_t egid, gid_t sgid); +#endif + +#ifndef HAVE_SETRESUID +int setresuid(uid_t ruid, uid_t euid, uid_t suid); +#endif + #endif