Resolved auth2-pubkey.c misc.c ssh-keygen.c
This commit is contained in:
Manoj Ampalam 2017-08-27 22:05:23 -07:00
commit eaf004d1c4
39 changed files with 1016 additions and 965 deletions

View File

@ -19,3 +19,5 @@ fe5b31f69a60d47171836911f144acff77810217 Makefile.inc bits
ea80f445e819719ccdcb237022cacfac990fdc5c Makefile.inc warning flags
b92c93266d8234d493857bb822260dacf4366157 moduli-gen.sh tweak
b25bf747544265b39af74fe0716dc8d9f5b63b95 Updated moduli
1bd41cba06a7752de4df304305a8153ebfb6b0ac rsa.[ch] already removed
e39b3902fe1d6c4a7ba6a3c58e072219f3c1e604 Makefile changes

View File

@ -81,7 +81,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
cipher-ctr.o cleanup.o \
compat.o crc32.o fatal.o hostfile.o \
log.o match.o moduli.o nchan.o packet.o opacket.o \
readpass.o rsa.o ttymodes.o xmalloc.o addrmatch.o \
readpass.o ttymodes.o xmalloc.o addrmatch.o \
atomicio.o key.o dispatch.o mac.o uidswap.o uuencode.o misc.o utf8.o \
monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \
msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \
@ -92,7 +92,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \
kexdhc.o kexgexc.o kexecdhc.o kexc25519c.o \
kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o \
platform-pledge.o platform-tracing.o
platform-pledge.o platform-tracing.o platform-misc.o
SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
sshconnect.o sshconnect2.o mux.o

8
README
View File

@ -30,7 +30,8 @@ The PAM support is now more functional than the popular packages of
commercial ssh-1.2.x. It checks "account" and "session" modules for
all logins, not just when using password authentication.
OpenSSH depends on Zlib[3], OpenSSL[4] and optionally PAM[5].
OpenSSH depends on Zlib[3], OpenSSL[4], and optionally PAM[5] and
libedit[6]
There is now several mailing lists for this port of OpenSSH. Please
refer to https://www.openssh.com/list.html for details on how to join.
@ -38,7 +39,7 @@ refer to https://www.openssh.com/list.html for details on how to join.
Please send bug reports and patches to the mailing list
openssh-unix-dev@mindrot.org. The list is open to posting by unsubscribed
users. Code contribution are welcomed, but please follow the OpenBSD
style guidelines[6].
style guidelines[7].
Please refer to the INSTALL document for information on how to install
OpenSSH on your system.
@ -61,4 +62,5 @@ References -
[5] http://www.openpam.org
http://www.kernel.org/pub/linux/libs/pam/
(PAM also is standard on Solaris and HP-UX 11)
[6] http://man.openbsd.org/style.9
[6] http://thrysoee.dk/editline/ (portable version)
[7] http://man.openbsd.org/style.9

View File

@ -926,6 +926,27 @@ finish_pam(void)
sshpam_cleanup();
}
static void
expose_authinfo(const char *caller)
{
char *auth_info;
/*
* Expose authentication information to PAM.
* The enviornment variable is versioned. Please increment the
* version suffix if the format of session_info changes.
*/
if (sshpam_authctxt->session_info == NULL)
auth_info = xstrdup("");
else if ((auth_info = sshbuf_dup_string(
sshpam_authctxt->session_info)) == NULL)
fatal("%s: sshbuf_dup_string failed", __func__);
debug2("%s: auth information in SSH_AUTH_INFO_0", caller);
do_pam_putenv("SSH_AUTH_INFO_0", auth_info);
free(auth_info);
}
u_int
do_pam_account(void)
{
@ -933,6 +954,8 @@ do_pam_account(void)
if (sshpam_account_status != -1)
return (sshpam_account_status);
expose_authinfo(__func__);
sshpam_err = pam_acct_mgmt(sshpam_handle, 0);
debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err,
pam_strerror(sshpam_handle, sshpam_err));
@ -1057,6 +1080,9 @@ void
do_pam_session(void)
{
debug3("PAM: opening session");
expose_authinfo(__func__);
sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
(const void *)&store_conv);
if (sshpam_err != PAM_SUCCESS)

