Source snapshot from Powershell/openssh-portable:latestw_all

This commit is contained in:
Yanbing Wang 2017-09-05 20:43:24 -07:00
parent c1680168e4
commit 25a4ae6a3c
56 changed files with 1764 additions and 979 deletions

View File

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

View File

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

8
README
View File

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

View File

@ -1,4 +1,4 @@
version: 0.0.19.0.{build}
version: 0.0.20.0.{build}
image: Visual Studio 2015
branches:

View File

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

99
auth.c
View File

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

6
auth.h
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -168,7 +168,9 @@ function Repair-AuthorizedKeyPermission
$userProfilePath = $properties.ProfileImagePath
}
$userProfilePath = $userProfilePath.Replace("\", "\\")
$fullPath -match "^$userProfilePath[\\|\W|\w]+authorized_keys$"
if ( $properties.PSChildName -notmatch '\.bak$') {
$fullPath -match "^$userProfilePath\\[\\|\W|\w]+authorized_keys$"
}
}
if($profileItem)
{

View File

@ -248,9 +248,6 @@
<ClCompile Include="$(OpenSSH-Src-Path)progressmeter.c" />
<ClCompile Include="$(OpenSSH-Src-Path)readpass.c" />
<ClCompile Include="$(OpenSSH-Src-Path)rijndael.c" />
<ClCompile Include="$(OpenSSH-Src-Path)rsa.c">
<ExcludedFromBuild Condition="$(UseOpenSSL)==false">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="$(OpenSSH-Src-Path)sc25519.c" />
<ClCompile Include="$(OpenSSH-Src-Path)smult_curve25519_ref.c" />
<ClCompile Include="$(OpenSSH-Src-Path)ssh-dss.c">
@ -275,6 +272,7 @@
<ClCompile Include="$(OpenSSH-Src-Path)uuencode.c" />
<ClCompile Include="$(OpenSSH-Src-Path)verify.c" />
<ClCompile Include="$(OpenSSH-Src-Path)xmalloc.c" />
<ClCompile Include="$(OpenSSH-Src-Path)platform-misc.c" />
<ClCompile Include="$(OpenSSH-Src-Path)platform-pledge.c" />
<ClCompile Include="$(OpenSSH-Src-Path)platform-tracing.c" />
<ClCompile Include="$(OpenSSH-Src-Path)platform.c" />

View File

@ -14,17 +14,14 @@
<ClCompile Include="$(OpenSSH-Src-Path)canohost.c" />
<ClCompile Include="$(OpenSSH-Src-Path)chacha.c" />
<ClCompile Include="$(OpenSSH-Src-Path)channels.c" />
<ClCompile Include="$(OpenSSH-Src-Path)cipher-3des1.c" />
<ClCompile Include="$(OpenSSH-Src-Path)cipher-aes.c" />
<ClCompile Include="$(OpenSSH-Src-Path)cipher-aesctr.c" />
<ClCompile Include="$(OpenSSH-Src-Path)cipher-bf1.c" />
<ClCompile Include="$(OpenSSH-Src-Path)cipher-chachapoly.c" />
<ClCompile Include="$(OpenSSH-Src-Path)cipher-ctr.c" />
<ClCompile Include="$(OpenSSH-Src-Path)cipher.c" />
<ClCompile Include="$(OpenSSH-Src-Path)cleanup.c" />
<ClCompile Include="$(OpenSSH-Src-Path)compat.c" />
<ClCompile Include="$(OpenSSH-Src-Path)crc32.c" />
<ClCompile Include="$(OpenSSH-Src-Path)deattack.c" />
<ClCompile Include="$(OpenSSH-Src-Path)dh.c" />
<ClCompile Include="$(OpenSSH-Src-Path)digest-libc.c" />
<ClCompile Include="$(OpenSSH-Src-Path)dispatch.c" />
@ -60,7 +57,6 @@
<ClCompile Include="$(OpenSSH-Src-Path)opacket.c" />
<ClCompile Include="$(OpenSSH-Src-Path)packet.c" />
<ClCompile Include="$(OpenSSH-Src-Path)poly1305.c" />
<ClCompile Include="$(OpenSSH-Src-Path)rsa.c" />
<ClCompile Include="$(OpenSSH-Src-Path)sc25519.c" />
<ClCompile Include="$(OpenSSH-Src-Path)smult_curve25519_ref.c" />
<ClCompile Include="$(OpenSSH-Src-Path)ssh-dss.c" />
@ -83,7 +79,15 @@
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\ttymodes_windows.c" />
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\w32-sshfileperm.c" />
<ClCompile Include="$(OpenSSH-Src-Path)digest-openssl.c" />
<ClCompile Include="..\..\..\kexgexs.c" />
<ClCompile Include="$(OpenSSH-Src-Path)match.c" />
<ClCompile Include="$(OpenSSH-Src-Path)misc.c" />
<ClCompile Include="$(OpenSSH-Src-Path)moduli.c" />
<ClCompile Include="$(OpenSSH-Src-Path)progressmeter.c" />
<ClCompile Include="$(OpenSSH-Src-Path)readpass.c" />
<ClCompile Include="$(OpenSSH-Src-Path)rijndael.c" />
<ClCompile Include="$(OpenSSH-Src-Path)uuencode.c" />
<ClCompile Include="$(OpenSSH-Src-Path)verify.c" />
<ClCompile Include="$(OpenSSH-Src-Path)xmalloc.c" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(OpenSSH-Src-Path)addrmatch.c">
@ -245,15 +249,6 @@
<ClCompile Include="$(OpenSSH-Src-Path)mac.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(OpenSSH-Src-Path)match.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(OpenSSH-Src-Path)misc.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(OpenSSH-Src-Path)moduli.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(OpenSSH-Src-Path)monitor_fdpass.c">
<Filter>Source Files</Filter>
</ClCompile>
@ -272,15 +267,6 @@
<ClCompile Include="$(OpenSSH-Src-Path)poly1305.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(OpenSSH-Src-Path)progressmeter.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(OpenSSH-Src-Path)readpass.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(OpenSSH-Src-Path)rijndael.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(OpenSSH-Src-Path)rsa.c">
<Filter>Source Files</Filter>
</ClCompile>
@ -329,15 +315,6 @@
<ClCompile Include="$(OpenSSH-Src-Path)umac.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(OpenSSH-Src-Path)uuencode.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(OpenSSH-Src-Path)verify.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(OpenSSH-Src-Path)xmalloc.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(OpenSSH-Src-Path)platform-pledge.c">
<Filter>Source Files</Filter>
</ClCompile>
@ -361,11 +338,7 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(OpenSSH-Src-Path)crypto-wrap.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(OpenSSH-Src-Path)sshfileperm.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(OpenSSH-Src-Path)crypto-wrap.h" />
<ClInclude Include="$(OpenSSH-Src-Path)sshfileperm.h" />
</ItemGroup>
</Project>

Binary file not shown.

View File

@ -1,6 +1,16 @@
#ifndef COMPAT_GRP_H
#define COMPAT_GRP_H 1
#include <Windows.h>
#include "sys/types.h"
char *group_from_gid(gid_t gid, int nogroup);
typedef enum {
LOCAL_GROUP = 0,
DOMAIN_GROUP = 1,
GLOBAL_UNIVERSAL_GROUP = 2
} group_type;
char ** getusergroups(const char *user, int *numgroups);
void populate_user_groups(char **group_name, int *group_index, DWORD groupsread, DWORD totalgroups, LPBYTE buf, group_type groupType);
void print_user_groups(const char *user, char **user_groups, int num_user_groups);
#endif

View File

@ -91,4 +91,8 @@ int w32_sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
#define SIG_IGN W32_SIG_IGN
#define SIG_ERR W32_SIG_ERR
/* TOTO - implement http://www.manpagez.com/man/3/sys_siglist/*/
#undef NSIG
#define NSIG 0
#endif

View File

@ -33,6 +33,7 @@
#include <time.h>
#include <Shlwapi.h>
#include <conio.h>
#include <LM.h>
#include "inc\unistd.h"
#include "inc\sys\stat.h"
@ -49,6 +50,7 @@
#include "debug.h"
#include "w32fd.h"
#include "inc\string.h"
#include "inc\grp.h"
static char* s_programdir = NULL;
@ -1046,8 +1048,259 @@ readpassphrase(const char *prompt, char *outBuf, size_t outBufLen, int flags)
return outBuf;
}
void invalid_parameter_handler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved)
void
invalid_parameter_handler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved)
{
debug3("Invalid parameter in function: %ls. File: %ls Line: %d.", function, file, line);
debug3("Expression: %s", expression);
}
int
get_machine_domain_name(wchar_t *domain, int size)
{
LPWKSTA_INFO_100 pBuf = NULL;
NET_API_STATUS nStatus;
LPWSTR pszServerName = NULL;
nStatus = NetWkstaGetInfo(pszServerName, 100, (LPBYTE *)&pBuf);
if (nStatus != NERR_Success) {
error("Unable to fetch the machine domain, error:%d\n", nStatus);
return 0;
}
debug3("Machine domain:%ls", pBuf->wki100_langroup);
wcscpy_s(domain, size, pBuf->wki100_langroup);
if (pBuf != NULL)
NetApiBufferFree(pBuf);
return 1;
}
/*
* This method will fetch all the groups (listed below) even if the user is indirectly a member.
* - Local machine groups
* - Domain groups
* - global group
* - universal groups
*/
char **
getusergroups(const char *user, int *ngroups)
{
LPGROUP_USERS_INFO_0 local_groups = NULL;
LPGROUP_USERS_INFO_0 domain_groups = NULL;
LPGROUP_USERS_INFO_0 global_universal_groups = NULL;
DWORD num_local_groups_read = 0;
DWORD total_local_groups = 0;
DWORD num_domain_groups_read = 0;
DWORD total_domain_groups = 0;
DWORD num_global_universal_groups_read = 0;
DWORD total_global_universal_groups = 0;
DWORD flags = LG_INCLUDE_INDIRECT;
NET_API_STATUS nStatus;
wchar_t *user_name_utf16 = NULL;
char *user_domain = NULL;
LPWSTR dc_name_utf16 = NULL;
char **user_groups = NULL;
int num_user_groups = 0;
wchar_t machine_domain_name_utf16[DNLEN + 1] = { 0 };
wchar_t local_user_fmt_utf16[UNLEN + DNLEN + 2] = { 0 };
size_t local_user_fmt_len = UNLEN + DNLEN + 2;
char *user_name = NULL;
user_name = malloc(strlen(user)+1);
if(!user_name) {
error("failed to allocate memory!");
goto cleanup;
}
memcpy(user_name, user, strlen(user)+1);
if (user_domain = strchr(user_name, '@')) {
char *t = user_domain;
user_domain++;
*t='\0';
}
user_name_utf16 = utf8_to_utf16(user_name);
if (!user_name_utf16) {
error("utf8_to_utf16 failed! for %s", user_name);
goto cleanup;
}
/* Fetch groups on the Local machine */
if(get_machine_domain_name(machine_domain_name_utf16, DNLEN+1)) {
if (machine_domain_name_utf16) {
if(!machine_domain_name)
machine_domain_name = utf16_to_utf8(machine_domain_name_utf16);
if (user_domain) {
wcscpy_s(local_user_fmt_utf16, local_user_fmt_len, machine_domain_name_utf16);
wcscat_s(local_user_fmt_utf16, local_user_fmt_len, L"\\");
}
wcscat_s(local_user_fmt_utf16, local_user_fmt_len, user_name_utf16);
nStatus = NetUserGetLocalGroups(NULL,
local_user_fmt_utf16,
0,
flags,
(LPBYTE *)&local_groups,
MAX_PREFERRED_LENGTH,
&num_local_groups_read,
&total_local_groups);
if (NERR_Success != nStatus)
error("Failed to get local groups on this machine, error: %d\n", nStatus);
}
}
if (user_domain) {
/* Fetch Domain groups */
nStatus = NetGetDCName(NULL, machine_domain_name_utf16, (LPBYTE *)&dc_name_utf16);
if (NERR_Success == nStatus) {
debug3("domain controller name: %ls", dc_name_utf16);
nStatus = NetUserGetLocalGroups(dc_name_utf16,
user_name_utf16,
0,
flags,
(LPBYTE *)&domain_groups,
MAX_PREFERRED_LENGTH,
&num_domain_groups_read,
&total_domain_groups);
if (NERR_Success != nStatus)
error("Failed to get domain groups from DC:%s error: %d\n", dc_name_utf16, nStatus);
}
else
error("Failed to get the domain controller name, error: %d\n", nStatus);
/* Fetch global, universal groups */
nStatus = NetUserGetGroups(dc_name_utf16,
user_name_utf16,
0,
(LPBYTE *)&global_universal_groups,
MAX_PREFERRED_LENGTH,
&num_global_universal_groups_read,
&total_global_universal_groups);
if (NERR_Success != nStatus)
error("Failed to get global,universal groups from DC:%ls error: %d\n", dc_name_utf16, nStatus);
}
int total_user_groups = num_local_groups_read + num_domain_groups_read + num_global_universal_groups_read;
/* populate the output */
user_groups = malloc(total_user_groups * sizeof(*user_groups));
populate_user_groups(user_groups, &num_user_groups, num_local_groups_read, total_local_groups, (LPBYTE) local_groups, LOCAL_GROUP);
if (user_domain) {
populate_user_groups(user_groups, &num_user_groups, num_domain_groups_read, total_domain_groups, (LPBYTE)domain_groups, DOMAIN_GROUP);
populate_user_groups(user_groups, &num_user_groups, num_global_universal_groups_read, total_global_universal_groups, (LPBYTE)global_universal_groups, GLOBAL_UNIVERSAL_GROUP);
}
for (int i = 0; i < num_user_groups; i++)
to_lower_case(user_groups[i]);
print_user_groups(user, user_groups, num_user_groups);
cleanup:
if(local_groups)
NetApiBufferFree(local_groups);
if(domain_groups)
NetApiBufferFree(domain_groups);
if(global_universal_groups)
NetApiBufferFree(global_universal_groups);
if(dc_name_utf16)
NetApiBufferFree(dc_name_utf16);
if(user_name_utf16)
free(user_name_utf16);
if(user_name)
free(user_name);
*ngroups = num_user_groups;
return user_groups;
}
/* This method will return in "group@domain" format */
char *
append_domain_to_groupname(char *groupname)
{
if(!groupname) return NULL;
int len = (int) strlen(machine_domain_name) + (int) strlen(groupname) + 2;
char *groupname_with_domain = malloc(len);
if(!groupname_with_domain) {
error("failed to allocate memory!");
return NULL;
}
strcpy_s(groupname_with_domain, len, groupname);
strcat_s(groupname_with_domain, len, "@");
strcat_s(groupname_with_domain, len, machine_domain_name);
groupname_with_domain[len-1]= '\0';
return groupname_with_domain;
}
void
populate_user_groups(char **group_name, int *group_index, DWORD groupsread, DWORD totalgroups, LPBYTE buf, group_type groupType)
{
if(0 == groupsread) return;
char *user_group_name = NULL;
if (groupType == GLOBAL_UNIVERSAL_GROUP) {
LPGROUP_USERS_INFO_0 pTmpBuf = (LPGROUP_USERS_INFO_0)buf;
for (DWORD i = 0; (i < groupsread) && pTmpBuf; i++, pTmpBuf++) {
if (!(user_group_name = utf16_to_utf8(pTmpBuf->grui0_name))) {
error("utf16_to_utf8 failed to convert:%ls", pTmpBuf->grui0_name);
return;
}
group_name[*group_index] = append_domain_to_groupname(user_group_name);
if(group_name[*group_index])
(*group_index)++;
}
} else {
LPLOCALGROUP_USERS_INFO_0 pTmpBuf = (LPLOCALGROUP_USERS_INFO_0)buf;
for (DWORD i = 0; (i < groupsread) && pTmpBuf; i++, pTmpBuf++) {
if (!(user_group_name = utf16_to_utf8(pTmpBuf->lgrui0_name))) {
error("utf16_to_utf8 failed to convert:%ls", pTmpBuf->lgrui0_name);
return;
}
if(groupType == DOMAIN_GROUP)
group_name[*group_index] = append_domain_to_groupname(user_group_name);
else
group_name[*group_index] = user_group_name;
if (group_name[*group_index])
(*group_index)++;
}
}
if (groupsread < totalgroups)
error("groupsread:%d totalgroups:%d groupType:%d", groupsread, totalgroups, groupType);
}
void
print_user_groups(const char *user, char **user_groups, int num_user_groups)
{
debug3("Group list for user:%s", user);
for(int i=0; i < num_user_groups; i++)
debug3("group name:%s", user_groups[i]);
}
void
to_lower_case(char *s)
{
for (; *s; s++)
*s = tolower((u_char)*s);
}

