]> git.armaanb.net Git - opendoas.git/commitdiff
Merge doas.c 1.34 from OpenBSD CVS.
authorNathan Holstein <nathan.holstein@gmail.com>
Wed, 5 Aug 2015 15:01:36 +0000 (11:01 -0400)
committerNathan Holstein <nathan.holstein@gmail.com>
Wed, 5 Aug 2015 16:38:09 +0000 (12:38 -0400)
16 files changed:
.git-author-conv-file [new file with mode: 0644]
.gitignore [new file with mode: 0644]
LICENSE [new file with mode: 0644]
Makefile
README.md [new file with mode: 0644]
bsd.prog.mk [new file with mode: 0644]
doas.c
libopenbsd/auth_userokay.c [new file with mode: 0644]
libopenbsd/execvpe.c [new file with mode: 0644]
libopenbsd/explicit_bzero.c [new file with mode: 0644]
libopenbsd/openbsd.h [new file with mode: 0644]
libopenbsd/reallocarray.c [new file with mode: 0644]
libopenbsd/setresuid.c [new file with mode: 0644]
libopenbsd/setusercontext.c [new file with mode: 0644]
libopenbsd/strtonum.c [new file with mode: 0644]
parse.y

diff --git a/.git-author-conv-file b/.git-author-conv-file
new file mode 100644 (file)
index 0000000..7a0a29a
--- /dev/null
@@ -0,0 +1,11 @@
+bcallah=Brian Callahan <bcallah@devio.us>
+benno= <benno@openbsd.org>
+bentley= <bentley@openbsd.org>
+deraadt=Theo de Raadt <deraadt@openbsd.org>
+doug= <doug@openbsd.org>
+espie=Marc Espie <espie@openbsd.org>
+jmc=Jean-Marie Cannie <jmc@openbsd.org>
+nicm=Nicholas Marriott <nicm@openbsd.org>
+schwarze=Ingo Schwarze <schwarze@openbsd.org>
+tedu=Ted Unangst <tedu@openbsd.org>
+zhuk=Vadim Zhukov <zhuk@openbsd.org>
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..6fd68eb
--- /dev/null
@@ -0,0 +1,7 @@
+doas
+
+*.a
+*.o
+
+*.swp
+*.swo
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..0c16551
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,7 @@
+portions copyright (c) 2015 Nathan Holstein
+portions copyright (c) 2015 Ted Unangst
+
+To the best of my knowledge, everything is released under the BSD license.
+
+Additional bits copyright of their respective authors, see individual
+files for details.
index 191d00faedbe4910211c71ec01af44ad916c63ff..f2277ab8bbc9a649b23569cbcc4da084e753629c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -6,9 +6,11 @@ PROG=  doas
 MAN=   doas.1 doas.conf.5
 
 BINOWN= root
-BINMODE=4555
+BINGRP= wheel
+BINMODE=4511
 
-CFLAGS+= -I${.CURDIR}
-COPTS+=        -Wall
+CFLAGS+= -I${CURDIR}
+COPTS+= -Wall -Wextra -Werror -pedantic -std=c11
+LDFLAGS+= -lpam
 
