opkg

statically linked package installer
git clone anongit@rnpnr.xyz:opkg.git
Log | Files | Refs | Feed | Submodules | README | LICENSE

0015-doas-Port-to-linux-musl.patch (14339B)


      1 From 8fa1e97f6927bf1afddb5923fff3d29c3389817d Mon Sep 17 00:00:00 2001
      2 From: Michael Forney <mforney@mforney.org>
      3 Date: Sun, 26 Feb 2017 16:50:55 -0800
      4 Subject: [PATCH] doas: Port to linux/musl
      5 
      6 Remove -a login style option and BSD authentication. Instead, compare
      7 against shadow file.
      8 
      9 Use timestamp files in /run/doas instead of TIOC*VERAUTH to implement
     10 persist.
     11 
     12 Use initgroups/setgid/setuid instead of setusercontext.
     13 
     14 Provide UID_MAX and GID_MAX defaults.
     15 
     16 Use LOGIN_NAME_MAX instead of _PW_NAME_LEN.
     17 
     18 Remove call to closefrom.
     19 
     20 Replace calls to errc with err after setting errno.
     21 
     22 Call openlog at start to set syslog identity.
     23 
     24 Remove unveil/pledge since they aren't supported on Linux.
     25 
     26 Simplify handling of PATH in the environment since we don't have
     27 login.conf with per-user default PATH.
     28 ---
     29  usr.bin/doas/doas.1    |   9 ---
     30  usr.bin/doas/doas.c    | 168 +++++++++++++----------------------------
     31  usr.bin/doas/doas.h    |   6 +-
     32  usr.bin/doas/env.c     |  17 ++---
     33  usr.bin/doas/parse.y   |   1 +
     34  usr.bin/doas/persist.c | 133 ++++++++++++++++++++++++++++++++
     35  6 files changed, 198 insertions(+), 136 deletions(-)
     36  create mode 100644 usr.bin/doas/persist.c
     37 
     38 diff --git a/usr.bin/doas/doas.1 b/usr.bin/doas/doas.1
     39 index 25827cc7104..3542680faf5 100644
     40 --- a/usr.bin/doas/doas.1
     41 +++ b/usr.bin/doas/doas.1
     42 @@ -22,7 +22,6 @@
     43  .Sh SYNOPSIS
     44  .Nm doas
     45  .Op Fl Lns
     46 -.Op Fl a Ar style
     47  .Op Fl C Ar config
     48  .Op Fl u Ar user
     49  .Ar command
     50 @@ -67,14 +66,6 @@ The working directory is not changed.
     51  .Pp
     52  The options are as follows:
     53  .Bl -tag -width tenletters
     54 -.It Fl a Ar style
     55 -Use the specified authentication style when validating the user,
     56 -as allowed by
     57 -.Pa /etc/login.conf .
     58 -A list of doas-specific authentication methods may be configured by adding an
     59 -.Sq auth-doas
     60 -entry in
     61 -.Xr login.conf 5 .
     62  .It Fl C Ar config
     63  Parse and check the configuration file
     64  .Ar config ,
     65 diff --git a/usr.bin/doas/doas.c b/usr.bin/doas/doas.c
     66 index 8b684d6006c..27d7b01014e 100644
     67 --- a/usr.bin/doas/doas.c
     68 +++ b/usr.bin/doas/doas.c
     69 @@ -20,8 +20,6 @@
     70  #include <sys/ioctl.h>
     71  
     72  #include <limits.h>
     73 -#include <login_cap.h>
     74 -#include <bsd_auth.h>
     75  #include <readpassphrase.h>
     76  #include <string.h>
     77  #include <stdio.h>
     78 @@ -33,13 +31,22 @@
     79  #include <syslog.h>
     80  #include <errno.h>
     81  #include <fcntl.h>
     82 +#include <shadow.h>
     83  
     84  #include "doas.h"
     85  
     86 +#ifndef UID_MAX
     87 +#define UID_MAX 65535
     88 +#endif
     89 +
     90 +#ifndef GID_MAX
     91 +#define GID_MAX 65535
     92 +#endif
     93 +
     94  static void __dead
     95  usage(void)
     96  {
     97 -	fprintf(stderr, "usage: doas [-Lns] [-a style] [-C config] [-u user]"
     98 +	fprintf(stderr, "usage: doas [-Lns] [-C config] [-u user]"
     99  	    " command [arg ...]\n");
    100  	exit(1);
    101  }
    102 @@ -200,16 +207,28 @@ checkconfig(const char *confpath, int argc, char **argv,
    103  }
    104  
    105  static int
    106 -authuser_checkpass(char *myname, char *login_style)
    107 +verifypasswd(const char *user, const char *pass)
    108 +{
    109 +	struct spwd *sp;
    110 +	char *p1, *p2;
    111 +
    112 +	sp = getspnam(user);
    113 +	if (!sp)
    114 +		return 0;
    115 +	p1 = sp->sp_pwdp;
    116 +	if (p1[0] == '!' || p1[0] == '*')
    117 +		return 0;
    118 +	p2 = crypt(pass, p1);
    119 +	if (!p2)
    120 +		return 0;
    121 +	return strcmp(p1, p2) == 0;
    122 +}
    123 +
    124 +static int
    125 +authuser_checkpass(char *myname)
    126  {
    127  	char *challenge = NULL, *response, rbuf[1024], cbuf[128];
    128 -	auth_session_t *as;
    129  
    130 -	if (!(as = auth_userchallenge(myname, login_style, "auth-doas",
    131 -	    &challenge))) {
    132 -		warnx("Authentication failed");
    133 -		return AUTH_FAILED;
    134 -	}
    135  	if (!challenge) {
    136  		char host[HOST_NAME_MAX + 1];
    137  
    138 @@ -222,14 +241,12 @@ authuser_checkpass(char *myname, char *login_style)
    139  	response = readpassphrase(challenge, rbuf, sizeof(rbuf),
    140  	    RPP_REQUIRE_TTY);
    141  	if (response == NULL && errno == ENOTTY) {
    142 -		syslog(LOG_AUTHPRIV | LOG_NOTICE,
    143 -		    "tty required for %s", myname);
    144 +		syslog(LOG_NOTICE, "tty required for %s", myname);
    145  		errx(1, "a tty is required");
    146  	}
    147 -	if (!auth_userresponse(as, response, 0)) {
    148 +	if (!verifypasswd(myname, response)) {
    149  		explicit_bzero(rbuf, sizeof(rbuf));
    150 -		syslog(LOG_AUTHPRIV | LOG_NOTICE,
    151 -		    "failed auth for %s", myname);
    152 +		syslog(LOG_NOTICE, "failed auth for %s", myname);
    153  		warnx("Authentication failed");
    154  		return AUTH_FAILED;
    155  	}
    156 @@ -238,79 +255,36 @@ authuser_checkpass(char *myname, char *login_style)
    157  }
    158  
    159  static void
    160 -authuser(char *myname, char *login_style, int persist)
    161 +authuser(char *myname, int persist)
    162  {
    163 -	int i, fd = -1;
    164 +	int i, fd = -1, valid = 0;
    165  
    166 -	if (persist)
    167 -		fd = open("/dev/tty", O_RDWR);
    168 -	if (fd != -1) {
    169 -		if (ioctl(fd, TIOCCHKVERAUTH) == 0)
    170 +	if (persist) {
    171 +		fd = openpersist(&valid);
    172 +		if (valid)
    173  			goto good;
    174  	}
    175  	for (i = 0; i < AUTH_RETRIES; i++) {
    176 -		if (authuser_checkpass(myname, login_style) == AUTH_OK)
    177 +		if (authuser_checkpass(myname) == AUTH_OK)
    178  			goto good;
    179  	}
    180  	exit(1);
    181  good:
    182  	if (fd != -1) {
    183 -		int secs = 5 * 60;
    184 -		ioctl(fd, TIOCSETVERAUTH, &secs);
    185 +		setpersist(fd);
    186  		close(fd);
    187  	}
    188  }
    189  
    190 -int
    191 -unveilcommands(const char *ipath, const char *cmd)
    192 -{
    193 -	char *path = NULL, *p;
    194 -	int unveils = 0;
    195 -
    196 -	if (strchr(cmd, '/') != NULL) {
    197 -		if (unveil(cmd, "x") != -1)
    198 -			unveils++;
    199 -		goto done;
    200 -	}
    201 -
    202 -	if (!ipath) {
    203 -		errno = ENOENT;
    204 -		goto done;
    205 -	}
    206 -	path = strdup(ipath);
    207 -	if (!path) {
    208 -		errno = ENOENT;
    209 -		goto done;
    210 -	}
    211 -	for (p = path; p && *p; ) {
    212 -		char buf[PATH_MAX];
    213 -		char *cp = strsep(&p, ":");
    214 -
    215 -		if (cp) {
    216 -			int r = snprintf(buf, sizeof buf, "%s/%s", cp, cmd);
    217 -			if (r >= 0 && r < sizeof buf) {
    218 -				if (unveil(buf, "x") != -1)
    219 -					unveils++;
    220 -			}
    221 -		}
    222 -	}
    223 -done:
    224 -	free(path);
    225 -	return (unveils);
    226 -}
    227 -
    228  int
    229  main(int argc, char **argv)
    230  {
    231 -	const char *safepath = "/bin:/sbin:/usr/bin:/usr/sbin:"
    232 -	    "/usr/local/bin:/usr/local/sbin";
    233  	const char *confpath = NULL;
    234  	char *shargv[] = { NULL, NULL };
    235  	char *sh;
    236 -	const char *p;
    237  	const char *cmd;
    238  	char cmdline[LINE_MAX];
    239 -	char mypwbuf[_PW_BUF_LEN], targpwbuf[_PW_BUF_LEN];
    240 +	char mypwbuf[1024], targpwbuf[1024];
    241  	struct passwd mypwstore, targpwstore;
    242  	struct passwd *mypw, *targpw;
    243  	const struct rule *rule;
    244 @@ -323,28 +297,20 @@ main(int argc, char **argv)
    245  	int nflag = 0;
    246  	char cwdpath[PATH_MAX];
    247  	const char *cwd;
    248 -	char *login_style = NULL;
    249  	char **envp;
    250  
    251  	setprogname("doas");
    252 -
    253 -	closefrom(STDERR_FILENO + 1);
    254 +	openlog("doas", 0, LOG_AUTHPRIV);
    255  
    256  	uid = getuid();
    257  
    258 -	while ((ch = getopt(argc, argv, "a:C:Lnsu:")) != -1) {
    259 +	while ((ch = getopt(argc, argv, "C:Lnsu:")) != -1) {
    260  		switch (ch) {
    261 -		case 'a':
    262 -			login_style = optarg;
    263 -			break;
    264  		case 'C':
    265  			confpath = optarg;
    266  			break;
    267  		case 'L':
    268 -			i = open("/dev/tty", O_RDWR);
    269 -			if (i != -1)
    270 -				ioctl(i, TIOCCLRVERAUTH);
    271 -			exit(i == -1);
    272 +			exit(clearpersist() != 0);
    273  		case 'u':
    274  			if (parseuid(optarg, &target) != 0)
    275  				errx(1, "unknown user");
    276 @@ -414,50 +380,30 @@ main(int argc, char **argv)
    277  	cmd = argv[0];
    278  	if (!permit(uid, groups, ngroups, &rule, target, cmd,
    279  	    (const char **)argv + 1)) {
    280 -		syslog(LOG_AUTHPRIV | LOG_NOTICE,
    281 -		    "command not permitted for %s: %s", mypw->pw_name, cmdline);
    282 -		errc(1, EPERM, NULL);
    283 +		syslog(LOG_NOTICE, "command not permitted for %s: %s", mypw->pw_name, cmdline);
    284 +		errno = EPERM;
    285 +		err(1, NULL);
    286  	}
    287  
    288  	if (!(rule->options & NOPASS)) {
    289  		if (nflag)
    290  			errx(1, "Authentication required");
    291  
    292 -		authuser(mypw->pw_name, login_style, rule->options & PERSIST);
    293 +		authuser(mypw->pw_name, rule->options & PERSIST);
    294  	}
    295  
    296 -	if ((p = getenv("PATH")) != NULL)
    297 -		formerpath = strdup(p);
    298 -	if (formerpath == NULL)
    299 -		formerpath = "";
    300 -
    301 -	if (unveil(_PATH_LOGIN_CONF, "r") == -1)
    302 -		err(1, "unveil %s", _PATH_LOGIN_CONF);
    303 -	if (unveil(_PATH_LOGIN_CONF ".db", "r") == -1)
    304 -		err(1, "unveil %s.db", _PATH_LOGIN_CONF);
    305 -	if (unveil(_PATH_LOGIN_CONF_D, "r") == -1)
    306 -		err(1, "unveil %s", _PATH_LOGIN_CONF_D);
    307 -	if (rule->cmd) {
    308 -		if (setenv("PATH", safepath, 1) == -1)
    309 -			err(1, "failed to set PATH '%s'", safepath);
    310 -	}
    311 -	if (unveilcommands(getenv("PATH"), cmd) == 0)
    312 -		goto fail;
    313 -
    314 -	if (pledge("stdio rpath getpw exec id", NULL) == -1)
    315 -		err(1, "pledge");
    316 -
    317  	rv = getpwuid_r(target, &targpwstore, targpwbuf, sizeof(targpwbuf), &targpw);
    318  	if (rv != 0)
    319  		err(1, "getpwuid_r failed");
    320  	if (targpw == NULL)
    321  		errx(1, "no passwd entry for target");
    322  
    323 -	if (setusercontext(NULL, targpw, target, LOGIN_SETGROUP |
    324 -	    LOGIN_SETPATH |
    325 -	    LOGIN_SETPRIORITY | LOGIN_SETRESOURCES | LOGIN_SETUMASK |
    326 -	    LOGIN_SETUSER | LOGIN_SETENV | LOGIN_SETRTABLE) != 0)
    327 -		errx(1, "failed to set user context for target");
    328 +	if (initgroups(targpw->pw_name, targpw->pw_gid) == -1)
    329 +		err(1, "initgroups");
    330 +	if (setgid(targpw->pw_gid) == -1)
    331 +		err(1, "setgid");
    332 +	if (setuid(targpw->pw_uid) == -1)
    333 +		err(1, "setuid");
    334  
    335  	if (pledge("stdio rpath exec", NULL) == -1)
    336  		err(1, "pledge");
    337 @@ -471,23 +417,17 @@ main(int argc, char **argv)
    338  		err(1, "pledge");
    339  
    340  	if (!(rule->options & NOLOG)) {
    341 -		syslog(LOG_AUTHPRIV | LOG_INFO,
    342 -		    "%s ran command %s as %s from %s",
    343 +		syslog(LOG_INFO, "%s ran command %s as %s from %s",
    344  		    mypw->pw_name, cmdline, targpw->pw_name, cwd);
    345  	}
    346  
    347  	envp = prepenv(rule, mypw, targpw);
    348  
    349 -	/* setusercontext set path for the next process, so reset it for us */
    350  	if (rule->cmd) {
    351  		if (setenv("PATH", safepath, 1) == -1)
    352  			err(1, "failed to set PATH '%s'", safepath);
    353 -	} else {
    354 -		if (setenv("PATH", formerpath, 1) == -1)
    355 -			err(1, "failed to set PATH '%s'", formerpath);
    356  	}
    357  	execvpe(cmd, argv, envp);
    358 -fail:
    359  	if (errno == ENOENT)
    360  		errx(1, "%s: command not found", cmd);
    361  	err(1, "%s", cmd);
    362 diff --git a/usr.bin/doas/doas.h b/usr.bin/doas/doas.h
    363 index b98fe353b18..6567625c471 100644
    364 --- a/usr.bin/doas/doas.h
    365 +++ b/usr.bin/doas/doas.h
    366 @@ -29,13 +29,17 @@ extern struct rule **rules;
    367  extern size_t nrules;
    368  extern int parse_error;
    369  
    370 -extern const char *formerpath;
    371 +extern const char *safepath;
    372  
    373  struct passwd;
    374  
    375  char **prepenv(const struct rule *, const struct passwd *,
    376      const struct passwd *);
    377  
    378 +int openpersist(int *valid);
    379 +int setpersist(int fd);
    380 +int clearpersist(void);
    381 +
    382  #define PERMIT	1
    383  #define DENY	2
    384  
    385 diff --git a/usr.bin/doas/env.c b/usr.bin/doas/env.c
    386 index 2d93a4089b6..dc9be691955 100644
    387 --- a/usr.bin/doas/env.c
    388 +++ b/usr.bin/doas/env.c
    389 @@ -28,7 +28,7 @@
    390  
    391  #include "doas.h"
    392  
    393 -const char *formerpath;
    394 +const char *safepath = "/bin";
    395  
    396  struct envnode {
    397  	RB_ENTRY(envnode) node;
    398 @@ -103,7 +103,7 @@ createenv(const struct rule *rule, const struct passwd *mypw,
    399  	addnode(env, "DOAS_USER", mypw->pw_name);
    400  	addnode(env, "HOME", targpw->pw_dir);
    401  	addnode(env, "LOGNAME", targpw->pw_name);
    402 -	addnode(env, "PATH", getenv("PATH"));
    403 +	addnode(env, "PATH", safepath);
    404  	addnode(env, "SHELL", targpw->pw_shell);
    405  	addnode(env, "USER", targpw->pw_name);
    406  
    407 @@ -200,17 +200,10 @@ fillenv(struct env *env, const char **envlist)
    408  		/* assign value or inherit from environ */
    409  		if (eq) {
    410  			val = eq + 1;
    411 -			if (*val == '$') {
    412 -				if (strcmp(val + 1, "PATH") == 0)
    413 -					val = formerpath;
    414 -				else
    415 -					val = getenv(val + 1);
    416 -			}
    417 +			if (*val == '$')
    418 +				val = getenv(val + 1);
    419  		} else {
    420 -			if (strcmp(name, "PATH") == 0)
    421 -				val = formerpath;
    422 -			else
    423 -				val = getenv(name);
    424 +			val = getenv(name);
    425  		}
    426  		/* at last, we have something to insert */
    427  		if (val) {
    428 diff --git a/usr.bin/doas/parse.y b/usr.bin/doas/parse.y
    429 index 604becb5445..e5fc912a9c4 100644
    430 --- a/usr.bin/doas/parse.y
    431 +++ b/usr.bin/doas/parse.y
    432 @@ -20,6 +20,7 @@
    433  #include <ctype.h>
    434  #include <limits.h>
    435  #include <unistd.h>
    436 +#include <stdlib.h>
    437  #include <stdint.h>
    438  #include <stdarg.h>
    439  #include <stdio.h>
    440 diff --git a/usr.bin/doas/persist.c b/usr.bin/doas/persist.c
    441 new file mode 100644
    442 index 00000000000..4ad1bf1efbf
    443 --- /dev/null
    444 +++ b/usr.bin/doas/persist.c
    445 @@ -0,0 +1,133 @@
    446 +#include <errno.h>
    447 +#include <fcntl.h>
    448 +#include <limits.h>
    449 +#include <stdio.h>
    450 +#include <stdlib.h>
    451 +#include <string.h>
    452 +#include <sys/stat.h>
    453 +#include <sys/types.h>
    454 +#include <time.h>
    455 +#include <unistd.h>
    456 +
    457 +#include "doas.h"
    458 +
    459 +#define PERSIST_DIR "/run/doas"
    460 +#define PERSIST_TIMEOUT 5 * 60
    461 +
    462 +static int
    463 +ttyid(dev_t *tty)
    464 +{
    465 +	int fd, i;
    466 +	char buf[BUFSIZ], *p;
    467 +	ssize_t n;
    468 +
    469 +	fd = open("/proc/self/stat", O_RDONLY);
    470 +	if (fd == -1)
    471 +		return -1;
    472 +	n = read(fd, buf, sizeof(buf) - 1);
    473 +	if (n >= 0)
    474 +		buf[n] = '\0';
    475 +	/* check that we read the whole file */
    476 +	n = read(fd, buf, 1);
    477 +	close(fd);
    478 +	if (n != 0)
    479 +		return -1;
    480 +	p = strrchr(buf, ')');
    481 +	if (!p)
    482 +		return -1;
    483 +	++p;
    484 +	/* ttr_nr is the 5th field after executable name, so skip the next 4 */
    485 +	for (i = 0; i < 4; ++i) {
    486 +		p = strchr(++p, ' ');
    487 +		if (!p)
    488 +			return -1;
    489 +	}
    490 +	*tty = strtol(p, &p, 10);
    491 +	if (*p != ' ')
    492 +		return -1;
    493 +	return 0;
    494 +}
    495 +
    496 +static int
    497 +persistpath(char *buf, size_t len)
    498 +{
    499 +	dev_t tty;
    500 +	int n;
    501 +
    502 +	if (ttyid(&tty) < 0)
    503 +		return -1;
    504 +	n = snprintf(buf, len, PERSIST_DIR "/%ju-%ju", (uintmax_t)getuid(), (uintmax_t)tty);
    505 +	if (n < 0 || n >= (int)len)
    506 +		return -1;
    507 +	return 0;
    508 +}
    509 +
    510 +int
    511 +openpersist(int *valid)
    512 +{
    513 +	char path[256];
    514 +	struct stat st;
    515 +	struct timespec ts;
    516 +	int fd;
    517 +
    518 +	if (stat(PERSIST_DIR, &st) < 0) {
    519 +		if (errno != ENOENT)
    520 +			return -1;
    521 +		if (mkdir(PERSIST_DIR, 0700) < 0)
    522 +			return -1;
    523 +	} else if (st.st_uid != 0 || st.st_mode != (S_IFDIR | 0700)) {
    524 +		return -1;
    525 +	}
    526 +	if (persistpath(path, sizeof(path)) < 0)
    527 +		return -1;
    528 +	fd = open(path, O_RDONLY);
    529 +	if (fd == -1) {
    530 +		char tmp[256];
    531 +		struct timespec ts[2] = { { .tv_nsec = UTIME_OMIT }, { 0 } };
    532 +		int n;
    533 +
    534 +		n = snprintf(tmp, sizeof(tmp), PERSIST_DIR "/.tmp-%d", getpid());
    535 +		if (n < 0 || n >= (int)sizeof(tmp))
    536 +			return -1;
    537 +		fd = open(tmp, O_RDONLY | O_CREAT | O_EXCL, 0);
    538 +		if (fd == -1)
    539 +			return -1;
    540 +		if (futimens(fd, ts) < 0 || rename(tmp, path) < 0) {
    541 +			close(fd);
    542 +			unlink(tmp);
    543 +			return -1;
    544 +		}
    545 +		*valid = 0;
    546 +	} else {
    547 +		*valid = clock_gettime(CLOCK_BOOTTIME, &ts) == 0 &&
    548 +		         fstat(fd, &st) == 0 &&
    549 +		         (ts.tv_sec < st.st_mtim.tv_sec ||
    550 +		          (ts.tv_sec == st.st_mtim.tv_sec && ts.tv_nsec < st.st_mtim.tv_nsec)) &&
    551 +		         st.st_mtime - ts.tv_sec <= PERSIST_TIMEOUT;
    552 +	}
    553 +	return fd;
    554 +}
    555 +
    556 +int
    557 +setpersist(int fd)
    558 +{
    559 +	struct timespec times[2];
    560 +
    561 +	if (clock_gettime(CLOCK_BOOTTIME, &times[1]) < 0)
    562 +		return -1;
    563 +	times[0].tv_nsec = UTIME_OMIT;
    564 +	times[1].tv_sec += PERSIST_TIMEOUT;
    565 +	return futimens(fd, times);
    566 +}
    567 +
    568 +int
    569 +clearpersist(void)
    570 +{
    571 +	char path[256];
    572 +
    573 +	if (persistpath(path, sizeof(path)) < 0)
    574 +		return -1;
    575 +	if (unlink(path) < 0 && errno != ENOENT)
    576 +		return -1;
    577 +	return 0;
    578 +}
    579 -- 
    580 2.37.3
    581