Merge branch 'master' of https://github.com/openssh/openssh-portable into m_temp
Resolved auth2-pubkey.c misc.c ssh-keygen.c
This commit is contained in:
commit
eaf004d1c4
.skipped-commit-idsMakefile.inREADMEauth-pam.cauth.cauth.hauth2-pubkey.cauthfd.cauthfile.cclientloop.ccompat.cconfigure.acmisc.cmisc.h
openbsd-compat
packet.cplatform-misc.cplatform.crsa.crsa.hserverloop.csession.csession.hsftp-client.cssh-add.cssh-agent.cssh-keygen.1ssh-keygen.cssh-rsa.cssh.cssh_config.5sshconnect.csshconnect2.csshd.csshd_config.5sshkey.csshkey.h
|
@ -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
|
||||
|
|
|
@ -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
8
README
|
@ -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
|
||||
|
|
26
auth-pam.c
26
auth-pam.c
|
@ -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
99
auth.c
|
@ -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
6
auth.h
|
@ -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);
|
||||
|
|
308
auth2-pubkey.c
308
auth2-pubkey.c
|
@ -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 */
|
||||
|
|
3
authfd.c
3
authfd.c
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
11
compat.c
11
compat.c
|
@ -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,"
|
||||
|
|
|
@ -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
469
misc.c
|
@ -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
22
misc.h
|
@ -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
|
||||
|
|
|
@ -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, ...)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
4
packet.c
4
packet.c
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
16
platform.c
16
platform.c
|
@ -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
188
rsa.c
|
@ -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
26
rsa.h
|
@ -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 */
|
18
serverloop.c
18
serverloop.c
|
@ -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);
|
||||
}
|
||||
|
|
87
session.c
87
session.c
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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"
|
||||
|
|
315
ssh-agent.c
315
ssh-agent.c
|
@ -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 */
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
106
ssh-keygen.c
106
ssh-keygen.c
|
@ -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");
|
||||
|
|
37
ssh-rsa.c
37
ssh-rsa.c
|
@ -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
11
ssh.c
|
@ -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;
|
||||
}
|
||||
|
|
11
ssh_config.5
11
ssh_config.5
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
3
sshd.c
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
14
sshkey.c
14
sshkey.c
|
@ -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;
|
||||
|
|
5
sshkey.h
5
sshkey.h
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue