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;
} ;