add a special edition doas that only lets root drop privs.
authortedu <tedu@openbsd.org>
Tue, 16 Aug 2016 04:55:33 +0000 (04:55 +0000)
committertedu <tedu@openbsd.org>
Tue, 16 Aug 2016 04:55:33 +0000 (04:55 +0000)
maybe the installer can use something like this, wink wink.
ok deraadt

distrib/special/Makefile
distrib/special/doas/Makefile [new file with mode: 0644]
distrib/special/doas/doas.c [new file with mode: 0644]

index 71c61a2..b87f067 100644 (file)
@@ -1,8 +1,8 @@
-#      $OpenBSD: Makefile,v 1.39 2015/04/13 21:27:07 deraadt Exp $
+#      $OpenBSD: Makefile,v 1.40 2016/08/16 04:55:33 tedu Exp $
 
 SUBDIR=        libstubs \
        arch bioctl cat chmod chroot cp date dd df dhclient disklabel dmesg \
-       ed eeprom encrypt fdisk fsck fsck_ext2fs fsck_ffs fsck_msdos ftp \
+       doas ed eeprom encrypt fdisk fsck fsck_ext2fs fsck_ffs fsck_msdos ftp \
        grep gzip hostname ifconfig init installboot kbd ksh ln ls md5 \
        mkdir mknod mkuboot more mount mount_cd9660 mount_ext2fs \
        mount_ffs mount_msdos mount_nfs mount_udf mt mv newfs newfs_ext2fs \
diff --git a/distrib/special/doas/Makefile b/distrib/special/doas/Makefile
new file mode 100644 (file)
index 0000000..ae95c24
--- /dev/null
@@ -0,0 +1,6 @@
+#      $OpenBSD: Makefile,v 1.1 2016/08/16 04:55:33 tedu Exp $
+
+PROG=  doas
+SRCS=  doas.c
+
+.include <bsd.prog.mk>
diff --git a/distrib/special/doas/doas.c b/distrib/special/doas/doas.c
new file mode 100644 (file)
index 0000000..42c4d80
--- /dev/null
@@ -0,0 +1,107 @@
+/* $OpenBSD: doas.c,v 1.1 2016/08/16 04:55:33 tedu Exp $ */
+/*
+ * Copyright (c) 2015 Ted Unangst <tedu@openbsd.org>
+ *
+ * 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 <sys/stat.h>
+
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <err.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+#include <syslog.h>
+#include <errno.h>
+
+static void __dead
+usage(void)
+{
+       fprintf(stderr, "usage: doas [-u user] command [args]\n");
+       exit(1);
+}
+
+static int
+parseuid(const char *s, uid_t *uid)
+{
+       struct passwd *pw;
+       const char *errstr;
+
+       if ((pw = getpwnam(s)) != NULL) {
+               *uid = pw->pw_uid;
+               return 0;
+       }
+       *uid = strtonum(s, 0, UID_MAX, &errstr);
+       if (errstr)
+               return -1;
+       return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+       const char *cmd;
+       struct passwd *pw;
+       uid_t uid;
+       uid_t target = 0;
+       gid_t groups[1];
+       int ngroups;
+       int i, ch;
+
+       setprogname("doas");
+
+       closefrom(STDERR_FILENO + 1);
+
+       uid = getuid();
+       if (uid != 0)
+               errc(1, EPERM, "root only");
+
+       while ((ch = getopt(argc, argv, "u:")) != -1) {
+               switch (ch) {
+               case 'u':
+                       if (parseuid(optarg, &target) != 0)
+                               errx(1, "unknown user");
+                       break;
+               default:
+                       usage();
+                       break;
+               }
+       }
+       argv += optind;
+       argc -= optind;
+
+       if (!argc)
+               usage();
+
+       cmd = argv[0];
+
+       pw = getpwuid(target);
+       if (!pw)
+               errx(1, "no passwd entry for target");
+       groups[0] = pw->pw_gid;
+
+       if (setgroups(1, groups) ||
+           setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
+           setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
+               err(1, "failed to change user"); 
+
+       execvp(cmd, argv);
+       if (errno == ENOENT)
+               errx(1, "%s: command not found", cmd);
+       err(1, "%s", cmd);
+}