View File

@ -31,4 +31,7 @@ int errno_from_Win32Error(int);
void unix_time_to_file_time(ULONG, LPFILETIME);
void file_time_to_unix_time(const LPFILETIME, time_t *);
int file_attr_to_st_mode(wchar_t * path, DWORD attributes);
void invalid_parameter_handler(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t);
void invalid_parameter_handler(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t);
static char *machine_domain_name;
void to_lower_case(char *s);
int get_machine_domain_name(wchar_t *domain, int size);

View File

@ -203,6 +203,8 @@ get_passwd(const char *user_utf8, LPWSTR user_sid)
goto done;
}
}
to_lower_case(uname_upn);
pw.pw_name = uname_upn;
uname_upn = NULL;
pw.pw_dir = pw_home_utf8;

View File

@ -164,7 +164,6 @@ struct key_translation keys[] = {
{ L"\x1bOQ", VK_F2, 0 , 0 , 0},
{ L"\x1bOR", VK_F3, 0 , 0 , 0},
{ L"\x1bOS", VK_F4, 0 , 0 , 0},
{ L"\x1b?", VK_OEM_2, L'?' , 0 , SHIFT_PRESSED | LEFT_ALT_PRESSED},
{ L"\x1", VK_A, L'\x1' , 0 , LEFT_CTRL_PRESSED},
{ L"\x2", VK_B, L'\x2' , 0 , LEFT_CTRL_PRESSED},
//{ L"\x3", VK_C, L'\x3' , 0 , LEFT_CTRL_PRESSED}, /* Control + C is handled differently */
@ -311,7 +310,7 @@ SendKeyStrokeEx(HANDLE hInput, int vKey, wchar_t character, DWORD ctrlState, BOO
ir.EventType = KEY_EVENT;
ir.Event.KeyEvent.bKeyDown = keyDown;
ir.Event.KeyEvent.wRepeatCount = 0;
ir.Event.KeyEvent.wRepeatCount = 1;
ir.Event.KeyEvent.wVirtualKeyCode = vKey;
ir.Event.KeyEvent.wVirtualScanCode = MapVirtualKeyA(vKey, MAPVK_VK_TO_VSC);
ir.Event.KeyEvent.dwControlKeyState = ctrlState;

View File

@ -31,9 +31,10 @@
#include <errno.h>
#include "w32fd.h"
#include "signal_internal.h"
#include "inc\signal.h"
#include "debug.h"
/* Apply caution while changing this order of inclusion of below 2 signal.h headers */
#include "inc\signal.h"
#undef signal
#undef raise
#undef SIGINT
@ -46,7 +47,11 @@
#undef SIG_DFL
#undef SIG_IGN
#undef SIG_ERR
#undef NSIG
#include <signal.h>
#undef NSIG
#define NSIG 0
/* pending signals to be processed */
sigset_t pending_signals;

View File

@ -3,9 +3,9 @@ typedef unsigned short u_int16_t;
typedef unsigned int u_int32_t;
typedef unsigned __int64 u_int64_t;
#define __attribute__(a)
#include "rsa.h"
#include "sshbuf.h"
#include "sshkey.h"
#include <openssl/bn.h>
#include "authfd.h"
#include "digest.h"

View File

@ -155,7 +155,7 @@ ReadConsoleForTermEmul(HANDLE hInput, char *destin, int destinlen)
switch (InputRecord.Event.KeyEvent.uChar.UnicodeChar) {
case 0xd:
if (pParams->nReceiveCRLF == ENUM_LF)
NetWriteString2(pParams->Socket, "\n", 1, 0);
NetWriteString2(pParams->Socket, "\r", 1, 0);
else
NetWriteString2(pParams->Socket, "\r\n", 2, 0);
break;
@ -208,9 +208,6 @@ ReadConsoleForTermEmul(HANDLE hInput, char *destin, int destinlen)
case VK_ESCAPE:
NetWriteString2(pParams->Socket, (char *)ESCAPE_KEY, 1, 0);
break;
case VK_OEM_2:
NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_Q, 2, 0);
break;
case VK_SHIFT:
case VK_CONTROL:
case VK_CAPITAL:

View File

@ -54,84 +54,13 @@ int
ga_init(const char *user, gid_t base)
{
#ifdef WINDOWS
#pragma warning(push, 3)
LPLOCALGROUP_USERS_INFO_0 local_groups_info = NULL, tmp_groups_info;
wchar_t *user_utf16 = NULL, *full_name_utf16 = NULL, *udom_utf16 = NULL, *tmp;
char *group_utf8 = NULL;
DWORD i = 0, j = 0;
DWORD entries_read = 0, total_entries = 0, full_name_len = 0, index = 0;
NET_API_STATUS nStatus;
if (ngroups > 0)
ga_free();
if ((user_utf16 = utf8_to_utf16(user)) == NULL) {
errno = ENOMEM;
goto done;
}
full_name_len = (DWORD)wcslen(user_utf16) + 1;
if ((full_name_utf16 = malloc(full_name_len * sizeof(wchar_t))) == NULL) {
errno = ENOMEM;
goto done;
}
if ((tmp = wcschr(user_utf16, L'@')) != NULL) {
udom_utf16 = tmp + 1;
*tmp = L'\0';
index = (DWORD)wcslen(udom_utf16) + 1;
wmemcpy(full_name_utf16, udom_utf16, index);
full_name_utf16[wcslen(udom_utf16)] = L'\\';
}
wmemcpy(full_name_utf16 + index, user_utf16, wcslen(user_utf16) + 1);
nStatus = NetUserGetLocalGroups(NULL,
full_name_utf16,
0,
LG_INCLUDE_INDIRECT,
(LPBYTE *)&local_groups_info,
MAX_PREFERRED_LENGTH,
&entries_read,
&total_entries);
if (NERR_Success != nStatus) {
error("NetUserGetLocalGroups() failed with error: %u",
nStatus);
errno = ENOENT;
goto done;
}
if (entries_read != total_entries) {
error("NetUserGetLocalGroups(): entries_read (%u) is not equal to "
"total_entries (%u) for user %.100s", entries_read, total_entries, user);
errno = ENOENT;
goto done;
}
if ((tmp_groups_info = local_groups_info) != NULL) {
groups_byname = xcalloc(entries_read, sizeof(*groups_byname));
for (i = 0, j = 0; i < total_entries; i++)
{
if ((group_utf8 = utf16_to_utf8(tmp_groups_info->lgrui0_name)) == NULL) {
errno = ENOMEM;
goto done;
}
groups_byname[j++] = group_utf8;
tmp_groups_info++;
}
}
done:
if(user_utf16 != NULL)
free(user_utf16);
if(full_name_utf16 != NULL)
free(full_name_utf16);
if (local_groups_info != NULL)
NetApiBufferFree(local_groups_info);
#pragma warning(pop)
ngroups = 0;
groups_byname = NULL;
groups_byname = getusergroups(user, &ngroups);
return ngroups;
#else /* !WINDOWS */
gid_t *groups_bygid;
int i, j;
struct group *gr;
@ -153,8 +82,8 @@ done:
if ((gr = getgrgid(groups_bygid[i])) != NULL)
groups_byname[j++] = xstrdup(gr->gr_name);
free(groups_bygid);
#endif /* !WINDOWS */
return (ngroups = j);
#endif /* !WINDOWS */
}
/*

474
misc.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: misc.c,v 1.110 2017/05/31 09:15:42 deraadt Exp $ */
/* $OpenBSD: misc.c,v 1.113 2017/08/18 05:48:04 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2005,2006 Damien Miller. All rights reserved.
@ -29,10 +29,16 @@
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <limits.h>
#ifdef HAVE_LIBGEN_H
# include <libgen.h>
#endif
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@ -61,6 +67,10 @@
#include "misc.h"
#include "log.h"
#include "ssh.h"
#include "sshbuf.h"
#include "ssherr.h"
#include "uidswap.h"
#include "platform.h"
/* remove newline at end of string */
char *
@ -1105,6 +1115,7 @@ static const struct {
const char *name;
int value;
} ipqos[] = {
{ "none", INT_MAX }, /* can't use 0 here; that's CS0 */
{ "af11", IPTOS_DSCP_AF11 },
{ "af12", IPTOS_DSCP_AF12 },
{ "af13", IPTOS_DSCP_AF13 },
@ -1303,3 +1314,464 @@ 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)
{
#ifdef WINDOWS
error("subprocess is not implemented in Windows yet");
return 0;
#else
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;
#endif
}
/* Returns 0 if pid exited cleanly, non-zero otherwise */
int
exited_cleanly(pid_t pid, const char *tag, const char *cmd, int quiet)
{
int status;
while (waitpid(pid, &status, 0) == -1) {
if (errno != EINTR) {
error("%s: waitpid: %s", tag, strerror(errno));
return -1;
}
}
if (WIFSIGNALED(status)) {
error("%s %s exited on signal %d", tag, cmd, WTERMSIG(status));
return -1;
} else if (WEXITSTATUS(status) != 0) {
do_log2(quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_INFO,
"%s %s failed, status %d", tag, cmd, WEXITSTATUS(status));
return -1;
}
return 0;
}
/*
* Check a given path for security. This is defined as all components
* of the path to the file must be owned by either the owner of
* of the file or root and no directories must be group or world writable.
*
* XXX Should any specific check be done for sym links ?
*
* Takes a file name, its stat information (preferably from fstat() to
* avoid races), the uid of the expected owner, their home directory and an
* error buffer plus max size as arguments.
*
* Returns 0 on success and -1 on failure
*/
int
safe_path(const char *name, struct stat *stp, const char *pw_dir,
uid_t uid, char *err, size_t errlen)
{
char buf[PATH_MAX], homedir[PATH_MAX];
char *cp;
int comparehome = 0;
struct stat st;
if (realpath(name, buf) == NULL) {
snprintf(err, errlen, "realpath %s failed: %s", name,
strerror(errno));
return -1;
}
if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)
comparehome = 1;
if (!S_ISREG(stp->st_mode)) {
snprintf(err, errlen, "%s is not a regular file", buf);
return -1;
}
if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) ||
(stp->st_mode & 022) != 0) {
snprintf(err, errlen, "bad ownership or modes for file %s",
buf);
return -1;
}
/* for each component of the canonical path, walking upwards */
for (;;) {
if ((cp = dirname(buf)) == NULL) {
snprintf(err, errlen, "dirname() failed");
return -1;
}
strlcpy(buf, cp, sizeof(buf));
if (stat(buf, &st) < 0 ||
(!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) ||
(st.st_mode & 022) != 0) {
snprintf(err, errlen,
"bad ownership or modes for directory %s", buf);
return -1;
}
/* If are past the homedir then we can stop */
if (comparehome && strcmp(homedir, buf) == 0)
break;
/*
* dirname should always complete with a "/" path,
* but we can be paranoid and check for "." too
*/
if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
break;
}
return 0;
}
/*
* Version of safe_path() that accepts an open file descriptor to
* avoid races.
*
* Returns 0 on success and -1 on failure
*/
int
safe_path_fd(int fd, const char *file, struct passwd *pw,
char *err, size_t errlen)
{
struct stat st;
/* check the open file to avoid races */
if (fstat(fd, &st) < 0) {
snprintf(err, errlen, "cannot stat file %s: %s",
file, strerror(errno));
return -1;
}
return safe_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);
}
/*
* Sets the value of the given variable in the environment. If the variable
* already exists, its value is overridden.
*/
void
child_set_env(char ***envp, u_int *envsizep, const char *name,
const char *value)
{
char **env;
u_int envsize;
u_int i, namelen;
if (strchr(name, '=') != NULL) {
error("Invalid environment variable \"%.100s\"", name);
return;
}
/*
* If we're passed an uninitialized list, allocate a single null
* entry before continuing.
*/
if (*envp == NULL && *envsizep == 0) {
*envp = xmalloc(sizeof(char *));
*envp[0] = NULL;
*envsizep = 1;
}
/*
* Find the slot where the value should be stored. If the variable
* already exists, we reuse the slot; otherwise we append a new slot
* at the end of the array, expanding if necessary.
*/
env = *envp;
namelen = strlen(name);
for (i = 0; env[i]; i++)
if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
break;
if (env[i]) {
/* Reuse the slot. */
free(env[i]);
} else {
/* New variable. Expand if necessary. */
envsize = *envsizep;
if (i >= envsize - 1) {
if (envsize >= 1000)
fatal("child_set_env: too many env vars");
envsize += 50;
env = (*envp) = xreallocarray(env, envsize, sizeof(char *));
*envsizep = envsize;
}
/* Need to set the NULL pointer at end of array beyond the new slot. */
env[i + 1] = NULL;
}
/* Allocate space and format the variable in the appropriate slot. */
env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
}

