mirror of
https://github.com/PowerShell/Win32-OpenSSH.git
synced 2025-07-27 07:54:50 +02:00
Source snapshot from Powershell/openssh-portable:latestw_all
This commit is contained in:
parent
c1680168e4
commit
25a4ae6a3c
@ -19,3 +19,5 @@ fe5b31f69a60d47171836911f144acff77810217 Makefile.inc bits
|
||||
ea80f445e819719ccdcb237022cacfac990fdc5c Makefile.inc warning flags
|
||||
b92c93266d8234d493857bb822260dacf4366157 moduli-gen.sh tweak
|
||||
b25bf747544265b39af74fe0716dc8d9f5b63b95 Updated moduli
|
||||
1bd41cba06a7752de4df304305a8153ebfb6b0ac rsa.[ch] already removed
|
||||
e39b3902fe1d6c4a7ba6a3c58e072219f3c1e604 Makefile changes
|
||||
|
@ -81,7 +81,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
|
||||
cipher-ctr.o cleanup.o \
|
||||
compat.o crc32.o fatal.o hostfile.o \
|
||||
log.o match.o moduli.o nchan.o packet.o opacket.o \
|
||||
readpass.o rsa.o ttymodes.o xmalloc.o addrmatch.o \
|
||||
readpass.o ttymodes.o xmalloc.o addrmatch.o \
|
||||
atomicio.o key.o dispatch.o mac.o uidswap.o uuencode.o misc.o utf8.o \
|
||||
monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \
|
||||
msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \
|
||||
@ -92,7 +92,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
|
||||
kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \
|
||||
kexdhc.o kexgexc.o kexecdhc.o kexc25519c.o \
|
||||
kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o \
|
||||
platform-pledge.o platform-tracing.o
|
||||
platform-pledge.o platform-tracing.o platform-misc.o
|
||||
|
||||
SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
|
||||
sshconnect.o sshconnect2.o mux.o
|
||||
|
8
README
8
README
@ -30,7 +30,8 @@ The PAM support is now more functional than the popular packages of
|
||||
commercial ssh-1.2.x. It checks "account" and "session" modules for
|
||||
all logins, not just when using password authentication.
|
||||
|
||||
OpenSSH depends on Zlib[3], OpenSSL[4] and optionally PAM[5].
|
||||
OpenSSH depends on Zlib[3], OpenSSL[4], and optionally PAM[5] and
|
||||
libedit[6]
|
||||
|
||||
There is now several mailing lists for this port of OpenSSH. Please
|
||||
refer to https://www.openssh.com/list.html for details on how to join.
|
||||
@ -38,7 +39,7 @@ refer to https://www.openssh.com/list.html for details on how to join.
|
||||
Please send bug reports and patches to the mailing list
|
||||
openssh-unix-dev@mindrot.org. The list is open to posting by unsubscribed
|
||||
users. Code contribution are welcomed, but please follow the OpenBSD
|
||||
style guidelines[6].
|
||||
style guidelines[7].
|
||||
|
||||
Please refer to the INSTALL document for information on how to install
|
||||
OpenSSH on your system.
|
||||
@ -61,4 +62,5 @@ References -
|
||||
[5] http://www.openpam.org
|
||||
http://www.kernel.org/pub/linux/libs/pam/
|
||||
(PAM also is standard on Solaris and HP-UX 11)
|
||||
[6] http://man.openbsd.org/style.9
|
||||
[6] http://thrysoee.dk/editline/ (portable version)
|
||||
[7] http://man.openbsd.org/style.9
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: 0.0.19.0.{build}
|
||||
version: 0.0.20.0.{build}
|
||||
image: Visual Studio 2015
|
||||
|
||||
branches:
|
||||
|
26
auth-pam.c
26
auth-pam.c
@ -926,6 +926,27 @@ finish_pam(void)
|
||||
sshpam_cleanup();
|
||||
}
|
||||
|
||||
static void
|
||||
expose_authinfo(const char *caller)
|
||||
{
|
||||
char *auth_info;
|
||||
|
||||
/*
|
||||
* Expose authentication information to PAM.
|
||||
* The enviornment variable is versioned. Please increment the
|
||||
* version suffix if the format of session_info changes.
|
||||
*/
|
||||
if (sshpam_authctxt->session_info == NULL)
|
||||
auth_info = xstrdup("");
|
||||
else if ((auth_info = sshbuf_dup_string(
|
||||
sshpam_authctxt->session_info)) == NULL)
|
||||
fatal("%s: sshbuf_dup_string failed", __func__);
|
||||
|
||||
debug2("%s: auth information in SSH_AUTH_INFO_0", caller);
|
||||
do_pam_putenv("SSH_AUTH_INFO_0", auth_info);
|
||||
free(auth_info);
|
||||
}
|
||||
|
||||
u_int
|
||||
do_pam_account(void)
|
||||
{
|
||||
@ -933,6 +954,8 @@ do_pam_account(void)
|
||||
if (sshpam_account_status != -1)
|
||||
return (sshpam_account_status);
|
||||
|
||||
expose_authinfo(__func__);
|
||||
|
||||
sshpam_err = pam_acct_mgmt(sshpam_handle, 0);
|
||||
debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err,
|
||||
pam_strerror(sshpam_handle, sshpam_err));
|
||||
@ -1057,6 +1080,9 @@ void
|
||||
do_pam_session(void)
|
||||
{
|
||||
debug3("PAM: opening session");
|
||||
|
||||
expose_authinfo(__func__);
|
||||
|
||||
sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
|
||||
(const void *)&store_conv);
|
||||
if (sshpam_err != PAM_SUCCESS)
|
||||
|
99
auth.c
99
auth.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: auth.c,v 1.122 2017/06/24 06:34:38 djm Exp $ */
|
||||
/* $OpenBSD: auth.c,v 1.123 2017/08/18 05:36:45 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -43,9 +43,6 @@
|
||||
#ifdef USE_SHADOW
|
||||
#include <shadow.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIBGEN_H
|
||||
#include <libgen.h>
|
||||
#endif
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@ -508,98 +505,6 @@ check_key_in_hostfiles(struct passwd *pw, struct sshkey *key, const char *host,
|
||||
return host_status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check a given path for security. This is defined as all components
|
||||
* of the path to the file must be owned by either the owner of
|
||||
* of the file or root and no directories must be group or world writable.
|
||||
*
|
||||
* XXX Should any specific check be done for sym links ?
|
||||
*
|
||||
* Takes a file name, its stat information (preferably from fstat() to
|
||||
* avoid races), the uid of the expected owner, their home directory and an
|
||||
* error buffer plus max size as arguments.
|
||||
*
|
||||
* Returns 0 on success and -1 on failure
|
||||
*/
|
||||
int
|
||||
auth_secure_path(const char *name, struct stat *stp, const char *pw_dir,
|
||||
uid_t uid, char *err, size_t errlen)
|
||||
{
|
||||
char buf[PATH_MAX], homedir[PATH_MAX];
|
||||
char *cp;
|
||||
int comparehome = 0;
|
||||
struct stat st;
|
||||
|
||||
if (realpath(name, buf) == NULL) {
|
||||
snprintf(err, errlen, "realpath %s failed: %s", name,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)
|
||||
comparehome = 1;
|
||||
|
||||
if (!S_ISREG(stp->st_mode)) {
|
||||
snprintf(err, errlen, "%s is not a regular file", buf);
|
||||
return -1;
|
||||
}
|
||||
if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) ||
|
||||
(stp->st_mode & 022) != 0) {
|
||||
snprintf(err, errlen, "bad ownership or modes for file %s",
|
||||
buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* for each component of the canonical path, walking upwards */
|
||||
for (;;) {
|
||||
if ((cp = dirname(buf)) == NULL) {
|
||||
snprintf(err, errlen, "dirname() failed");
|
||||
return -1;
|
||||
}
|
||||
strlcpy(buf, cp, sizeof(buf));
|
||||
|
||||
if (stat(buf, &st) < 0 ||
|
||||
(!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) ||
|
||||
(st.st_mode & 022) != 0) {
|
||||
snprintf(err, errlen,
|
||||
"bad ownership or modes for directory %s", buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If are past the homedir then we can stop */
|
||||
if (comparehome && strcmp(homedir, buf) == 0)
|
||||
break;
|
||||
|
||||
/*
|
||||
* dirname should always complete with a "/" path,
|
||||
* but we can be paranoid and check for "." too
|
||||
*/
|
||||
if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Version of secure_path() that accepts an open file descriptor to
|
||||
* avoid races.
|
||||
*
|
||||
* Returns 0 on success and -1 on failure
|
||||
*/
|
||||
static int
|
||||
secure_filename(FILE *f, const char *file, struct passwd *pw,
|
||||
char *err, size_t errlen)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
/* check the open file to avoid races */
|
||||
if (fstat(fileno(f), &st) < 0) {
|
||||
snprintf(err, errlen, "cannot stat file %s: %s",
|
||||
file, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return auth_secure_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);
|
||||
}
|
||||
|
||||
static FILE *
|
||||
auth_openfile(const char *file, struct passwd *pw, int strict_modes,
|
||||
int log_missing, char *file_type)
|
||||
@ -646,7 +551,7 @@ auth_openfile(const char *file, struct passwd *pw, int strict_modes,
|
||||
return NULL;
|
||||
}
|
||||
if (strict_modes &&
|
||||
secure_filename(f, file, pw, line, sizeof(line)) != 0) {
|
||||
safe_path_fd(fileno(f), file, pw, line, sizeof(line)) != 0) {
|
||||
fclose(f);
|
||||
logit("Authentication refused: %s", line);
|
||||
auth_debug_add("Ignored %s: %s", file_type, line);
|
||||
|
6
auth.h
6
auth.h
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: auth.h,v 1.92 2017/06/24 06:34:38 djm Exp $ */
|
||||
/* $OpenBSD: auth.h,v 1.93 2017/08/18 05:36:45 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
@ -149,10 +149,6 @@ void auth2_record_info(Authctxt *authctxt, const char *, ...)
|
||||
__attribute__((__nonnull__ (2)));
|
||||
void auth2_update_session_info(Authctxt *, const char *, const char *);
|
||||
|
||||
struct stat;
|
||||
int auth_secure_path(const char *, struct stat *, const char *, uid_t,
|
||||
char *, size_t);
|
||||
|
||||
#ifdef KRB5
|
||||
int auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client, krb5_data *);
|
||||
int auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt);
|
||||
|
308
auth2-pubkey.c
308
auth2-pubkey.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: auth2-pubkey.c,v 1.68 2017/06/24 06:34:38 djm Exp $ */
|
||||
/* $OpenBSD: auth2-pubkey.c,v 1.70 2017/08/18 05:48:04 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -27,7 +27,6 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
@ -249,293 +248,6 @@ done:
|
||||
return authenticated;
|
||||
}
|
||||
|
||||
/*
|
||||
* Splits 's' into an argument vector. Handles quoted string and basic
|
||||
* escape characters (\\, \", \'). Caller must free the argument vector
|
||||
* and its members.
|
||||
*/
|
||||
static int
|
||||
split_argv(const char *s, int *argcp, char ***argvp)
|
||||
{
|
||||
int r = SSH_ERR_INTERNAL_ERROR;
|
||||
int argc = 0, quote, i, j;
|
||||
char *arg, **argv = xcalloc(1, sizeof(*argv));
|
||||
|
||||
*argvp = NULL;
|
||||
*argcp = 0;
|
||||
|
||||
for (i = 0; s[i] != '\0'; i++) {
|
||||
/* Skip leading whitespace */
|
||||
if (s[i] == ' ' || s[i] == '\t')
|
||||
continue;
|
||||
|
||||
/* Start of a token */
|
||||
quote = 0;
|
||||
if (s[i] == '\\' &&
|
||||
(s[i + 1] == '\'' || s[i + 1] == '\"' || s[i + 1] == '\\'))
|
||||
i++;
|
||||
else if (s[i] == '\'' || s[i] == '"')
|
||||
quote = s[i++];
|
||||
|
||||
argv = xreallocarray(argv, (argc + 2), sizeof(*argv));
|
||||
arg = argv[argc++] = xcalloc(1, strlen(s + i) + 1);
|
||||
argv[argc] = NULL;
|
||||
|
||||
/* Copy the token in, removing escapes */
|
||||
for (j = 0; s[i] != '\0'; i++) {
|
||||
if (s[i] == '\\') {
|
||||
if (s[i + 1] == '\'' ||
|
||||
s[i + 1] == '\"' ||
|
||||
s[i + 1] == '\\') {
|
||||
i++; /* Skip '\' */
|
||||
arg[j++] = s[i];
|
||||
} else {
|
||||
/* Unrecognised escape */
|
||||
arg[j++] = s[i];
|
||||
}
|
||||
} else if (quote == 0 && (s[i] == ' ' || s[i] == '\t'))
|
||||
break; /* done */
|
||||
else if (quote != 0 && s[i] == quote)
|
||||
break; /* done */
|
||||
else
|
||||
arg[j++] = s[i];
|
||||
}
|
||||
if (s[i] == '\0') {
|
||||
if (quote != 0) {
|
||||
/* Ran out of string looking for close quote */
|
||||
r = SSH_ERR_INVALID_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Success */
|
||||
*argcp = argc;
|
||||
*argvp = argv;
|
||||
argc = 0;
|
||||
argv = NULL;
|
||||
r = 0;
|
||||
out:
|
||||
if (argc != 0 && argv != NULL) {
|
||||
for (i = 0; i < argc; i++)
|
||||
free(argv[i]);
|
||||
free(argv);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reassemble an argument vector into a string, quoting and escaping as
|
||||
* necessary. Caller must free returned string.
|
||||
*/
|
||||
static char *
|
||||
assemble_argv(int argc, char **argv)
|
||||
{
|
||||
int i, j, ws, r;
|
||||
char c, *ret;
|
||||
struct sshbuf *buf, *arg;
|
||||
|
||||
if ((buf = sshbuf_new()) == NULL || (arg = sshbuf_new()) == NULL)
|
||||
fatal("%s: sshbuf_new failed", __func__);
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
ws = 0;
|
||||
sshbuf_reset(arg);
|
||||
for (j = 0; argv[i][j] != '\0'; j++) {
|
||||
r = 0;
|
||||
c = argv[i][j];
|
||||
switch (c) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
ws = 1;
|
||||
r = sshbuf_put_u8(arg, c);
|
||||
break;
|
||||
case '\\':
|
||||
case '\'':
|
||||
case '"':
|
||||
if ((r = sshbuf_put_u8(arg, '\\')) != 0)
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
r = sshbuf_put_u8(arg, c);
|
||||
break;
|
||||
}
|
||||
if (r != 0)
|
||||
fatal("%s: sshbuf_put_u8: %s",
|
||||
__func__, ssh_err(r));
|
||||
}
|
||||
if ((i != 0 && (r = sshbuf_put_u8(buf, ' ')) != 0) ||
|
||||
(ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0) ||
|
||||
(r = sshbuf_putb(buf, arg)) != 0 ||
|
||||
(ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0))
|
||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
}
|
||||
if ((ret = malloc(sshbuf_len(buf) + 1)) == NULL)
|
||||
fatal("%s: malloc failed", __func__);
|
||||
memcpy(ret, sshbuf_ptr(buf), sshbuf_len(buf));
|
||||
ret[sshbuf_len(buf)] = '\0';
|
||||
sshbuf_free(buf);
|
||||
sshbuf_free(arg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Runs command in a subprocess. Returns pid on success and a FILE* to the
|
||||
* subprocess' stdout or 0 on failure.
|
||||
* NB. "command" is only used for logging.
|
||||
*/
|
||||
static pid_t
|
||||
subprocess(const char *tag, struct passwd *pw, const char *command,
|
||||
int ac, char **av, FILE **child)
|
||||
{
|
||||
#ifdef WINDOWS
|
||||
logit("AuthorizedPrincipalsCommand and AuthorizedKeysCommand are not supported in Windows yet");
|
||||
return 0;
|
||||
#else /* !WINDOWS */
|
||||
FILE *f;
|
||||
struct stat st;
|
||||
int devnull, p[2], i;
|
||||
pid_t pid;
|
||||
char *cp, errmsg[512];
|
||||
u_int envsize;
|
||||
char **child_env;
|
||||
|
||||
*child = NULL;
|
||||
|
||||
debug3("%s: %s command \"%s\" running as %s", __func__,
|
||||
tag, command, pw->pw_name);
|
||||
|
||||
/* Verify the path exists and is safe-ish to execute */
|
||||
if (*av[0] != '/') {
|
||||
error("%s path is not absolute", tag);
|
||||
return 0;
|
||||
}
|
||||
temporarily_use_uid(pw);
|
||||
if (stat(av[0], &st) < 0) {
|
||||
error("Could not stat %s \"%s\": %s", tag,
|
||||
av[0], strerror(errno));
|
||||
restore_uid();
|
||||
return 0;
|
||||
}
|
||||
if (auth_secure_path(av[0], &st, NULL, 0,
|
||||
errmsg, sizeof(errmsg)) != 0) {
|
||||
error("Unsafe %s \"%s\": %s", tag, av[0], errmsg);
|
||||
restore_uid();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run the command; stderr is left in place, stdout is the
|
||||
* authorized_keys output.
|
||||
*/
|
||||
if (pipe(p) != 0) {
|
||||
error("%s: pipe: %s", tag, strerror(errno));
|
||||
restore_uid();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't want to call this in the child, where it can fatal() and
|
||||
* run cleanup_exit() code.
|
||||
*/
|
||||
restore_uid();
|
||||
|
||||
switch ((pid = fork())) {
|
||||
case -1: /* error */
|
||||
error("%s: fork: %s", tag, strerror(errno));
|
||||
close(p[0]);
|
||||
close(p[1]);
|
||||
return 0;
|
||||
case 0: /* child */
|
||||
/* Prepare a minimal environment for the child. */
|
||||
envsize = 5;
|
||||
child_env = xcalloc(sizeof(*child_env), envsize);
|
||||
child_set_env(&child_env, &envsize, "PATH", _PATH_STDPATH);
|
||||
child_set_env(&child_env, &envsize, "USER", pw->pw_name);
|
||||
child_set_env(&child_env, &envsize, "LOGNAME", pw->pw_name);
|
||||
child_set_env(&child_env, &envsize, "HOME", pw->pw_dir);
|
||||
if ((cp = getenv("LANG")) != NULL)
|
||||
child_set_env(&child_env, &envsize, "LANG", cp);
|
||||
|
||||
for (i = 0; i < NSIG; i++)
|
||||
signal(i, SIG_DFL);
|
||||
|
||||
if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
|
||||
error("%s: open %s: %s", tag, _PATH_DEVNULL,
|
||||
strerror(errno));
|
||||
_exit(1);
|
||||
}
|
||||
/* Keep stderr around a while longer to catch errors */
|
||||
if (dup2(devnull, STDIN_FILENO) == -1 ||
|
||||
dup2(p[1], STDOUT_FILENO) == -1) {
|
||||
error("%s: dup2: %s", tag, strerror(errno));
|
||||
_exit(1);
|
||||
}
|
||||
closefrom(STDERR_FILENO + 1);
|
||||
|
||||
/* Don't use permanently_set_uid() here to avoid fatal() */
|
||||
if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) {
|
||||
error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid,
|
||||
strerror(errno));
|
||||
_exit(1);
|
||||
}
|
||||
if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) {
|
||||
error("%s: setresuid %u: %s", tag, (u_int)pw->pw_uid,
|
||||
strerror(errno));
|
||||
_exit(1);
|
||||
}
|
||||
/* stdin is pointed to /dev/null at this point */
|
||||
if (dup2(STDIN_FILENO, STDERR_FILENO) == -1) {
|
||||
error("%s: dup2: %s", tag, strerror(errno));
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
execve(av[0], av, child_env);
|
||||
error("%s exec \"%s\": %s", tag, command, strerror(errno));
|
||||
_exit(127);
|
||||
default: /* parent */
|
||||
break;
|
||||
}
|
||||
|
||||
close(p[1]);
|
||||
if ((f = fdopen(p[0], "r")) == NULL) {
|
||||
error("%s: fdopen: %s", tag, strerror(errno));
|
||||
close(p[0]);
|
||||
/* Don't leave zombie child */
|
||||
kill(pid, SIGTERM);
|
||||
while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
/* Success */
|
||||
debug3("%s: %s pid %ld", __func__, tag, (long)pid);
|
||||
*child = f;
|
||||
return pid;
|
||||
#endif /* !WINDOWS */
|
||||
}
|
||||
|
||||
/* Returns 0 if pid exited cleanly, non-zero otherwise */
|
||||
static int
|
||||
exited_cleanly(pid_t pid, const char *tag, const char *cmd)
|
||||
{
|
||||
int status;
|
||||
|
||||
while (waitpid(pid, &status, 0) == -1) {
|
||||
if (errno != EINTR) {
|
||||
error("%s: waitpid: %s", tag, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (WIFSIGNALED(status)) {
|
||||
error("%s %s exited on signal %d", tag, cmd, WTERMSIG(status));
|
||||
return -1;
|
||||
} else if (WEXITSTATUS(status) != 0) {
|
||||
error("%s %s failed, status %d", tag, cmd, WEXITSTATUS(status));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
match_principals_option(const char *principal_list, struct sshkey_cert *cert)
|
||||
{
|
||||
@ -668,7 +380,7 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
|
||||
}
|
||||
|
||||
/* Turn the command into an argument vector */
|
||||
if (split_argv(options.authorized_principals_command, &ac, &av) != 0) {
|
||||
if (argv_split(options.authorized_principals_command, &ac, &av) != 0) {
|
||||
error("AuthorizedPrincipalsCommand \"%s\" contains "
|
||||
"invalid quotes", command);
|
||||
goto out;
|
||||
@ -717,10 +429,11 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
|
||||
av[i] = tmp;
|
||||
}
|
||||
/* Prepare a printable command for logs, etc. */
|
||||
command = assemble_argv(ac, av);
|
||||
command = argv_assemble(ac, av);
|
||||
|
||||
if ((pid = subprocess("AuthorizedPrincipalsCommand", pw, command,
|
||||
ac, av, &f)) == 0)
|
||||
ac, av, &f,
|
||||
SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0)
|
||||
goto out;
|
||||
|
||||
uid_swapped = 1;
|
||||
@ -731,7 +444,7 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
|
||||
fclose(f);
|
||||
f = NULL;
|
||||
|
||||
if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command) != 0)
|
||||
if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command, 0) != 0)
|
||||
goto out;
|
||||
|
||||
/* Read completed successfully */
|
||||
@ -1008,7 +721,7 @@ user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
|
||||
}
|
||||
|
||||
/* Turn the command into an argument vector */
|
||||
if (split_argv(options.authorized_keys_command, &ac, &av) != 0) {
|
||||
if (argv_split(options.authorized_keys_command, &ac, &av) != 0) {
|
||||
error("AuthorizedKeysCommand \"%s\" contains invalid quotes",
|
||||
command);
|
||||
goto out;
|
||||
@ -1032,7 +745,7 @@ user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
|
||||
av[i] = tmp;
|
||||
}
|
||||
/* Prepare a printable command for logs, etc. */
|
||||
command = assemble_argv(ac, av);
|
||||
command = argv_assemble(ac, av);
|
||||
|
||||
/*
|
||||
* If AuthorizedKeysCommand was run without arguments
|
||||
@ -1049,7 +762,8 @@ user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
|
||||
}
|
||||
|
||||
if ((pid = subprocess("AuthorizedKeysCommand", pw, command,
|
||||
ac, av, &f)) == 0)
|
||||
ac, av, &f,
|
||||
SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0)
|
||||
goto out;
|
||||
|
||||
uid_swapped = 1;
|
||||
@ -1060,7 +774,7 @@ user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
|
||||
fclose(f);
|
||||
f = NULL;
|
||||
|
||||
if (exited_cleanly(pid, "AuthorizedKeysCommand", command) != 0)
|
||||
if (exited_cleanly(pid, "AuthorizedKeysCommand", command, 0) != 0)
|
||||
goto out;
|
||||
|
||||
/* Read completed successfully */
|
||||
|
3
authfd.c
3
authfd.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: authfd.c,v 1.104 2017/06/28 01:09:22 djm Exp $ */
|
||||
/* $OpenBSD: authfd.c,v 1.105 2017/07/01 13:50:45 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -51,7 +51,6 @@
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
#include "rsa.h"
|
||||
#include "sshbuf.h"
|
||||
#include "sshkey.h"
|
||||
#include "authfd.h"
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: authfile.c,v 1.126 2017/05/31 09:15:42 deraadt Exp $ */
|
||||
/* $OpenBSD: authfile.c,v 1.127 2017/07/01 13:50:45 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000, 2013 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -42,7 +42,6 @@
|
||||
#include "ssh.h"
|
||||
#include "log.h"
|
||||
#include "authfile.h"
|
||||
#include "rsa.h"
|
||||
#include "misc.h"
|
||||
#include "atomicio.h"
|
||||
#include "sshkey.h"
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: clientloop.c,v 1.300 2017/06/23 07:24:48 mestre Exp $ */
|
||||
/* $OpenBSD: clientloop.c,v 1.301 2017/07/14 03:18:21 dtucker Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -1422,8 +1422,10 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
|
||||
exit_status = 0;
|
||||
}
|
||||
|
||||
if (received_signal)
|
||||
fatal("Killed by signal %d.", (int) received_signal);
|
||||
if (received_signal) {
|
||||
verbose("Killed by signal %d.", (int) received_signal);
|
||||
cleanup_exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* In interactive mode (with pseudo tty) display a message indicating
|
||||
|
11
compat.c
11
compat.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: compat.c,v 1.103 2017/04/30 23:13:25 djm Exp $ */
|
||||
/* $OpenBSD: compat.c,v 1.104 2017/07/25 09:22:25 dtucker Exp $ */
|
||||
/*
|
||||
* Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -177,9 +177,12 @@ compat_datafellows(const char *version)
|
||||
"TTSSH/2.72*", SSH_BUG_HOSTKEYS },
|
||||
{ "WinSCP_release_4*,"
|
||||
"WinSCP_release_5.0*,"
|
||||
"WinSCP_release_5.1*,"
|
||||
"WinSCP_release_5.5*,"
|
||||
"WinSCP_release_5.6*,"
|
||||
"WinSCP_release_5.1,"
|
||||
"WinSCP_release_5.1.*,"
|
||||
"WinSCP_release_5.5,"
|
||||
"WinSCP_release_5.5.*,"
|
||||
"WinSCP_release_5.6,"
|
||||
"WinSCP_release_5.6.*,"
|
||||
"WinSCP_release_5.7,"
|
||||
"WinSCP_release_5.7.1,"
|
||||
"WinSCP_release_5.7.2,"
|
||||
|
@ -980,6 +980,7 @@ mips-sony-bsd|mips-sony-newsos4)
|
||||
AC_DEFINE([BROKEN_SETREUID])
|
||||
AC_DEFINE([BROKEN_SETREGID])
|
||||
AC_DEFINE([PASSWD_NEEDS_USERNAME])
|
||||
AC_DEFINE([BROKEN_TCGETATTR_ICANON])
|
||||
TEST_SHELL=$SHELL # let configure find us a capable shell
|
||||
case "$host" in
|
||||
*-*-sysv5SCO_SV*) # SCO OpenServer 6.x
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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" />
|
||||
|
@ -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.
@ -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
|
||||
|
@ -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
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
474
misc.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: misc.c,v 1.110 2017/05/31 09:15:42 deraadt Exp $ */
|
||||
/* $OpenBSD: misc.c,v 1.113 2017/08/18 05:48:04 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
* Copyright (c) 2005,2006 Damien Miller. All rights reserved.
|
||||
@ -29,10 +29,16 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <limits.h>
|
||||
#ifdef HAVE_LIBGEN_H
|
||||
# include <libgen.h>
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -61,6 +67,10 @@
|
||||
#include "misc.h"
|
||||
#include "log.h"
|
||||
#include "ssh.h"
|
||||
#include "sshbuf.h"
|
||||
#include "ssherr.h"
|
||||
#include "uidswap.h"
|
||||
#include "platform.h"
|
||||
|
||||
/* remove newline at end of string */
|
||||
char *
|
||||
@ -1105,6 +1115,7 @@ static const struct {
|
||||
const char *name;
|
||||
int value;
|
||||
} ipqos[] = {
|
||||
{ "none", INT_MAX }, /* can't use 0 here; that's CS0 */
|
||||
{ "af11", IPTOS_DSCP_AF11 },
|
||||
{ "af12", IPTOS_DSCP_AF12 },
|
||||
{ "af13", IPTOS_DSCP_AF13 },
|
||||
@ -1303,3 +1314,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
22
misc.h
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: misc.h,v 1.61 2016/11/30 00:28:31 dtucker Exp $ */
|
||||
/* $OpenBSD: misc.h,v 1.63 2017/08/18 05:48:04 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
@ -16,6 +16,7 @@
|
||||
#define _MISC_H
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* Data structure for representing a forwarding request. */
|
||||
struct Forward {
|
||||
@ -132,6 +133,25 @@ int parse_ipqos(const char *);
|
||||
const char *iptos2str(int);
|
||||
void mktemp_proto(char *, size_t);
|
||||
|
||||
void child_set_env(char ***envp, u_int *envsizep, const char *name,
|
||||
const char *value);
|
||||
|
||||
int argv_split(const char *, int *, char ***);
|
||||
char *argv_assemble(int, char **argv);
|
||||
int exited_cleanly(pid_t, const char *, const char *, int);
|
||||
|
||||
#define SSH_SUBPROCESS_STDOUT_DISCARD (1) /* Discard stdout */
|
||||
#define SSH_SUBPROCESS_STDOUT_CAPTURE (1<<1) /* Redirect stdout */
|
||||
#define SSH_SUBPROCESS_STDERR_DISCARD (1<<2) /* Discard stderr */
|
||||
pid_t subprocess(const char *, struct passwd *,
|
||||
const char *, int, char **, FILE **, u_int flags);
|
||||
|
||||
struct stat;
|
||||
int safe_path(const char *, struct stat *, const char *, uid_t,
|
||||
char *, size_t);
|
||||
int safe_path_fd(int, const char *, struct passwd *,
|
||||
char *err, size_t errlen);
|
||||
|
||||
/* readpass.c */
|
||||
|
||||
#define RP_ECHO 0x0001
|
||||
|
@ -27,6 +27,12 @@
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef HAVE_ERR
|
||||
void
|
||||
err(int r, const char *fmt, ...)
|
||||
|
@ -20,6 +20,8 @@
|
||||
void
|
||||
explicit_bzero(void *p, size_t n)
|
||||
{
|
||||
if (n == 0)
|
||||
return;
|
||||
(void)memset_s(p, n, 0, n);
|
||||
}
|
||||
|
||||
@ -34,6 +36,8 @@ static void (* volatile ssh_bzero)(void *, size_t) = bzero;
|
||||
void
|
||||
explicit_bzero(void *p, size_t n)
|
||||
{
|
||||
if (n == 0)
|
||||
return;
|
||||
/*
|
||||
* clang -fsanitize=memory needs to intercept memset-like functions
|
||||
* to correctly detect memory initialisation. Make sure one is called
|
||||
|
@ -199,49 +199,50 @@ sys_tun_open(int tun, int mode)
|
||||
*/
|
||||
|
||||
#if defined(SSH_TUN_FILTER)
|
||||
/*
|
||||
* The tunnel forwarding protocol prepends the address family of forwarded
|
||||
* IP packets using OpenBSD's numbers.
|
||||
*/
|
||||
#define OPENBSD_AF_INET 2
|
||||
#define OPENBSD_AF_INET6 24
|
||||
|
||||
int
|
||||
sys_tun_infilter(struct Channel *c, char *buf, int len)
|
||||
sys_tun_infilter(struct Channel *c, char *buf, int _len)
|
||||
{
|
||||
int r;
|
||||
size_t len;
|
||||
char *ptr = buf;
|
||||
#if defined(SSH_TUN_PREPEND_AF)
|
||||
char rbuf[CHAN_RBUF];
|
||||
struct ip *iph;
|
||||
struct ip iph;
|
||||
#endif
|
||||
u_int32_t *af;
|
||||
char *ptr = buf;
|
||||
int r;
|
||||
#if defined(SSH_TUN_PREPEND_AF) || defined(SSH_TUN_COMPAT_AF)
|
||||
u_int32_t af;
|
||||
#endif
|
||||
|
||||
/* XXX update channel input filter API to use unsigned length */
|
||||
if (_len < 0)
|
||||
return -1;
|
||||
len = _len;
|
||||
|
||||
#if defined(SSH_TUN_PREPEND_AF)
|
||||
if (len <= 0 || len > (int)(sizeof(rbuf) - sizeof(*af)))
|
||||
return (-1);
|
||||
ptr = (char *)&rbuf[0];
|
||||
bcopy(buf, ptr + sizeof(u_int32_t), len);
|
||||
len += sizeof(u_int32_t);
|
||||
af = (u_int32_t *)ptr;
|
||||
|
||||
iph = (struct ip *)(ptr + sizeof(u_int32_t));
|
||||
switch (iph->ip_v) {
|
||||
case 6:
|
||||
*af = AF_INET6;
|
||||
break;
|
||||
case 4:
|
||||
default:
|
||||
*af = AF_INET;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(SSH_TUN_COMPAT_AF)
|
||||
if (len < (int)sizeof(u_int32_t))
|
||||
return (-1);
|
||||
|
||||
af = (u_int32_t *)ptr;
|
||||
if (*af == htonl(AF_INET6))
|
||||
*af = htonl(OPENBSD_AF_INET6);
|
||||
else
|
||||
*af = htonl(OPENBSD_AF_INET);
|
||||
if (len <= sizeof(iph) || len > sizeof(rbuf) - 4)
|
||||
return -1;
|
||||
/* Determine address family from packet IP header. */
|
||||
memcpy(&iph, buf, sizeof(iph));
|
||||
af = iph.ip_v == 6 ? OPENBSD_AF_INET6 : OPENBSD_AF_INET;
|
||||
/* Prepend address family to packet using OpenBSD constants */
|
||||
memcpy(rbuf + 4, buf, len);
|
||||
len += 4;
|
||||
POKE_U32(rbuf, af);
|
||||
ptr = rbuf;
|
||||
#elif defined(SSH_TUN_COMPAT_AF)
|
||||
/* Convert existing address family header to OpenBSD value */
|
||||
if (len <= 4)
|
||||
return -1;
|
||||
af = PEEK_U32(buf);
|
||||
/* Put it back */
|
||||
POKE_U32(buf, af == AF_INET6 ? OPENBSD_AF_INET6 : OPENBSD_AF_INET);
|
||||
#endif
|
||||
|
||||
if ((r = sshbuf_put_string(&c->input, ptr, len)) != 0)
|
||||
@ -253,7 +254,7 @@ u_char *
|
||||
sys_tun_outfilter(struct Channel *c, u_char **data, u_int *dlen)
|
||||
{
|
||||
u_char *buf;
|
||||
u_int32_t *af;
|
||||
u_int32_t af;
|
||||
int r;
|
||||
size_t xxx_dlen;
|
||||
|
||||
@ -262,21 +263,19 @@ sys_tun_outfilter(struct Channel *c, u_char **data, u_int *dlen)
|
||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
if (dlen != NULL)
|
||||
*dlen = xxx_dlen;
|
||||
if (*dlen < sizeof(*af))
|
||||
if (*dlen < sizeof(af))
|
||||
return (NULL);
|
||||
buf = *data;
|
||||
|
||||
#if defined(SSH_TUN_PREPEND_AF)
|
||||
*dlen -= sizeof(u_int32_t);
|
||||
buf = *data + sizeof(u_int32_t);
|
||||
/* skip address family */
|
||||
*dlen -= sizeof(af);
|
||||
buf = *data + sizeof(af);
|
||||
#elif defined(SSH_TUN_COMPAT_AF)
|
||||
af = ntohl(*(u_int32_t *)buf);
|
||||
if (*af == OPENBSD_AF_INET6)
|
||||
*af = htonl(AF_INET6);
|
||||
else
|
||||
*af = htonl(AF_INET);
|
||||
/* translate address family */
|
||||
af = (PEEK_U32(buf) == OPENBSD_AF_INET6) ? AF_INET6 : AF_INET;
|
||||
POKE_U32(buf, af);
|
||||
#endif
|
||||
|
||||
return (buf);
|
||||
}
|
||||
#endif /* SSH_TUN_FILTER */
|
||||
|
4
packet.c
4
packet.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: packet.c,v 1.262 2017/06/24 06:38:11 djm Exp $ */
|
||||
/* $OpenBSD: packet.c,v 1.263 2017/07/23 23:37:02 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -1997,7 +1997,7 @@ void
|
||||
ssh_packet_set_tos(struct ssh *ssh, int tos)
|
||||
{
|
||||
#ifndef IP_TOS_IS_BROKEN
|
||||
if (!ssh_packet_connection_is_on_socket(ssh))
|
||||
if (!ssh_packet_connection_is_on_socket(ssh) || tos == INT_MAX)
|
||||
return;
|
||||
switch (ssh_packet_connection_af(ssh)) {
|
||||
# ifdef IP_TOS
|
||||
|
35
platform-misc.c
Normal file
35
platform-misc.c
Normal 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;
|
||||
}
|
16
platform.c
16
platform.c
@ -197,19 +197,3 @@ platform_krb5_get_principal_name(const char *pw_name)
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* return 1 if the specified uid is a uid that may own a system directory
|
||||
* otherwise 0.
|
||||
*/
|
||||
int
|
||||
platform_sys_dir_uid(uid_t uid)
|
||||
{
|
||||
if (uid == 0)
|
||||
return 1;
|
||||
#ifdef PLATFORM_SYS_DIR_UID
|
||||
if (uid == PLATFORM_SYS_DIR_UID)
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
119
regress/pesterTests/testdata/SSHD_Config
vendored
Normal 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
|
26
servconf.c
26
servconf.c
@ -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 *
|
||||
|
18
serverloop.c
18
serverloop.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: serverloop.c,v 1.193 2017/05/31 07:00:13 markus Exp $ */
|
||||
/* $OpenBSD: serverloop.c,v 1.195 2017/08/11 04:16:35 dtucker Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -204,6 +204,7 @@ wait_until_can_do_something(int connection_in, int connection_out,
|
||||
int ret;
|
||||
time_t minwait_secs = 0;
|
||||
int client_alive_scheduled = 0;
|
||||
static time_t last_client_time;
|
||||
|
||||
/* Allocate and update select() masks for channel descriptors. */
|
||||
channel_prepare_select(readsetp, writesetp, maxfdp, nallocp,
|
||||
@ -268,8 +269,19 @@ wait_until_can_do_something(int connection_in, int connection_out,
|
||||
memset(*writesetp, 0, *nallocp);
|
||||
if (errno != EINTR)
|
||||
error("select: %.100s", strerror(errno));
|
||||
} else if (ret == 0 && client_alive_scheduled)
|
||||
client_alive_check();
|
||||
} else if (client_alive_scheduled) {
|
||||
time_t now = monotime();
|
||||
|
||||
if (ret == 0) { /* timeout */
|
||||
client_alive_check();
|
||||
} else if (FD_ISSET(connection_in, *readsetp)) {
|
||||
last_client_time = now;
|
||||
} else if (last_client_time != 0 && last_client_time +
|
||||
options.client_alive_interval <= now) {
|
||||
client_alive_check();
|
||||
last_client_time = now;
|
||||
}
|
||||
}
|
||||
|
||||
notify_done(*readsetp);
|
||||
}
|
||||
|
87
session.c
87
session.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: session.c,v 1.290 2017/06/24 06:34:38 djm Exp $ */
|
||||
/* $OpenBSD: session.c,v 1.291 2017/08/18 05:36:45 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
@ -1102,65 +1102,6 @@ check_quietlogin(Session *s, const char *command)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the value of the given variable in the environment. If the variable
|
||||
* already exists, its value is overridden.
|
||||
*/
|
||||
void
|
||||
child_set_env(char ***envp, u_int *envsizep, const char *name,
|
||||
const char *value)
|
||||
{
|
||||
char **env;
|
||||
u_int envsize;
|
||||
u_int i, namelen;
|
||||
|
||||
if (strchr(name, '=') != NULL) {
|
||||
error("Invalid environment variable \"%.100s\"", name);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're passed an uninitialized list, allocate a single null
|
||||
* entry before continuing.
|
||||
*/
|
||||
if (*envp == NULL && *envsizep == 0) {
|
||||
*envp = xmalloc(sizeof(char *));
|
||||
*envp[0] = NULL;
|
||||
*envsizep = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the slot where the value should be stored. If the variable
|
||||
* already exists, we reuse the slot; otherwise we append a new slot
|
||||
* at the end of the array, expanding if necessary.
|
||||
*/
|
||||
env = *envp;
|
||||
namelen = strlen(name);
|
||||
for (i = 0; env[i]; i++)
|
||||
if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
|
||||
break;
|
||||
if (env[i]) {
|
||||
/* Reuse the slot. */
|
||||
free(env[i]);
|
||||
} else {
|
||||
/* New variable. Expand if necessary. */
|
||||
envsize = *envsizep;
|
||||
if (i >= envsize - 1) {
|
||||
if (envsize >= 1000)
|
||||
fatal("child_set_env: too many env vars");
|
||||
envsize += 50;
|
||||
env = (*envp) = xreallocarray(env, envsize, sizeof(char *));
|
||||
*envsizep = envsize;
|
||||
}
|
||||
/* Need to set the NULL pointer at end of array beyond the new slot. */
|
||||
env[i + 1] = NULL;
|
||||
}
|
||||
|
||||
/* Allocate space and format the variable in the appropriate slot. */
|
||||
env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
|
||||
snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads environment variables from the given file and adds/overrides them
|
||||
* into the environment. If the file does not exist, this does nothing.
|
||||
@ -1262,8 +1203,9 @@ read_etc_default_login(char ***env, u_int *envsize, uid_t uid)
|
||||
}
|
||||
#endif /* HAVE_ETC_DEFAULT_LOGIN */
|
||||
|
||||
void
|
||||
copy_environment(char **source, char ***env, u_int *envsize)
|
||||
static void
|
||||
copy_environment_blacklist(char **source, char ***env, u_int *envsize,
|
||||
const char *blacklist)
|
||||
{
|
||||
char *var_name, *var_val;
|
||||
int i;
|
||||
@ -1279,13 +1221,22 @@ copy_environment(char **source, char ***env, u_int *envsize)
|
||||
}
|
||||
*var_val++ = '\0';
|
||||
|
||||
debug3("Copy environment: %s=%s", var_name, var_val);
|
||||
child_set_env(env, envsize, var_name, var_val);
|
||||
if (blacklist == NULL ||
|
||||
match_pattern_list(var_name, blacklist, 0) != 1) {
|
||||
debug3("Copy environment: %s=%s", var_name, var_val);
|
||||
child_set_env(env, envsize, var_name, var_val);
|
||||
}
|
||||
|
||||
free(var_name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
copy_environment(char **source, char ***env, u_int *envsize)
|
||||
{
|
||||
copy_environment_blacklist(source, env, envsize, NULL);
|
||||
}
|
||||
|
||||
static char **
|
||||
do_setup_env(Session *s, const char *shell)
|
||||
{
|
||||
@ -1447,12 +1398,16 @@ do_setup_env(Session *s, const char *shell)
|
||||
if (options.use_pam) {
|
||||
char **p;
|
||||
|
||||
/*
|
||||
* Don't allow SSH_AUTH_INFO variables posted to PAM to leak
|
||||
* back into the environment.
|
||||
*/
|
||||
p = fetch_pam_child_environment();
|
||||
copy_environment(p, &env, &envsize);
|
||||
copy_environment_blacklist(p, &env, &envsize, "SSH_AUTH_INFO*");
|
||||
free_pam_environment(p);
|
||||
|
||||
p = fetch_pam_environment();
|
||||
copy_environment(p, &env, &envsize);
|
||||
copy_environment_blacklist(p, &env, &envsize, "SSH_AUTH_INFO*");
|
||||
free_pam_environment(p);
|
||||
}
|
||||
#endif /* USE_PAM */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: session.h,v 1.33 2016/08/13 17:47:41 markus Exp $ */
|
||||
/* $OpenBSD: session.h,v 1.34 2017/08/18 05:36:45 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
||||
@ -77,8 +77,6 @@ Session *session_new(void);
|
||||
Session *session_by_tty(char *);
|
||||
void session_close(Session *);
|
||||
void do_setusercontext(struct passwd *);
|
||||
void child_set_env(char ***envp, u_int *envsizep, const char *name,
|
||||
const char *value);
|
||||
|
||||
const char *session_get_remote_name_or_ip(struct ssh *, u_int, int);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: sftp-client.c,v 1.126 2017/01/03 05:46:51 djm Exp $ */
|
||||
/* $OpenBSD: sftp-client.c,v 1.127 2017/08/11 04:41:08 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
|
||||
*
|
||||
@ -140,7 +140,7 @@ get_msg(struct sftp_conn *conn, struct sshbuf *m)
|
||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
if (atomicio6(read, conn->fd_in, p, 4,
|
||||
conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) != 4) {
|
||||
if (errno == EPIPE)
|
||||
if (errno == EPIPE || errno == ECONNRESET)
|
||||
fatal("Connection closed");
|
||||
else
|
||||
fatal("Couldn't read packet: %s", strerror(errno));
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ssh-add.c,v 1.132 2017/05/30 14:16:41 markus Exp $ */
|
||||
/* $OpenBSD: ssh-add.c,v 1.133 2017/07/01 13:50:45 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -55,7 +55,6 @@
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
#include "rsa.h"
|
||||
#include "log.h"
|
||||
#include "sshkey.h"
|
||||
#include "sshbuf.h"
|
||||
|
315
ssh-agent.c
315
ssh-agent.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ssh-agent.c,v 1.221 2017/04/30 23:29:10 djm Exp $ */
|
||||
/* $OpenBSD: ssh-agent.c,v 1.224 2017/07/24 04:34:28 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -60,6 +60,9 @@
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
#ifdef HAVE_POLL_H
|
||||
# include <poll.h>
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
@ -73,7 +76,6 @@
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
#include "rsa.h"
|
||||
#include "sshbuf.h"
|
||||
#include "sshkey.h"
|
||||
#include "authfd.h"
|
||||
@ -92,6 +94,9 @@
|
||||
# define DEFAULT_PKCS11_WHITELIST "/usr/lib*/*,/usr/local/lib*/*"
|
||||
#endif
|
||||
|
||||
/* Maximum accepted message length */
|
||||
#define AGENT_MAX_LEN (256*1024)
|
||||
|
||||
typedef enum {
|
||||
AUTH_UNUSED,
|
||||
AUTH_SOCKET,
|
||||
@ -635,30 +640,46 @@ send:
|
||||
|
||||
/* dispatch incoming messages */
|
||||
|
||||
static void
|
||||
process_message(SocketEntry *e)
|
||||
static int
|
||||
process_message(u_int socknum)
|
||||
{
|
||||
u_int msg_len;
|
||||
u_char type;
|
||||
const u_char *cp;
|
||||
int r;
|
||||
SocketEntry *e;
|
||||
|
||||
if (socknum >= sockets_alloc) {
|
||||
fatal("%s: socket number %u >= allocated %u",
|
||||
__func__, socknum, sockets_alloc);
|
||||
}
|
||||
e = &sockets[socknum];
|
||||
|
||||
if (sshbuf_len(e->input) < 5)
|
||||
return; /* Incomplete message. */
|
||||
return 0; /* Incomplete message header. */
|
||||
cp = sshbuf_ptr(e->input);
|
||||
msg_len = PEEK_U32(cp);
|
||||
if (msg_len > 256 * 1024) {
|
||||
close_socket(e);
|
||||
return;
|
||||
if (msg_len > AGENT_MAX_LEN) {
|
||||
debug("%s: socket %u (fd=%d) message too long %u > %u",
|
||||
__func__, socknum, e->fd, msg_len, AGENT_MAX_LEN);
|
||||
return -1;
|
||||
}
|
||||
if (sshbuf_len(e->input) < msg_len + 4)
|
||||
return;
|
||||
return 0; /* Incomplete message body. */
|
||||
|
||||
/* move the current input to e->request */
|
||||
sshbuf_reset(e->request);
|
||||
if ((r = sshbuf_get_stringb(e->input, e->request)) != 0 ||
|
||||
(r = sshbuf_get_u8(e->request, &type)) != 0)
|
||||
(r = sshbuf_get_u8(e->request, &type)) != 0) {
|
||||
if (r == SSH_ERR_MESSAGE_INCOMPLETE ||
|
||||
r == SSH_ERR_STRING_TOO_LARGE) {
|
||||
debug("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
return -1;
|
||||
}
|
||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
}
|
||||
|
||||
debug("%s: socket %u (fd=%d) type %d", __func__, socknum, e->fd, type);
|
||||
|
||||
/* check wheter agent is locked */
|
||||
if (locked && type != SSH_AGENTC_UNLOCK) {
|
||||
@ -672,10 +693,9 @@ process_message(SocketEntry *e)
|
||||
/* send a fail message for all other request types */
|
||||
send_status(e, 0);
|
||||
}
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug("type %d", type);
|
||||
switch (type) {
|
||||
case SSH_AGENTC_LOCK:
|
||||
case SSH_AGENTC_UNLOCK:
|
||||
@ -717,6 +737,7 @@ process_message(SocketEntry *e)
|
||||
send_status(e, 0);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -758,19 +779,141 @@ new_socket(sock_type type, int fd)
|
||||
}
|
||||
|
||||
static int
|
||||
prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl, u_int *nallocp,
|
||||
struct timeval **tvpp)
|
||||
handle_socket_read(u_int socknum)
|
||||
{
|
||||
u_int i, sz;
|
||||
int n = 0;
|
||||
static struct timeval tv;
|
||||
struct sockaddr_un sunaddr;
|
||||
socklen_t slen;
|
||||
uid_t euid;
|
||||
gid_t egid;
|
||||
int fd;
|
||||
|
||||
slen = sizeof(sunaddr);
|
||||
fd = accept(sockets[socknum].fd, (struct sockaddr *)&sunaddr, &slen);
|
||||
if (fd < 0) {
|
||||
error("accept from AUTH_SOCKET: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (getpeereid(fd, &euid, &egid) < 0) {
|
||||
error("getpeereid %d failed: %s", fd, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
if ((euid != 0) && (getuid() != euid)) {
|
||||
error("uid mismatch: peer euid %u != uid %u",
|
||||
(u_int) euid, (u_int) getuid());
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
new_socket(AUTH_CONNECTION, fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
handle_conn_read(u_int socknum)
|
||||
{
|
||||
char buf[1024];
|
||||
ssize_t len;
|
||||
int r;
|
||||
|
||||
if ((len = read(sockets[socknum].fd, buf, sizeof(buf))) <= 0) {
|
||||
if (len == -1) {
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
return 0;
|
||||
error("%s: read error on socket %u (fd %d): %s",
|
||||
__func__, socknum, sockets[socknum].fd,
|
||||
strerror(errno));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if ((r = sshbuf_put(sockets[socknum].input, buf, len)) != 0)
|
||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
explicit_bzero(buf, sizeof(buf));
|
||||
process_message(socknum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
handle_conn_write(u_int socknum)
|
||||
{
|
||||
ssize_t len;
|
||||
int r;
|
||||
|
||||
if (sshbuf_len(sockets[socknum].output) == 0)
|
||||
return 0; /* shouldn't happen */
|
||||
if ((len = write(sockets[socknum].fd,
|
||||
sshbuf_ptr(sockets[socknum].output),
|
||||
sshbuf_len(sockets[socknum].output))) <= 0) {
|
||||
if (len == -1) {
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
return 0;
|
||||
error("%s: read error on socket %u (fd %d): %s",
|
||||
__func__, socknum, sockets[socknum].fd,
|
||||
strerror(errno));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if ((r = sshbuf_consume(sockets[socknum].output, len)) != 0)
|
||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
after_poll(struct pollfd *pfd, size_t npfd)
|
||||
{
|
||||
size_t i;
|
||||
u_int socknum;
|
||||
|
||||
for (i = 0; i < npfd; i++) {
|
||||
if (pfd[i].revents == 0)
|
||||
continue;
|
||||
/* Find sockets entry */
|
||||
for (socknum = 0; socknum < sockets_alloc; socknum++) {
|
||||
if (sockets[socknum].type != AUTH_SOCKET &&
|
||||
sockets[socknum].type != AUTH_CONNECTION)
|
||||
continue;
|
||||
if (pfd[i].fd == sockets[socknum].fd)
|
||||
break;
|
||||
}
|
||||
if (socknum >= sockets_alloc) {
|
||||
error("%s: no socket for fd %d", __func__, pfd[i].fd);
|
||||
continue;
|
||||
}
|
||||
/* Process events */
|
||||
switch (sockets[socknum].type) {
|
||||
case AUTH_SOCKET:
|
||||
if ((pfd[i].revents & (POLLIN|POLLERR)) != 0 &&
|
||||
handle_socket_read(socknum) != 0)
|
||||
close_socket(&sockets[socknum]);
|
||||
break;
|
||||
case AUTH_CONNECTION:
|
||||
if ((pfd[i].revents & (POLLIN|POLLERR)) != 0 &&
|
||||
handle_conn_read(socknum) != 0) {
|
||||
close_socket(&sockets[socknum]);
|
||||
break;
|
||||
}
|
||||
if ((pfd[i].revents & (POLLOUT|POLLHUP)) != 0 &&
|
||||
handle_conn_write(socknum) != 0)
|
||||
close_socket(&sockets[socknum]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
prepare_poll(struct pollfd **pfdp, size_t *npfdp, int *timeoutp)
|
||||
{
|
||||
struct pollfd *pfd = *pfdp;
|
||||
size_t i, j, npfd = 0;
|
||||
time_t deadline;
|
||||
|
||||
/* Count active sockets */
|
||||
for (i = 0; i < sockets_alloc; i++) {
|
||||
switch (sockets[i].type) {
|
||||
case AUTH_SOCKET:
|
||||
case AUTH_CONNECTION:
|
||||
n = MAXIMUM(n, sockets[i].fd);
|
||||
npfd++;
|
||||
break;
|
||||
case AUTH_UNUSED:
|
||||
break;
|
||||
@ -779,28 +922,23 @@ prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl, u_int *nallocp,
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (npfd != *npfdp &&
|
||||
(pfd = recallocarray(pfd, *npfdp, npfd, sizeof(*pfd))) == NULL)
|
||||
fatal("%s: recallocarray failed", __func__);
|
||||
*pfdp = pfd;
|
||||
*npfdp = npfd;
|
||||
|
||||
sz = howmany(n+1, NFDBITS) * sizeof(fd_mask);
|
||||
if (*fdrp == NULL || sz > *nallocp) {
|
||||
free(*fdrp);
|
||||
free(*fdwp);
|
||||
*fdrp = xmalloc(sz);
|
||||
*fdwp = xmalloc(sz);
|
||||
*nallocp = sz;
|
||||
}
|
||||
if (n < *fdl)
|
||||
debug("XXX shrink: %d < %d", n, *fdl);
|
||||
*fdl = n;
|
||||
memset(*fdrp, 0, sz);
|
||||
memset(*fdwp, 0, sz);
|
||||
|
||||
for (i = 0; i < sockets_alloc; i++) {
|
||||
for (i = j = 0; i < sockets_alloc; i++) {
|
||||
switch (sockets[i].type) {
|
||||
case AUTH_SOCKET:
|
||||
case AUTH_CONNECTION:
|
||||
FD_SET(sockets[i].fd, *fdrp);
|
||||
pfd[j].fd = sockets[i].fd;
|
||||
pfd[j].revents = 0;
|
||||
/* XXX backoff when input buffer full */
|
||||
pfd[j].events = POLLIN;
|
||||
if (sshbuf_len(sockets[i].output) > 0)
|
||||
FD_SET(sockets[i].fd, *fdwp);
|
||||
pfd[j].events |= POLLOUT;
|
||||
j++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -811,98 +949,16 @@ prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl, u_int *nallocp,
|
||||
deadline = (deadline == 0) ? parent_alive_interval :
|
||||
MINIMUM(deadline, parent_alive_interval);
|
||||
if (deadline == 0) {
|
||||
*tvpp = NULL;
|
||||
*timeoutp = -1; /* INFTIM */
|
||||
} else {
|
||||
tv.tv_sec = deadline;
|
||||
tv.tv_usec = 0;
|
||||
*tvpp = &tv;
|
||||
if (deadline > INT_MAX / 1000)
|
||||
*timeoutp = INT_MAX / 1000;
|
||||
else
|
||||
*timeoutp = deadline * 1000;
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
static void
|
||||
after_select(fd_set *readset, fd_set *writeset)
|
||||
{
|
||||
struct sockaddr_un sunaddr;
|
||||
socklen_t slen;
|
||||
char buf[1024];
|
||||
int len, sock, r;
|
||||
u_int i, orig_alloc;
|
||||
uid_t euid;
|
||||
gid_t egid;
|
||||
|
||||
for (i = 0, orig_alloc = sockets_alloc; i < orig_alloc; i++)
|
||||
switch (sockets[i].type) {
|
||||
case AUTH_UNUSED:
|
||||
break;
|
||||
case AUTH_SOCKET:
|
||||
if (FD_ISSET(sockets[i].fd, readset)) {
|
||||
slen = sizeof(sunaddr);
|
||||
sock = accept(sockets[i].fd,
|
||||
(struct sockaddr *)&sunaddr, &slen);
|
||||
if (sock < 0) {
|
||||
error("accept from AUTH_SOCKET: %s",
|
||||
strerror(errno));
|
||||
break;
|
||||
}
|
||||
if (getpeereid(sock, &euid, &egid) < 0) {
|
||||
error("getpeereid %d failed: %s",
|
||||
sock, strerror(errno));
|
||||
close(sock);
|
||||
break;
|
||||
}
|
||||
if ((euid != 0) && (getuid() != euid)) {
|
||||
error("uid mismatch: "
|
||||
"peer euid %u != uid %u",
|
||||
(u_int) euid, (u_int) getuid());
|
||||
close(sock);
|
||||
break;
|
||||
}
|
||||
new_socket(AUTH_CONNECTION, sock);
|
||||
}
|
||||
break;
|
||||
case AUTH_CONNECTION:
|
||||
if (sshbuf_len(sockets[i].output) > 0 &&
|
||||
FD_ISSET(sockets[i].fd, writeset)) {
|
||||
len = write(sockets[i].fd,
|
||||
sshbuf_ptr(sockets[i].output),
|
||||
sshbuf_len(sockets[i].output));
|
||||
if (len == -1 && (errno == EAGAIN ||
|
||||
errno == EWOULDBLOCK ||
|
||||
errno == EINTR))
|
||||
continue;
|
||||
if (len <= 0) {
|
||||
close_socket(&sockets[i]);
|
||||
break;
|
||||
}
|
||||
if ((r = sshbuf_consume(sockets[i].output,
|
||||
len)) != 0)
|
||||
fatal("%s: buffer error: %s",
|
||||
__func__, ssh_err(r));
|
||||
}
|
||||
if (FD_ISSET(sockets[i].fd, readset)) {
|
||||
len = read(sockets[i].fd, buf, sizeof(buf));
|
||||
if (len == -1 && (errno == EAGAIN ||
|
||||
errno == EWOULDBLOCK ||
|
||||
errno == EINTR))
|
||||
continue;
|
||||
if (len <= 0) {
|
||||
close_socket(&sockets[i]);
|
||||
break;
|
||||
}
|
||||
if ((r = sshbuf_put(sockets[i].input,
|
||||
buf, len)) != 0)
|
||||
fatal("%s: buffer error: %s",
|
||||
__func__, ssh_err(r));
|
||||
explicit_bzero(buf, sizeof(buf));
|
||||
process_message(&sockets[i]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fatal("Unknown type %d", sockets[i].type);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup_socket(void)
|
||||
{
|
||||
@ -962,9 +1018,7 @@ main(int ac, char **av)
|
||||
{
|
||||
int c_flag = 0, d_flag = 0, D_flag = 0, k_flag = 0, s_flag = 0;
|
||||
int sock, fd, ch, result, saved_errno;
|
||||
u_int nalloc;
|
||||
char *shell, *format, *pidstr, *agentsocket = NULL;
|
||||
fd_set *readsetp = NULL, *writesetp = NULL;
|
||||
#ifdef HAVE_SETRLIMIT
|
||||
struct rlimit rlim;
|
||||
#endif
|
||||
@ -972,9 +1026,11 @@ main(int ac, char **av)
|
||||
extern char *optarg;
|
||||
pid_t pid;
|
||||
char pidstrbuf[1 + 3 * sizeof pid];
|
||||
struct timeval *tvp = NULL;
|
||||
size_t len;
|
||||
mode_t prev_mask;
|
||||
int timeout = -1; /* INFTIM */
|
||||
struct pollfd *pfd = NULL;
|
||||
size_t npfd = 0;
|
||||
|
||||
ssh_malloc_init(); /* must be called before any mallocs */
|
||||
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
|
||||
@ -1195,15 +1251,14 @@ skip:
|
||||
signal(SIGINT, (d_flag | D_flag) ? cleanup_handler : SIG_IGN);
|
||||
signal(SIGHUP, cleanup_handler);
|
||||
signal(SIGTERM, cleanup_handler);
|
||||
nalloc = 0;
|
||||
|
||||
if (pledge("stdio rpath cpath unix id proc exec", NULL) == -1)
|
||||
fatal("%s: pledge: %s", __progname, strerror(errno));
|
||||
platform_pledge_agent();
|
||||
|
||||
while (1) {
|
||||
prepare_select(&readsetp, &writesetp, &max_fd, &nalloc, &tvp);
|
||||
result = select(max_fd + 1, readsetp, writesetp, NULL, tvp);
|
||||
prepare_poll(&pfd, &npfd, &timeout);
|
||||
result = poll(pfd, npfd, timeout);
|
||||
saved_errno = errno;
|
||||
if (parent_alive_interval != 0)
|
||||
check_parent_exists();
|
||||
@ -1211,9 +1266,9 @@ skip:
|
||||
if (result < 0) {
|
||||
if (saved_errno == EINTR)
|
||||
continue;
|
||||
fatal("select: %s", strerror(saved_errno));
|
||||
fatal("poll: %s", strerror(saved_errno));
|
||||
} else if (result > 0)
|
||||
after_select(readsetp, writesetp);
|
||||
after_poll(pfd, npfd);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: ssh-keygen.1,v 1.142 2017/06/28 01:09:22 djm Exp $
|
||||
.\" $OpenBSD: ssh-keygen.1,v 1.144 2017/07/08 18:32:54 jmc Exp $
|
||||
.\"
|
||||
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -35,7 +35,7 @@
|
||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd $Mdocdate: June 28 2017 $
|
||||
.Dd $Mdocdate: July 8 2017 $
|
||||
.Dt SSH-KEYGEN 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -126,6 +126,7 @@
|
||||
.Op Fl f Ar input_keyfile
|
||||
.Nm ssh-keygen
|
||||
.Fl A
|
||||
.Op Fl f Ar prefix_path
|
||||
.Nm ssh-keygen
|
||||
.Fl k
|
||||
.Fl f Ar krl_file
|
||||
@ -224,6 +225,10 @@ For each of the key types (rsa, dsa, ecdsa and ed25519)
|
||||
for which host keys
|
||||
do not exist, generate the host keys with the default key file path,
|
||||
an empty passphrase, default bits for the key type, and default comment.
|
||||
If
|
||||
.Fl f
|
||||
has also been specified, its argument is used as a prefix to the
|
||||
default path for the resulting host key files.
|
||||
This is used by
|
||||
.Pa /etc/rc
|
||||
to generate new host keys.
|
||||
|
111
ssh-keygen.c
111
ssh-keygen.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ssh-keygen.c,v 1.305 2017/06/28 01:09:22 djm Exp $ */
|
||||
/* $OpenBSD: ssh-keygen.c,v 1.307 2017/07/07 03:53:12 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -41,7 +41,6 @@
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "sshkey.h"
|
||||
#include "rsa.h"
|
||||
#include "authfile.h"
|
||||
#include "uuencode.h"
|
||||
#include "sshbuf.h"
|
||||
@ -533,7 +532,7 @@ do_convert_private_ssh2_from_blob(u_char *blob, u_int blen)
|
||||
buffer_get_bignum_bits(b, key->rsa->iqmp);
|
||||
buffer_get_bignum_bits(b, key->rsa->q);
|
||||
buffer_get_bignum_bits(b, key->rsa->p);
|
||||
if ((r = rsa_generate_additional_parameters(key->rsa)) != 0)
|
||||
if ((r = ssh_rsa_generate_additional_parameters(key)) != 0)
|
||||
fatal("generate RSA parameters failed: %s", ssh_err(r));
|
||||
break;
|
||||
}
|
||||
@ -1003,20 +1002,38 @@ do_gen_all_hostkeys(struct passwd *pw)
|
||||
int first = 0;
|
||||
struct stat st;
|
||||
struct sshkey *private, *public;
|
||||
char comment[1024];
|
||||
char comment[1024], *prv_tmp, *pub_tmp, *prv_file, *pub_file;
|
||||
int i, type, fd, r;
|
||||
FILE *f;
|
||||
|
||||
for (i = 0; key_types[i].key_type; i++) {
|
||||
if (stat(key_types[i].path, &st) == 0)
|
||||
continue;
|
||||
if (errno != ENOENT) {
|
||||
public = private = NULL;
|
||||
prv_tmp = pub_tmp = prv_file = pub_file = NULL;
|
||||
|
||||
xasprintf(&prv_file, "%s%s",
|
||||
identity_file, key_types[i].path);
|
||||
|
||||
/* Check whether private key exists and is not zero-length */
|
||||
if (stat(prv_file, &st) == 0) {
|
||||
if (st.st_size != 0)
|
||||
goto next;
|
||||
} else if (errno != ENOENT) {
|
||||
error("Could not stat %s: %s", key_types[i].path,
|
||||
strerror(errno));
|
||||
first = 0;
|
||||
continue;
|
||||
goto failnext;
|
||||
}
|
||||
|
||||
/*
|
||||
* Private key doesn't exist or is invalid; proceed with
|
||||
* key generation.
|
||||
*/
|
||||
xasprintf(&prv_tmp, "%s%s.XXXXXXXXXX",
|
||||
identity_file, key_types[i].path);
|
||||
xasprintf(&pub_tmp, "%s%s.pub.XXXXXXXXXX",
|
||||
identity_file, key_types[i].path);
|
||||
xasprintf(&pub_file, "%s%s.pub",
|
||||
identity_file, key_types[i].path);
|
||||
|
||||
if (first == 0) {
|
||||
first = 1;
|
||||
printf("%s: generating new host keys: ", __progname);
|
||||
@ -1024,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");
|
||||
|
37
ssh-rsa.c
37
ssh-rsa.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ssh-rsa.c,v 1.61 2017/05/07 23:15:59 djm Exp $ */
|
||||
/* $OpenBSD: ssh-rsa.c,v 1.62 2017/07/01 13:50:45 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
|
||||
*
|
||||
@ -78,6 +78,41 @@ rsa_hash_alg_nid(int type)
|
||||
}
|
||||
}
|
||||
|
||||
/* calculate p-1 and q-1 */
|
||||
int
|
||||
ssh_rsa_generate_additional_parameters(struct sshkey *key)
|
||||
{
|
||||
RSA *rsa;
|
||||
BIGNUM *aux = NULL;
|
||||
BN_CTX *ctx = NULL;
|
||||
int r;
|
||||
|
||||
if (key == NULL || key->rsa == NULL ||
|
||||
sshkey_type_plain(key->type) != KEY_RSA)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
|
||||
if ((ctx = BN_CTX_new()) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
if ((aux = BN_new()) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
rsa = key->rsa;
|
||||
|
||||
if ((BN_sub(aux, rsa->q, BN_value_one()) == 0) ||
|
||||
(BN_mod(rsa->dmq1, rsa->d, aux, ctx) == 0) ||
|
||||
(BN_sub(aux, rsa->p, BN_value_one()) == 0) ||
|
||||
(BN_mod(rsa->dmp1, rsa->d, aux, ctx) == 0)) {
|
||||
r = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
goto out;
|
||||
}
|
||||
r = 0;
|
||||
out:
|
||||
BN_clear_free(aux);
|
||||
BN_CTX_free(ctx);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
|
||||
int
|
||||
ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
|
||||
|
11
ssh.c
11
ssh.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ssh.c,v 1.461 2017/05/30 18:58:37 bluhm Exp $ */
|
||||
/* $OpenBSD: ssh.c,v 1.462 2017/08/12 06:46:01 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -509,13 +509,13 @@ int
|
||||
main(int ac, char **av)
|
||||
{
|
||||
struct ssh *ssh = NULL;
|
||||
int i, r, opt, exit_status, use_syslog, direct, config_test = 0;
|
||||
int i, r, opt, exit_status, use_syslog, direct, timeout_ms;
|
||||
int config_test = 0, opt_terminated = 0;
|
||||
char *p, *cp, *line, *argv0, buf[PATH_MAX], *host_arg, *logfile;
|
||||
char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
|
||||
char cname[NI_MAXHOST], uidstr[32], *conn_hash_hex;
|
||||
struct stat st;
|
||||
struct passwd *pw;
|
||||
int timeout_ms;
|
||||
extern int optind, optreset;
|
||||
extern char *optarg;
|
||||
struct Forward fwd;
|
||||
@ -917,6 +917,9 @@ main(int ac, char **av)
|
||||
}
|
||||
}
|
||||
|
||||
if (optind > 1 && strcmp(av[optind - 1], "--") == 0)
|
||||
opt_terminated = 1;
|
||||
|
||||
ac -= optind;
|
||||
av += optind;
|
||||
|
||||
@ -931,7 +934,7 @@ main(int ac, char **av)
|
||||
host = xstrdup(++cp);
|
||||
} else
|
||||
host = xstrdup(*av);
|
||||
if (ac > 1) {
|
||||
if (ac > 1 && !opt_terminated) {
|
||||
optind = optreset = 1;
|
||||
goto again;
|
||||
}
|
||||
|
11
ssh_config.5
11
ssh_config.5
@ -33,16 +33,13 @@
|
||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $OpenBSD: ssh_config.5,v 1.251 2017/06/24 05:35:05 djm Exp $
|
||||
.Dd $Mdocdate: June 24 2017 $
|
||||
.\" $OpenBSD: ssh_config.5,v 1.253 2017/07/23 23:37:02 djm Exp $
|
||||
.Dd $Mdocdate: July 23 2017 $
|
||||
.Dt SSH_CONFIG 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ssh_config
|
||||
.Nd OpenSSH SSH client configuration files
|
||||
.Sh SYNOPSIS
|
||||
.Nm ~/.ssh/config
|
||||
.Nm /etc/ssh/ssh_config
|
||||
.Sh DESCRIPTION
|
||||
.Xr ssh 1
|
||||
obtains configuration data from the following sources in
|
||||
@ -972,7 +969,9 @@ Accepted values are
|
||||
.Cm lowdelay ,
|
||||
.Cm throughput ,
|
||||
.Cm reliability ,
|
||||
or a numeric value.
|
||||
a numeric value, or
|
||||
.Cm none
|
||||
to use the operating system default.
|
||||
This option may take one or two arguments, separated by whitespace.
|
||||
If one argument is specified, it is used as the packet class unconditionally.
|
||||
If two values are specified, the first is automatically selected for
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: sshconnect.c,v 1.282 2017/06/24 05:37:44 djm Exp $ */
|
||||
/* $OpenBSD: sshconnect.c,v 1.283 2017/07/01 13:50:45 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -48,7 +48,6 @@
|
||||
#include "key.h"
|
||||
#include "hostfile.h"
|
||||
#include "ssh.h"
|
||||
#include "rsa.h"
|
||||
#include "buffer.h"
|
||||
#include "packet.h"
|
||||
#include "uidswap.h"
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: sshconnect2.c,v 1.264 2017/06/14 00:31:38 dtucker Exp $ */
|
||||
/* $OpenBSD: sshconnect2.c,v 1.265 2017/08/11 04:47:12 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
* Copyright (c) 2008 Damien Miller. All rights reserved.
|
||||
@ -1042,6 +1042,11 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
|
||||
/* load the private key from the file */
|
||||
if ((prv = load_identity_file(id)) == NULL)
|
||||
return SSH_ERR_KEY_NOT_FOUND;
|
||||
if (id->key != NULL && !sshkey_equal_public(prv, id->key)) {
|
||||
error("%s: private key %s contents do not match public",
|
||||
__func__, id->filename);
|
||||
return SSH_ERR_KEY_NOT_FOUND;
|
||||
}
|
||||
ret = sshkey_sign(prv, sigp, lenp, data, datalen,
|
||||
key_sign_encode(prv), compat);
|
||||
sshkey_free(prv);
|
||||
|
3
sshd.c
3
sshd.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: sshd.c,v 1.490 2017/05/31 08:09:45 markus Exp $ */
|
||||
/* $OpenBSD: sshd.c,v 1.491 2017/07/01 13:50:45 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -88,7 +88,6 @@
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
#include "ssh2.h"
|
||||
#include "rsa.h"
|
||||
#include "sshpty.h"
|
||||
#include "packet.h"
|
||||
#include "log.h"
|
||||
|
@ -33,15 +33,13 @@
|
||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $OpenBSD: sshd_config.5,v 1.248 2017/06/24 07:08:57 djm Exp $
|
||||
.Dd $Mdocdate: June 24 2017 $
|
||||
.\" $OpenBSD: sshd_config.5,v 1.250 2017/07/23 23:37:02 djm Exp $
|
||||
.Dd $Mdocdate: July 23 2017 $
|
||||
.Dt SSHD_CONFIG 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm sshd_config
|
||||
.Nd OpenSSH SSH daemon configuration file
|
||||
.Sh SYNOPSIS
|
||||
.Nm /etc/ssh/sshd_config
|
||||
.Sh DESCRIPTION
|
||||
.Xr sshd 8
|
||||
reads configuration data from
|
||||
@ -794,7 +792,9 @@ Accepted values are
|
||||
.Cm lowdelay ,
|
||||
.Cm throughput ,
|
||||
.Cm reliability ,
|
||||
or a numeric value.
|
||||
a numeric value, or
|
||||
.Cm none
|
||||
to use the operating system default.
|
||||
This option may take one or two arguments, separated by whitespace.
|
||||
If one argument is specified, it is used as the packet class unconditionally.
|
||||
If two values are specified, the first is automatically selected for
|
||||
|
14
sshkey.c
14
sshkey.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: sshkey.c,v 1.53 2017/06/28 01:09:22 djm Exp $ */
|
||||
/* $OpenBSD: sshkey.c,v 1.56 2017/08/12 06:42:52 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
||||
* Copyright (c) 2008 Alexander von Gernler. All rights reserved.
|
||||
@ -51,7 +51,6 @@
|
||||
#include "ssherr.h"
|
||||
#include "misc.h"
|
||||
#include "sshbuf.h"
|
||||
#include "rsa.h"
|
||||
#include "cipher.h"
|
||||
#include "digest.h"
|
||||
#define SSHKEY_INTERNAL
|
||||
@ -66,7 +65,7 @@
|
||||
#define KDFNAME "bcrypt"
|
||||
#define AUTH_MAGIC "openssh-key-v1"
|
||||
#define SALT_LEN 16
|
||||
#define DEFAULT_CIPHERNAME "aes256-cbc"
|
||||
#define DEFAULT_CIPHERNAME "aes256-ctr"
|
||||
#define DEFAULT_ROUNDS 16
|
||||
|
||||
/* Version identification string for SSH v1 identity files. */
|
||||
@ -1987,11 +1986,6 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
|
||||
pk = NULL;
|
||||
break;
|
||||
case KEY_UNSPEC:
|
||||
if ((key = sshkey_new(type)) == NULL) {
|
||||
ret = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = SSH_ERR_KEY_TYPE_UNKNOWN;
|
||||
goto out;
|
||||
@ -2667,7 +2661,7 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
|
||||
(r = sshbuf_get_bignum2(buf, k->rsa->iqmp)) != 0 ||
|
||||
(r = sshbuf_get_bignum2(buf, k->rsa->p)) != 0 ||
|
||||
(r = sshbuf_get_bignum2(buf, k->rsa->q)) != 0 ||
|
||||
(r = rsa_generate_additional_parameters(k->rsa)) != 0)
|
||||
(r = ssh_rsa_generate_additional_parameters(k)) != 0)
|
||||
goto out;
|
||||
if (BN_num_bits(k->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
|
||||
r = SSH_ERR_KEY_LENGTH;
|
||||
@ -2681,7 +2675,7 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
|
||||
(r = sshbuf_get_bignum2(buf, k->rsa->iqmp)) != 0 ||
|
||||
(r = sshbuf_get_bignum2(buf, k->rsa->p)) != 0 ||
|
||||
(r = sshbuf_get_bignum2(buf, k->rsa->q)) != 0 ||
|
||||
(r = rsa_generate_additional_parameters(k->rsa)) != 0)
|
||||
(r = ssh_rsa_generate_additional_parameters(k)) != 0)
|
||||
goto out;
|
||||
if (BN_num_bits(k->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
|
||||
r = SSH_ERR_KEY_LENGTH;
|
||||
|
5
sshkey.h
5
sshkey.h
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: sshkey.h,v 1.20 2017/06/28 01:09:22 djm Exp $ */
|
||||
/* $OpenBSD: sshkey.h,v 1.21 2017/07/01 13:50:45 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
||||
@ -196,6 +196,9 @@ int sshkey_parse_private_fileblob(struct sshbuf *buffer,
|
||||
int sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
|
||||
const char *passphrase, struct sshkey **keyp, char **commentp);
|
||||
|
||||
/* XXX should be internal, but used by ssh-keygen */
|
||||
int ssh_rsa_generate_additional_parameters(struct sshkey *);
|
||||
|
||||
#ifdef SSHKEY_INTERNAL
|
||||
int ssh_rsa_sign(const struct sshkey *key,
|
||||
u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,
|
||||
|
Loading…
x
Reference in New Issue
Block a user