aboutsummaryrefslogtreecommitdiff
path: root/patches/0016-doas-Port-to-linux-musl.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/0016-doas-Port-to-linux-musl.patch')
-rw-r--r--patches/0016-doas-Port-to-linux-musl.patch435
1 files changed, 435 insertions, 0 deletions
diff --git a/patches/0016-doas-Port-to-linux-musl.patch b/patches/0016-doas-Port-to-linux-musl.patch
new file mode 100644
index 0000000..877d3f0
--- /dev/null
+++ b/patches/0016-doas-Port-to-linux-musl.patch
@@ -0,0 +1,435 @@
+From c95443d87b64650823e41016c26b1f5a3b38e7b3 Mon Sep 17 00:00:00 2001
+From: Michael Forney <mforney@mforney.org>
+Date: Sun, 26 Feb 2017 16:50:55 -0800
+Subject: [PATCH] doas: Port to linux/musl
+
+Remove -a login style option and BSD authentication. Instead, compare
+against shadow file.
+
+Use timestamp files in /run/doas instead of TIOC*VERAUTH to implement
+persist.
+
+Use initgroups/setgid/setuid instead of setusercontext.
+
+Provide UID_MAX and GID_MAX defaults.
+
+Use LOGIN_NAME_MAX instead of _PW_NAME_LEN.
+
+Remove call to closefrom.
+
+Replace calls to errc with err after setting errno.
+
+Call openlog at start to set syslog identity.
+---
+ usr.bin/doas/doas.1 | 9 ---
+ usr.bin/doas/doas.c | 97 ++++++++++++++++--------------
+ usr.bin/doas/doas.h | 4 ++
+ usr.bin/doas/parse.y | 1 +
+ usr.bin/doas/persist.c | 133 +++++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 191 insertions(+), 53 deletions(-)
+ create mode 100644 usr.bin/doas/persist.c
+
+diff --git a/usr.bin/doas/doas.1 b/usr.bin/doas/doas.1
+index fc769bdb336..c7196e347a9 100644
+--- a/usr.bin/doas/doas.1
++++ b/usr.bin/doas/doas.1
+@@ -22,7 +22,6 @@
+ .Sh SYNOPSIS
+ .Nm doas
+ .Op Fl Lns
+-.Op Fl a Ar style
+ .Op Fl C Ar config
+ .Op Fl u Ar user
+ .Ar command
+@@ -67,14 +66,6 @@ The working directory is not changed.
+ .Pp
+ The options are as follows:
+ .Bl -tag -width tenletters
+-.It Fl a Ar style
+-Use the specified authentication style when validating the user,
+-as allowed by
+-.Pa /etc/login.conf .
+-A list of doas-specific authentication methods may be configured by adding an
+-.Sq auth-doas
+-entry in
+-.Xr login.conf 5 .
+ .It Fl C Ar config
+ Parse and check the configuration file
+ .Ar config ,
+diff --git a/usr.bin/doas/doas.c b/usr.bin/doas/doas.c
+index a723c67a3eb..e7e3e639401 100644
+--- a/usr.bin/doas/doas.c
++++ b/usr.bin/doas/doas.c
+@@ -20,8 +20,6 @@
+ #include <sys/ioctl.h>
+
+ #include <limits.h>
+-#include <login_cap.h>
+-#include <bsd_auth.h>
+ #include <readpassphrase.h>
+ #include <string.h>
+ #include <stdio.h>
+@@ -33,13 +31,22 @@
+ #include <syslog.h>
+ #include <errno.h>
+ #include <fcntl.h>
++#include <shadow.h>
+
+ #include "doas.h"
+
++#ifndef UID_MAX
++#define UID_MAX 65535
++#endif
++
++#ifndef GID_MAX
++#define GID_MAX 65535
++#endif
++
+ static void __dead
+ usage(void)
+ {
+- fprintf(stderr, "usage: doas [-Lns] [-a style] [-C config] [-u user]"
++ fprintf(stderr, "usage: doas [-Lns] [-C config] [-u user]"
+ " command [args]\n");
+ exit(1);
+ }
+@@ -197,23 +204,36 @@ checkconfig(const char *confpath, int argc, char **argv,
+ }
+ }
+
++static int
++verifypasswd(const char *user, const char *pass)
++{
++ struct spwd *sp;
++ char *p1, *p2;
++
++ sp = getspnam(user);
++ if (!sp)
++ return 0;
++ p1 = sp->sp_pwdp;
++ if (p1[0] == '!' || p1[0] == '*')
++ return 0;
++ p2 = crypt(pass, p1);
++ if (!p2)
++ return 0;
++ return strcmp(p1, p2) == 0;
++}
++
+ static void
+-authuser(char *myname, char *login_style, int persist)
++authuser(char *myname, int persist)
+ {
+ char *challenge = NULL, *response, rbuf[1024], cbuf[128];
+- auth_session_t *as;
+- int fd = -1;
++ int fd = -1, valid = 0;
+
+- if (persist)
+- fd = open("/dev/tty", O_RDWR);
+- if (fd != -1) {
+- if (ioctl(fd, TIOCCHKVERAUTH) == 0)
++ if (persist) {
++ fd = openpersist(&valid);
++ if (valid)
+ goto good;
+ }
+
+- if (!(as = auth_userchallenge(myname, login_style, "auth-doas",
+- &challenge)))
+- errx(1, "Authorization failed");
+ if (!challenge) {
+ char host[HOST_NAME_MAX + 1];
+ if (gethostname(host, sizeof(host)))
+@@ -225,21 +245,18 @@ authuser(char *myname, char *login_style, int persist)
+ response = readpassphrase(challenge, rbuf, sizeof(rbuf),
+ RPP_REQUIRE_TTY);
+ if (response == NULL && errno == ENOTTY) {
+- syslog(LOG_AUTHPRIV | LOG_NOTICE,
+- "tty required for %s", myname);
++ syslog(LOG_NOTICE, "tty required for %s", myname);
+ errx(1, "a tty is required");
+ }
+- if (!auth_userresponse(as, response, 0)) {
++ if (!verifypasswd(myname, response)) {
+ explicit_bzero(rbuf, sizeof(rbuf));
+- syslog(LOG_AUTHPRIV | LOG_NOTICE,
+- "failed auth for %s", myname);
++ syslog(LOG_NOTICE, "failed auth for %s", myname);
+ errx(1, "Authorization failed");
+ }
+ explicit_bzero(rbuf, sizeof(rbuf));
+ good:
+ if (fd != -1) {
+- int secs = 5 * 60;
+- ioctl(fd, TIOCSETVERAUTH, &secs);
++ setpersist(fd);
+ close(fd);
+ }
+ }
+@@ -285,15 +302,14 @@ done:
+ int
+ main(int argc, char **argv)
+ {
+- const char *safepath = "/bin:/sbin:/usr/bin:/usr/sbin:"
+- "/usr/local/bin:/usr/local/sbin";
++ const char *safepath = "/bin";
+ const char *confpath = NULL;
+ char *shargv[] = { NULL, NULL };
+ char *sh;
+ const char *p;
+ const char *cmd;
+ char cmdline[LINE_MAX];
+- char mypwbuf[_PW_BUF_LEN], targpwbuf[_PW_BUF_LEN];
++ char mypwbuf[1024], targpwbuf[1024];
+ struct passwd mypwstore, targpwstore;
+ struct passwd *mypw, *targpw;
+ const struct rule *rule;
+@@ -306,28 +322,20 @@ main(int argc, char **argv)
+ int nflag = 0;
+ char cwdpath[PATH_MAX];
+ const char *cwd;
+- char *login_style = NULL;
+ char **envp;
+
+ setprogname("doas");
+-
+- closefrom(STDERR_FILENO + 1);
++ openlog("doas", 0, LOG_AUTHPRIV);
+
+ uid = getuid();
+
+- while ((ch = getopt(argc, argv, "a:C:Lnsu:")) != -1) {
++ while ((ch = getopt(argc, argv, "C:Lnsu:")) != -1) {
+ switch (ch) {
+- case 'a':
+- login_style = optarg;
+- break;
+ case 'C':
+ confpath = optarg;
+ break;
+ case 'L':
+- i = open("/dev/tty", O_RDWR);
+- if (i != -1)
+- ioctl(i, TIOCCLRVERAUTH);
+- exit(i == -1);
++ exit(clearpersist() != 0);
+ case 'u':
+ if (parseuid(optarg, &target) != 0)
+ errx(1, "unknown user");
+@@ -395,16 +403,16 @@ main(int argc, char **argv)
+ cmd = argv[0];
+ if (!permit(uid, groups, ngroups, &rule, target, cmd,
+ (const char **)argv + 1)) {
+- syslog(LOG_AUTHPRIV | LOG_NOTICE,
+- "failed command for %s: %s", mypw->pw_name, cmdline);
+- errc(1, EPERM, NULL);
++ syslog(LOG_NOTICE, "failed command for %s: %s", mypw->pw_name, cmdline);
++ errno = EPERM;
++ err(1, NULL);
+ }
+
+ if (!(rule->options & NOPASS)) {
+ if (nflag)
+ errx(1, "Authorization required");
+
+- authuser(mypw->pw_name, login_style, rule->options & PERSIST);
++ authuser(mypw->pw_name, rule->options & PERSIST);
+ }
+
+ if ((p = getenv("PATH")) != NULL)
+@@ -431,11 +439,12 @@ main(int argc, char **argv)
+ if (targpw == NULL)
+ errx(1, "no passwd entry for target");
+
+- if (setusercontext(NULL, targpw, target, LOGIN_SETGROUP |
+- LOGIN_SETPATH |
+- LOGIN_SETPRIORITY | LOGIN_SETRESOURCES | LOGIN_SETUMASK |
+- LOGIN_SETUSER) != 0)
+- errx(1, "failed to set user context for target");
++ if (initgroups(targpw->pw_name, targpw->pw_gid) < 0)
++ err(1, "initgroups");
++ if (setgid(targpw->pw_gid) < 0)
++ err(1, "setgid");
++ if (setuid(targpw->pw_uid) < 0)
++ err(1, "setuid");
+
+ if (pledge("stdio rpath exec", NULL) == -1)
+ err(1, "pledge");
+@@ -448,7 +457,7 @@ main(int argc, char **argv)
+ if (pledge("stdio exec", NULL) == -1)
+ err(1, "pledge");
+
+- syslog(LOG_AUTHPRIV | LOG_INFO, "%s ran command %s as %s from %s",
++ syslog(LOG_INFO, "%s ran command %s as %s from %s",
+ mypw->pw_name, cmdline, targpw->pw_name, cwd);
+
+ envp = prepenv(rule, mypw, targpw);
+diff --git a/usr.bin/doas/doas.h b/usr.bin/doas/doas.h
+index 6f50fc22869..c97986e3cf3 100644
+--- a/usr.bin/doas/doas.h
++++ b/usr.bin/doas/doas.h
+@@ -36,6 +36,10 @@ struct passwd;
+ char **prepenv(const struct rule *, const struct passwd *,
+ const struct passwd *);
+
++int openpersist(int *valid);
++int setpersist(int fd);
++int clearpersist(void);
++
+ #define PERMIT 1
+ #define DENY 2
+
+diff --git a/usr.bin/doas/parse.y b/usr.bin/doas/parse.y
+index dd9466e5f13..d1f698c7679 100644
+--- a/usr.bin/doas/parse.y
++++ b/usr.bin/doas/parse.y
+@@ -19,6 +19,7 @@
+ #include <sys/types.h>
+ #include <ctype.h>
+ #include <unistd.h>
++#include <stdlib.h>
+ #include <stdint.h>
+ #include <stdarg.h>
+ #include <stdio.h>
+diff --git a/usr.bin/doas/persist.c b/usr.bin/doas/persist.c
+new file mode 100644
+index 00000000000..4ad1bf1efbf
+--- /dev/null
++++ b/usr.bin/doas/persist.c
+@@ -0,0 +1,133 @@
++#include <errno.h>
++#include <fcntl.h>
++#include <limits.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/stat.h>
++#include <sys/types.h>
++#include <time.h>
++#include <unistd.h>
++
++#include "doas.h"
++
++#define PERSIST_DIR "/run/doas"
++#define PERSIST_TIMEOUT 5 * 60
++
++static int
++ttyid(dev_t *tty)
++{
++ int fd, i;
++ char buf[BUFSIZ], *p;
++ ssize_t n;
++
++ fd = open("/proc/self/stat", O_RDONLY);
++ if (fd == -1)
++ return -1;
++ n = read(fd, buf, sizeof(buf) - 1);
++ if (n >= 0)
++ buf[n] = '\0';
++ /* check that we read the whole file */
++ n = read(fd, buf, 1);
++ close(fd);
++ if (n != 0)
++ return -1;
++ p = strrchr(buf, ')');
++ if (!p)
++ return -1;
++ ++p;
++ /* ttr_nr is the 5th field after executable name, so skip the next 4 */
++ for (i = 0; i < 4; ++i) {
++ p = strchr(++p, ' ');
++ if (!p)
++ return -1;
++ }
++ *tty = strtol(p, &p, 10);
++ if (*p != ' ')
++ return -1;
++ return 0;
++}
++
++static int
++persistpath(char *buf, size_t len)
++{
++ dev_t tty;
++ int n;
++
++ if (ttyid(&tty) < 0)
++ return -1;
++ n = snprintf(buf, len, PERSIST_DIR "/%ju-%ju", (uintmax_t)getuid(), (uintmax_t)tty);
++ if (n < 0 || n >= (int)len)
++ return -1;
++ return 0;
++}
++
++int
++openpersist(int *valid)
++{
++ char path[256];
++ struct stat st;
++ struct timespec ts;
++ int fd;
++
++ if (stat(PERSIST_DIR, &st) < 0) {
++ if (errno != ENOENT)
++ return -1;
++ if (mkdir(PERSIST_DIR, 0700) < 0)
++ return -1;
++ } else if (st.st_uid != 0 || st.st_mode != (S_IFDIR | 0700)) {
++ return -1;
++ }
++ if (persistpath(path, sizeof(path)) < 0)
++ return -1;
++ fd = open(path, O_RDONLY);
++ if (fd == -1) {
++ char tmp[256];
++ struct timespec ts[2] = { { .tv_nsec = UTIME_OMIT }, { 0 } };
++ int n;
++
++ n = snprintf(tmp, sizeof(tmp), PERSIST_DIR "/.tmp-%d", getpid());
++ if (n < 0 || n >= (int)sizeof(tmp))
++ return -1;
++ fd = open(tmp, O_RDONLY | O_CREAT | O_EXCL, 0);
++ if (fd == -1)
++ return -1;
++ if (futimens(fd, ts) < 0 || rename(tmp, path) < 0) {
++ close(fd);
++ unlink(tmp);
++ return -1;
++ }
++ *valid = 0;
++ } else {
++ *valid = clock_gettime(CLOCK_BOOTTIME, &ts) == 0 &&
++ fstat(fd, &st) == 0 &&
++ (ts.tv_sec < st.st_mtim.tv_sec ||
++ (ts.tv_sec == st.st_mtim.tv_sec && ts.tv_nsec < st.st_mtim.tv_nsec)) &&
++ st.st_mtime - ts.tv_sec <= PERSIST_TIMEOUT;
++ }
++ return fd;
++}
++
++int
++setpersist(int fd)
++{
++ struct timespec times[2];
++
++ if (clock_gettime(CLOCK_BOOTTIME, &times[1]) < 0)
++ return -1;
++ times[0].tv_nsec = UTIME_OMIT;
++ times[1].tv_sec += PERSIST_TIMEOUT;
++ return futimens(fd, times);
++}
++
++int
++clearpersist(void)
++{
++ char path[256];
++
++ if (persistpath(path, sizeof(path)) < 0)
++ return -1;
++ if (unlink(path) < 0 && errno != ENOENT)
++ return -1;
++ return 0;
++}
+--
+2.27.0
+