22
misc.h
View File

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

View File

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

View File

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

View File

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

View File

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

35
platform-misc.c Normal file
View File

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

View File

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

View File

@ -38,7 +38,10 @@ Describe "E2E scenarios for ssh key management" -Tags "CI" {
#only validate owner and ACEs of the file
function ValidateKeyFile {
param([string]$FilePath)
param(
[string]$FilePath,
[bool]$IsHostKey = $true
)
$myACL = Get-ACL $FilePath
$currentOwnerSid = Get-UserSid -User $myACL.Owner
@ -53,8 +56,14 @@ Describe "E2E scenarios for ssh key management" -Tags "CI" {
$FullControlPerm = [System.UInt32] [System.Security.AccessControl.FileSystemRights]::FullControl.value__
if($FilePath.EndsWith(".pub")) {
$myACL.Access.Count | Should Be 4
$identities = @($systemSid, $adminsSid, $currentUserSid, $everyoneSid)
if ($IsHostKey) {
$myACL.Access.Count | Should Be 3
$identities = @($systemSid, $adminsSid, $currentUserSid)
}
else {
$myACL.Access.Count | Should Be 4
$identities = @($systemSid, $adminsSid, $currentUserSid, $everyoneSid)
}
}
else {
$myACL.Access.Count | Should Be 3
@ -135,7 +144,7 @@ Describe "E2E scenarios for ssh key management" -Tags "CI" {
ssh-keygen -t $type -P $keypassphrase -f $keyPath
}
ValidateKeyFile -FilePath $keyPath
ValidateKeyFile -FilePath "$keyPath.pub"
ValidateKeyFile -FilePath "$keyPath.pub" -IsHostKey $false
}
}
}

View File

@ -1,17 +1,133 @@
Describe "Tests of sshd_config" -Tags "Scenario" {
If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path}
Import-Module $PSScriptRoot\CommonUtils.psm1 -Force
$tC = 1
$tI = 0
$suite = "sshdConfig"
Describe "Tests of sshd_config" -Tags "CI" {
BeforeAll {
$fileName = "test.txt"
$filePath = Join-Path ${TestDrive} $fileName
if($OpenSSHTestInfo -eq $null)
{
Throw "`$OpenSSHTestInfo is null. Please run Set-OpenSSHTestEnvironment to set test environments."
}
$testDir = "$($OpenSSHTestInfo["TestDataPath"])\$suite"
if( -not (Test-path $testDir -PathType Container))
{
$null = New-Item $testDir -ItemType directory -Force -ErrorAction SilentlyContinue
}
[Machine] $client = [Machine]::new([MachineRole]::Client)
[Machine] $server = [Machine]::new([MachineRole]::Server)
$client.SetupClient($server)
$server.SetupServer($client)
$fileName = "test.txt"
$logName = "sshdlog.txt"
$server = $OpenSSHTestInfo["Target"]
$port = 47003
Remove-Item -Path (Join-Path $testDir "*$fileName") -Force -ErrorAction SilentlyContinue
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
$ContextName = $env:COMPUTERNAME
$ContextType = [System.DirectoryServices.AccountManagement.ContextType]::Machine
$PrincipalContext = [System.DirectoryServices.AccountManagement.PrincipalContext]::new($ContextType, $ContextName)
$IdentityType = [System.DirectoryServices.AccountManagement.IdentityType]::SamAccountName
function Add-LocalUser
{
param([string] $UserName, [string] $Password)
$user = [System.DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($PrincipalContext, $IdentityType, $UserName)
if($user -eq $null)
{
try {
$user = [System.DirectoryServices.AccountManagement.UserPrincipal]::new($PrincipalContext,$UserName,$Password, $true)
$user.Save()
}
finally {
$user.Dispose()
}
}
}
function Add-LocalGroup
{
param([string] $groupName)
$group = [System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($PrincipalContext, $IdentityType, $GroupName)
if($group -eq $null)
{
try {
$group = [System.DirectoryServices.AccountManagement.GroupPrincipal]::new($PrincipalContext,$groupName)
$group.Save()
}
finally {
$group.Dispose()
}
}
}
function Add-UserToLocalGroup
{
param([string]$UserName, [string]$Password, [string]$GroupName)
Add-LocalGroup -groupName $GroupName
Add-LocalUser -UserName $UserName -Password $Password
$group = [System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($PrincipalContext, $IdentityType, $GroupName)
$user = [System.DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($PrincipalContext, $IdentityType, $UserName)
if(-not $group.Members.Contains($user))
{
try {
$group.Members.Add($user)
$group.save()
}
finally {
$group.Dispose()
}
}
}
function Remove-UserFromLocalGroup
{
param([string]$UserName, [string]$GroupName)
$group = [System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($PrincipalContext, $IdentityType, $GroupName)
$user = [System.DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($PrincipalContext, $IdentityType, $UserName)
if($group.Members.Contains($user))
{
try {
$group.Members.Remove($user)
$group.save()
}
finally {
$group.Dispose()
}
}
}
function Clenaup-LocalGroup
{
param([string]$GroupName)
$group = [System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($PrincipalContext, $IdentityType, $GroupName)
if($group -ne $null)
{
try {
$group.Delete()
}
finally {
$group.Dispose()
}
}
}
$platform = Get-Platform
$skip = ($platform -eq [PlatformType]::Windows) -and ($PSVersionTable.PSVersion.Major -le 2)
if(($platform -eq [PlatformType]::Windows) -and ($psversiontable.BuildVersion.Major -le 6))
{
#suppress the firewall blocking dialogue on win7
netsh advfirewall firewall add rule name="sshd" program="$($OpenSSHTestInfo['OpenSSHBinPath'])\sshd.exe" protocol=any action=allow dir=in
}
}
AfterEach { $tI++ }
AfterAll {
$client.CleanupClient()
$server.CleanupServer()
$PrincipalContext.Dispose()
if(($platform -eq [PlatformType]::Windows) -and ($psversiontable.BuildVersion.Major -le 6))
{
netsh advfirewall firewall delete rule name="sshd" program="$($OpenSSHTestInfo['OpenSSHBinPath'])\sshd.exe" protocol=any dir=in
}
}
<#
@ -24,7 +140,6 @@
#>
Context "Tests of AllowGroups, AllowUsers, DenyUsers, DenyGroups" {
BeforeAll {
Remove-Item -Path $filePath -Force -ea silentlycontinue
$password = "Bull_dog1"
$allowUser1 = "allowuser1"
@ -47,113 +162,183 @@
$denyGroup1 = "denygroup1"
$denyGroup2 = "denygroup2"
$denyGroup3 = "denygroup3"
$client.AddPasswordSetting($password)
}
AfterEach {
Remove-Item -Path $filePath -Force -ea SilentlyContinue
$sshdConfigPath = Join-Path $PSScriptRoot testdata\SSHD_Config
$testknownhosts = Join-path $PSScriptRoot testdata\test_known_hosts
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
#add wrong password so ssh does not prompt password if failed with authorized keys
Add-PasswordSetting -Pass $password
$tI=1
}
BeforeEach {
$filePath = Join-Path $testDir "$tC.$tI.$fileName"
$logPath = Join-Path $testDir "$tC.$tI.$logName"
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
AfterAll {
$client.CleanupPasswordSetting()
AfterAll {
Remove-PasswordSetting
$tC++
}
It 'User with full name in the list of AllowUsers' {
$server.AddUserToLocalGroup($allowUser1, $password, $allowGroup1)
It "$tC.$tI-User with full name in the list of AllowUsers" {
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-f $sshdConfigPath", "-E $logPath") -NoNewWindow
Add-UserToLocalGroup -UserName $allowUser1 -Password $password -GroupName $allowGroup1
$o = ssh -p $port $allowUser1@$server -o "UserKnownHostsFile $testknownhosts" echo 1234
$o | Should Be "1234"
Remove-UserFromLocalGroup -UserName $allowUser1 -GroupName $allowGroup1
#Cleanup
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It "$tC.$tI-User with * wildcard" {
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-f $sshdConfigPath", "-E $logPath") -NoNewWindow
Add-UserToLocalGroup -UserName $allowUser2 -Password $password -GroupName $allowGroup1
$client.RunCmd(".\ssh $($allowUser1)@$($server.MachineName) hostname > $filePath")
Get-Content $filePath | Should be $server.MachineName
$server.RemoveUserFromLocalGroup($allowUser1, $allowGroup1)
$o = ssh -p $port $allowUser2@$server -o "UserKnownHostsFile $testknownhosts" echo 1234
$o | Should Be "1234"
Remove-UserFromLocalGroup -UserName $allowUser2 -GroupName $allowGroup1
#Cleanup
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It 'User with * wildcard' {
$server.AddUserToLocalGroup($allowUser2, $password, $allowGroup1)
It "$tC.$tI-User with ? wildcard" {
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-f $sshdConfigPath", "-E $logPath") -NoNewWindow
Add-UserToLocalGroup -UserName $allowUser3 -Password $password -GroupName $allowGroup1
$client.RunCmd(".\ssh $($allowUser2)@$($server.MachineName) hostname > $filePath")
$LASTEXITCODE | Should Be 0
Get-Content $filePath | Should be $server.MachineName
$server.RemoveUserFromLocalGroup($allowUser2, $allowGroup1)
$o = ssh -p $port $allowUser3@$server -o "UserKnownHostsFile $testknownhosts" echo 1234
$o | Should Be "1234"
Remove-UserFromLocalGroup -UserName $allowUser3 -GroupName $allowGroup1
#Cleanup
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It 'User with ? wildcard' {
$server.AddUserToLocalGroup($allowUser3, $password, $allowGroup1)
It "$tC.$tI-User with full name in the list of AllowUsers but not in any AllowGroups" {
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-f $sshdConfigPath", "-E $logPath") -NoNewWindow
Add-LocalUser -UserName $allowUser4 -Password $password
ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $allowUser4@$server echo 1234
$LASTEXITCODE | Should Not Be 0
$matches = Get-Content $filePath | Select-String -pattern "Permission denied"
$matches.Count | Should BeGreaterThan 2
#Cleanup
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It "$tC.$tI-User with full name in the list of DenyUsers" {
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-f $sshdConfigPath", "-E $logPath") -NoNewWindow
Add-UserToLocalGroup -UserName $denyUser1 -Password $password -GroupName $allowGroup1
ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $denyUser1@$server echo 1234
$LASTEXITCODE | Should Not Be 0
$matches = Get-Content $filePath | Select-String -pattern "Permission denied"
$matches.Count | Should BeGreaterThan 2
Remove-UserFromLocalGroup -UserName $denyUser1 -GroupName $allowGroup1
#Cleanup
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It "$tC.$tI-User with * wildcard in the list of DenyUsers" {
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-f $sshdConfigPath", "-E $logPath") -NoNewWindow
Add-UserToLocalGroup -UserName $denyUser2 -Password $password -GroupName $allowGroup1
ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $denyUser2@$server echo 1234
$LASTEXITCODE | Should Not Be 0
$matches = Get-Content $filePath | Select-String -pattern "Permission denied"
$matches.Count | Should BeGreaterThan 2
Remove-UserFromLocalGroup -UserName $denyUser2 -GroupName $allowGroup1
#Cleanup
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It "$tC.$tI-User with ? wildcard in the list of DenyUsers" {
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-f $sshdConfigPath", "-E $logPath") -NoNewWindow
Add-UserToLocalGroup -UserName $denyUser3 -Password $password -GroupName $allowGroup1
ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $denyUser3@$server echo 1234
$LASTEXITCODE | Should Not Be 0
$matches = Get-Content $filePath | Select-String -pattern "Permission denied"
$matches.Count | Should BeGreaterThan 2
$client.RunCmd(".\ssh $($allowUser3)@$($server.MachineName) hostname > $filePath")
$LASTEXITCODE | Should Be 0
Get-Content $filePath | Should be $server.MachineName
$server.RemoveUserFromLocalGroup($allowUser3, $allowGroup1)
Remove-UserFromLocalGroup -UserName $denyUser3 -GroupName $allowGroup1
#Cleanup
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It 'User with full name in the list of AllowUsers but not in any AllowGroups' {
$server.AddLocalUser($allowUser4, $password)
It "$tC.$tI-User is listed in the list of AllowUsers but also in a full name DenyGroups and AllowGroups" {
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-f $sshdConfigPath", "-E $logPath") -NoNewWindow
Add-UserToLocalGroup -UserName $localuser1 -Password $password -GroupName $allowGroup1
Add-UserToLocalGroup -UserName $localuser1 -Password $password -GroupName $denyGroup1
$client.RunCmd(".\ssh $($allowUser4)@$($server.MachineName) hostname > $filePath")
ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $localuser1@$server echo 1234
$LASTEXITCODE | Should Not Be 0
Get-Content $filePath | Should BeNullOrEmpty
$matches = Get-Content $filePath | Select-String -pattern "Permission denied"
$matches.Count | Should BeGreaterThan 2
Remove-UserFromLocalGroup -UserName $localuser1 -GroupName $allowGroup1
Remove-UserFromLocalGroup -UserName $localuser1 -GroupName $denyGroup1
#Cleanup
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It 'User with full name in the list of DenyUsers' {
$server.AddUserToLocalGroup($denyUser1, $password, $allowGroup1)
It "$tC.$tI-User is listed in the list of AllowUsers but also in a wildcard * DenyGroups" {
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-f $sshdConfigPath", "-E $logPath") -NoNewWindow
$client.RunCmd(".\ssh $($denyUser1)@$($server.MachineName) hostname > $filePath")
$LASTEXITCODE | Should Not Be 0
Get-Content $filePath | Should BeNullOrEmpty
$server.RemoveUserFromLocalGroup($denyUser1, $allowGroup1)
}
It 'User with * wildcard in the list of DenyUsers' {
$server.AddUserToLocalGroup($denyUser2, $password, $allowGroup1)
$str = ".\ssh $($denyUser2)@$($server.MachineName) hostname > $filePath"
$client.RunCmd(".\ssh $($denyUser2)@$($server.MachineName) hostname > $filePath")
$LASTEXITCODE | Should Not Be 0
Get-Content $filePath | Should BeNullOrEmpty
$server.RemoveUserFromLocalGroup($denyUser2, $allowGroup1)
}
It 'User with ? wildcard in the list of DenyUsers' {
$server.AddUserToLocalGroup($denyUser3, $password, $allowGroup1)
Add-UserToLocalGroup -UserName $localuser2 -Password $password -GroupName $denyGroup2
$client.RunCmd(".\ssh $($denyUser3)@$($server.MachineName) hostname > $filePath")
ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $localuser2@$server echo 1234
$LASTEXITCODE | Should Not Be 0
Get-Content $filePath | Should BeNullOrEmpty
$server.RemoveUserFromLocalGroup($denyUser3, $allowGroup1)
}
It 'User is listed in the list of AllowUsers but also in a full name DenyGroups and AllowGroups' {
$server.AddUserToLocalGroup($localuser1, $password, $allowGroup1)
$server.AddUserToLocalGroup($localuser1, $password, $denyGroup1)
$matches = Get-Content $filePath | Select-String -pattern "Permission denied"
$matches.Count | Should BeGreaterThan 2
$client.RunCmd(".\ssh $($localuser1)@$($server.MachineName) hostname > $filePath")
Remove-UserFromLocalGroup -UserName $localuser2 -GroupName $denyGroup2
$LASTEXITCODE | Should Not Be 0
Get-Content $filePath | Should BeNullOrEmpty
$server.RemoveUserFromLocalGroup($localuser1, $allowGroup1)
$server.RemoveUserFromLocalGroup($localuser1, $denyGroup1)
#Cleanup
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
It 'User is listed in the list of AllowUsers but also in a wildcard * DenyGroups' {
$server.AddUserToLocalGroup($localuser2, $password, $denyGroup2)
$client.RunCmd(".\ssh $($localuser2)@$($server.MachineName) hostname > $filePath")
It "$tC.$tI-User is listed in the list of AllowUsers but also in a wildcard ? DenyGroups" {
#Run
Start-Process -FilePath sshd.exe -WorkingDirectory $($OpenSSHTestInfo['OpenSSHBinPath']) -ArgumentList @("-d", "-f $sshdConfigPath", "-E $logPath") -NoNewWindow
Add-UserToLocalGroup -UserName $localuser3 -Password $password -GroupName $denyGroup3
ssh -p $port -E $filePath -o "UserKnownHostsFile $testknownhosts" $localuser3@$server echo 1234
$LASTEXITCODE | Should Not Be 0
Get-Content $filePath | Should BeNullOrEmpty
$matches = Get-Content $filePath | Select-String -pattern "Permission denied"
$matches.Count | Should BeGreaterThan 2
Remove-UserFromLocalGroup -UserName $localuser3 -GroupName $denyGroup3
$server.RemoveUserFromLocalGroup($localuser2, $denyGroup2)
}
It 'User is listed in the list of AllowUsers but also in a wildcard ? DenyGroups' {
$server.AddUserToLocalGroup($localuser3, $password, $denyGroup3)
$client.RunCmd(".\ssh $($localuser3)@$($server.MachineName) hostname > $filePath")
$LASTEXITCODE | Should Not Be 0
Get-Content $filePath | Should BeNullOrEmpty
$server.RemoveUserFromLocalGroup($localuser3, $denyGroup3)
#Cleanup
Get-Process -Name sshd -ErrorAction SilentlyContinue | Where-Object {$_.SessionID -ne 0} | Stop-process -force -ErrorAction SilentlyContinue
}
}
}

119
regress/pesterTests/testdata/SSHD_Config vendored Normal file
View File

@ -0,0 +1,119 @@
# test usage of sshd_config
Port 47003
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
# The default requires explicit activation of protocol 1
#Protocol 2
# HostKey for protocol version 1
#HostKey /etc/ssh/ssh_host_key
# HostKeys for protocol version 2
HostKey sshtest_hostkey_rsa
HostKey sshtest_hostkey_dsa
HostKey sshtest_hostkey_ecdsa
HostKey sshtest_hostkey_ed25519
# Lifetime and size of ephemeral version 1 server key
#KeyRegenerationInterval 1h
#ServerKeyBits 1024
# Logging
# obsoletes QuietMode and FascistLogging
#SyslogFacility AUTH
LogLevel DEBUG3
# Authentication:
#LoginGraceTime 2m
#PermitRootLogin yes
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
#RSAAuthentication yes
#PubkeyAuthentication yes
# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
# but this is overridden so installations will only check .ssh/authorized_keys
AuthorizedKeysFile .ssh/authorized_keys
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#RhostsRSAAuthentication no
# similar for protocol version 2
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# RhostsRSAAuthentication and HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
# To disable tunneled clear text passwords, change to no here!
#PasswordAuthentication yes
#PermitEmptyPasswords no
# Change to no to disable s/key passwords
#ChallengeResponseAuthentication yes
# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
#UsePAM no
#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
#X11Forwarding no
#X11DisplayOffset 10
#X11UseLocalhost yes
#PrintMotd yes
#PrintLastLog yes
#TCPKeepAlive yes
#UseLogin no
#UsePrivilegeSeparation yes
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#UseDNS yes
#PidFile /var/run/sshd.pid
#MaxStartups 10
#PermitTunnel no
#ChrootDirectory none
# no default banner path
#Banner none
# override default of no subsystems
Subsystem sftp sftp-server.exe -l DEBUG3
# Example of overriding settings on a per-user basis
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# ForceCommand cvs server
PubkeyAcceptedKeyTypes ssh-ed25519*
DenyUsers denyuser1 deny*2 denyuse?3,
AllowUsers allowuser1 allowu*r2 allow?se?3 allowuser4 localuser1 localu*r2 loc?lu?er3 localadmin
DenyGroups denygroup1 denygr*p2 deny?rou?3
AllowGroups allowgroup1 allowg*2 allowg?ou?3 Adm*
hostkeyagent \\.\pipe\openssh-ssh-agent

View File

@ -2084,6 +2084,32 @@ parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
fatal("%s: terminating, %d bad configuration options",
filename, bad_options);
process_queued_listen_addrs(options);
#ifdef WINDOWS
/* TODO - Refactor this into a platform specific post-read config processing routine.
* TODO - support all forms of username, groupname.
* a) domain\groupname
* b) domain\groupname@hostip
* c) full_domain_name\groupname
* d) full_domain_name\groupname@hostip
* e) user@domain
* f) domain\user
* g) fulldomain\user
* h) user@domain@hostip
*/
/* convert the users, user groups to lower case */
for(int i = 0; i < options->num_allow_users; i++)
lowercase(options->allow_users[i]);
for (int i = 0; i < options->num_deny_users; i++)
lowercase(options->deny_users[i]);
for (int i = 0; i < options->num_allow_groups; i++)
lowercase(options->allow_groups[i]);
for (int i = 0; i < options->num_deny_groups; i++)
lowercase(options->deny_groups[i]);
#endif // WINDOWS
}
static const char *

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

11
ssh.c
View File

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

View File

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

View File

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

View File

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

3
sshd.c
View File

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

View File

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

View File

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

View File

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