99
auth.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth.c,v 1.122 2017/06/24 06:34:38 djm Exp $ */
/* $OpenBSD: auth.c,v 1.123 2017/08/18 05:36:45 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -43,9 +43,6 @@
#ifdef USE_SHADOW
#include <shadow.h>
#endif
#ifdef HAVE_LIBGEN_H
#include <libgen.h>
#endif
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
@ -508,98 +505,6 @@ check_key_in_hostfiles(struct passwd *pw, struct sshkey *key, const char *host,
return host_status;
}
/*
* Check a given path for security. This is defined as all components
* of the path to the file must be owned by either the owner of
* of the file or root and no directories must be group or world writable.
*
* XXX Should any specific check be done for sym links ?
*
* Takes a file name, its stat information (preferably from fstat() to
* avoid races), the uid of the expected owner, their home directory and an
* error buffer plus max size as arguments.
*
* Returns 0 on success and -1 on failure
*/
int
auth_secure_path(const char *name, struct stat *stp, const char *pw_dir,
uid_t uid, char *err, size_t errlen)
{
char buf[PATH_MAX], homedir[PATH_MAX];
char *cp;
int comparehome = 0;
struct stat st;
if (realpath(name, buf) == NULL) {
snprintf(err, errlen, "realpath %s failed: %s", name,
strerror(errno));
return -1;
}
if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)
comparehome = 1;
if (!S_ISREG(stp->st_mode)) {
snprintf(err, errlen, "%s is not a regular file", buf);
return -1;
}
if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) ||
(stp->st_mode & 022) != 0) {
snprintf(err, errlen, "bad ownership or modes for file %s",
buf);
return -1;
}
/* for each component of the canonical path, walking upwards */
for (;;) {
if ((cp = dirname(buf)) == NULL) {
snprintf(err, errlen, "dirname() failed");
return -1;
}
strlcpy(buf, cp, sizeof(buf));
if (stat(buf, &st) < 0 ||
(!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) ||
(st.st_mode & 022) != 0) {
snprintf(err, errlen,
"bad ownership or modes for directory %s", buf);
return -1;
}
/* If are past the homedir then we can stop */
if (comparehome && strcmp(homedir, buf) == 0)
break;
/*
* dirname should always complete with a "/" path,
* but we can be paranoid and check for "." too
*/
if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
break;
}
return 0;
}
/*
* Version of secure_path() that accepts an open file descriptor to
* avoid races.
*
* Returns 0 on success and -1 on failure
*/
static int
secure_filename(FILE *f, const char *file, struct passwd *pw,
char *err, size_t errlen)
{
struct stat st;
/* check the open file to avoid races */
if (fstat(fileno(f), &st) < 0) {
snprintf(err, errlen, "cannot stat file %s: %s",
file, strerror(errno));
return -1;
}
return auth_secure_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);
}
static FILE *
auth_openfile(const char *file, struct passwd *pw, int strict_modes,
int log_missing, char *file_type)
@ -646,7 +551,7 @@ auth_openfile(const char *file, struct passwd *pw, int strict_modes,
return NULL;
}
if (strict_modes &&
secure_filename(f, file, pw, line, sizeof(line)) != 0) {
safe_path_fd(fileno(f), file, pw, line, sizeof(line)) != 0) {
fclose(f);
logit("Authentication refused: %s", line);
auth_debug_add("Ignored %s: %s", file_type, line);

6
auth.h
View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth.h,v 1.92 2017/06/24 06:34:38 djm Exp $ */
/* $OpenBSD: auth.h,v 1.93 2017/08/18 05:36:45 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
@ -149,10 +149,6 @@ void auth2_record_info(Authctxt *authctxt, const char *, ...)
__attribute__((__nonnull__ (2)));
void auth2_update_session_info(Authctxt *, const char *, const char *);
struct stat;
int auth_secure_path(const char *, struct stat *, const char *, uid_t,
char *, size_t);
#ifdef KRB5
int auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client, krb5_data *);
int auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth2-pubkey.c,v 1.68 2017/06/24 06:34:38 djm Exp $ */
/* $OpenBSD: auth2-pubkey.c,v 1.70 2017/08/18 05:48:04 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -27,7 +27,6 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
@ -249,293 +248,6 @@ done:
return authenticated;
}
/*
* Splits 's' into an argument vector. Handles quoted string and basic
* escape characters (\\, \", \'). Caller must free the argument vector
* and its members.
*/
static int
split_argv(const char *s, int *argcp, char ***argvp)
{
int r = SSH_ERR_INTERNAL_ERROR;
int argc = 0, quote, i, j;
char *arg, **argv = xcalloc(1, sizeof(*argv));
*argvp = NULL;
*argcp = 0;
for (i = 0; s[i] != '\0'; i++) {
/* Skip leading whitespace */
if (s[i] == ' ' || s[i] == '\t')
continue;
/* Start of a token */
quote = 0;
if (s[i] == '\\' &&
(s[i + 1] == '\'' || s[i + 1] == '\"' || s[i + 1] == '\\'))
i++;
else if (s[i] == '\'' || s[i] == '"')
quote = s[i++];
argv = xreallocarray(argv, (argc + 2), sizeof(*argv));
arg = argv[argc++] = xcalloc(1, strlen(s + i) + 1);
argv[argc] = NULL;
/* Copy the token in, removing escapes */
for (j = 0; s[i] != '\0'; i++) {
if (s[i] == '\\') {
if (s[i + 1] == '\'' ||
s[i + 1] == '\"' ||
s[i + 1] == '\\') {
i++; /* Skip '\' */
arg[j++] = s[i];
} else {
/* Unrecognised escape */
arg[j++] = s[i];
}
} else if (quote == 0 && (s[i] == ' ' || s[i] == '\t'))
break; /* done */
else if (quote != 0 && s[i] == quote)
break; /* done */
else
arg[j++] = s[i];
}
if (s[i] == '\0') {
if (quote != 0) {
/* Ran out of string looking for close quote */
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
break;
}
}
/* Success */
*argcp = argc;
*argvp = argv;
argc = 0;
argv = NULL;
r = 0;
out:
if (argc != 0 && argv != NULL) {
for (i = 0; i < argc; i++)
free(argv[i]);
free(argv);
}
return r;
}
/*
* Reassemble an argument vector into a string, quoting and escaping as
* necessary. Caller must free returned string.
*/
static char *
assemble_argv(int argc, char **argv)
{
int i, j, ws, r;
char c, *ret;
struct sshbuf *buf, *arg;
if ((buf = sshbuf_new()) == NULL || (arg = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__);
for (i = 0; i < argc; i++) {
ws = 0;
sshbuf_reset(arg);
for (j = 0; argv[i][j] != '\0'; j++) {
r = 0;
c = argv[i][j];
switch (c) {
case ' ':
case '\t':
ws = 1;
r = sshbuf_put_u8(arg, c);
break;
case '\\':
case '\'':
case '"':
if ((r = sshbuf_put_u8(arg, '\\')) != 0)
break;
/* FALLTHROUGH */
default:
r = sshbuf_put_u8(arg, c);
break;
}
if (r != 0)
fatal("%s: sshbuf_put_u8: %s",
__func__, ssh_err(r));
}
if ((i != 0 && (r = sshbuf_put_u8(buf, ' ')) != 0) ||
(ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0) ||
(r = sshbuf_putb(buf, arg)) != 0 ||
(ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0))
fatal("%s: buffer error: %s", __func__, ssh_err(r));
}
if ((ret = malloc(sshbuf_len(buf) + 1)) == NULL)
fatal("%s: malloc failed", __func__);
memcpy(ret, sshbuf_ptr(buf), sshbuf_len(buf));
ret[sshbuf_len(buf)] = '\0';
sshbuf_free(buf);
sshbuf_free(arg);
return ret;
}
/*
* Runs command in a subprocess. Returns pid on success and a FILE* to the
* subprocess' stdout or 0 on failure.
* NB. "command" is only used for logging.
*/
static pid_t
subprocess(const char *tag, struct passwd *pw, const char *command,
int ac, char **av, FILE **child)
{
#ifdef WINDOWS
logit("AuthorizedPrincipalsCommand and AuthorizedKeysCommand are not supported in Windows yet");
return 0;
#else /* !WINDOWS */
FILE *f;
struct stat st;
int devnull, p[2], i;
pid_t pid;
char *cp, errmsg[512];
u_int envsize;
char **child_env;
*child = NULL;
debug3("%s: %s command \"%s\" running as %s", __func__,
tag, command, pw->pw_name);
/* Verify the path exists and is safe-ish to execute */
if (*av[0] != '/') {
error("%s path is not absolute", tag);
return 0;
}
temporarily_use_uid(pw);
if (stat(av[0], &st) < 0) {
error("Could not stat %s \"%s\": %s", tag,
av[0], strerror(errno));
restore_uid();
return 0;
}
if (auth_secure_path(av[0], &st, NULL, 0,
errmsg, sizeof(errmsg)) != 0) {
error("Unsafe %s \"%s\": %s", tag, av[0], errmsg);
restore_uid();
return 0;
}
/*
* Run the command; stderr is left in place, stdout is the
* authorized_keys output.
*/
if (pipe(p) != 0) {
error("%s: pipe: %s", tag, strerror(errno));
restore_uid();
return 0;
}
/*
* Don't want to call this in the child, where it can fatal() and
* run cleanup_exit() code.
*/
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++)
signal(i, SIG_DFL);
if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
error("%s: open %s: %s", tag, _PATH_DEVNULL,
strerror(errno));
_exit(1);
}
/* Keep stderr around a while longer to catch errors */
if (dup2(devnull, STDIN_FILENO) == -1 ||
dup2(p[1], 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) != 0) {
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) != 0) {
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 (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 ((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("%s: %s pid %ld", __func__, tag, (long)pid);
*child = f;
return pid;
#endif /* !WINDOWS */
}
/* Returns 0 if pid exited cleanly, non-zero otherwise */
static int
exited_cleanly(pid_t pid, const char *tag, const char *cmd)
{
int status;
while (waitpid(pid, &status, 0) == -1) {
if (errno != EINTR) {
error("%s: waitpid: %s", tag, strerror(errno));
return -1;
}
}
if (WIFSIGNALED(status)) {
error("%s %s exited on signal %d", tag, cmd, WTERMSIG(status));
return -1;
} else if (WEXITSTATUS(status) != 0) {
error("%s %s failed, status %d", tag, cmd, WEXITSTATUS(status));
return -1;
}
return 0;
}
static int
match_principals_option(const char *principal_list, struct sshkey_cert *cert)
{
@ -668,7 +380,7 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
}
/* Turn the command into an argument vector */
if (split_argv(options.authorized_principals_command, &ac, &av) != 0) {
if (argv_split(options.authorized_principals_command, &ac, &av) != 0) {
error("AuthorizedPrincipalsCommand \"%s\" contains "
"invalid quotes", command);
goto out;
@ -717,10 +429,11 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
av[i] = tmp;
}
/* Prepare a printable command for logs, etc. */
command = assemble_argv(ac, av);
command = argv_assemble(ac, av);
if ((pid = subprocess("AuthorizedPrincipalsCommand", pw, command,
ac, av, &f)) == 0)
ac, av, &f,
SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0)
goto out;
uid_swapped = 1;
@ -731,7 +444,7 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
fclose(f);
f = NULL;
if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command) != 0)
if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command, 0) != 0)
goto out;
/* Read completed successfully */
@ -1008,7 +721,7 @@ user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
}
/* Turn the command into an argument vector */
if (split_argv(options.authorized_keys_command, &ac, &av) != 0) {
if (argv_split(options.authorized_keys_command, &ac, &av) != 0) {
error("AuthorizedKeysCommand \"%s\" contains invalid quotes",
command);
goto out;
@ -1032,7 +745,7 @@ user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
av[i] = tmp;
}
/* Prepare a printable command for logs, etc. */
command = assemble_argv(ac, av);
command = argv_assemble(ac, av);
/*
* If AuthorizedKeysCommand was run without arguments
@ -1049,7 +762,8 @@ user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
}
if ((pid = subprocess("AuthorizedKeysCommand", pw, command,
ac, av, &f)) == 0)
ac, av, &f,
SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0)
goto out;
uid_swapped = 1;
@ -1060,7 +774,7 @@ user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
fclose(f);
f = NULL;
if (exited_cleanly(pid, "AuthorizedKeysCommand", command) != 0)
if (exited_cleanly(pid, "AuthorizedKeysCommand", command, 0) != 0)
goto out;
/* Read completed successfully */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: authfd.c,v 1.104 2017/06/28 01:09:22 djm Exp $ */
/* $OpenBSD: authfd.c,v 1.105 2017/07/01 13:50:45 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -51,7 +51,6 @@
#include "xmalloc.h"
#include "ssh.h"
#include "rsa.h"
#include "sshbuf.h"
#include "sshkey.h"
#include "authfd.h"

View File

@ -1,4 +1,4 @@
/* $OpenBSD: authfile.c,v 1.126 2017/05/31 09:15:42 deraadt Exp $ */
/* $OpenBSD: authfile.c,v 1.127 2017/07/01 13:50:45 djm Exp $ */
/*
* Copyright (c) 2000, 2013 Markus Friedl. All rights reserved.
*
@ -42,7 +42,6 @@
#include "ssh.h"
#include "log.h"
#include "authfile.h"
#include "rsa.h"
#include "misc.h"
#include "atomicio.h"
#include "sshkey.h"

View File

@ -1,4 +1,4 @@
/* $OpenBSD: clientloop.c,v 1.300 2017/06/23 07:24:48 mestre Exp $ */
/* $OpenBSD: clientloop.c,v 1.301 2017/07/14 03:18:21 dtucker Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -1422,8 +1422,10 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
exit_status = 0;
}
if (received_signal)
fatal("Killed by signal %d.", (int) received_signal);
if (received_signal) {
verbose("Killed by signal %d.", (int) received_signal);
cleanup_exit(0);
}
/*
* In interactive mode (with pseudo tty) display a message indicating

View File

@ -1,4 +1,4 @@
/* $OpenBSD: compat.c,v 1.103 2017/04/30 23:13:25 djm Exp $ */
/* $OpenBSD: compat.c,v 1.104 2017/07/25 09:22:25 dtucker Exp $ */
/*
* Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
*
@ -177,9 +177,12 @@ compat_datafellows(const char *version)
"TTSSH/2.72*", SSH_BUG_HOSTKEYS },
{ "WinSCP_release_4*,"
"WinSCP_release_5.0*,"
"WinSCP_release_5.1*,"
"WinSCP_release_5.5*,"
"WinSCP_release_5.6*,"
"WinSCP_release_5.1,"
"WinSCP_release_5.1.*,"
"WinSCP_release_5.5,"
"WinSCP_release_5.5.*,"
"WinSCP_release_5.6,"
"WinSCP_release_5.6.*,"
"WinSCP_release_5.7,"
"WinSCP_release_5.7.1,"
"WinSCP_release_5.7.2,"

View File

@ -980,6 +980,7 @@ mips-sony-bsd|mips-sony-newsos4)
AC_DEFINE([BROKEN_SETREUID])
AC_DEFINE([BROKEN_SETREGID])
AC_DEFINE([PASSWD_NEEDS_USERNAME])
AC_DEFINE([BROKEN_TCGETATTR_ICANON])
TEST_SHELL=$SHELL # let configure find us a capable shell
case "$host" in
*-*-sysv5SCO_SV*) # SCO OpenServer 6.x

469
misc.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: misc.c,v 1.110 2017/05/31 09:15:42 deraadt Exp $ */
/* $OpenBSD: misc.c,v 1.113 2017/08/18 05:48:04 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2005,2006 Damien Miller. All rights reserved.
@ -29,10 +29,16 @@
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <limits.h>
#ifdef HAVE_LIBGEN_H
# include <libgen.h>
#endif
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@ -61,6 +67,10 @@
#include "misc.h"
#include "log.h"
#include "ssh.h"
#include "sshbuf.h"
#include "ssherr.h"
#include "uidswap.h"
#include "platform.h"
/* remove newline at end of string */
char *
@ -1105,6 +1115,7 @@ static const struct {
const char *name;
int value;
} ipqos[] = {
{ "none", INT_MAX }, /* can't use 0 here; that's CS0 */
{ "af11", IPTOS_DSCP_AF11 },
{ "af12", IPTOS_DSCP_AF12 },
{ "af13", IPTOS_DSCP_AF13 },
@ -1303,3 +1314,459 @@ daemonized(void)
return 1;
}
#endif /* !WINDOWS */
/*
* Splits 's' into an argument vector. Handles quoted string and basic
* escape characters (\\, \", \'). Caller must free the argument vector
* and its members.
*/
int
argv_split(const char *s, int *argcp, char ***argvp)
{
int r = SSH_ERR_INTERNAL_ERROR;
int argc = 0, quote, i, j;
char *arg, **argv = xcalloc(1, sizeof(*argv));
*argvp = NULL;
*argcp = 0;
for (i = 0; s[i] != '\0'; i++) {
/* Skip leading whitespace */
if (s[i] == ' ' || s[i] == '\t')
continue;
/* Start of a token */
quote = 0;
if (s[i] == '\\' &&
(s[i + 1] == '\'' || s[i + 1] == '\"' || s[i + 1] == '\\'))
i++;
else if (s[i] == '\'' || s[i] == '"')
quote = s[i++];
argv = xreallocarray(argv, (argc + 2), sizeof(*argv));
arg = argv[argc++] = xcalloc(1, strlen(s + i) + 1);
argv[argc] = NULL;
/* Copy the token in, removing escapes */
for (j = 0; s[i] != '\0'; i++) {
if (s[i] == '\\') {
if (s[i + 1] == '\'' ||
s[i + 1] == '\"' ||
s[i + 1] == '\\') {
i++; /* Skip '\' */
arg[j++] = s[i];
} else {
/* Unrecognised escape */
arg[j++] = s[i];
}
} else if (quote == 0 && (s[i] == ' ' || s[i] == '\t'))
break; /* done */
else if (quote != 0 && s[i] == quote)
break; /* done */
else
arg[j++] = s[i];
}
if (s[i] == '\0') {
if (quote != 0) {
/* Ran out of string looking for close quote */
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
break;
}
}
/* Success */
*argcp = argc;
*argvp = argv;
argc = 0;
argv = NULL;
r = 0;
out:
if (argc != 0 && argv != NULL) {
for (i = 0; i < argc; i++)
free(argv[i]);
free(argv);
}
return r;
}
/*
* Reassemble an argument vector into a string, quoting and escaping as
* necessary. Caller must free returned string.
*/
char *
argv_assemble(int argc, char **argv)
{
int i, j, ws, r;
char c, *ret;
struct sshbuf *buf, *arg;
if ((buf = sshbuf_new()) == NULL || (arg = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__);
for (i = 0; i < argc; i++) {
ws = 0;
sshbuf_reset(arg);
for (j = 0; argv[i][j] != '\0'; j++) {
r = 0;
c = argv[i][j];
switch (c) {
case ' ':
case '\t':
ws = 1;
r = sshbuf_put_u8(arg, c);
break;
case '\\':
case '\'':
case '"':
if ((r = sshbuf_put_u8(arg, '\\')) != 0)
break;
/* FALLTHROUGH */
default:
r = sshbuf_put_u8(arg, c);
break;
}
if (r != 0)
fatal("%s: sshbuf_put_u8: %s",
__func__, ssh_err(r));
}
if ((i != 0 && (r = sshbuf_put_u8(buf, ' ')) != 0) ||
(ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0) ||
(r = sshbuf_putb(buf, arg)) != 0 ||
(ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0))
fatal("%s: buffer error: %s", __func__, ssh_err(r));
}
if ((ret = malloc(sshbuf_len(buf) + 1)) == NULL)
fatal("%s: malloc failed", __func__);
memcpy(ret, sshbuf_ptr(buf), sshbuf_len(buf));
ret[sshbuf_len(buf)] = '\0';
sshbuf_free(buf);
sshbuf_free(arg);
return ret;
}
/*
* Runs command in a subprocess wuth 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("%s: %s command \"%s\" running as %s (flags 0x%x)", __func__,
tag, command, pw->pw_name, flags);
/* Check consistency */
if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 &&
(flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0) {
error("%s: inconsistent flags", __func__);
return 0;
}
if (((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0) != (child == NULL)) {
error("%s: inconsistent flags/output", __func__);
return 0;
}
/*
* If executing an explicit binary, then verify the it exists
* and appears safe-ish to execute
*/
if (*av[0] != '/') {
error("%s path is not absolute", tag);
return 0;
}
temporarily_use_uid(pw);
if (stat(av[0], &st) < 0) {
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) != 0) {
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++)
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) != 0) {
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) != 0) {
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("%s: %s pid %ld", __func__, tag, (long)pid);
if (child != NULL)
*child = f;
return pid;
}
/* Returns 0 if pid exited cleanly, non-zero otherwise */
int
exited_cleanly(pid_t pid, const char *tag, const char *cmd, int quiet)
{
int status;
while (waitpid(pid, &status, 0) == -1) {
if (errno != EINTR) {
error("%s: waitpid: %s", tag, strerror(errno));
return -1;
}
}
if (WIFSIGNALED(status)) {
error("%s %s exited on signal %d", tag, cmd, WTERMSIG(status));
return -1;
} else if (WEXITSTATUS(status) != 0) {
do_log2(quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_INFO,
"%s %s failed, status %d", tag, cmd, WEXITSTATUS(status));
return -1;
}
return 0;
}
/*
* Check a given path for security. This is defined as all components
* of the path to the file must be owned by either the owner of
* of the file or root and no directories must be group or world writable.
*
* XXX Should any specific check be done for sym links ?
*
* Takes a file name, its stat information (preferably from fstat() to
* avoid races), the uid of the expected owner, their home directory and an
* error buffer plus max size as arguments.
*
* Returns 0 on success and -1 on failure
*/
int
safe_path(const char *name, struct stat *stp, const char *pw_dir,
uid_t uid, char *err, size_t errlen)
{
char buf[PATH_MAX], homedir[PATH_MAX];
char *cp;
int comparehome = 0;
struct stat st;
if (realpath(name, buf) == NULL) {
snprintf(err, errlen, "realpath %s failed: %s", name,
strerror(errno));
return -1;
}
if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)
comparehome = 1;
if (!S_ISREG(stp->st_mode)) {
snprintf(err, errlen, "%s is not a regular file", buf);
return -1;
}
if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) ||
(stp->st_mode & 022) != 0) {
snprintf(err, errlen, "bad ownership or modes for file %s",
buf);
return -1;
}
/* for each component of the canonical path, walking upwards */
for (;;) {
if ((cp = dirname(buf)) == NULL) {
snprintf(err, errlen, "dirname() failed");
return -1;
}
strlcpy(buf, cp, sizeof(buf));
if (stat(buf, &st) < 0 ||
(!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) ||
(st.st_mode & 022) != 0) {
snprintf(err, errlen,
"bad ownership or modes for directory %s", buf);
return -1;
}
/* If are past the homedir then we can stop */
if (comparehome && strcmp(homedir, buf) == 0)
break;
/*
* dirname should always complete with a "/" path,
* but we can be paranoid and check for "." too
*/
if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
break;
}
return 0;
}
/*
* Version of safe_path() that accepts an open file descriptor to
* avoid races.
*
* Returns 0 on success and -1 on failure
*/
int
safe_path_fd(int fd, const char *file, struct passwd *pw,
char *err, size_t errlen)
{
struct stat st;
/* check the open file to avoid races */
if (fstat(fd, &st) < 0) {
snprintf(err, errlen, "cannot stat file %s: %s",
file, strerror(errno));
return -1;
}
return safe_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);
}
/*
* Sets the value of the given variable in the environment. If the variable
* already exists, its value is overridden.
*/
void
child_set_env(char ***envp, u_int *envsizep, const char *name,
const char *value)
{
char **env;
u_int envsize;
u_int i, namelen;
if (strchr(name, '=') != NULL) {
error("Invalid environment variable \"%.100s\"", name);
return;
}
/*
* If we're passed an uninitialized list, allocate a single null
* entry before continuing.
*/
if (*envp == NULL && *envsizep == 0) {
*envp = xmalloc(sizeof(char *));
*envp[0] = NULL;
*envsizep = 1;
}
/*
* Find the slot where the value should be stored. If the variable
* already exists, we reuse the slot; otherwise we append a new slot
* at the end of the array, expanding if necessary.
*/
env = *envp;
namelen = strlen(name);
for (i = 0; env[i]; i++)
if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
break;
if (env[i]) {
/* Reuse the slot. */
free(env[i]);
} else {
/* New variable. Expand if necessary. */
envsize = *envsizep;
if (i >= envsize - 1) {
if (envsize >= 1000)
fatal("child_set_env: too many env vars");
envsize += 50;
env = (*envp) = xreallocarray(env, envsize, sizeof(char *));
*envsizep = envsize;
}
/* Need to set the NULL pointer at end of array beyond the new slot. */
env[i + 1] = NULL;
}
/* Allocate space and format the variable in the appropriate slot. */
env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
}

