From 4272fe4a9344245a61a55fb8d4091f459c235dcc Mon Sep 17 00:00:00 2001 From: Nathan Holstein Date: Sun, 2 Aug 2015 13:30:58 -0400 Subject: [PATCH] Add compatibility functions from OpenBSD. This adds a shim library to mimic features of OpenBSD. Some of these functions are written from scratch, others are simply copies of their OpenBSD namesakes. Current implementation of the from-scratch variants are simply shims that intentionally fail. They'll need to be extended with secure implementations. --- .gitignore | 1 + Makefile | 12 ++- libopenbsd/auth_userokay.c | 21 +++++ libopenbsd/execvpe.c | 156 ++++++++++++++++++++++++++++++++++++ libopenbsd/openbsd.h | 2 + libopenbsd/reallocarray.c | 38 +++++++++ libopenbsd/setresuid.c | 22 +++++ libopenbsd/setusercontext.c | 24 ++++++ libopenbsd/strtonum.c | 65 +++++++++++++++ 9 files changed, 339 insertions(+), 2 deletions(-) create mode 100644 libopenbsd/auth_userokay.c create mode 100644 libopenbsd/execvpe.c create mode 100644 libopenbsd/reallocarray.c create mode 100644 libopenbsd/setresuid.c create mode 100644 libopenbsd/setusercontext.c create mode 100644 libopenbsd/strtonum.c diff --git a/.gitignore b/.gitignore index 970069b..6fd68eb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ doas +*.a *.o *.swp diff --git a/Makefile b/Makefile index 7bb667e..167d8dd 100644 --- a/Makefile +++ b/Makefile @@ -17,11 +17,17 @@ MANDIR?=/usr/share/man default: ${PROG} +OPENBSD:=reallocarray.c strtonum.c execvpe.c setresuid.c \ + auth_userokay.c setusercontext.c +OPENBSD:=$(addprefix libopenbsd/,${OPENBSD:.c=.o}) +libopenbsd.a: ${OPENBSD} + ${AR} -r $@ $? + OBJS:=${SRCS:.y=.c} OBJS:=${OBJS:.c=.o} -${PROG}: ${OBJS} - ${CC} ${COPTS} ${LDOPTS} $^ -o $@ +${PROG}: ${OBJS} libopenbsd.a + ${CC} ${CFLAGS} ${LDFLAGS} $^ -o $@ ${BINDIR}/${PROG}: ${PROG} cp $< $@ @@ -31,6 +37,8 @@ ${BINDIR}/${PROG}: ${PROG} install: ${BINDIR}/${PROG} clean: + rm -f libopenbsd.a + rm -f ${OPENBSD} rm -f ${OBJS} rm -f ${PROG} diff --git a/libopenbsd/auth_userokay.c b/libopenbsd/auth_userokay.c new file mode 100644 index 0000000..3890e03 --- /dev/null +++ b/libopenbsd/auth_userokay.c @@ -0,0 +1,21 @@ +/* Copyright 2015 Nathan Holstein */ + +#include +#include +#include + +#include "openbsd.h" + +int +auth_userokay(char *name, char *style, char *type, char *password) +{ + if (style || type || password) { + fprintf(stderr, "auth_userokay(name, NULL, NULL, NULL)!\n"); + exit(1); + } + + fprintf(stderr, "failing auth check for %s\n", name); + + return 0; +} + diff --git a/libopenbsd/execvpe.c b/libopenbsd/execvpe.c new file mode 100644 index 0000000..f080148 --- /dev/null +++ b/libopenbsd/execvpe.c @@ -0,0 +1,156 @@ +/* $OpenBSD: exec.c,v 1.20 2013/01/08 02:26:09 deraadt Exp $ */ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +int +execvpe(const char *name, char *const *argv, char *const *envp) +{ + char **memp; + int cnt; + size_t lp, ln, len; + char *p; + int eacces = 0; + char *bp, *cur, *path, buf[PATH_MAX]; + + /* + * Do not allow null name + */ + if (name == NULL || *name == '\0') { + errno = ENOENT; + return (-1); + } + + /* If it's an absolute or relative path name, it's easy. */ + if (strchr(name, '/')) { + bp = (char *)name; + cur = path = NULL; + goto retry; + } + bp = buf; + + /* Get the path we're searching. */ + if (!(path = getenv("PATH"))) + path = _PATH_DEFPATH; + len = strlen(path) + 1; + cur = alloca(len); + if (cur == NULL) { + errno = ENOMEM; + return (-1); + } + strlcpy(cur, path, len); + path = cur; + while ((p = strsep(&cur, ":"))) { + /* + * It's a SHELL path -- double, leading and trailing colons + * mean the current directory. + */ + if (!*p) { + p = "."; + lp = 1; + } else + lp = strlen(p); + ln = strlen(name); + + /* + * If the path is too long complain. This is a possible + * security issue; given a way to make the path too long + * the user may execute the wrong program. + */ + if (lp + ln + 2 > sizeof(buf)) { + struct iovec iov[3]; + + iov[0].iov_base = "execvp: "; + iov[0].iov_len = 8; + iov[1].iov_base = p; + iov[1].iov_len = lp; + iov[2].iov_base = ": path too long\n"; + iov[2].iov_len = 16; + (void)writev(STDERR_FILENO, iov, 3); + continue; + } + bcopy(p, buf, lp); + buf[lp] = '/'; + bcopy(name, buf + lp + 1, ln); + buf[lp + ln + 1] = '\0'; + +retry: (void)execve(bp, argv, envp); + switch(errno) { + case E2BIG: + goto done; + case EISDIR: + case ELOOP: + case ENAMETOOLONG: + case ENOENT: + break; + case ENOEXEC: + for (cnt = 0; argv[cnt]; ++cnt) + ; + memp = alloca((cnt + 2) * sizeof(char *)); + if (memp == NULL) + goto done; + memp[0] = "sh"; + memp[1] = bp; + bcopy(argv + 1, memp + 2, cnt * sizeof(char *)); + (void)execve(_PATH_BSHELL, memp, envp); + goto done; + case ENOMEM: + goto done; + case ENOTDIR: + break; + case ETXTBSY: + /* + * We used to retry here, but sh(1) doesn't. + */ + goto done; + case EACCES: + eacces = 1; + break; + default: + goto done; + } + } + if (eacces) + errno = EACCES; + else if (!errno) + errno = ENOENT; +done: + return (-1); +} diff --git a/libopenbsd/openbsd.h b/libopenbsd/openbsd.h index bcf0e3b..5f7c364 100644 --- a/libopenbsd/openbsd.h +++ b/libopenbsd/openbsd.h @@ -1,6 +1,8 @@ #ifndef _LIB_OPENBSD_H_ #define _LIB_OPENBSD_H_ +#include + /* API definitions lifted from OpenBSD src/include */ /* bsd_auth.h */ diff --git a/libopenbsd/reallocarray.c b/libopenbsd/reallocarray.c new file mode 100644 index 0000000..aa70686 --- /dev/null +++ b/libopenbsd/reallocarray.c @@ -0,0 +1,38 @@ +/* $OpenBSD: reallocarray.c,v 1.1 2014/05/08 21:43:49 deraadt Exp $ */ +/* + * Copyright (c) 2008 Otto Moerbeek + * + * 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 + +/* + * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX + * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW + */ +#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) + +void * +reallocarray(void *optr, size_t nmemb, size_t size) +{ + if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && + nmemb > 0 && SIZE_MAX / nmemb < size) { + errno = ENOMEM; + return NULL; + } + return realloc(optr, size * nmemb); +} diff --git a/libopenbsd/setresuid.c b/libopenbsd/setresuid.c new file mode 100644 index 0000000..5837f2b --- /dev/null +++ b/libopenbsd/setresuid.c @@ -0,0 +1,22 @@ +/* Copyright 2015 Nathan Holstein */ + +#include +#include +#include + +/* I don't think we can actually mimic the right semantics? */ +int +setresuid(uid_t ruid, uid_t euid, uid_t suid) +{ + int ret; + if (suid != ruid) { + errno = EPERM; + return -1; + } + if ((ret = setuid(ruid)) != 0) + return ret; + if ((ret = seteuid(euid)) != 0) + return ret; + return 0; +} + diff --git a/libopenbsd/setusercontext.c b/libopenbsd/setusercontext.c new file mode 100644 index 0000000..692b51a --- /dev/null +++ b/libopenbsd/setusercontext.c @@ -0,0 +1,24 @@ +/* Copyright 2015 Nathan Holstein */ + +#include +#include +#include + +#include "openbsd.h" + +int +setusercontext(login_cap_t *lc, struct passwd *pwd, uid_t uid, unsigned int flags) +{ + if (lc != NULL || pwd == NULL || + (flags & ~(LOGIN_SETGROUP | LOGIN_SETPRIORITY | + LOGIN_SETRESOURCES | LOGIN_SETUMASK | + LOGIN_SETUSER)) != 0) { + errno = EINVAL; + return -1; + } + + fprintf(stderr, "failing setusercontext() for %d\n", (int) uid); + + return -1; +} + diff --git a/libopenbsd/strtonum.c b/libopenbsd/strtonum.c new file mode 100644 index 0000000..3725177 --- /dev/null +++ b/libopenbsd/strtonum.c @@ -0,0 +1,65 @@ +/* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */ + +/* + * Copyright (c) 2004 Ted Unangst and Todd Miller + * All rights reserved. + * + * 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 + +#define INVALID 1 +#define TOOSMALL 2 +#define TOOLARGE 3 + +long long +strtonum(const char *numstr, long long minval, long long maxval, + const char **errstrp) +{ + long long ll = 0; + int error = 0; + char *ep; + struct errval { + const char *errstr; + int err; + } ev[4] = { + { NULL, 0 }, + { "invalid", EINVAL }, + { "too small", ERANGE }, + { "too large", ERANGE }, + }; + + ev[0].err = errno; + errno = 0; + if (minval > maxval) { + error = INVALID; + } else { + ll = strtoll(numstr, &ep, 10); + if (numstr == ep || *ep != '\0') + error = INVALID; + else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) + error = TOOSMALL; + else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) + error = TOOLARGE; + } + if (errstrp != NULL) + *errstrp = ev[error].errstr; + errno = ev[error].err; + if (error) + ll = 0; + + return (ll); +} -- 2.39.2