-.include <bsd.prog.mk>
+include bsd.prog.mk
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..ca08ca7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,51 @@
+# OpenDoas: a portable version of OpenBSD's `doas` command
+
+`doas` is a minimal replacement for the venerable `sudo`. It was
+initially [written by Ted Unangst](http://www.tedunangst.com/flak/post/doas)
+of the OpenBSD project to provide 95% of the features of `sudo` with a
+fraction of the codebase.
+
+This is still a work in progress! Please do not deploy yet in a critical
+environment! Of note, `doas` semantics may yet change, and I haven't
+completed PAM integration yet!
+
+## Building and installing
+
+Building `doas` should be just a simple `make` away.
+
+The included makefile also has an installation target. Installation
+requires root access to properly set the executable permissions. You'll
+also need to install a `doas.conf` file:
+
+```
+make && sudo make install
+echo "permit :admin" | sudo tee /etc/doas.conf
+```
+
+Oh the irony, using `sudo` to install `doas`!
+
+## About the port
+
+As much as possible I've attempted to stick to `doas` as tedu desired
+it. As things stand it's essentially just code lifted from OpenBSD with
+PAM based authentication glommed on to it.
+
+I've used cvsync and git-cvsimport to retain the history of the core
+source files. I may choose to go back and do the same with some of the
+compatibility functions (such as reallocarray.c).
+
+I have found it necessary to make some fixes to the codebase. One was
+a segfault due to differences in yacc/bison, others were just minor
+fixes to warnings. Once this appears stable, I may try to upstream some
+of these.
+
+Currently, this is only tested on MacOSX 10.10 with Clang. My next goal
+is support for Fedora Linux as well. Contributions gladly accepted. ;-)
+
+## Copyright
+
+All code from OpenBSD is licensed under the BSD license, please see
+individual files for details as the specific text varies from file to
+file.
+
+All code I've written is licensed with the 2-clause BSD.
diff --git a/bsd.prog.mk b/bsd.prog.mk
new file mode 100644 (file)
index 0000000..197455a
--- /dev/null
@@ -0,0 +1,45 @@
+# Copyright 2015 Nathan Holstein
+
+BINDIR?=/usr/bin
+MANDIR?=/usr/share/man
+
+default: ${PROG}
+
+OPENBSD:=reallocarray.c strtonum.c execvpe.c setresuid.c \
+       auth_userokay.c setusercontext.c explicit_bzero.c
+OPENBSD:=$(addprefix libopenbsd/,${OPENBSD:.c=.o})
+libopenbsd.a: ${OPENBSD}
+       ${AR} -r $@ $?
+
+CFLAGS:=${CFLAGS} -I${CURDIR}/libopenbsd ${COPTS}
+
+OBJS:=${SRCS:.y=.c}
+OBJS:=${OBJS:.c=.o}
+
+${PROG}: ${OBJS} libopenbsd.a
+       ${CC} ${CFLAGS} ${LDFLAGS} $^ -o $@
+
+.%.chmod: %
+       cp $< $@
+       chmod ${BINMODE} $@
+       chown ${BINOWN}:${BINGRP} $@
+
+${BINDIR}:
+       mkdir -pm 0755 $@
+
+${BINDIR}/${PROG}: .${PROG}.chmod ${BINDIR}
+       mv $< $@
+
+MAN:=$(join $(addprefix ${MANDIR}/man,$(patsubst .%,%/,$(suffix ${MAN}))),${MAN})
+$(foreach M,${MAN},$(eval $M: $(notdir $M); cp $$< $$@))
+
+install: ${BINDIR}/${PROG} ${MAN}
+
+clean:
+       rm -f libopenbsd.a
+       rm -f ${OPENBSD}
+       rm -f ${OBJS}
+       rm -f ${PROG}
+
+.PHONY: default clean install man
+.INTERMEDIATE: .${PROG}.chmod
diff --git a/doas.c b/doas.c
index a7c7be238d3f971eadc504037bf9324b60b688f7..f0cbab295bfb265cc4c03f9bf2e4077c0e68d293 100644 (file)
--- a/doas.c
+++ b/doas.c
@@ -19,8 +19,6 @@
 #include <sys/stat.h>
 
 #include <limits.h>
-#include <login_cap.h>
-#include <bsd_auth.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -31,6 +29,8 @@
 #include <syslog.h>
 #include <errno.h>
 
+#include "openbsd.h"
+
 #include "doas.h"
 
 static void __dead