22
misc.h
View File

@ -1,4 +1,4 @@
/* $OpenBSD: misc.h,v 1.61 2016/11/30 00:28:31 dtucker Exp $ */
/* $OpenBSD: misc.h,v 1.63 2017/08/18 05:48:04 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -16,6 +16,7 @@
#define _MISC_H
#include <sys/time.h>
#include <sys/types.h>
/* Data structure for representing a forwarding request. */
struct Forward {
@ -132,6 +133,25 @@ int parse_ipqos(const char *);
const char *iptos2str(int);
void mktemp_proto(char *, size_t);
void child_set_env(char ***envp, u_int *envsizep, const char *name,
const char *value);
int argv_split(const char *, int *, char ***);
char *argv_assemble(int, char **argv);
int exited_cleanly(pid_t, const char *, const char *, int);
#define SSH_SUBPROCESS_STDOUT_DISCARD (1) /* Discard stdout */
#define SSH_SUBPROCESS_STDOUT_CAPTURE (1<<1) /* Redirect stdout */
#define SSH_SUBPROCESS_STDERR_DISCARD (1<<2) /* Discard stderr */
pid_t subprocess(const char *, struct passwd *,
const char *, int, char **, FILE **, u_int flags);
struct stat;
int safe_path(const char *, struct stat *, const char *, uid_t,
char *, size_t);
int safe_path_fd(int, const char *, struct passwd *,
char *err, size_t errlen);
/* readpass.c */
#define RP_ECHO 0x0001

View File

@ -27,6 +27,12 @@
#include "includes.h"
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef HAVE_ERR
void
err(int r, const char *fmt, ...)

View File

@ -20,6 +20,8 @@
void
explicit_bzero(void *p, size_t n)
{
if (n == 0)
return;
(void)memset_s(p, n, 0, n);
}
@ -34,6 +36,8 @@ static void (* volatile ssh_bzero)(void *, size_t) = bzero;
void
explicit_bzero(void *p, size_t n)
{
if (n == 0)
return;
/*
* clang -fsanitize=memory needs to intercept memset-like functions
* to correctly detect memory initialisation. Make sure one is called

View File

@ -199,49 +199,50 @@ sys_tun_open(int tun, int mode)
*/
#if defined(SSH_TUN_FILTER)
/*
* The tunnel forwarding protocol prepends the address family of forwarded
* IP packets using OpenBSD's numbers.
*/
#define OPENBSD_AF_INET 2
#define OPENBSD_AF_INET6 24
int
sys_tun_infilter(struct Channel *c, char *buf, int len)
sys_tun_infilter(struct Channel *c, char *buf, int _len)
{
int r;
size_t len;
char *ptr = buf;
#if defined(SSH_TUN_PREPEND_AF)
char rbuf[CHAN_RBUF];
struct ip *iph;
struct ip iph;
#endif
u_int32_t *af;
char *ptr = buf;
int r;
#if defined(SSH_TUN_PREPEND_AF) || defined(SSH_TUN_COMPAT_AF)
u_int32_t af;
#endif
/* XXX update channel input filter API to use unsigned length */
if (_len < 0)
return -1;
len = _len;
#if defined(SSH_TUN_PREPEND_AF)
if (len <= 0 || len > (int)(sizeof(rbuf) - sizeof(*af)))
return (-1);
ptr = (char *)&rbuf[0];
bcopy(buf, ptr + sizeof(u_int32_t), len);
len += sizeof(u_int32_t);
af = (u_int32_t *)ptr;
iph = (struct ip *)(ptr + sizeof(u_int32_t));
switch (iph->ip_v) {
case 6:
*af = AF_INET6;
break;
case 4:
default:
*af = AF_INET;
break;
}
#endif
#if defined(SSH_TUN_COMPAT_AF)
if (len < (int)sizeof(u_int32_t))
return (-1);
af = (u_int32_t *)ptr;
if (*af == htonl(AF_INET6))
*af = htonl(OPENBSD_AF_INET6);
else
*af = htonl(OPENBSD_AF_INET);
if (len <= sizeof(iph) || len > sizeof(rbuf) - 4)
return -1;
/* Determine address family from packet IP header. */
memcpy(&iph, buf, sizeof(iph));
af = iph.ip_v == 6 ? OPENBSD_AF_INET6 : OPENBSD_AF_INET;
/* Prepend address family to packet using OpenBSD constants */
memcpy(rbuf + 4, buf, len);
len += 4;
POKE_U32(rbuf, af);
ptr = rbuf;
#elif defined(SSH_TUN_COMPAT_AF)
/* Convert existing address family header to OpenBSD value */
if (len <= 4)
return -1;
af = PEEK_U32(buf);
/* Put it back */
POKE_U32(buf, af == AF_INET6 ? OPENBSD_AF_INET6 : OPENBSD_AF_INET);
#endif
if ((r = sshbuf_put_string(&c->input, ptr, len)) != 0)
@ -253,7 +254,7 @@ u_char *
sys_tun_outfilter(struct Channel *c, u_char **data, u_int *dlen)
{
u_char *buf;
u_int32_t *af;
u_int32_t af;
int r;
size_t xxx_dlen;
@ -262,21 +263,19 @@ sys_tun_outfilter(struct Channel *c, u_char **data, u_int *dlen)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
if (dlen != NULL)
*dlen = xxx_dlen;
if (*dlen < sizeof(*af))
if (*dlen < sizeof(af))
return (NULL);
buf = *data;
#if defined(SSH_TUN_PREPEND_AF)
*dlen -= sizeof(u_int32_t);
buf = *data + sizeof(u_int32_t);
/* skip address family */
*dlen -= sizeof(af);
buf = *data + sizeof(af);
#elif defined(SSH_TUN_COMPAT_AF)
af = ntohl(*(u_int32_t *)buf);
if (*af == OPENBSD_AF_INET6)
*af = htonl(AF_INET6);
else
*af = htonl(AF_INET);
/* translate address family */
af = (PEEK_U32(buf) == OPENBSD_AF_INET6) ? AF_INET6 : AF_INET;
POKE_U32(buf, af);
#endif
return (buf);
}
#endif /* SSH_TUN_FILTER */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: packet.c,v 1.262 2017/06/24 06:38:11 djm Exp $ */
/* $OpenBSD: packet.c,v 1.263 2017/07/23 23:37:02 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -1997,7 +1997,7 @@ void
ssh_packet_set_tos(struct ssh *ssh, int tos)
{
#ifndef IP_TOS_IS_BROKEN
if (!ssh_packet_connection_is_on_socket(ssh))
if (!ssh_packet_connection_is_on_socket(ssh) || tos == INT_MAX)
return;
switch (ssh_packet_connection_af(ssh)) {
# ifdef IP_TOS

35
platform-misc.c Normal file
View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2006 Darren Tucker. All rights reserved.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
#include "openbsd-compat/openbsd-compat.h"
/*
* return 1 if the specified uid is a uid that may own a system directory
* otherwise 0.
*/
int
platform_sys_dir_uid(uid_t uid)
{
if (uid == 0)
return 1;
#ifdef PLATFORM_SYS_DIR_UID
if (uid == PLATFORM_SYS_DIR_UID)
return 1;
#endif
return 0;
}

View File

@ -197,19 +197,3 @@ platform_krb5_get_principal_name(const char *pw_name)
return NULL;
#endif
}
/*
* return 1 if the specified uid is a uid that may own a system directory
* otherwise 0.
*/
int
platform_sys_dir_uid(uid_t uid)
{
if (uid == 0)
return 1;
#ifdef PLATFORM_SYS_DIR_UID
if (uid == PLATFORM_SYS_DIR_UID)
return 1;
#endif
return 0;
}

188
rsa.c
View File

@ -1,188 +0,0 @@
/* $OpenBSD: rsa.c,v 1.32 2014/06/24 01:13:21 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*
*
* Copyright (c) 1999 Niels Provos. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* Description of the RSA algorithm can be found e.g. from the following
* sources:
*
* Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1994.
*
* Jennifer Seberry and Josed Pieprzyk: Cryptography: An Introduction to
* Computer Security. Prentice-Hall, 1989.
*
* Man Young Rhee: Cryptography and Secure Data Communications. McGraw-Hill,
* 1994.
*
* R. Rivest, A. Shamir, and L. M. Adleman: Cryptographic Communications
* System and Method. US Patent 4,405,829, 1983.
*
* Hans Riesel: Prime Numbers and Computer Methods for Factorization.
* Birkhauser, 1994.
*
* The RSA Frequently Asked Questions document by RSA Data Security,
* Inc., 1995.
*
* RSA in 3 lines of perl by Adam Back <aba@atlax.ex.ac.uk>, 1995, as
* included below:
*
* [gone - had to be deleted - what a pity]
*/
#include "includes.h"
#include <sys/types.h>
#include <stdarg.h>
#include <string.h>
#include "rsa.h"
#include "log.h"
#include "ssherr.h"
int
rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *key)
{
u_char *inbuf = NULL, *outbuf = NULL;
int len, ilen, olen, r = SSH_ERR_INTERNAL_ERROR;
if (BN_num_bits(key->e) < 2 || !BN_is_odd(key->e))
return SSH_ERR_INVALID_ARGUMENT;
olen = BN_num_bytes(key->n);
if ((outbuf = malloc(olen)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
ilen = BN_num_bytes(in);
if ((inbuf = malloc(ilen)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
BN_bn2bin(in, inbuf);
if ((len = RSA_public_encrypt(ilen, inbuf, outbuf, key,
RSA_PKCS1_PADDING)) <= 0) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
if (BN_bin2bn(outbuf, len, out) == NULL) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
r = 0;
out:
if (outbuf != NULL) {
explicit_bzero(outbuf, olen);
free(outbuf);
}
if (inbuf != NULL) {
explicit_bzero(inbuf, ilen);
free(inbuf);
}
return r;
}
int
rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key)
{
u_char *inbuf = NULL, *outbuf = NULL;
int len, ilen, olen, r = SSH_ERR_INTERNAL_ERROR;
olen = BN_num_bytes(key->n);
if ((outbuf = malloc(olen)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
ilen = BN_num_bytes(in);
if ((inbuf = malloc(ilen)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
BN_bn2bin(in, inbuf);
if ((len = RSA_private_decrypt(ilen, inbuf, outbuf, key,
RSA_PKCS1_PADDING)) <= 0) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
} else if (BN_bin2bn(outbuf, len, out) == NULL) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
r = 0;
out:
if (outbuf != NULL) {
explicit_bzero(outbuf, olen);
free(outbuf);
}
if (inbuf != NULL) {
explicit_bzero(inbuf, ilen);
free(inbuf);
}
return r;
}
/* calculate p-1 and q-1 */
int
rsa_generate_additional_parameters(RSA *rsa)
{
BIGNUM *aux = NULL;
BN_CTX *ctx = NULL;
int r;
if ((ctx = BN_CTX_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((aux = BN_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((BN_sub(aux, rsa->q, BN_value_one()) == 0) ||
(BN_mod(rsa->dmq1, rsa->d, aux, ctx) == 0) ||
(BN_sub(aux, rsa->p, BN_value_one()) == 0) ||
(BN_mod(rsa->dmp1, rsa->d, aux, ctx) == 0)) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
r = 0;
out:
BN_clear_free(aux);
BN_CTX_free(ctx);
return r;
}

26
rsa.h
View File

@ -1,26 +0,0 @@
/* $OpenBSD: rsa.h,v 1.17 2014/06/24 01:13:21 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* RSA key generation, encryption and decryption.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
#ifndef RSA_H
#define RSA_H
#include <openssl/bn.h>
#include <openssl/rsa.h>
int rsa_public_encrypt(BIGNUM *, BIGNUM *, RSA *);
int rsa_private_decrypt(BIGNUM *, BIGNUM *, RSA *);
int rsa_generate_additional_parameters(RSA *);
#endif /* RSA_H */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: serverloop.c,v 1.193 2017/05/31 07:00:13 markus Exp $ */
/* $OpenBSD: serverloop.c,v 1.195 2017/08/11 04:16:35 dtucker Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -204,6 +204,7 @@ wait_until_can_do_something(int connection_in, int connection_out,
int ret;
time_t minwait_secs = 0;
int client_alive_scheduled = 0;
static time_t last_client_time;
/* Allocate and update select() masks for channel descriptors. */
channel_prepare_select(readsetp, writesetp, maxfdp, nallocp,
@ -268,8 +269,19 @@ wait_until_can_do_something(int connection_in, int connection_out,
memset(*writesetp, 0, *nallocp);
if (errno != EINTR)
error("select: %.100s", strerror(errno));
} else if (ret == 0 && client_alive_scheduled)
client_alive_check();
} else if (client_alive_scheduled) {
time_t now = monotime();
if (ret == 0) { /* timeout */
client_alive_check();
} else if (FD_ISSET(connection_in, *readsetp)) {
last_client_time = now;
} else if (last_client_time != 0 && last_client_time +
options.client_alive_interval <= now) {
client_alive_check();
last_client_time = now;
}
}
notify_done(*readsetp);
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: session.c,v 1.290 2017/06/24 06:34:38 djm Exp $ */
/* $OpenBSD: session.c,v 1.291 2017/08/18 05:36:45 djm Exp $ */
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
@ -1102,65 +1102,6 @@ check_quietlogin(Session *s, const char *command)
return 0;
}
/*
* Sets the value of the given variable in the environment. If the variable
* already exists, its value is overridden.
*/
void
child_set_env(char ***envp, u_int *envsizep, const char *name,
const char *value)
{
char **env;
u_int envsize;
u_int i, namelen;
if (strchr(name, '=') != NULL) {
error("Invalid environment variable \"%.100s\"", name);
return;
}
/*
* If we're passed an uninitialized list, allocate a single null
* entry before continuing.
*/
if (*envp == NULL && *envsizep == 0) {
*envp = xmalloc(sizeof(char *));
*envp[0] = NULL;
*envsizep = 1;
}
/*
* Find the slot where the value should be stored. If the variable
* already exists, we reuse the slot; otherwise we append a new slot
* at the end of the array, expanding if necessary.
*/
env = *envp;
namelen = strlen(name);
for (i = 0; env[i]; i++)
if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
break;
if (env[i]) {
/* Reuse the slot. */
free(env[i]);
} else {
/* New variable. Expand if necessary. */
envsize = *envsizep;
if (i >= envsize - 1) {
if (envsize >= 1000)
fatal("child_set_env: too many env vars");
envsize += 50;
env = (*envp) = xreallocarray(env, envsize, sizeof(char *));
*envsizep = envsize;
}
/* Need to set the NULL pointer at end of array beyond the new slot. */
env[i + 1] = NULL;
}
/* Allocate space and format the variable in the appropriate slot. */
env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
}
/*
* Reads environment variables from the given file and adds/overrides them
* into the environment. If the file does not exist, this does nothing.
@ -1262,8 +1203,9 @@ read_etc_default_login(char ***env, u_int *envsize, uid_t uid)
}
#endif /* HAVE_ETC_DEFAULT_LOGIN */
void
copy_environment(char **source, char ***env, u_int *envsize)
static void
copy_environment_blacklist(char **source, char ***env, u_int *envsize,
const char *blacklist)
{
char *var_name, *var_val;
int i;
@ -1279,13 +1221,22 @@ copy_environment(char **source, char ***env, u_int *envsize)
}
*var_val++ = '\0';
debug3("Copy environment: %s=%s", var_name, var_val);
child_set_env(env, envsize, var_name, var_val);
if (blacklist == NULL ||
match_pattern_list(var_name, blacklist, 0) != 1) {
debug3("Copy environment: %s=%s", var_name, var_val);
child_set_env(env, envsize, var_name, var_val);
}
free(var_name);
}
}
void
copy_environment(char **source, char ***env, u_int *envsize)
{
copy_environment_blacklist(source, env, envsize, NULL);
}
static char **
do_setup_env(Session *s, const char *shell)
{
@ -1447,12 +1398,16 @@ do_setup_env(Session *s, const char *shell)
if (options.use_pam) {
char **p;
/*
* Don't allow SSH_AUTH_INFO variables posted to PAM to leak
* back into the environment.
*/
p = fetch_pam_child_environment();
copy_environment(p, &env, &envsize);
copy_environment_blacklist(p, &env, &envsize, "SSH_AUTH_INFO*");
free_pam_environment(p);
p = fetch_pam_environment();
copy_environment(p, &env, &envsize);
copy_environment_blacklist(p, &env, &envsize, "SSH_AUTH_INFO*");
free_pam_environment(p);
}
#endif /* USE_PAM */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: session.h,v 1.33 2016/08/13 17:47:41 markus Exp $ */
/* $OpenBSD: session.h,v 1.34 2017/08/18 05:36:45 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@ -77,8 +77,6 @@ Session *session_new(void);
Session *session_by_tty(char *);
void session_close(Session *);
void do_setusercontext(struct passwd *);
void child_set_env(char ***envp, u_int *envsizep, const char *name,
const char *value);
const char *session_get_remote_name_or_ip(struct ssh *, u_int, int);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp-client.c,v 1.126 2017/01/03 05:46:51 djm Exp $ */
/* $OpenBSD: sftp-client.c,v 1.127 2017/08/11 04:41:08 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@ -140,7 +140,7 @@ get_msg(struct sftp_conn *conn, struct sshbuf *m)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
if (atomicio6(read, conn->fd_in, p, 4,
conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) != 4) {
if (errno == EPIPE)
if (errno == EPIPE || errno == ECONNRESET)
fatal("Connection closed");
else
fatal("Couldn't read packet: %s", strerror(errno));

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-add.c,v 1.132 2017/05/30 14:16:41 markus Exp $ */
/* $OpenBSD: ssh-add.c,v 1.133 2017/07/01 13:50:45 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -55,7 +55,6 @@
#include "xmalloc.h"
#include "ssh.h"
#include "rsa.h"
#include "log.h"
#include "sshkey.h"
#include "sshbuf.h"

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-agent.c,v 1.221 2017/04/30 23:29:10 djm Exp $ */
/* $OpenBSD: ssh-agent.c,v 1.224 2017/07/24 04:34:28 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -60,6 +60,9 @@
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
#ifdef HAVE_POLL_H
# include <poll.h>
#endif
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
@ -73,7 +76,6 @@
#include "xmalloc.h"
#include "ssh.h"
#include "rsa.h"
#include "sshbuf.h"
#include "sshkey.h"
#include "authfd.h"
@ -92,6 +94,9 @@
# define DEFAULT_PKCS11_WHITELIST "/usr/lib*/*,/usr/local/lib*/*"
#endif
/* Maximum accepted message length */
#define AGENT_MAX_LEN (256*1024)
typedef enum {
AUTH_UNUSED,
AUTH_SOCKET,
@ -635,30 +640,46 @@ send:
/* dispatch incoming messages */
static void
process_message(SocketEntry *e)
static int
process_message(u_int socknum)
{
u_int msg_len;
u_char type;
const u_char *cp;
int r;
SocketEntry *e;
if (socknum >= sockets_alloc) {
fatal("%s: socket number %u >= allocated %u",
__func__, socknum, sockets_alloc);
}
e = &sockets[socknum];
if (sshbuf_len(e->input) < 5)
return; /* Incomplete message. */
return 0; /* Incomplete message header. */
cp = sshbuf_ptr(e->input);
msg_len = PEEK_U32(cp);
if (msg_len > 256 * 1024) {
close_socket(e);
return;
if (msg_len > AGENT_MAX_LEN) {
debug("%s: socket %u (fd=%d) message too long %u > %u",
__func__, socknum, e->fd, msg_len, AGENT_MAX_LEN);
return -1;
}
if (sshbuf_len(e->input) < msg_len + 4)
return;
return 0; /* Incomplete message body. */
/* move the current input to e->request */
sshbuf_reset(e->request);
if ((r = sshbuf_get_stringb(e->input, e->request)) != 0 ||
(r = sshbuf_get_u8(e->request, &type)) != 0)
(r = sshbuf_get_u8(e->request, &type)) != 0) {
if (r == SSH_ERR_MESSAGE_INCOMPLETE ||
r == SSH_ERR_STRING_TOO_LARGE) {
debug("%s: buffer error: %s", __func__, ssh_err(r));
return -1;
}
fatal("%s: buffer error: %s", __func__, ssh_err(r));
}
debug("%s: socket %u (fd=%d) type %d", __func__, socknum, e->fd, type);
/* check wheter agent is locked */
if (locked && type != SSH_AGENTC_UNLOCK) {
@ -672,10 +693,9 @@ process_message(SocketEntry *e)
/* send a fail message for all other request types */
send_status(e, 0);
}
return;
return 0;
}
debug("type %d", type);
switch (type) {
case SSH_AGENTC_LOCK:
case SSH_AGENTC_UNLOCK:
@ -717,6 +737,7 @@ process_message(SocketEntry *e)
send_status(e, 0);
break;
}
return 0;
}
static void
@ -758,19 +779,141 @@ new_socket(sock_type type, int fd)
}
static int
prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl, u_int *nallocp,
struct timeval **tvpp)
handle_socket_read(u_int socknum)
{
u_int i, sz;
int n = 0;
static struct timeval tv;
struct sockaddr_un sunaddr;
socklen_t slen;
uid_t euid;
gid_t egid;
int fd;
slen = sizeof(sunaddr);
fd = accept(sockets[socknum].fd, (struct sockaddr *)&sunaddr, &slen);
if (fd < 0) {
error("accept from AUTH_SOCKET: %s", strerror(errno));
return -1;
}
if (getpeereid(fd, &euid, &egid) < 0) {
error("getpeereid %d failed: %s", fd, strerror(errno));
close(fd);
return -1;
}
if ((euid != 0) && (getuid() != euid)) {
error("uid mismatch: peer euid %u != uid %u",
(u_int) euid, (u_int) getuid());
close(fd);
return -1;
}
new_socket(AUTH_CONNECTION, fd);
return 0;
}
static int
handle_conn_read(u_int socknum)
{
char buf[1024];
ssize_t len;
int r;
if ((len = read(sockets[socknum].fd, buf, sizeof(buf))) <= 0) {
if (len == -1) {
if (errno == EAGAIN || errno == EINTR)
return 0;
error("%s: read error on socket %u (fd %d): %s",
__func__, socknum, sockets[socknum].fd,
strerror(errno));
}
return -1;
}
if ((r = sshbuf_put(sockets[socknum].input, buf, len)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
explicit_bzero(buf, sizeof(buf));
process_message(socknum);
return 0;
}
static int
handle_conn_write(u_int socknum)
{
ssize_t len;
int r;
if (sshbuf_len(sockets[socknum].output) == 0)
return 0; /* shouldn't happen */
if ((len = write(sockets[socknum].fd,
sshbuf_ptr(sockets[socknum].output),
sshbuf_len(sockets[socknum].output))) <= 0) {
if (len == -1) {
if (errno == EAGAIN || errno == EINTR)
return 0;
error("%s: read error on socket %u (fd %d): %s",
__func__, socknum, sockets[socknum].fd,
strerror(errno));
}
return -1;
}
if ((r = sshbuf_consume(sockets[socknum].output, len)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
return 0;
}
static void
after_poll(struct pollfd *pfd, size_t npfd)
{
size_t i;
u_int socknum;
for (i = 0; i < npfd; i++) {
if (pfd[i].revents == 0)
continue;
/* Find sockets entry */
for (socknum = 0; socknum < sockets_alloc; socknum++) {
if (sockets[socknum].type != AUTH_SOCKET &&
sockets[socknum].type != AUTH_CONNECTION)
continue;
if (pfd[i].fd == sockets[socknum].fd)
break;
}
if (socknum >= sockets_alloc) {
error("%s: no socket for fd %d", __func__, pfd[i].fd);
continue;
}
/* Process events */
switch (sockets[socknum].type) {
case AUTH_SOCKET:
if ((pfd[i].revents & (POLLIN|POLLERR)) != 0 &&
handle_socket_read(socknum) != 0)
close_socket(&sockets[socknum]);
break;
case AUTH_CONNECTION:
if ((pfd[i].revents & (POLLIN|POLLERR)) != 0 &&
handle_conn_read(socknum) != 0) {
close_socket(&sockets[socknum]);
break;
}
if ((pfd[i].revents & (POLLOUT|POLLHUP)) != 0 &&
handle_conn_write(socknum) != 0)
close_socket(&sockets[socknum]);
break;
default:
break;
}
}
}
static int
prepare_poll(struct pollfd **pfdp, size_t *npfdp, int *timeoutp)
{
struct pollfd *pfd = *pfdp;
size_t i, j, npfd = 0;
time_t deadline;
/* Count active sockets */
for (i = 0; i < sockets_alloc; i++) {
switch (sockets[i].type) {
case AUTH_SOCKET:
case AUTH_CONNECTION:
n = MAXIMUM(n, sockets[i].fd);
npfd++;
break;
case AUTH_UNUSED:
break;
@ -779,28 +922,23 @@ prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl, u_int *nallocp,
break;
}
}
if (npfd != *npfdp &&
(pfd = recallocarray(pfd, *npfdp, npfd, sizeof(*pfd))) == NULL)
fatal("%s: recallocarray failed", __func__);
*pfdp = pfd;
*npfdp = npfd;
sz = howmany(n+1, NFDBITS) * sizeof(fd_mask);
if (*fdrp == NULL || sz > *nallocp) {
free(*fdrp);
free(*fdwp);
*fdrp = xmalloc(sz);
*fdwp = xmalloc(sz);
*nallocp = sz;
}
if (n < *fdl)
debug("XXX shrink: %d < %d", n, *fdl);
*fdl = n;
memset(*fdrp, 0, sz);
memset(*fdwp, 0, sz);
for (i = 0; i < sockets_alloc; i++) {
for (i = j = 0; i < sockets_alloc; i++) {
switch (sockets[i].type) {
case AUTH_SOCKET:
case AUTH_CONNECTION:
FD_SET(sockets[i].fd, *fdrp);
pfd[j].fd = sockets[i].fd;
pfd[j].revents = 0;
/* XXX backoff when input buffer full */
pfd[j].events = POLLIN;
if (sshbuf_len(sockets[i].output) > 0)
FD_SET(sockets[i].fd, *fdwp);
pfd[j].events |= POLLOUT;
j++;
break;
default:
break;
@ -811,98 +949,16 @@ prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl, u_int *nallocp,
deadline = (deadline == 0) ? parent_alive_interval :
MINIMUM(deadline, parent_alive_interval);
if (deadline == 0) {
*tvpp = NULL;
*timeoutp = -1; /* INFTIM */
} else {
tv.tv_sec = deadline;
tv.tv_usec = 0;
*tvpp = &tv;
if (deadline > INT_MAX / 1000)
*timeoutp = INT_MAX / 1000;
else
*timeoutp = deadline * 1000;
}
return (1);
}
static void
after_select(fd_set *readset, fd_set *writeset)
{
struct sockaddr_un sunaddr;
socklen_t slen;
char buf[1024];
int len, sock, r;
u_int i, orig_alloc;
uid_t euid;
gid_t egid;
for (i = 0, orig_alloc = sockets_alloc; i < orig_alloc; i++)
switch (sockets[i].type) {
case AUTH_UNUSED:
break;
case AUTH_SOCKET:
if (FD_ISSET(sockets[i].fd, readset)) {
slen = sizeof(sunaddr);
sock = accept(sockets[i].fd,
(struct sockaddr *)&sunaddr, &slen);
if (sock < 0) {
error("accept from AUTH_SOCKET: %s",
strerror(errno));
break;
}
if (getpeereid(sock, &euid, &egid) < 0) {
error("getpeereid %d failed: %s",
sock, strerror(errno));
close(sock);
break;
}
if ((euid != 0) && (getuid() != euid)) {
error("uid mismatch: "
"peer euid %u != uid %u",
(u_int) euid, (u_int) getuid());
close(sock);
break;
}
new_socket(AUTH_CONNECTION, sock);
}
break;
case AUTH_CONNECTION:
if (sshbuf_len(sockets[i].output) > 0 &&
FD_ISSET(sockets[i].fd, writeset)) {
len = write(sockets[i].fd,
sshbuf_ptr(sockets[i].output),
sshbuf_len(sockets[i].output));
if (len == -1 && (errno == EAGAIN ||
errno == EWOULDBLOCK ||
errno == EINTR))
continue;
if (len <= 0) {
close_socket(&sockets[i]);
break;
}
if ((r = sshbuf_consume(sockets[i].output,
len)) != 0)
fatal("%s: buffer error: %s",
__func__, ssh_err(r));
}
if (FD_ISSET(sockets[i].fd, readset)) {
len = read(sockets[i].fd, buf, sizeof(buf));
if (len == -1 && (errno == EAGAIN ||
errno == EWOULDBLOCK ||
errno == EINTR))
continue;
if (len <= 0) {
close_socket(&sockets[i]);
break;
}
if ((r = sshbuf_put(sockets[i].input,
buf, len)) != 0)
fatal("%s: buffer error: %s",
__func__, ssh_err(r));
explicit_bzero(buf, sizeof(buf));
process_message(&sockets[i]);
}
break;
default:
fatal("Unknown type %d", sockets[i].type);
}
}
static void
cleanup_socket(void)
{
@ -962,9 +1018,7 @@ main(int ac, char **av)
{
int c_flag = 0, d_flag = 0, D_flag = 0, k_flag = 0, s_flag = 0;
int sock, fd, ch, result, saved_errno;
u_int nalloc;
char *shell, *format, *pidstr, *agentsocket = NULL;
fd_set *readsetp = NULL, *writesetp = NULL;
#ifdef HAVE_SETRLIMIT
struct rlimit rlim;
#endif
@ -972,9 +1026,11 @@ main(int ac, char **av)
extern char *optarg;
pid_t pid;
char pidstrbuf[1 + 3 * sizeof pid];
struct timeval *tvp = NULL;
size_t len;
mode_t prev_mask;
int timeout = -1; /* INFTIM */
struct pollfd *pfd = NULL;
size_t npfd = 0;
ssh_malloc_init(); /* must be called before any mallocs */
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
@ -1195,15 +1251,14 @@ skip:
signal(SIGINT, (d_flag | D_flag) ? cleanup_handler : SIG_IGN);
signal(SIGHUP, cleanup_handler);
signal(SIGTERM, cleanup_handler);
nalloc = 0;
if (pledge("stdio rpath cpath unix id proc exec", NULL) == -1)
fatal("%s: pledge: %s", __progname, strerror(errno));
platform_pledge_agent();
while (1) {
prepare_select(&readsetp, &writesetp, &max_fd, &nalloc, &tvp);
result = select(max_fd + 1, readsetp, writesetp, NULL, tvp);
prepare_poll(&pfd, &npfd, &timeout);
result = poll(pfd, npfd, timeout);
saved_errno = errno;
if (parent_alive_interval != 0)
check_parent_exists();
@ -1211,9 +1266,9 @@ skip:
if (result < 0) {
if (saved_errno == EINTR)
continue;
fatal("select: %s", strerror(saved_errno));
fatal("poll: %s", strerror(saved_errno));
} else if (result > 0)
after_select(readsetp, writesetp);
after_poll(pfd, npfd);
}
/* NOTREACHED */
}

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: ssh-keygen.1,v 1.142 2017/06/28 01:09:22 djm Exp $
.\" $OpenBSD: ssh-keygen.1,v 1.144 2017/07/08 18:32:54 jmc Exp $
.\"
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -35,7 +35,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd $Mdocdate: June 28 2017 $
.Dd $Mdocdate: July 8 2017 $
.Dt SSH-KEYGEN 1
.Os
.Sh NAME
@ -126,6 +126,7 @@
.Op Fl f Ar input_keyfile
.Nm ssh-keygen
.Fl A
.Op Fl f Ar prefix_path
.Nm ssh-keygen
.Fl k
.Fl f Ar krl_file
@ -224,6 +225,10 @@ For each of the key types (rsa, dsa, ecdsa and ed25519)
for which host keys
do not exist, generate the host keys with the default key file path,
an empty passphrase, default bits for the key type, and default comment.
If
.Fl f
has also been specified, its argument is used as a prefix to the
default path for the resulting host key files.
This is used by
.Pa /etc/rc
to generate new host keys.

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-keygen.c,v 1.305 2017/06/28 01:09:22 djm Exp $ */
/* $OpenBSD: ssh-keygen.c,v 1.307 2017/07/07 03:53:12 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -41,7 +41,6 @@
#include "xmalloc.h"
#include "sshkey.h"
#include "rsa.h"
#include "authfile.h"
#include "uuencode.h"
#include "sshbuf.h"
@ -533,7 +532,7 @@ do_convert_private_ssh2_from_blob(u_char *blob, u_int blen)
buffer_get_bignum_bits(b, key->rsa->iqmp);
buffer_get_bignum_bits(b, key->rsa->q);
buffer_get_bignum_bits(b, key->rsa->p);
if ((r = rsa_generate_additional_parameters(key->rsa)) != 0)
if ((r = ssh_rsa_generate_additional_parameters(key)) != 0)
fatal("generate RSA parameters failed: %s", ssh_err(r));
break;
}
@ -1003,20 +1002,38 @@ do_gen_all_hostkeys(struct passwd *pw)
int first = 0;
struct stat st;
struct sshkey *private, *public;
char comment[1024];
char comment[1024], *prv_tmp, *pub_tmp, *prv_file, *pub_file;
int i, type, fd, r;
FILE *f;
for (i = 0; key_types[i].key_type; i++) {
if (stat(key_types[i].path, &st) == 0)
continue;
if (errno != ENOENT) {
public = private = NULL;
prv_tmp = pub_tmp = prv_file = pub_file = NULL;
xasprintf(&prv_file, "%s%s",
identity_file, key_types[i].path);
/* Check whether private key exists and is not zero-length */
if (stat(prv_file, &st) == 0) {
if (st.st_size != 0)
goto next;
} else if (errno != ENOENT) {
error("Could not stat %s: %s", key_types[i].path,
strerror(errno));
first = 0;
continue;
goto failnext;
}
/*
* Private key doesn't exist or is invalid; proceed with
* key generation.
*/
xasprintf(&prv_tmp, "%s%s.XXXXXXXXXX",
identity_file, key_types[i].path);
xasprintf(&pub_tmp, "%s%s.pub.XXXXXXXXXX",
identity_file, key_types[i].path);
xasprintf(&pub_file, "%s%s.pub",
identity_file, key_types[i].path);
if (first == 0) {
first = 1;
printf("%s: generating new host keys: ", __progname);
@ -1024,37 +1041,34 @@ do_gen_all_hostkeys(struct passwd *pw)
printf("%s ", key_types[i].key_type_display);
fflush(stdout);
type = sshkey_type_from_name(key_types[i].key_type);
strlcpy(identity_file, key_types[i].path, sizeof(identity_file));
if ((fd = mkstemp(prv_tmp)) == -1) {
error("Could not save your public key in %s: %s",
prv_tmp, strerror(errno));
goto failnext;
}
close(fd); /* just using mkstemp() to generate/reserve a name */
bits = 0;
type_bits_valid(type, NULL, &bits);
if ((r = sshkey_generate(type, bits, &private)) != 0) {
error("sshkey_generate failed: %s", ssh_err(r));
first = 0;
continue;
goto failnext;
}
if ((r = sshkey_from_private(private, &public)) != 0)
fatal("sshkey_from_private failed: %s", ssh_err(r));
snprintf(comment, sizeof comment, "%s@%s", pw->pw_name,
hostname);
if ((r = sshkey_save_private(private, identity_file, "",
if ((r = sshkey_save_private(private, prv_tmp, "",
comment, use_new_format, new_format_cipher, rounds)) != 0) {
error("Saving key \"%s\" failed: %s",
identity_file, ssh_err(r));
sshkey_free(private);
sshkey_free(public);
first = 0;
continue;
prv_tmp, ssh_err(r));
goto failnext;
}
sshkey_free(private);
strlcat(identity_file, ".pub", sizeof(identity_file));
fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd == -1) {
error("Could not save your public key in %s",
identity_file);
sshkey_free(public);
first = 0;
continue;
if ((fd = mkstemp(pub_tmp)) == -1) {
error("Could not save your public key in %s: %s",
pub_tmp, strerror(errno));
goto failnext;
}
(void)fchmod(fd, 0644);
#ifdef WINDOWS
/* Windows POSIX adpater does not support fdopen() on open(file)*/
close(fd);
@ -1063,24 +1077,50 @@ do_gen_all_hostkeys(struct passwd *pw)
#else /* !WINDOWS */
f = fdopen(fd, "w");
if (f == NULL) {
error("fdopen %s failed", identity_file);
error("fdopen %s failed: %s", pub_tmp, strerror(errno));
close(fd);
#endif /* !WINDOWS */
sshkey_free(public);
first = 0;
continue;
goto failnext;
}
if ((r = sshkey_write(public, f)) != 0) {
error("write key failed: %s", ssh_err(r));
fclose(f);
sshkey_free(public);
first = 0;
continue;
goto failnext;
}
fprintf(f, " %s\n", comment);
fclose(f);
sshkey_free(public);
if (ferror(f) != 0) {
error("write key failed: %s", strerror(errno));
fclose(f);
goto failnext;
}
if (fclose(f) != 0) {
error("key close failed: %s", strerror(errno));
goto failnext;
}
/* Rename temporary files to their permanent locations. */
if (rename(pub_tmp, pub_file) != 0) {
error("Unable to move %s into position: %s",
pub_file, strerror(errno));
goto failnext;
}
if (rename(prv_tmp, prv_file) != 0) {
error("Unable to move %s into position: %s",
key_types[i].path, strerror(errno));
failnext:
first = 0;
goto next;
}
next:
sshkey_free(private);
sshkey_free(public);
free(prv_tmp);
free(pub_tmp);
free(prv_file);
free(pub_file);
}
if (first != 0)
printf("\n");

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-rsa.c,v 1.61 2017/05/07 23:15:59 djm Exp $ */
/* $OpenBSD: ssh-rsa.c,v 1.62 2017/07/01 13:50:45 djm Exp $ */
/*
* Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
*
@ -78,6 +78,41 @@ rsa_hash_alg_nid(int type)
}
}
/* calculate p-1 and q-1 */
int
ssh_rsa_generate_additional_parameters(struct sshkey *key)
{
RSA *rsa;
BIGNUM *aux = NULL;
BN_CTX *ctx = NULL;
int r;
if (key == NULL || key->rsa == NULL ||
sshkey_type_plain(key->type) != KEY_RSA)
return SSH_ERR_INVALID_ARGUMENT;
if ((ctx = BN_CTX_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((aux = BN_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
rsa = key->rsa;
if ((BN_sub(aux, rsa->q, BN_value_one()) == 0) ||
(BN_mod(rsa->dmq1, rsa->d, aux, ctx) == 0) ||
(BN_sub(aux, rsa->p, BN_value_one()) == 0) ||
(BN_mod(rsa->dmp1, rsa->d, aux, ctx) == 0)) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
r = 0;
out:
BN_clear_free(aux);
BN_CTX_free(ctx);
return r;
}
/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
int
ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,

11
ssh.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh.c,v 1.461 2017/05/30 18:58:37 bluhm Exp $ */
/* $OpenBSD: ssh.c,v 1.462 2017/08/12 06:46:01 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -509,13 +509,13 @@ int
main(int ac, char **av)
{
struct ssh *ssh = NULL;
int i, r, opt, exit_status, use_syslog, direct, config_test = 0;
int i, r, opt, exit_status, use_syslog, direct, timeout_ms;
int config_test = 0, opt_terminated = 0;
char *p, *cp, *line, *argv0, buf[PATH_MAX], *host_arg, *logfile;
char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
char cname[NI_MAXHOST], uidstr[32], *conn_hash_hex;
struct stat st;
struct passwd *pw;
int timeout_ms;
extern int optind, optreset;
extern char *optarg;
struct Forward fwd;
@ -917,6 +917,9 @@ main(int ac, char **av)
}
}
if (optind > 1 && strcmp(av[optind - 1], "--") == 0)
opt_terminated = 1;
ac -= optind;
av += optind;
@ -931,7 +934,7 @@ main(int ac, char **av)
host = xstrdup(++cp);
} else
host = xstrdup(*av);
if (ac > 1) {
if (ac > 1 && !opt_terminated) {
optind = optreset = 1;
goto again;
}

View File

@ -33,16 +33,13 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $OpenBSD: ssh_config.5,v 1.251 2017/06/24 05:35:05 djm Exp $
.Dd $Mdocdate: June 24 2017 $
.\" $OpenBSD: ssh_config.5,v 1.253 2017/07/23 23:37:02 djm Exp $
.Dd $Mdocdate: July 23 2017 $
.Dt SSH_CONFIG 5
.Os
.Sh NAME
.Nm ssh_config
.Nd OpenSSH SSH client configuration files
.Sh SYNOPSIS
.Nm ~/.ssh/config
.Nm /etc/ssh/ssh_config
.Sh DESCRIPTION
.Xr ssh 1
obtains configuration data from the following sources in
@ -972,7 +969,9 @@ Accepted values are
.Cm lowdelay ,
.Cm throughput ,
.Cm reliability ,
or a numeric value.
a numeric value, or
.Cm none
to use the operating system default.
This option may take one or two arguments, separated by whitespace.
If one argument is specified, it is used as the packet class unconditionally.
If two values are specified, the first is automatically selected for

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshconnect.c,v 1.282 2017/06/24 05:37:44 djm Exp $ */
/* $OpenBSD: sshconnect.c,v 1.283 2017/07/01 13:50:45 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -48,7 +48,6 @@
#include "key.h"
#include "hostfile.h"
#include "ssh.h"
#include "rsa.h"
#include "buffer.h"
#include "packet.h"
#include "uidswap.h"

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshconnect2.c,v 1.264 2017/06/14 00:31:38 dtucker Exp $ */
/* $OpenBSD: sshconnect2.c,v 1.265 2017/08/11 04:47:12 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Damien Miller. All rights reserved.
@ -1042,6 +1042,11 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
/* load the private key from the file */
if ((prv = load_identity_file(id)) == NULL)
return SSH_ERR_KEY_NOT_FOUND;
if (id->key != NULL && !sshkey_equal_public(prv, id->key)) {
error("%s: private key %s contents do not match public",
__func__, id->filename);
return SSH_ERR_KEY_NOT_FOUND;
}
ret = sshkey_sign(prv, sigp, lenp, data, datalen,
key_sign_encode(prv), compat);
sshkey_free(prv);

3
sshd.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshd.c,v 1.490 2017/05/31 08:09:45 markus Exp $ */
/* $OpenBSD: sshd.c,v 1.491 2017/07/01 13:50:45 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -88,7 +88,6 @@
#include "xmalloc.h"
#include "ssh.h"
#include "ssh2.h"
#include "rsa.h"
#include "sshpty.h"
#include "packet.h"
#include "log.h"

View File

@ -33,15 +33,13 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $OpenBSD: sshd_config.5,v 1.248 2017/06/24 07:08:57 djm Exp $
.Dd $Mdocdate: June 24 2017 $
.\" $OpenBSD: sshd_config.5,v 1.250 2017/07/23 23:37:02 djm Exp $
.Dd $Mdocdate: July 23 2017 $
.Dt SSHD_CONFIG 5
.Os
.Sh NAME
.Nm sshd_config
.Nd OpenSSH SSH daemon configuration file
.Sh SYNOPSIS
.Nm /etc/ssh/sshd_config
.Sh DESCRIPTION
.Xr sshd 8
reads configuration data from
@ -794,7 +792,9 @@ Accepted values are
.Cm lowdelay ,
.Cm throughput ,
.Cm reliability ,
or a numeric value.
a numeric value, or
.Cm none
to use the operating system default.
This option may take one or two arguments, separated by whitespace.
If one argument is specified, it is used as the packet class unconditionally.
If two values are specified, the first is automatically selected for

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshkey.c,v 1.53 2017/06/28 01:09:22 djm Exp $ */
/* $OpenBSD: sshkey.c,v 1.56 2017/08/12 06:42:52 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Alexander von Gernler. All rights reserved.
@ -51,7 +51,6 @@
#include "ssherr.h"
#include "misc.h"
#include "sshbuf.h"
#include "rsa.h"
#include "cipher.h"
#include "digest.h"
#define SSHKEY_INTERNAL
@ -66,7 +65,7 @@
#define KDFNAME "bcrypt"
#define AUTH_MAGIC "openssh-key-v1"
#define SALT_LEN 16
#define DEFAULT_CIPHERNAME "aes256-cbc"
#define DEFAULT_CIPHERNAME "aes256-ctr"
#define DEFAULT_ROUNDS 16
/* Version identification string for SSH v1 identity files. */
@ -1987,11 +1986,6 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
pk = NULL;
break;
case KEY_UNSPEC:
if ((key = sshkey_new(type)) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
break;
default:
ret = SSH_ERR_KEY_TYPE_UNKNOWN;
goto out;
@ -2667,7 +2661,7 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
(r = sshbuf_get_bignum2(buf, k->rsa->iqmp)) != 0 ||
(r = sshbuf_get_bignum2(buf, k->rsa->p)) != 0 ||
(r = sshbuf_get_bignum2(buf, k->rsa->q)) != 0 ||
(r = rsa_generate_additional_parameters(k->rsa)) != 0)
(r = ssh_rsa_generate_additional_parameters(k)) != 0)
goto out;
if (BN_num_bits(k->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
r = SSH_ERR_KEY_LENGTH;
@ -2681,7 +2675,7 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
(r = sshbuf_get_bignum2(buf, k->rsa->iqmp)) != 0 ||
(r = sshbuf_get_bignum2(buf, k->rsa->p)) != 0 ||
(r = sshbuf_get_bignum2(buf, k->rsa->q)) != 0 ||
(r = rsa_generate_additional_parameters(k->rsa)) != 0)
(r = ssh_rsa_generate_additional_parameters(k)) != 0)
goto out;
if (BN_num_bits(k->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
r = SSH_ERR_KEY_LENGTH;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshkey.h,v 1.20 2017/06/28 01:09:22 djm Exp $ */
/* $OpenBSD: sshkey.h,v 1.21 2017/07/01 13:50:45 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@ -196,6 +196,9 @@ int sshkey_parse_private_fileblob(struct sshbuf *buffer,
int sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
const char *passphrase, struct sshkey **keyp, char **commentp);
/* XXX should be internal, but used by ssh-keygen */
int ssh_rsa_generate_additional_parameters(struct sshkey *);
#ifdef SSHKEY_INTERNAL
int ssh_rsa_sign(const struct sshkey *key,
u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,