File openssh-8.9p1-custom-3.patch of Package openssh
From df59fbd1fffde1f4c06d4bda5a5d7fb3538dcc55 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 2e1b5fec..f4b95df6 100644
--- a/misc.h
+++ b/misc.h
@@ -209,20 +209,21 @@ void opt_array_append2(const char *file, const int line,
/* 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 f26fabaa..8bbf9da4 100644
--- a/readconf.c
+++ b/readconf.c
@@ -168,20 +168,21 @@ typedef enum {
oLocalCommand, oPermitLocalCommand, oRemoteCommand,
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,
+ oPasswordCommand,
oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
} OpCodes;
/* Textual representations of the tokens. */
static struct {
const char *name;
OpCodes opcode;
} keywords[] = {
/* Deprecated options */
@@ -313,20 +314,21 @@ static struct {
{ "fingerprinthash", oFingerprintHash },
{ "updatehostkeys", oUpdateHostkeys },
{ "hostbasedacceptedalgorithms", oHostbasedAcceptedAlgorithms },
{ "hostbasedkeytypes", oHostbasedAcceptedAlgorithms }, /* obsolete */
{ "pubkeyacceptedalgorithms", oPubkeyAcceptedAlgorithms },
{ "pubkeyacceptedkeytypes", oPubkeyAcceptedAlgorithms }, /* obsolete */
{ "ignoreunknown", oIgnoreUnknown },
{ "proxyjump", oProxyJump },
{ "securitykeyprovider", oSecurityKeyProvider },
{ "knownhostscommand", oKnownHostsCommand },
+ { "passwordcommand", oPasswordCommand },
{ NULL, oBadOption }
};
static const char *lookup_opcode_name(OpCodes code);
const char *
kex_default_pk_alg(void)
{
static char *pkalgs;
@@ -2184,20 +2186,24 @@ parse_pubkey_algos:
if (arg[0] == '$' && arg[1] != '{' &&
!valid_env_name(arg + 1)) {
error("%.200s line %d: Invalid environment name %s.",
filename, linenum, arg);
goto out;
}
if (*activep && *charptr == NULL)
*charptr = xstrdup(arg);
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);
@@ -2431,20 +2437,21 @@ initialize_options(Options * options)
options->num_permitted_cnames = 0;
options->canonicalize_max_dots = -1;
options->canonicalize_fallback_local = -1;
options->canonicalize_hostname = -1;
options->revoked_host_keys = NULL;
options->fingerprint_hash = -1;
options->update_hostkeys = -1;
options->hostbased_accepted_algos = NULL;
options->pubkey_accepted_algos = NULL;
options->known_hosts_command = NULL;
+ 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)
@@ -2671,20 +2678,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(options->password_command);
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)) {
/* clean up CanonicalizePermittedCNAMEs=none */
free(options->permitted_cnames[0].source_list);
@@ -3343,20 +3351,21 @@ dump_client_config(Options *o, const char *host)
dump_cfg_string(oMacs, o->macs);
#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(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 ded13c94..e935eb4e 100644
--- a/readconf.h
+++ b/readconf.h
@@ -168,20 +168,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;
char *ignored_unknown; /* Pattern list of unknown tokens to ignore */
} Options;
#define SSH_PUBKEY_AUTH_NO 0x00
#define SSH_PUBKEY_AUTH_UNBOUND 0x01
#define SSH_PUBKEY_AUTH_HBOUND 0x02
#define SSH_PUBKEY_AUTH_ALL 0x03
#define SSH_CANONICALISE_NO 0
diff --git a/readpass.c b/readpass.c
index 39af25c8..f82e6003 100644
--- a/readpass.c
+++ b/readpass.c
@@ -322,10 +322,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 8ff97881..a355a6d0 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1384,20 +1384,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 b25225e6..a7ba2948 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -1064,21 +1064,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.36.1