@@ -45,9 +45,11 @@ arraylen(const char **arr)
 {
        size_t cnt = 0;
 
-       while (*arr) {
-               cnt++;
-               arr++;
+       if (arr) {
+               while (*arr) {
+                       cnt++;
+                       arr++;
+               }
        }
        return cnt;
 }
@@ -162,10 +164,7 @@ parseconfig(const char *filename, int checkperms)
 
        yyfp = fopen(filename, "r");
        if (!yyfp) {
-               if (checkperms)
-                       fprintf(stderr, "doas is not enabled.\n");
-               else
-                       warn("could not open config file");
+               warn("could not open config file");
                exit(1);
        }
 
@@ -188,10 +187,10 @@ parseconfig(const char *filename, int checkperms)
  * Copy the environment variables in safeset from oldenvp to envp.
  */
 static int
-copyenvhelper(const char **oldenvp, const char **safeset, int nsafe,
+copyenvhelper(const char **oldenvp, const char **safeset, size_t nsafe,
     char **envp, int ei)
 {
-       int i;
+       size_t i;
 
        for (i = 0; i < nsafe; i++) {
                const char **oe = oldenvp;
@@ -224,8 +223,8 @@ copyenv(const char **oldenvp, struct rule *rule)
        char **envp;
        const char **extra;
        int ei;
-       int nsafe, nbad;
-       int nextras = 0;
+       size_t nsafe, nbad;
+       size_t nextras = 0;
 
        /* if there was no envvar whitelist, pass all except badset ones */
        nbad = arraylen(badset);
diff --git a/libopenbsd/auth_userokay.c b/libopenbsd/auth_userokay.c
new file mode 100644 (file)
index 0000000..9c89625
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2015 Nathan Holstein <nathan.holstein@gmail.com>
+ *
+ * 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 <sys/types.h>
+#include <errno.h>
+#include <pwd.h>
+#include <readpassphrase.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <security/pam_appl.h>
+
+#include "openbsd.h"
+
+#define PAM_SERVICE "sudo"
+
+#define __UNUSED __attribute__ ((unused))
+
+static int
+pam_conv(__UNUSED int huh, __UNUSED const struct pam_message **msg,
+               __UNUSED struct pam_response **rsp, __UNUSED void *ptr)
+{
+       return 0;
+}
+
+static struct pam_conv conv = {
+       .conv = pam_conv,
+       .appdata_ptr = NULL,
+};
+
+static int
+check_pam(const char *user)
+{
+       fprintf(stderr, "check_pam(%s)\n", user);
+
+       int ret;
+       pam_handle_t *pamh = NULL;
+
+       ret = pam_start(PAM_SERVICE, user, &conv, &pamh);
+       if (ret != 0) {
+               fprintf(stderr, "pam_start(\"%s\", \"%s\", ?, ?): failed\n",
+                               PAM_SERVICE, user);
+               return -1;
+       }
+
+       if ((ret = pam_close_session(pamh, 0)) != 0) {
+               fprintf(stderr, "pam_close_session(): %s\n", pam_strerror(pamh, ret));
+               return -1;
+       }
+
+       return 0;
+}
+
+int
+auth_userokay(char *name, char *style, char *type, char *password)
+{
+       if (!name)
+               return 0;
+       if (style || type || password) {
+               fprintf(stderr, "auth_userokay(name, NULL, NULL, NULL)!\n");
+               exit(1);
+       }
+
+       int ret = check_pam(name);
+       if (ret != 0) {
+               fprintf(stderr, "PAM authentication failed\n");
+               return 0;
+       }
+
+       /*
+       char passbuf[256];
+       if (readpassphrase("Password: ", passbuf, sizeof(passbuf),
+                       RPP_REQUIRE_TTY) == NULL)
+               return 0;
+
+       explicit_bzero(passbuf, sizeof(passbuf));
+       */
+
+       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 (file)
index 0000000..f080148
--- /dev/null
@@ -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 <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>
+
+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/explicit_bzero.c b/libopenbsd/explicit_bzero.c
new file mode 100644 (file)
index 0000000..9a646c6
--- /dev/null
@@ -0,0 +1,21 @@
+/*     $OpenBSD: explicit_bzero.c,v 1.2 2014/06/10 04:17:37 deraadt Exp $ */
+/*
+ * Public domain.
+ * Written by Matthew Dempsky.
+ */
+
+#include <string.h>
+
+#define __UNUSED __attribute__ ((unused))
+
+__attribute__((weak)) void
+__explicit_bzero_hook(__UNUSED void *buf, __UNUSED size_t len)
+{
+}
+
+void
+explicit_bzero(void *buf, size_t len)
+{
+       memset(buf, 0, len);
+       __explicit_bzero_hook(buf, len);
+}
diff --git a/libopenbsd/openbsd.h b/libopenbsd/openbsd.h
new file mode 100644 (file)
index 0000000..1fa73af
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef _LIB_OPENBSD_H_
+#define _LIB_OPENBSD_H_
+
+#include <sys/types.h>
+
+/* API definitions lifted from OpenBSD src/include */
+
+/* bsd_auth.h */
+int auth_userokay(char *, char *, char *, char *);
+
+/* login_cap.h */
+#define        LOGIN_SETGROUP          0x0001  /* Set group */
+#define        LOGIN_SETLOGIN          0x0002  /* Set login */
+#define        LOGIN_SETPATH           0x0004  /* Set path */
+#define        LOGIN_SETPRIORITY       0x0008  /* Set priority */
+#define        LOGIN_SETRESOURCES      0x0010  /* Set resource limits */
+#define        LOGIN_SETUMASK          0x0020  /* Set umask */
+#define        LOGIN_SETUSER           0x0040  /* Set user */
+#define        LOGIN_SETENV            0x0080  /* Set environment */
+#define        LOGIN_SETALL            0x00ff  /* Set all. */
+
+typedef struct login_cap login_cap_t;
+struct passwd;
+int setusercontext(login_cap_t *, struct passwd *, uid_t, unsigned int);
+
+/* pwd.h */
+#define _PW_NAME_LEN 63
+
+/* stdlib.h */
+void * reallocarray(void *optr, size_t nmemb, size_t size);
+long long strtonum(const char *numstr, long long minval,
+               long long maxval, const char **errstrp);
+
+/* string.h */
+void explicit_bzero(void *, size_t);
+
+/* unistd.h */
+int execvpe(const char *, char *const *, char *const *);
+int setresuid(uid_t, uid_t, uid_t);
+
+#endif
diff --git a/libopenbsd/reallocarray.c b/libopenbsd/reallocarray.c
new file mode 100644 (file)
index 0000000..aa70686
--- /dev/null
@@ -0,0 +1,38 @@
+/*     $OpenBSD: reallocarray.c,v 1.1 2014/05/08 21:43:49 deraadt Exp $        */
+/*
+ * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
+ *
+ * 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 <sys/types.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+/*
+ * 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 (file)
index 0000000..a62b19a
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015 Nathan Holstein <nathan.holstein@gmail.com>
+ *
+ * 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 <sys/types.h>
+#include <errno.h>
+#include <unistd.h>
+
+/* 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 (file)
index 0000000..a6a9aef
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015 Nathan Holstein <nathan.holstein@gmail.com>
+ *
+ * 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 <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "openbsd.h"
+
+int
+setusercontext(login_cap_t *lc, struct passwd *pw, uid_t uid, unsigned int flags)
+{
+       int ret;
+
+       if (lc != NULL || pw == NULL ||
+                       (flags & ~(LOGIN_SETGROUP | LOGIN_SETPRIORITY |
+                                  LOGIN_SETRESOURCES | LOGIN_SETUMASK |
+                                  LOGIN_SETUSER)) != 0) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (flags & LOGIN_SETGROUP) {
+               if ((ret = setgid(pw->pw_gid)) != 0)
+                       return ret;
+               if ((ret = initgroups(pw->pw_name, pw->pw_gid)) != 0)
+                       return ret;
+       }
+
+       if (flags & LOGIN_SETPRIORITY) {
+               if ((ret = setpriority(PRIO_PROCESS, getpid(), 0)) != 0)
+                       return ret;
+               if ((ret = setpriority(PRIO_USER, uid, 0)) != 0)
+                       return ret;
+       }
+
+       if (flags & LOGIN_SETRESOURCES) {
+       }
+
+       if (flags & LOGIN_SETUMASK)
+               umask(S_IWGRP | S_IWOTH);
+
+       if (flags & LOGIN_SETUSER)
+               return setuid(uid);
+
+       return 0;
+}
+
diff --git a/libopenbsd/strtonum.c b/libopenbsd/strtonum.c
new file mode 100644 (file)
index 0000000..3725177
--- /dev/null
@@ -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 <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#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);
+}
diff --git a/parse.y b/parse.y
index ee5f11d04ab8b8c5ae60dc7749b78b106b31bcfb..0307b0f39be9d909c10351f894396a3046919546 100644 (file)
--- a/parse.y
+++ b/parse.y
 %{
 #include <sys/types.h>
 #include <ctype.h>
-#include <unistd.h>
-#include <stdint.h>
+#include <err.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
 #include <string.h>
-#include <err.h>
+#include <unistd.h>
+
+#include "openbsd.h"
 
 #include "doas.h"
 
@@ -99,8 +102,10 @@ action:             TPERMIT options {
                        $$.action = DENY;
                } ;
 
-options:       /* none */
-               | options option {
+options:       /* none */ {
+                       $$.options = 0;
+                       $$.envlist = NULL;
+               } | options option {
                        $$.options = $1.options | $2.options;
                        $$.envlist = $1.envlist;
                        if ($2.envlist) {
@@ -113,16 +118,17 @@ options:  /* none */
                } ;
 option:                TNOPASS {
                        $$.options = NOPASS;
+                       $$.envlist = NULL;
                } | TKEEPENV {
                        $$.options = KEEPENV;
+                       $$.envlist = NULL;
                } | TKEEPENV '{' envlist '}' {
                        $$.options = KEEPENV;
                        $$.envlist = $3.envlist;
                } ;
 
 envlist:       /* empty */ {
-                       if (!($$.envlist = calloc(1, sizeof(char *))))
-                               errx(1, "can't allocate envlist");
+                       $$.envlist = NULL;
                } | envlist TSTRING {
                        int nenv = arraylen($1.envlist);
                        if (!($$.envlist = reallocarray($1.envlist, nenv + 2,
@@ -158,8 +164,7 @@ args:               /* empty */ {
                } ;
 
 argslist:      /* empty */ {
-                       if (!($$.cmdargs = calloc(1, sizeof(char *))))
-                               errx(1, "can't allocate args");
+                       $$.cmdargs = NULL;
                } | argslist TSTRING {
                        int nargs = arraylen($1.cmdargs);
                        if (!($$.cmdargs = reallocarray($1.cmdargs, nargs + 2,
@@ -200,7 +205,7 @@ int
 yylex(void)
 {
        char buf[1024], *ebuf, *p, *str;
-       int i, c, quotes = 0, escape = 0, qpos = -1, nonkw = 0;
+       int c, quotes = 0, escape = 0, qpos = -1, nonkw = 0;
 
        p = buf;
        ebuf = buf + sizeof(buf);
@@ -303,6 +308,7 @@ eow:
                        goto repeat;
        }
        if (!nonkw) {
+               size_t i;
                for (i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
                        if (strcmp(buf, keywords[i].word) == 0)
                                return keywords[i].token;