]> git.armaanb.net Git - opendoas.git/commitdiff
add back execvpe fallback
authorDuncan Overbruck <mail@duncano.de>
Thu, 12 Nov 2020 16:48:28 +0000 (17:48 +0100)
committerDuncan Overbruck <mail@duncano.de>
Thu, 12 Nov 2020 21:29:09 +0000 (22:29 +0100)
configure
libopenbsd/execvpe.c [new file with mode: 0644]

index 632c74afff96c96218522059ef611accc8a6eca0..94ded41f2d0042253160c2b9b2c1721d47f4e09e 100755 (executable)
--- a/configure
+++ b/configure
@@ -360,7 +360,9 @@ int main(void) {
        execvpe("", p, p);
        return 0;
 }'
-check_func "execvpe" "$src" || die "system has no execvpe(3): not supported"
+check_func "execvpe" "$src" || {
+       printf 'SRCS += libopenbsd/execvpe.c\n' >>$CONFIG_MK
+}
 
 #
 # Check for setresuid().
diff --git a/libopenbsd/execvpe.c b/libopenbsd/execvpe.c
new file mode 100644 (file)
index 0000000..223daf4
--- /dev/null
@@ -0,0 +1,160 @@
+/*     $OpenBSD: exec.c,v 1.23 2016/03/13 18:34:20 guenther 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 "config.h"
+
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "openbsd.h"
+
+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);
+}