File openssh-9.9p1-custom-3.patch of Package openssh
From 696316e858c31cd3c8c883b770fbf99308bd44aa Mon Sep 17 00:00:00 2001
From: Ciprian Dorin Craciun <ciprian@volution.ro>
Date: Fri, 7 Apr 2017 01:42:33 +0300
Subject: [PATCH 3/3] Add `PasswordCommand` option which overrides
`SSH_ASKPASS` and should always provide a password (this is used only for
login passwords)
---
misc.h | 1 +
readconf.c | 9 +++++++
readconf.h | 1 +
readpass.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++
ssh.c | 10 ++++++++
sshconnect2.c | 5 +++-
6 files changed, 91 insertions(+), 1 deletion(-)
diff --git a/misc.h b/misc.h
index 113403896..f23515563 100644
--- a/misc.h
+++ b/misc.h
@@ -233,20 +233,21 @@ int ptimeout_isset(struct timespec *pt);
/* readpass.c */
#define RP_ECHO 0x0001
#define RP_ALLOW_STDIN 0x0002
#define RP_ALLOW_EOF 0x0004
#define RP_USE_ASKPASS 0x0008
struct notifier_ctx;
char *read_passphrase(const char *, int);
+char *read_passphrase_from_command(const char *);
int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2)));
struct notifier_ctx *notify_start(int, const char *, ...)
__attribute__((format(printf, 2, 3)));
void notify_complete(struct notifier_ctx *, const char *, ...)
__attribute__((format(printf, 2, 3)));
#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))
#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y))
diff --git a/readconf.c b/readconf.c
index 3d9cc6dbb..2393d4430 100644
--- a/readconf.c
+++ b/readconf.c
@@ -172,20 +172,21 @@ typedef enum {
oVisualHostKey,
oKexAlgorithms, oIPQoS, oRequestTTY, oSessionType, oStdinNull,
oForkAfterAuthentication, oIgnoreUnknown, oProxyUseFdpass,
oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms,
oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump,
oSecurityKeyProvider, oKnownHostsCommand, oRequiredRSASize,
oEnableEscapeCommandline, oObscureKeystrokeTiming, oChannelTimeout,
+ oPasswordCommand,
oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
} OpCodes;
/* Textual representations of the tokens. */
static struct {
const char *name;
OpCodes opcode;
} keywords[] = {
/* Deprecated options */
@@ -322,20 +323,21 @@ static struct {
{ "pubkeyacceptedalgorithms", oPubkeyAcceptedAlgorithms },
{ "pubkeyacceptedkeytypes", oPubkeyAcceptedAlgorithms }, /* obsolete */
{ "ignoreunknown", oIgnoreUnknown },
{ "proxyjump", oProxyJump },
{ "securitykeyprovider", oSecurityKeyProvider },
{ "knownhostscommand", oKnownHostsCommand },
{ "requiredrsasize", oRequiredRSASize },
{ "enableescapecommandline", oEnableEscapeCommandline },
{ "obscurekeystroketiming", oObscureKeystrokeTiming },
{ "channeltimeout", oChannelTimeout },
+ { "passwordcommand", oPasswordCommand },
{ NULL, oBadOption }
};
static const char *lookup_opcode_name(OpCodes code);
const char *
kex_default_pk_alg(void)
{
static char *pkalgs;
@@ -2415,20 +2417,24 @@ parse_pubkey_algos:
filename, linenum, keyword);
}
if (found && *activep) {
options->channel_timeouts = strs;
options->num_channel_timeouts = nstrs;
strs = NULL; /* transferred */
nstrs = 0;
}
break;
+ case oPasswordCommand:
+ charptr = &options->password_command;
+ goto parse_command;
+
case oDeprecated:
debug("%s line %d: Deprecated option \"%s\"",
filename, linenum, keyword);
argv_consume(&ac);
break;
case oUnsupported:
error("%s line %d: Unsupported option \"%s\"",
filename, linenum, keyword);
argv_consume(&ac);
@@ -2671,20 +2677,21 @@ initialize_options(Options * options)
options->update_hostkeys = -1;
options->hostbased_accepted_algos = NULL;
options->pubkey_accepted_algos = NULL;
options->known_hosts_command = NULL;
options->required_rsa_size = -1;
options->enable_escape_commandline = -1;
options->obscure_keystroke_timing_interval = -1;
options->tag = NULL;
options->channel_timeouts = NULL;
options->num_channel_timeouts = 0;
+ options->password_command = NULL;
}
/*
* A petite version of fill_default_options() that just fills the options
* needed for hostname canonicalization to proceed.
*/
void
fill_default_options_for_canonicalization(Options *options)
{
if (options->canonicalize_max_dots == -1)
@@ -2932,20 +2939,21 @@ fill_default_options(Options * options)
} while (0)
CLEAR_ON_NONE(options->local_command);
CLEAR_ON_NONE(options->remote_command);
CLEAR_ON_NONE(options->proxy_command);
CLEAR_ON_NONE(options->control_path);
CLEAR_ON_NONE(options->revoked_host_keys);
CLEAR_ON_NONE(options->pkcs11_provider);
CLEAR_ON_NONE(options->sk_provider);
CLEAR_ON_NONE(options->known_hosts_command);
CLEAR_ON_NONE_ARRAY(channel_timeouts, num_channel_timeouts, "none");
+ CLEAR_ON_NONE(options->password_command);
#undef CLEAR_ON_NONE
#undef CLEAR_ON_NONE_ARRAY
if (options->jump_host != NULL &&
strcmp(options->jump_host, "none") == 0 &&
options->jump_port == 0 && options->jump_user == NULL) {
free(options->jump_host);
options->jump_host = NULL;
}
if (options->num_permitted_cnames == 1 &&
!config_has_permitted_cnames(options)) {
@@ -3622,20 +3630,21 @@ dump_client_config(Options *o, const char *host)
#ifdef ENABLE_PKCS11
dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
#endif
dump_cfg_string(oSecurityKeyProvider, o->sk_provider);
dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
dump_cfg_string(oPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos);
dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
dump_cfg_string(oXAuthLocation, o->xauth_location);
dump_cfg_string(oKnownHostsCommand, o->known_hosts_command);
dump_cfg_string(oTag, o->tag);
+ dump_cfg_string(oPasswordCommand, o->password_command);
/* Forwards */
dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards);
dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards);
dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards);
/* String array options */
dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files);
dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains);
dump_cfg_strarray(oCertificateFile, o->num_certificate_files, o->certificate_files);
diff --git a/readconf.h b/readconf.h
index 9447d5d6e..13ea04ec7 100644
--- a/readconf.h
+++ b/readconf.h
@@ -170,20 +170,21 @@ typedef struct {
char *hostbased_accepted_algos;
char *pubkey_accepted_algos;
char *jump_user;
char *jump_host;
int jump_port;
char *jump_extra;
char *known_hosts_command;
+ char *password_command;
int required_rsa_size; /* minimum size of RSA keys */
int enable_escape_commandline; /* ~C commandline */
int obscure_keystroke_timing_interval;
char **channel_timeouts; /* inactivity timeout by channel type */
u_int num_channel_timeouts;
char *ignored_unknown; /* Pattern list of unknown tokens to ignore */
} Options;
diff --git a/readpass.c b/readpass.c
index d42b1185d..aba598734 100644
--- a/readpass.c
+++ b/readpass.c
@@ -324,10 +324,76 @@ notify_complete(struct notifier_ctx *ctx, const char *fmt, ...)
kill(ctx->pid, SIGTERM);
while ((ret = waitpid(ctx->pid, NULL, 0)) == -1) {
if (errno != EINTR)
break;
}
if (ret == -1)
fatal_f("waitpid: %s", strerror(errno));
ssh_signal(SIGCHLD, ctx->osigchld);
free(ctx);
}
+
+char *
+read_passphrase_from_command(const char *command)
+{
+ char *shell;
+ pid_t pid, ret;
+ size_t len;
+ char *pass;
+ int p[2], status;
+ char buf[1024];
+ void (*osigchld)(int);
+
+ if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
+ shell = _PATH_BSHELL;
+
+ if (fflush(stdout) != 0)
+ error("password_command: fflush: %s", strerror(errno));
+ if (shell == NULL)
+ fatal("internal error: shell undefined");
+ if (pipe(p) < 0) {
+ error("password_command: pipe: %s", strerror(errno));
+ return NULL;
+ }
+ osigchld = signal(SIGCHLD, SIG_DFL);
+ if ((pid = fork()) < 0) {
+ error("password_command: fork: %s", strerror(errno));
+ signal(SIGCHLD, osigchld);
+ return NULL;
+ }
+ if (pid == 0) {
+ close(p[0]);
+ if (dup2(p[1], STDOUT_FILENO) < 0)
+ fatal("password_command: dup2: %s", strerror(errno));
+ debug3("Executing (via shell %s): %s", shell, command);
+ execlp(shell, shell, "-c", command, (char *)NULL);
+ fatal("password_command: exec(%s): %s", command, strerror(errno));
+ }
+ close(p[1]);
+
+ len = 0;
+ do {
+ ssize_t r = read(p[0], buf + len, sizeof(buf) - 1 - len);
+
+ if (r == -1 && errno == EINTR)
+ continue;
+ if (r <= 0)
+ break;
+ len += r;
+ } while (sizeof(buf) - 1 - len > 0);
+ buf[len] = '\0';
+
+ close(p[0]);
+ while ((ret = waitpid(pid, &status, 0)) < 0)
+ if (errno != EINTR)
+ break;
+ signal(SIGCHLD, osigchld);
+ if (ret == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ explicit_bzero(buf, sizeof(buf));
+ return NULL;
+ }
+
+ buf[strcspn(buf, "\r\n")] = '\0';
+ pass = xstrdup(buf);
+ explicit_bzero(buf, sizeof(buf));
+ return pass;
+}
diff --git a/ssh.c b/ssh.c
index 0019281f4..7732f194e 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1448,20 +1448,30 @@ main(int ac, char **av)
cp = options.remote_command;
options.remote_command = default_client_percent_expand(cp,
cinfo);
debug3("expanded RemoteCommand: %s", options.remote_command);
free(cp);
if ((r = sshbuf_put(command, options.remote_command,
strlen(options.remote_command))) != 0)
fatal_fr(r, "buffer error");
}
+ if (options.password_command != NULL) {
+ debug3("expanding PasswordCommand: %s", options.password_command);
+ cp = options.password_command;
+ options.password_command = default_client_percent_expand(cp,
+ cinfo);
+ debug3("expanded PasswordCommand: %s", options.password_command);
+ free(cp);
+ }
+
+
if (options.control_path != NULL) {
cp = tilde_expand_filename(options.control_path, getuid());
free(options.control_path);
options.control_path = default_client_percent_dollar_expand(cp,
cinfo);
free(cp);
}
if (options.identity_agent != NULL) {
p = tilde_expand_filename(options.identity_agent, getuid());
diff --git a/sshconnect2.c b/sshconnect2.c
index 11fcdea8a..b29e5cb15 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -1037,21 +1037,24 @@ userauth_passwd(struct ssh *ssh)
authctxt->host;
int r;
if (authctxt->attempt_passwd++ >= options.number_of_password_prompts)
return 0;
if (authctxt->attempt_passwd != 1)
error("Permission denied, please try again.");
xasprintf(&prompt, "%s@%s's password: ", authctxt->server_user, host);
- password = read_passphrase(prompt, 0);
+ if (options.password_command == NULL)
+ password = read_passphrase(prompt, 0);
+ else
+ password = read_passphrase_from_command(options.password_command);
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 ||
(r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 ||
(r = sshpkt_put_u8(ssh, 0)) != 0 ||
(r = sshpkt_put_cstring(ssh, password)) != 0 ||
(r = sshpkt_add_padding(ssh, 64)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send packet");
--
2.47.1