]> git.armaanb.net Git - opendoas.git/blobdiff - doas.c
Add closefrom(2) from openssh-portable
[opendoas.git] / doas.c
diff --git a/doas.c b/doas.c
index e74881b7652b6dc114c2ce9874484164bb615d8f..d4d87cb7c930780effa5931cf944089cf4c3b083 100644 (file)
--- a/doas.c
+++ b/doas.c
@@ -28,6 +28,9 @@
 #include <grp.h>
 #include <syslog.h>
 #include <errno.h>
+#if HAVE_SHADOW_H
+#include <shadow.h>
+#endif
 
 #include "includes.h"
 
@@ -43,8 +46,11 @@ version(void)
 static void __dead
 usage(void)
 {
-       fprintf(stderr, "usage: doas [-nsv] [-a style] [-C config] [-u user]"
-           " command [args]\n");
+       fprintf(stderr, "usage: doas [-nsv] "
+#ifdef HAVE_BSD_AUTH_H
+           "[-a style] "
+#endif
+           "[-C config] [-u user] command [args]\n");
        exit(1);
 }
 
@@ -243,17 +249,17 @@ main(int argc, char **argv)
 
        setprogname("doas");
 
-       if (pledge("stdio rpath getpw tty proc exec id", NULL) == -1)
+       if (pledge("stdio rpath getpw tty recvfd proc exec id", NULL) == -1)
                err(1, "pledge");
 
-       /* closefrom(STDERR_FILENO + 1); */
+       closefrom(STDERR_FILENO + 1);
 
        uid = getuid();
 
 #ifdef HAVE_BSD_AUTH_H
 # define OPTSTRING "a:C:nsu:v"
 #else
-# define OPTSTRING "C:nsu:v"
+# define OPTSTRING "+C:nsu:v"
 #endif
 
        while ((ch = getopt(argc, argv, OPTSTRING)) != -1) {
@@ -308,9 +314,11 @@ main(int argc, char **argv)
 
        if (sflag) {
                sh = getenv("SHELL");
-               if (sh == NULL || *sh == '\0')
-                       shargv[0] = pw->pw_shell;
-               else
+               if (sh == NULL || *sh == '\0') {
+                       shargv[0] = strdup(pw->pw_shell);
+                       if (shargv[0] == NULL)
+                               err(1, NULL);
+               } else
                        shargv[0] = sh;
                argv = shargv;
                argc = 1;
@@ -325,7 +333,7 @@ main(int argc, char **argv)
        parseconfig("/etc/doas.conf", 1);
 
        /* cmdline is used only for logging, no need to abort on truncate */
-       (void) strlcpy(cmdline, argv[0], sizeof(cmdline));
+       (void)strlcpy(cmdline, argv[0], sizeof(cmdline));
        for (i = 1; i < argc; i++) {
                if (strlcat(cmdline, " ", sizeof(cmdline)) >= sizeof(cmdline))
                        break;
@@ -335,16 +343,12 @@ main(int argc, char **argv)
 
        cmd = argv[0];
        if (!permit(uid, groups, ngroups, &rule, target, cmd,
-           (const char**)argv + 1)) {
+           (const char **)argv + 1)) {
                syslog(LOG_AUTHPRIV | LOG_NOTICE,
                    "failed command for %s: %s", myname, cmdline);
                errc(1, EPERM, NULL);
        }
 
-       pw = getpwuid(target);
-       if (!pw)
-               errx(1, "no passwd entry for target");
-
 #ifdef HAVE_BSD_AUTH_H
        if (!(rule->options & NOPASS)) {
                if (nflag)
@@ -379,18 +383,60 @@ main(int argc, char **argv)
                explicit_bzero(rbuf, sizeof(rbuf));
        }
 #elif HAVE_PAM_APPL_H
+       pw = getpwuid(target);
+       if (!pw)
+               errx(1, "no passwd entry for target");
+
        if (!pamauth(pw->pw_name, myname, !nflag, rule->options & NOPASS)) {
                syslog(LOG_AUTHPRIV | LOG_NOTICE, "failed auth for %s", myname);
                errc(1, EPERM, NULL);
        }
-#else
+#elif HAVE_SHADOW_H
+       const char *pass;
+
        if (!(rule->options & NOPASS)) {
+               if (nflag)
                        errx(1, "Authorization required");
+
+               pass = pw->pw_passwd;
+               if (pass[0] == 'x' && pass[1] == '\0') {
+                       struct spwd *sp;
+                       if (!(sp = getspnam(myname)))
+                               errx(1, "Authorization failed");
+                       pass = sp->sp_pwdp;
+               }
+
+               char *challenge, *response, rbuf[1024], cbuf[128], 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 (strcmp(crypt(response, pass), pass) != 0) {
+                       syslog(LOG_AUTHPRIV | LOG_NOTICE, "failed auth for %s", myname);
+                       errc(1, EPERM, NULL);
+               }
+               explicit_bzero(rbuf, sizeof(rbuf));
+       }
+#else
+       if (!(rule->options & NOPASS))
+               errx(1, "Authorization required");
 #endif /* HAVE_BSD_AUTH_H */
 
        if (pledge("stdio rpath getpw exec id", NULL) == -1)
                err(1, "pledge");
 
+       pw = getpwuid(target);
+       if (!pw)
+               errx(1, "no passwd entry for target");
+
 #ifdef HAVE_BSD_AUTH_H
        if (setusercontext(NULL, pw, target, LOGIN_SETGROUP |
            LOGIN_SETPRIORITY | LOGIN_SETRESOURCES | LOGIN_SETUMASK |