Hello tech@,

The following patch adds $PATH resolving to doas. This has two advantages:
1) People are forced to configure doas with a full path, which makes sure that applications can't be spoofed by users changing their $PATH to a writeable location and making copies of other (potential dangerous) binaries to said directories 2) People who were already using full paths in doas.conf(5) are now allowed to run `shutdown` as a simple `shutdown` instead of typing `/sbin/shutdown` every time.

THIS PATCH CAN AND MIGHT BREAK YOUR doas.conf(5) CONFIGURATION FILE!

Sincerely,

Martijn van Duren
Index: doas.c
===================================================================
RCS file: /cvs/src/usr.bin/doas/doas.c,v
retrieving revision 1.42
diff -u -p -r1.42 doas.c
--- doas.c	19 Sep 2015 02:47:46 -0000	1.42
+++ doas.c	19 Sep 2015 18:38:22 -0000
@@ -26,6 +26,7 @@
 #include <stdlib.h>
 #include <err.h>
 #include <unistd.h>
+#include <paths.h>
 #include <pwd.h>
 #include <grp.h>
 #include <syslog.h>
@@ -300,6 +301,55 @@ checkconfig(const char *confpath, int ar
 	}
 }
 
+static const char *
+findprog(const char *cmd)
+{
+	struct stat	 sb;
+	char		 cwd[PATH_MAX];
+	static char	 path[PATH_MAX];
+	char		*epath, *cur, *p;
+
+	if (cmd[0] == '/') {
+		if (strlcpy(path, cmd, PATH_MAX) > PATH_MAX) {
+			errno = ENAMETOOLONG;
+			return NULL;
+		}
+		return path;
+	}
+
+	if (getcwd(cwd, PATH_MAX) == NULL)
+		return NULL;
+	if (strchr(cmd, '/')) {
+		if (snprintf(path, PATH_MAX, "%s/%s", cwd, cmd) > PATH_MAX) {
+			errno = ENAMETOOLONG;
+			return NULL;
+		}
+		return path;
+	}
+
+	epath = getenv("PATH");
+	if (epath == NULL)
+		epath = _PATH_STDPATH;
+	epath = strdup(epath);
+	cur = epath;
+
+	while ((p = strsep(&cur, ":")) != NULL) {
+		if (snprintf(path, PATH_MAX, "%s/%s", !*p ? cwd : p, cmd) >
+		    PATH_MAX) {
+			errno = ENAMETOOLONG;
+			continue;
+		}
+		if (stat(path, &sb) == 0 && S_ISREG(sb.st_mode) &&
+		    access(path, X_OK) == 0)
+			break;
+	}
+	free(epath);
+
+	if (p == NULL)
+		errno = ENOENT;
+	return p == NULL ? NULL : path;
+}
+
 int
 main(int argc, char **argv, char **envp)
 {
@@ -393,7 +443,11 @@ main(int argc, char **argv, char **envp)
 			break;
 	}
 
-	cmd = argv[0];
+	if ((cmd = findprog(argv[0])) == NULL) {
+		if (errno == ENOENT)
+			errx(1, "%s: command not found", argv[0]);
+		err(1, "%s", argv[0]);
+	}
 	if (!permit(uid, groups, ngroups, &rule, target, cmd,
 	    (const char**)argv + 1)) {
 		syslog(LOG_AUTHPRIV | LOG_NOTICE,
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.bin/doas/parse.y,v
retrieving revision 1.12
diff -u -p -r1.12 parse.y
--- parse.y	1 Sep 2015 16:20:55 -0000	1.12
+++ parse.y	19 Sep 2015 18:38:22 -0000
@@ -148,6 +148,8 @@ cmd:		/* optional */ {
 			$$.cmdargs = NULL;
 		} | TCMD TSTRING args {
 			$$.cmd = $2.str;
+			if ($$.cmd[0] != '/')
+				yyerror("cmd must be a full path.");
 			$$.cmdargs = $3.cmdargs;
 		} ;
 

Reply via email to