diff options
Diffstat (limited to 'usr/src/cmd/ssh/sshd/auth.c')
-rw-r--r-- | usr/src/cmd/ssh/sshd/auth.c | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/usr/src/cmd/ssh/sshd/auth.c b/usr/src/cmd/ssh/sshd/auth.c index 9df2117ea8..64e6959ecf 100644 --- a/usr/src/cmd/ssh/sshd/auth.c +++ b/usr/src/cmd/ssh/sshd/auth.c @@ -55,6 +55,8 @@ RCSID("$OpenBSD: auth.c,v 1.45 2002/09/20 18:41:29 stevesk Exp $"); #include "misc.h" #include "bufaux.h" #include "packet.h" +#include "channels.h" +#include "session.h" #ifdef HAVE_BSM #include "bsmaudit.h" @@ -613,6 +615,144 @@ getpwnamallow(const char *user) return (NULL); } + +/* + * The fatal_cleanup method to kill the hook. Since hook has been put into + * new process group all descendants will be killed as well. + */ +static void +kill_hook(void *arg) +{ + pid_t pid; + + pid = *(pid_t*)arg; + debug("killing hook and all it's children, process group: %ld", pid); + xfree(arg); + (void)killpg(pid, SIGTERM); +} + +/* + * Runs the PreUserauthHook. + * Returns -1 on execution error or the exit code of the hook if execution is + * successful. + */ +int +run_auth_hook(const char *path, const char *user, const char *method) +{ + struct stat st; + int i, status, ret = 1; + u_int envsize, argsize; + char buf[256]; + char **env, **args; + pid_t pid, *ppid; + + if (path == NULL || user == NULL || method == NULL) { + return (-1); + } + + /* Initialize the environment/arguments for the hook. */ + envsize = 4; /* 3 env vars + EndOfList marker */ + argsize = 4; /* 2 args + exe name + EndOfList marker */ + env = xmalloc(envsize * sizeof (char *)); + args = xmalloc(argsize * sizeof (char *)); + env[0] = NULL; + + /* we use the SSH env handling scheme */ + child_set_env_silent(&env, &envsize, "PATH", "/usr/bin:/bin"); + child_set_env_silent(&env, &envsize, "IFS", " \t\n"); + + (void) snprintf(buf, sizeof (buf), "%.50s %d %.50s %d", + get_remote_ipaddr(), get_remote_port(), + get_local_ipaddr(packet_get_connection_in()), get_local_port()); + child_set_env_silent(&env, &envsize, "SSH_CONNECTION", buf); + + args[0] = xstrdup(path); + args[1] = xstrdup(method); + args[2] = xstrdup(user); + args[3] = NULL; + + /* + * sanity checks + * note: the checks do not make sure that the file checked is actually + * the same which is executed. However, in this case it shouldn't be a + * major issue since the hook is rather static and the worst case would + * be an uncorrect message in the log or a hook is run even though the + * permissions are not right. + */ + + /* check if script does exist */ + if (stat(path, &st) < 0) { + log("Error executing PreUserauthHook \"%s\": %s", path, + strerror(errno)); + goto cleanup; + } + + /* Check correct permissions for script (uid of SSHD, mode 500) */ + if (st.st_uid != getuid() || ((st.st_mode & 0777) != 0500)) { + log("PreUserauthHook has invalid permissions (should be 500, is" + " %o) or ownership (should be %d, is %d)", + (uint) st.st_mode & 0777, getuid(), st.st_uid); + goto cleanup; + } + + if ((pid = fork()) == 0) { + /* + * We put the hook and all its (possible) descendants into + * a new process group so that in case of a hanging hook + * we can wipe out the whole "family". + */ + if (setpgid(0, 0) != 0) { + log("setpgid: %s", strerror(errno)); + _exit(255); + } + (void) execve(path, args, env); + /* child is gone so we shouldn't get here */ + log("Error executing PreUserauthHook \"%s\": %s", path, + strerror(errno)); + _exit(255); + } else if (pid == -1) { + log("Error executing PreUserauthHook \"%s\": %s", path, + strerror(errno)); + goto cleanup; + } + + /* make preparations to kill hook if it is hanging */ + ppid = xmalloc(sizeof (pid_t)); + *ppid = pid; + fatal_add_cleanup((void (*)(void *))kill_hook, (void *) ppid); + + if (waitpid(pid, &status, 0) == -1) { + log("Error executing PreUserauthHook \"%s\": %s", path, + strerror(errno)); + goto cleanup; + } + + ret = WEXITSTATUS(status); + + if (ret == 255) { + ret = -1; /* execve() failed, error msg already logged */ + } else if (ret != 0) { + log("PreUserauthHook \"%s\" failed with exit code %d", + path, ret); + } else { + debug("PreUserauthHook \"%s\" finished successfully", path); + } + +cleanup: + for (i = 0; args[i] != NULL; i++) { + xfree(args[i]); + } + for (i = 0; env[i] != NULL; i++) { + xfree(env[i]); + } + xfree(args); + xfree(env); + + fatal_remove_cleanup((void (*)(void *))kill_hook, (void *) ppid); + + return (ret); +} + void auth_debug_add(const char *fmt,...) { |