diff options
Diffstat (limited to 'pkg/openbsd/patch')
3 files changed, 724 insertions, 199 deletions
diff --git a/pkg/openbsd/patch/0016-doas-Apply-some-patches-from-OpenBSD-CVS.patch b/pkg/openbsd/patch/0016-doas-Apply-some-patches-from-OpenBSD-CVS.patch new file mode 100644 index 00000000..05bf3cb7 --- /dev/null +++ b/pkg/openbsd/patch/0016-doas-Apply-some-patches-from-OpenBSD-CVS.patch @@ -0,0 +1,317 @@ +From 5f959925db4a0d71cb926820b42780de8820f9d7 Mon Sep 17 00:00:00 2001 +From: tedu <tedu@openbsd.org> +Date: Thu, 1 Sep 2016 13:16:38 +0000 +Subject: [PATCH] doas: Apply some patches from OpenBSD CVS + +move the authentication code to a function +unconst these parameters; i won't be changing bsd auth today. +add support for the verified auth ioctls using 'persist' rules. +clarify that -L will exit without running a command. +the sudo timeout was 5 minutes i believe, so we'll match that. +don't allow combining nopass and persist in a single rule +-L means no command +--- + usr.bin/doas/doas.1 | 13 ++++--- + usr.bin/doas/doas.c | 90 ++++++++++++++++++++++++++++++------------------ + usr.bin/doas/doas.conf.5 | 7 ++-- + usr.bin/doas/doas.h | 3 +- + usr.bin/doas/parse.y | 12 +++++-- + 5 files changed, 83 insertions(+), 42 deletions(-) + +diff --git a/usr.bin/doas/doas.1 b/usr.bin/doas/doas.1 +index c5b8e00f3..d39c4aab2 100644 +--- a/usr.bin/doas/doas.1 ++++ b/usr.bin/doas/doas.1 +@@ -1,4 +1,4 @@ +-.\" $OpenBSD: doas.1,v 1.16 2016/06/11 04:38:21 tedu Exp $ ++.\" $OpenBSD: doas.1,v 1.19 2016/09/04 15:20:37 tedu Exp $ + .\" + .\"Copyright (c) 2015 Ted Unangst <tedu@openbsd.org> + .\" +@@ -13,7 +13,7 @@ + .\"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. +-.Dd $Mdocdate: June 11 2016 $ ++.Dd $Mdocdate: September 4 2016 $ + .Dt DOAS 1 + .Os + .Sh NAME +@@ -21,7 +21,7 @@ + .Nd execute commands as another user + .Sh SYNOPSIS + .Nm doas +-.Op Fl ns ++.Op Fl Lns + .Op Fl a Ar style + .Op Fl C Ar config + .Op Fl u Ar user +@@ -34,7 +34,8 @@ utility executes the given command as another user. + The + .Ar command + argument is mandatory unless +-.Fl C ++.Fl C , ++.Fl L , + or + .Fl s + is specified. +@@ -67,6 +68,10 @@ or + will be printed on standard output, depending on command + matching results. + No command is executed. ++.It Fl L ++Clear any persisted authorizations from previous invocations, ++then immediately exit. ++No command is executed. + .It Fl n + Non interactive mode, fail if + .Nm +diff --git a/usr.bin/doas/doas.c b/usr.bin/doas/doas.c +index b17c8f13c..d82d9f119 100644 +--- a/usr.bin/doas/doas.c ++++ b/usr.bin/doas/doas.c +@@ -1,4 +1,4 @@ +-/* $OpenBSD: doas.c,v 1.60 2016/07/18 16:46:30 zhuk Exp $ */ ++/* $OpenBSD: doas.c,v 1.64 2016/09/03 11:03:18 tedu Exp $ */ + /* + * Copyright (c) 2015 Ted Unangst <tedu@openbsd.org> + * +@@ -17,6 +17,7 @@ + + #include <sys/types.h> + #include <sys/stat.h> ++#include <sys/ioctl.h> + + #include <limits.h> + #include <login_cap.h> +@@ -31,13 +32,14 @@ + #include <grp.h> + #include <syslog.h> + #include <errno.h> ++#include <fcntl.h> + + #include "doas.h" + + static void __dead + usage(void) + { +- fprintf(stderr, "usage: doas [-ns] [-a style] [-C config] [-u user]" ++ fprintf(stderr, "usage: doas [-Lns] [-a style] [-C config] [-u user]" + " command [args]\n"); + exit(1); + } +@@ -203,6 +205,52 @@ checkconfig(const char *confpath, int argc, char **argv, + } + } + ++static void ++authuser(char *myname, char *login_style, int persist) ++{ ++ char *challenge = NULL, *response, rbuf[1024], cbuf[128]; ++ auth_session_t *as; ++ int fd = -1; ++ ++ if (persist) ++ fd = open("/dev/tty", O_RDWR); ++ if (fd != -1) { ++ if (ioctl(fd, TIOCCHKVERAUTH) == 0) ++ 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))) ++ snprintf(host, sizeof(host), "?"); ++ snprintf(cbuf, sizeof(cbuf), ++ "\rdoas (%.32s@%.32s) password: ", myname, host); ++ challenge = cbuf; ++ } ++ response = readpassphrase(challenge, rbuf, sizeof(rbuf), ++ RPP_REQUIRE_TTY); ++ if (response == NULL && errno == ENOTTY) { ++ syslog(LOG_AUTHPRIV | LOG_NOTICE, ++ "tty required for %s", myname); ++ errx(1, "a tty is required"); ++ } ++ if (!auth_userresponse(as, response, 0)) { ++ syslog(LOG_AUTHPRIV | LOG_NOTICE, ++ "failed auth for %s", myname); ++ errc(1, EPERM, NULL); ++ } ++ explicit_bzero(rbuf, sizeof(rbuf)); ++good: ++ if (fd != -1) { ++ int secs = 5 * 60; ++ ioctl(fd, TIOCSETVERAUTH, &secs); ++ close(fd); ++ } ++} ++ + int + main(int argc, char **argv) + { +@@ -230,14 +278,11 @@ main(int argc, char **argv) + + setprogname("doas"); + +- if (pledge("stdio rpath getpw tty recvfd proc exec id", NULL) == -1) +- err(1, "pledge"); +- + closefrom(STDERR_FILENO + 1); + + uid = getuid(); + +- while ((ch = getopt(argc, argv, "a:C:nsu:")) != -1) { ++ while ((ch = getopt(argc, argv, "a:C:Lnsu:")) != -1) { + switch (ch) { + case 'a': + login_style = optarg; +@@ -245,6 +290,11 @@ main(int argc, char **argv) + case 'C': + confpath = optarg; + break; ++ case 'L': ++ i = open("/dev/tty", O_RDWR); ++ if (i != -1) ++ ioctl(i, TIOCCLRVERAUTH); ++ exit(i != -1); + case 'u': + if (parseuid(optarg, &target) != 0) + errx(1, "unknown user"); +@@ -317,36 +367,10 @@ main(int argc, char **argv) + } + + if (!(rule->options & NOPASS)) { +- char *challenge = NULL, *response, rbuf[1024], cbuf[128]; +- auth_session_t *as; +- + if (nflag) + errx(1, "Authorization required"); + +- 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))) +- snprintf(host, sizeof(host), "?"); +- snprintf(cbuf, sizeof(cbuf), +- "\rdoas (%.32s@%.32s) password: ", myname, host); +- challenge = cbuf; +- } +- response = readpassphrase(challenge, rbuf, sizeof(rbuf), +- RPP_REQUIRE_TTY); +- if (response == NULL && errno == ENOTTY) { +- syslog(LOG_AUTHPRIV | LOG_NOTICE, +- "tty required for %s", myname); +- errx(1, "a tty is required"); +- } +- if (!auth_userresponse(as, response, 0)) { +- syslog(LOG_AUTHPRIV | LOG_NOTICE, +- "failed auth for %s", myname); +- errc(1, EPERM, NULL); +- } +- explicit_bzero(rbuf, sizeof(rbuf)); ++ authuser(myname, login_style, rule->options & PERSIST); + } + + if (pledge("stdio rpath getpw exec id", NULL) == -1) +diff --git a/usr.bin/doas/doas.conf.5 b/usr.bin/doas/doas.conf.5 +index 864c37ec5..317ee0028 100644 +--- a/usr.bin/doas/doas.conf.5 ++++ b/usr.bin/doas/doas.conf.5 +@@ -1,4 +1,4 @@ +-.\" $OpenBSD: doas.conf.5,v 1.29 2016/06/27 17:36:33 jmc Exp $ ++.\" $OpenBSD: doas.conf.5,v 1.30 2016/09/02 18:12:30 tedu Exp $ + .\" + .\"Copyright (c) 2015 Ted Unangst <tedu@openbsd.org> + .\" +@@ -13,7 +13,7 @@ + .\"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. +-.Dd $Mdocdate: June 27 2016 $ ++.Dd $Mdocdate: September 2 2016 $ + .Dt DOAS.CONF 5 + .Os + .Sh NAME +@@ -47,6 +47,9 @@ Options are: + .Bl -tag -width keepenv + .It Ic nopass + The user is not required to enter a password. ++.It Ic persist ++After the user successfully authenticates, do not ask for a password ++again for some time. + .It Ic keepenv + The user's environment is maintained. + The default is to reset the environment, except for the variables +diff --git a/usr.bin/doas/doas.h b/usr.bin/doas/doas.h +index 067483ee3..93b68fadc 100644 +--- a/usr.bin/doas/doas.h ++++ b/usr.bin/doas/doas.h +@@ -1,4 +1,4 @@ +-/* $OpenBSD: doas.h,v 1.8 2016/06/19 19:29:43 martijn Exp $ */ ++/* $OpenBSD: doas.h,v 1.9 2016/09/02 18:12:30 tedu Exp $ */ + struct rule { + int action; + int options; +@@ -22,3 +22,4 @@ char **prepenv(struct rule *); + + #define NOPASS 0x1 + #define KEEPENV 0x2 ++#define PERSIST 0x4 +diff --git a/usr.bin/doas/parse.y b/usr.bin/doas/parse.y +index 7e68cb7c5..9a30e1ea7 100644 +--- a/usr.bin/doas/parse.y ++++ b/usr.bin/doas/parse.y +@@ -1,4 +1,4 @@ +-/* $OpenBSD: parse.y,v 1.19 2016/06/27 15:41:17 tedu Exp $ */ ++/* $OpenBSD: parse.y,v 1.21 2016/09/04 15:11:13 tedu Exp $ */ + /* + * Copyright (c) 2015 Ted Unangst <tedu@openbsd.org> + * +@@ -57,7 +57,7 @@ int yyparse(void); + %} + + %token TPERMIT TDENY TAS TCMD TARGS +-%token TNOPASS TKEEPENV TSETENV ++%token TNOPASS TPERSIST TKEEPENV TSETENV + %token TSTRING + + %% +@@ -108,6 +108,10 @@ options: /* none */ { + } | options option { + $$.options = $1.options | $2.options; + $$.envlist = $1.envlist; ++ if (($$.options & (NOPASS|PERSIST)) == (NOPASS|PERSIST)) { ++ yyerror("can't combine nopass and persist"); ++ YYERROR; ++ } + if ($2.envlist) { + if ($$.envlist) { + yyerror("can't have two setenv sections"); +@@ -119,6 +123,9 @@ options: /* none */ { + option: TNOPASS { + $$.options = NOPASS; + $$.envlist = NULL; ++ } | TPERSIST { ++ $$.options = PERSIST; ++ $$.envlist = NULL; + } | TKEEPENV { + $$.options = KEEPENV; + $$.envlist = NULL; +@@ -208,6 +215,7 @@ struct keyword { + { "cmd", TCMD }, + { "args", TARGS }, + { "nopass", TNOPASS }, ++ { "persist", TPERSIST }, + { "keepenv", TKEEPENV }, + { "setenv", TSETENV }, + }; +-- +2.12.0 + diff --git a/pkg/openbsd/patch/0016-doas-Port-to-linux-musl.patch b/pkg/openbsd/patch/0016-doas-Port-to-linux-musl.patch deleted file mode 100644 index 3ba1474a..00000000 --- a/pkg/openbsd/patch/0016-doas-Port-to-linux-musl.patch +++ /dev/null @@ -1,199 +0,0 @@ -From e03e4343423178d21fbe7a6687c199367f3252e0 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 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. ---- - usr.bin/doas/doas.1 | 9 -------- - usr.bin/doas/doas.c | 63 ++++++++++++++++++++++++++++++++++------------------- - 2 files changed, 41 insertions(+), 31 deletions(-) - -diff --git a/usr.bin/doas/doas.1 b/usr.bin/doas/doas.1 -index c5b8e00f32c..fca943f6fc2 100644 ---- a/usr.bin/doas/doas.1 -+++ b/usr.bin/doas/doas.1 -@@ -22,7 +22,6 @@ - .Sh SYNOPSIS - .Nm doas - .Op Fl ns --.Op Fl a Ar style - .Op Fl C Ar config - .Op Fl u Ar user - .Ar command -@@ -41,14 +40,6 @@ is specified. - .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 b17c8f13c8a..c9eb3bb3049 100644 ---- a/usr.bin/doas/doas.c -+++ b/usr.bin/doas/doas.c -@@ -20,7 +20,6 @@ - - #include <limits.h> - #include <login_cap.h> --#include <bsd_auth.h> - #include <readpassphrase.h> - #include <string.h> - #include <stdio.h> -@@ -31,9 +30,18 @@ - #include <grp.h> - #include <syslog.h> - #include <errno.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) - { -@@ -203,17 +211,34 @@ 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; -+} -+ - 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 *cmd; - char cmdline[LINE_MAX]; -- char myname[_PW_NAME_LEN + 1]; -+ char myname[LOGIN_NAME_MAX + 1]; - struct passwd *pw; - struct rule *rule; - uid_t uid; -@@ -225,7 +250,6 @@ main(int argc, char **argv) - int nflag = 0; - char cwdpath[PATH_MAX]; - const char *cwd; -- char *login_style = NULL; - char **envp; - - setprogname("doas"); -@@ -233,15 +257,10 @@ main(int argc, char **argv) - if (pledge("stdio rpath getpw tty recvfd proc exec id", NULL) == -1) - err(1, "pledge"); - -- closefrom(STDERR_FILENO + 1); -- - uid = getuid(); - -- while ((ch = getopt(argc, argv, "a:C:nsu:")) != -1) { -+ while ((ch = getopt(argc, argv, "C:nsu:")) != -1) { - switch (ch) { -- case 'a': -- login_style = optarg; -- break; - case 'C': - confpath = optarg; - break; -@@ -313,19 +332,16 @@ main(int argc, char **argv) - (const char **)argv + 1)) { - syslog(LOG_AUTHPRIV | LOG_NOTICE, - "failed command for %s: %s", myname, cmdline); -- errc(1, EPERM, NULL); -+ errno = EPERM; -+ err(1, NULL); - } - - if (!(rule->options & NOPASS)) { - char *challenge = NULL, *response, rbuf[1024], cbuf[128]; -- auth_session_t *as; - - if (nflag) - errx(1, "Authorization required"); - -- 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))) -@@ -341,10 +357,11 @@ main(int argc, char **argv) - "tty required for %s", myname); - errx(1, "a tty is required"); - } -- if (!auth_userresponse(as, response, 0)) { -+ if (!verifypasswd(myname, response)) { - syslog(LOG_AUTHPRIV | LOG_NOTICE, - "failed auth for %s", myname); -- errc(1, EPERM, NULL); -+ errno = EPERM; -+ err(1, NULL); - } - explicit_bzero(rbuf, sizeof(rbuf)); - } -@@ -356,10 +373,12 @@ main(int argc, char **argv) - if (!pw) - errx(1, "no passwd entry for target"); - -- if (setusercontext(NULL, pw, target, LOGIN_SETGROUP | -- LOGIN_SETPRIORITY | LOGIN_SETRESOURCES | LOGIN_SETUMASK | -- LOGIN_SETUSER) != 0) -- errx(1, "failed to set user context for target"); -+ if (initgroups(pw->pw_name, pw->pw_gid) < 0) -+ err(1, "initgroups"); -+ if (setgid(pw->pw_gid) < 0) -+ err(1, "setgid"); -+ if (setuid(pw->pw_uid) < 0) -+ err(1, "setuid"); - - if (pledge("stdio rpath exec", NULL) == -1) - err(1, "pledge"); --- -2.11.1 - diff --git a/pkg/openbsd/patch/0017-doas-Port-to-linux-musl.patch b/pkg/openbsd/patch/0017-doas-Port-to-linux-musl.patch new file mode 100644 index 00000000..52b5d9f7 --- /dev/null +++ b/pkg/openbsd/patch/0017-doas-Port-to-linux-musl.patch @@ -0,0 +1,407 @@ +From 8f291c14b3c345ec66fb530dd719b2106ddc25e2 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. +--- + usr.bin/doas/doas.1 | 9 ---- + usr.bin/doas/doas.c | 86 +++++++++++++++++++-------------- + usr.bin/doas/doas.h | 4 ++ + usr.bin/doas/parse.y | 1 + + usr.bin/doas/persist.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 183 insertions(+), 45 deletions(-) + create mode 100644 usr.bin/doas/persist.c + +diff --git a/usr.bin/doas/doas.1 b/usr.bin/doas/doas.1 +index d39c4aab2..3097991bc 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 +@@ -42,14 +41,6 @@ is specified. + .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 d82d9f119..fb3f077f1 100644 +--- a/usr.bin/doas/doas.c ++++ b/usr.bin/doas/doas.c +@@ -21,7 +21,6 @@ + + #include <limits.h> + #include <login_cap.h> +-#include <bsd_auth.h> + #include <readpassphrase.h> + #include <string.h> + #include <stdio.h> +@@ -33,13 +32,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); + } +@@ -205,23 +213,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))) +@@ -237,16 +258,16 @@ authuser(char *myname, char *login_style, int persist) + "tty required for %s", myname); + errx(1, "a tty is required"); + } +- if (!auth_userresponse(as, response, 0)) { ++ if (!verifypasswd(myname, response)) { + syslog(LOG_AUTHPRIV | LOG_NOTICE, + "failed auth for %s", myname); +- errc(1, EPERM, NULL); ++ errno = EPERM; ++ err(1, NULL); + } + explicit_bzero(rbuf, sizeof(rbuf)); + good: + if (fd != -1) { +- int secs = 5 * 60; +- ioctl(fd, TIOCSETVERAUTH, &secs); ++ setpersist(fd); + close(fd); + } + } +@@ -254,14 +275,13 @@ good: + 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 *cmd; + char cmdline[LINE_MAX]; +- char myname[_PW_NAME_LEN + 1]; ++ char myname[LOGIN_NAME_MAX + 1]; + struct passwd *pw; + struct rule *rule; + uid_t uid; +@@ -273,28 +293,19 @@ 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); +- + 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"); +@@ -363,14 +374,15 @@ main(int argc, char **argv) + (const char **)argv + 1)) { + syslog(LOG_AUTHPRIV | LOG_NOTICE, + "failed command for %s: %s", myname, cmdline); +- errc(1, EPERM, NULL); ++ errno = EPERM; ++ err(1, NULL); + } + + if (!(rule->options & NOPASS)) { + if (nflag) + errx(1, "Authorization required"); + +- authuser(myname, login_style, rule->options & PERSIST); ++ authuser(myname, rule->options & PERSIST); + } + + if (pledge("stdio rpath getpw exec id", NULL) == -1) +@@ -380,10 +392,12 @@ main(int argc, char **argv) + if (!pw) + errx(1, "no passwd entry for target"); + +- if (setusercontext(NULL, pw, target, LOGIN_SETGROUP | +- LOGIN_SETPRIORITY | LOGIN_SETRESOURCES | LOGIN_SETUMASK | +- LOGIN_SETUSER) != 0) +- errx(1, "failed to set user context for target"); ++ if (initgroups(pw->pw_name, pw->pw_gid) < 0) ++ err(1, "initgroups"); ++ if (setgid(pw->pw_gid) < 0) ++ err(1, "setgid"); ++ if (setuid(pw->pw_uid) < 0) ++ err(1, "setuid"); + + if (pledge("stdio rpath exec", NULL) == -1) + err(1, "pledge"); +diff --git a/usr.bin/doas/doas.h b/usr.bin/doas/doas.h +index 93b68fadc..daf4307e7 100644 +--- a/usr.bin/doas/doas.h ++++ b/usr.bin/doas/doas.h +@@ -17,6 +17,10 @@ size_t arraylen(const char **); + + char **prepenv(struct rule *); + ++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 9a30e1ea7..fb59d3130 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 000000000..1ba1560d4 +--- /dev/null ++++ b/usr.bin/doas/persist.c +@@ -0,0 +1,128 @@ ++#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; ++ ++ if (ttyid(&tty) < 0) ++ return -1; ++ if (snprintf(buf, len, PERSIST_DIR "/%d-%d", getuid(), tty) >= 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 } }; ++ if (snprintf(tmp, sizeof(tmp), PERSIST_DIR "/.tmp-%d", getpid()) >= 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_MONOTONIC, &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_MONOTONIC, ×[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.12.0 + |
