summaryrefslogtreecommitdiff
path: root/usr.bin/ssh/auth.c
diff options
context:
space:
mode:
authorDamien Miller <djm@cvs.openbsd.org>2020-12-22 00:12:23 +0000
committerDamien Miller <djm@cvs.openbsd.org>2020-12-22 00:12:23 +0000
commitd46573e488106db315308ac4e37d5868ee5426a2 (patch)
tree3160a814f6b7ad5d084331a7573121a6a459196f /usr.bin/ssh/auth.c
parent70908fc2db11aa3a1e6b9f32d7c630640a8df783 (diff)
move subprocess() from auth.c to misc.c
make privilege dropping optional but allow it via callbacks (to avoid need to link uidswap.c everywhere) add some other flags (keep environment, disable strict path safety check) that make this more useful for client-side use. feedback & ok markus@
Diffstat (limited to 'usr.bin/ssh/auth.c')
-rw-r--r--usr.bin/ssh/auth.c154
1 files changed, 1 insertions, 153 deletions
diff --git a/usr.bin/ssh/auth.c b/usr.bin/ssh/auth.c
index c4c23407ea3..e40a96cea32 100644
--- a/usr.bin/ssh/auth.c
+++ b/usr.bin/ssh/auth.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth.c,v 1.150 2020/12/20 23:36:51 djm Exp $ */
+/* $OpenBSD: auth.c,v 1.151 2020/12/22 00:12:22 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@@ -720,158 +720,6 @@ auth_get_canonical_hostname(struct ssh *ssh, int use_dns)
}
}
-/*
- * Runs command in a subprocess with a minimal environment.
- * Returns pid on success, 0 on failure.
- * The child stdout and stderr maybe captured, left attached or sent to
- * /dev/null depending on the contents of flags.
- * "tag" is prepended to log messages.
- * NB. "command" is only used for logging; the actual command executed is
- * av[0].
- */
-pid_t
-subprocess(const char *tag, struct passwd *pw, const char *command,
- int ac, char **av, FILE **child, u_int flags)
-{
- FILE *f = NULL;
- struct stat st;
- int fd, devnull, p[2], i;
- pid_t pid;
- char *cp, errmsg[512];
- u_int envsize;
- char **child_env;
-
- if (child != NULL)
- *child = NULL;
-
- debug3_f("%s command \"%s\" running as %s (flags 0x%x)",
- tag, command, pw->pw_name, flags);
-
- /* Check consistency */
- if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 &&
- (flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0) {
- error_f("inconsistent flags");
- return 0;
- }
- if (((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0) != (child == NULL)) {
- error_f("inconsistent flags/output");
- return 0;
- }
-
- /*
- * If executing an explicit binary, then verify the it exists
- * and appears safe-ish to execute
- */
- if (!path_absolute(av[0])) {
- error("%s path is not absolute", tag);
- return 0;
- }
- temporarily_use_uid(pw);
- if (stat(av[0], &st) == -1) {
- error("Could not stat %s \"%s\": %s", tag,
- av[0], strerror(errno));
- restore_uid();
- return 0;
- }
- if (safe_path(av[0], &st, NULL, 0, errmsg, sizeof(errmsg)) != 0) {
- error("Unsafe %s \"%s\": %s", tag, av[0], errmsg);
- restore_uid();
- return 0;
- }
- /* Prepare to keep the child's stdout if requested */
- if (pipe(p) == -1) {
- error("%s: pipe: %s", tag, strerror(errno));
- restore_uid();
- return 0;
- }
- restore_uid();
-
- switch ((pid = fork())) {
- case -1: /* error */
- error("%s: fork: %s", tag, strerror(errno));
- close(p[0]);
- close(p[1]);
- return 0;
- case 0: /* child */
- /* Prepare a minimal environment for the child. */
- envsize = 5;
- child_env = xcalloc(sizeof(*child_env), envsize);
- child_set_env(&child_env, &envsize, "PATH", _PATH_STDPATH);
- child_set_env(&child_env, &envsize, "USER", pw->pw_name);
- child_set_env(&child_env, &envsize, "LOGNAME", pw->pw_name);
- child_set_env(&child_env, &envsize, "HOME", pw->pw_dir);
- if ((cp = getenv("LANG")) != NULL)
- child_set_env(&child_env, &envsize, "LANG", cp);
-
- for (i = 0; i < NSIG; i++)
- ssh_signal(i, SIG_DFL);
-
- if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
- error("%s: open %s: %s", tag, _PATH_DEVNULL,
- strerror(errno));
- _exit(1);
- }
- if (dup2(devnull, STDIN_FILENO) == -1) {
- error("%s: dup2: %s", tag, strerror(errno));
- _exit(1);
- }
-
- /* Set up stdout as requested; leave stderr in place for now. */
- fd = -1;
- if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0)
- fd = p[1];
- else if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0)
- fd = devnull;
- if (fd != -1 && dup2(fd, STDOUT_FILENO) == -1) {
- error("%s: dup2: %s", tag, strerror(errno));
- _exit(1);
- }
- closefrom(STDERR_FILENO + 1);
-
- /* Don't use permanently_set_uid() here to avoid fatal() */
- if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1) {
- error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid,
- strerror(errno));
- _exit(1);
- }
- if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) {
- error("%s: setresuid %u: %s", tag, (u_int)pw->pw_uid,
- strerror(errno));
- _exit(1);
- }
- /* stdin is pointed to /dev/null at this point */
- if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 &&
- dup2(STDIN_FILENO, STDERR_FILENO) == -1) {
- error("%s: dup2: %s", tag, strerror(errno));
- _exit(1);
- }
-
- execve(av[0], av, child_env);
- error("%s exec \"%s\": %s", tag, command, strerror(errno));
- _exit(127);
- default: /* parent */
- break;
- }
-
- close(p[1]);
- if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0)
- close(p[0]);
- else if ((f = fdopen(p[0], "r")) == NULL) {
- error("%s: fdopen: %s", tag, strerror(errno));
- close(p[0]);
- /* Don't leave zombie child */
- kill(pid, SIGTERM);
- while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
- ;
- return 0;
- }
- /* Success */
- debug3_f("%s pid %ld", tag, (long)pid);
- if (child != NULL)
- *child = f;
- return pid;
-}
-
/* These functions link key/cert options to the auth framework */
/* Log sshauthopt options locally and (optionally) for remote transmission */