- djm@cvs.openbsd.org 2013/10/16 02:31:47
[readconf.c readconf.h roaming_client.c ssh.1 ssh.c ssh_config.5] [sshconnect.c sshconnect.h] Implement client-side hostname canonicalisation to allow an explicit search path of domain suffixes to use to convert unqualified host names to fully-qualified ones for host key matching. This is particularly useful for host certificates, which would otherwise need to list unqualified names alongside fully-qualified ones (and this causes a number of problems). "looks fine" markus@
This commit is contained in:
parent
d77b81f856
commit
0faf747e2f
10
ChangeLog
10
ChangeLog
|
@ -3,6 +3,16 @@
|
||||||
- jmc@cvs.openbsd.org 2013/10/15 14:10:25
|
- jmc@cvs.openbsd.org 2013/10/15 14:10:25
|
||||||
[ssh.1 ssh_config.5]
|
[ssh.1 ssh_config.5]
|
||||||
tweak previous;
|
tweak previous;
|
||||||
|
- djm@cvs.openbsd.org 2013/10/16 02:31:47
|
||||||
|
[readconf.c readconf.h roaming_client.c ssh.1 ssh.c ssh_config.5]
|
||||||
|
[sshconnect.c sshconnect.h]
|
||||||
|
Implement client-side hostname canonicalisation to allow an explicit
|
||||||
|
search path of domain suffixes to use to convert unqualified host names
|
||||||
|
to fully-qualified ones for host key matching.
|
||||||
|
This is particularly useful for host certificates, which would otherwise
|
||||||
|
need to list unqualified names alongside fully-qualified ones (and this
|
||||||
|
causes a number of problems).
|
||||||
|
"looks fine" markus@
|
||||||
|
|
||||||
20131015
|
20131015
|
||||||
- (djm) OpenBSD CVS Sync
|
- (djm) OpenBSD CVS Sync
|
||||||
|
|
113
readconf.c
113
readconf.c
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: readconf.c,v 1.207 2013/10/14 23:28:23 djm Exp $ */
|
/* $OpenBSD: readconf.c,v 1.208 2013/10/16 02:31:45 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
|
@ -144,6 +144,8 @@ typedef enum {
|
||||||
oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
|
oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
|
||||||
oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication,
|
oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication,
|
||||||
oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
|
oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
|
||||||
|
oCanonicalDomains, oCanonicaliseHostname, oCanonicaliseMaxDots,
|
||||||
|
oCanonicaliseFallbackLocal, oCanonicalisePermittedCNAMEs,
|
||||||
oIgnoredUnknownOption, oDeprecated, oUnsupported
|
oIgnoredUnknownOption, oDeprecated, oUnsupported
|
||||||
} OpCodes;
|
} OpCodes;
|
||||||
|
|
||||||
|
@ -257,6 +259,11 @@ static struct {
|
||||||
{ "ipqos", oIPQoS },
|
{ "ipqos", oIPQoS },
|
||||||
{ "requesttty", oRequestTTY },
|
{ "requesttty", oRequestTTY },
|
||||||
{ "proxyusefdpass", oProxyUseFdpass },
|
{ "proxyusefdpass", oProxyUseFdpass },
|
||||||
|
{ "canonicaldomains", oCanonicalDomains },
|
||||||
|
{ "canonicalisefallbacklocal", oCanonicaliseFallbackLocal },
|
||||||
|
{ "canonicalisehostname", oCanonicaliseHostname },
|
||||||
|
{ "canonicalisemaxdots", oCanonicaliseMaxDots },
|
||||||
|
{ "canonicalisepermittedcnames", oCanonicalisePermittedCNAMEs },
|
||||||
{ "ignoreunknown", oIgnoreUnknown },
|
{ "ignoreunknown", oIgnoreUnknown },
|
||||||
|
|
||||||
{ NULL, oBadOption }
|
{ NULL, oBadOption }
|
||||||
|
@ -535,6 +542,34 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check and prepare a domain name: removes trailing '.' and lowercases */
|
||||||
|
static void
|
||||||
|
valid_domain(char *name, const char *filename, int linenum)
|
||||||
|
{
|
||||||
|
size_t i, l = strlen(name);
|
||||||
|
u_char c, last = '\0';
|
||||||
|
|
||||||
|
if (l == 0)
|
||||||
|
fatal("%s line %d: empty hostname suffix", filename, linenum);
|
||||||
|
if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0]))
|
||||||
|
fatal("%s line %d: hostname suffix \"%.100s\" "
|
||||||
|
"starts with invalid character", filename, linenum, name);
|
||||||
|
for (i = 0; i < l; i++) {
|
||||||
|
c = tolower((u_char)name[i]);
|
||||||
|
name[i] = (char)c;
|
||||||
|
if (last == '.' && c == '.')
|
||||||
|
fatal("%s line %d: hostname suffix \"%.100s\" contains "
|
||||||
|
"consecutive separators", filename, linenum, name);
|
||||||
|
if (c != '.' && c != '-' && !isalnum(c) &&
|
||||||
|
c != '_') /* technically invalid, but common */
|
||||||
|
fatal("%s line %d: hostname suffix \"%.100s\" contains "
|
||||||
|
"invalid characters", filename, linenum, name);
|
||||||
|
last = c;
|
||||||
|
}
|
||||||
|
if (name[l - 1] == '.')
|
||||||
|
name[l - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the number of the token pointed to by cp or oBadOption.
|
* Returns the number of the token pointed to by cp or oBadOption.
|
||||||
*/
|
*/
|
||||||
|
@ -609,6 +644,14 @@ static const struct multistate multistate_requesttty[] = {
|
||||||
{ "auto", REQUEST_TTY_AUTO },
|
{ "auto", REQUEST_TTY_AUTO },
|
||||||
{ NULL, -1 }
|
{ NULL, -1 }
|
||||||
};
|
};
|
||||||
|
static const struct multistate multistate_canonicalisehostname[] = {
|
||||||
|
{ "true", SSH_CANONICALISE_YES },
|
||||||
|
{ "false", SSH_CANONICALISE_NO },
|
||||||
|
{ "yes", SSH_CANONICALISE_YES },
|
||||||
|
{ "no", SSH_CANONICALISE_NO },
|
||||||
|
{ "always", SSH_CANONICALISE_ALWAYS },
|
||||||
|
{ NULL, -1 }
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Processes a single option line as used in the configuration files. This
|
* Processes a single option line as used in the configuration files. This
|
||||||
|
@ -628,6 +671,7 @@ process_config_line(Options *options, struct passwd *pw, const char *host,
|
||||||
size_t len;
|
size_t len;
|
||||||
Forward fwd;
|
Forward fwd;
|
||||||
const struct multistate *multistate_ptr;
|
const struct multistate *multistate_ptr;
|
||||||
|
struct allowed_cname *cname;
|
||||||
|
|
||||||
if (activep == NULL) { /* We are processing a command line directive */
|
if (activep == NULL) { /* We are processing a command line directive */
|
||||||
cmdline = 1;
|
cmdline = 1;
|
||||||
|
@ -1263,6 +1307,62 @@ parse_int:
|
||||||
intptr = &options->proxy_use_fdpass;
|
intptr = &options->proxy_use_fdpass;
|
||||||
goto parse_flag;
|
goto parse_flag;
|
||||||
|
|
||||||
|
case oCanonicalDomains:
|
||||||
|
value = options->num_canonical_domains != 0;
|
||||||
|
while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
|
||||||
|
valid_domain(arg, filename, linenum);
|
||||||
|
if (!*activep || value)
|
||||||
|
continue;
|
||||||
|
if (options->num_canonical_domains >= MAX_CANON_DOMAINS)
|
||||||
|
fatal("%s line %d: too many hostname suffixes.",
|
||||||
|
filename, linenum);
|
||||||
|
options->canonical_domains[
|
||||||
|
options->num_canonical_domains++] = xstrdup(arg);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case oCanonicalisePermittedCNAMEs:
|
||||||
|
value = options->num_permitted_cnames != 0;
|
||||||
|
while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
|
||||||
|
/* Either '*' for everything or 'list:list' */
|
||||||
|
if (strcmp(arg, "*") == 0)
|
||||||
|
arg2 = arg;
|
||||||
|
else {
|
||||||
|
lowercase(arg);
|
||||||
|
if ((arg2 = strchr(arg, ':')) == NULL ||
|
||||||
|
arg2[1] == '\0') {
|
||||||
|
fatal("%s line %d: "
|
||||||
|
"Invalid permitted CNAME \"%s\"",
|
||||||
|
filename, linenum, arg);
|
||||||
|
}
|
||||||
|
*arg2 = '\0';
|
||||||
|
arg2++;
|
||||||
|
}
|
||||||
|
if (!*activep || value)
|
||||||
|
continue;
|
||||||
|
if (options->num_permitted_cnames >= MAX_CANON_DOMAINS)
|
||||||
|
fatal("%s line %d: too many permitted CNAMEs.",
|
||||||
|
filename, linenum);
|
||||||
|
cname = options->permitted_cnames +
|
||||||
|
options->num_permitted_cnames++;
|
||||||
|
cname->source_list = xstrdup(arg);
|
||||||
|
cname->target_list = xstrdup(arg2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case oCanonicaliseHostname:
|
||||||
|
intptr = &options->canonicalise_hostname;
|
||||||
|
multistate_ptr = multistate_canonicalisehostname;
|
||||||
|
goto parse_multistate;
|
||||||
|
|
||||||
|
case oCanonicaliseMaxDots:
|
||||||
|
intptr = &options->canonicalise_max_dots;
|
||||||
|
goto parse_int;
|
||||||
|
|
||||||
|
case oCanonicaliseFallbackLocal:
|
||||||
|
intptr = &options->canonicalise_fallback_local;
|
||||||
|
goto parse_flag;
|
||||||
|
|
||||||
case oDeprecated:
|
case oDeprecated:
|
||||||
debug("%s line %d: Deprecated option \"%s\"",
|
debug("%s line %d: Deprecated option \"%s\"",
|
||||||
filename, linenum, keyword);
|
filename, linenum, keyword);
|
||||||
|
@ -1426,6 +1526,11 @@ initialize_options(Options * options)
|
||||||
options->request_tty = -1;
|
options->request_tty = -1;
|
||||||
options->proxy_use_fdpass = -1;
|
options->proxy_use_fdpass = -1;
|
||||||
options->ignored_unknown = NULL;
|
options->ignored_unknown = NULL;
|
||||||
|
options->num_canonical_domains = 0;
|
||||||
|
options->num_permitted_cnames = 0;
|
||||||
|
options->canonicalise_max_dots = -1;
|
||||||
|
options->canonicalise_fallback_local = -1;
|
||||||
|
options->canonicalise_hostname = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1579,6 +1684,12 @@ fill_default_options(Options * options)
|
||||||
options->request_tty = REQUEST_TTY_AUTO;
|
options->request_tty = REQUEST_TTY_AUTO;
|
||||||
if (options->proxy_use_fdpass == -1)
|
if (options->proxy_use_fdpass == -1)
|
||||||
options->proxy_use_fdpass = 0;
|
options->proxy_use_fdpass = 0;
|
||||||
|
if (options->canonicalise_max_dots == -1)
|
||||||
|
options->canonicalise_max_dots = 1;
|
||||||
|
if (options->canonicalise_fallback_local == -1)
|
||||||
|
options->canonicalise_fallback_local = 1;
|
||||||
|
if (options->canonicalise_hostname == -1)
|
||||||
|
options->canonicalise_hostname = SSH_CANONICALISE_NO;
|
||||||
#define CLEAR_ON_NONE(v) \
|
#define CLEAR_ON_NONE(v) \
|
||||||
do { \
|
do { \
|
||||||
if (v != NULL && strcasecmp(v, "none") == 0) { \
|
if (v != NULL && strcasecmp(v, "none") == 0) { \
|
||||||
|
|
22
readconf.h
22
readconf.h
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: readconf.h,v 1.97 2013/10/14 22:22:03 djm Exp $ */
|
/* $OpenBSD: readconf.h,v 1.98 2013/10/16 02:31:46 djm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
|
@ -29,7 +29,13 @@ typedef struct {
|
||||||
/* Data structure for representing option data. */
|
/* Data structure for representing option data. */
|
||||||
|
|
||||||
#define MAX_SEND_ENV 256
|
#define MAX_SEND_ENV 256
|
||||||
#define SSH_MAX_HOSTS_FILES 256
|
#define SSH_MAX_HOSTS_FILES 32
|
||||||
|
#define MAX_CANON_DOMAINS 32
|
||||||
|
|
||||||
|
struct allowed_cname {
|
||||||
|
char *source_list;
|
||||||
|
char *target_list;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int forward_agent; /* Forward authentication agent. */
|
int forward_agent; /* Forward authentication agent. */
|
||||||
|
@ -140,9 +146,21 @@ typedef struct {
|
||||||
|
|
||||||
int proxy_use_fdpass;
|
int proxy_use_fdpass;
|
||||||
|
|
||||||
|
int num_canonical_domains;
|
||||||
|
char *canonical_domains[MAX_CANON_DOMAINS];
|
||||||
|
int canonicalise_hostname;
|
||||||
|
int canonicalise_max_dots;
|
||||||
|
int canonicalise_fallback_local;
|
||||||
|
int num_permitted_cnames;
|
||||||
|
struct allowed_cname permitted_cnames[MAX_CANON_DOMAINS];
|
||||||
|
|
||||||
char *ignored_unknown; /* Pattern list of unknown tokens to ignore */
|
char *ignored_unknown; /* Pattern list of unknown tokens to ignore */
|
||||||
} Options;
|
} Options;
|
||||||
|
|
||||||
|
#define SSH_CANONICALISE_NO 0
|
||||||
|
#define SSH_CANONICALISE_YES 1
|
||||||
|
#define SSH_CANONICALISE_ALWAYS 2
|
||||||
|
|
||||||
#define SSHCTL_MASTER_NO 0
|
#define SSHCTL_MASTER_NO 0
|
||||||
#define SSHCTL_MASTER_YES 1
|
#define SSHCTL_MASTER_YES 1
|
||||||
#define SSHCTL_MASTER_AUTO 2
|
#define SSHCTL_MASTER_AUTO 2
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: roaming_client.c,v 1.5 2013/05/17 00:13:14 djm Exp $ */
|
/* $OpenBSD: roaming_client.c,v 1.6 2013/10/16 02:31:46 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2004-2009 AppGate Network Security AB
|
* Copyright (c) 2004-2009 AppGate Network Security AB
|
||||||
*
|
*
|
||||||
|
@ -259,10 +259,10 @@ wait_for_roaming_reconnect(void)
|
||||||
if (c != '\n' && c != '\r')
|
if (c != '\n' && c != '\r')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (ssh_connect(host, &hostaddr, options.port,
|
if (ssh_connect(host, NULL, &hostaddr, options.port,
|
||||||
options.address_family, 1, &timeout_ms,
|
options.address_family, 1, &timeout_ms,
|
||||||
options.tcp_keep_alive, options.use_privileged_port,
|
options.tcp_keep_alive, options.use_privileged_port) == 0 &&
|
||||||
options.proxy_command) == 0 && roaming_resume() == 0) {
|
roaming_resume() == 0) {
|
||||||
packet_restore_state();
|
packet_restore_state();
|
||||||
reenter_guard = 0;
|
reenter_guard = 0;
|
||||||
fprintf(stderr, "[connection resumed]\n");
|
fprintf(stderr, "[connection resumed]\n");
|
||||||
|
|
9
ssh.1
9
ssh.1
|
@ -33,8 +33,8 @@
|
||||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.\" $OpenBSD: ssh.1,v 1.337 2013/10/15 14:10:25 jmc Exp $
|
.\" $OpenBSD: ssh.1,v 1.338 2013/10/16 02:31:46 djm Exp $
|
||||||
.Dd $Mdocdate: October 15 2013 $
|
.Dd $Mdocdate: October 16 2013 $
|
||||||
.Dt SSH 1
|
.Dt SSH 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
@ -417,6 +417,11 @@ For full details of the options listed below, and their possible values, see
|
||||||
.It AddressFamily
|
.It AddressFamily
|
||||||
.It BatchMode
|
.It BatchMode
|
||||||
.It BindAddress
|
.It BindAddress
|
||||||
|
.It CanonicalDomains
|
||||||
|
.It CanonicaliseFallbackLocal
|
||||||
|
.It CanonicaliseHostname
|
||||||
|
.It CanonicaliseMaxDots
|
||||||
|
.It CanonicalisePermittedCNAMEs
|
||||||
.It ChallengeResponseAuthentication
|
.It ChallengeResponseAuthentication
|
||||||
.It CheckHostIP
|
.It CheckHostIP
|
||||||
.It Cipher
|
.It Cipher
|
||||||
|
|
183
ssh.c
183
ssh.c
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: ssh.c,v 1.384 2013/10/14 23:31:01 djm Exp $ */
|
/* $OpenBSD: ssh.c,v 1.385 2013/10/16 02:31:46 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
|
@ -231,6 +231,134 @@ tilde_expand_paths(char **paths, u_int num_paths)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct addrinfo *
|
||||||
|
resolve_host(const char *name, u_int port, int logerr, char *cname, size_t clen)
|
||||||
|
{
|
||||||
|
char strport[NI_MAXSERV];
|
||||||
|
struct addrinfo hints, *res;
|
||||||
|
int gaierr, loglevel = SYSLOG_LEVEL_DEBUG1;
|
||||||
|
|
||||||
|
snprintf(strport, sizeof strport, "%u", port);
|
||||||
|
bzero(&hints, sizeof(hints));
|
||||||
|
hints.ai_family = options.address_family;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
if (cname != NULL)
|
||||||
|
hints.ai_flags = AI_CANONNAME;
|
||||||
|
if ((gaierr = getaddrinfo(name, strport, &hints, &res)) != 0) {
|
||||||
|
if (logerr || (gaierr != EAI_NONAME && gaierr != EAI_NODATA))
|
||||||
|
loglevel = SYSLOG_LEVEL_ERROR;
|
||||||
|
do_log2(loglevel, "%s: Could not resolve hostname %.100s: %s",
|
||||||
|
__progname, name, ssh_gai_strerror(gaierr));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (cname != NULL && res->ai_canonname != NULL) {
|
||||||
|
if (strlcpy(cname, res->ai_canonname, clen) >= clen) {
|
||||||
|
error("%s: host \"%s\" cname \"%s\" too long (max %lu)",
|
||||||
|
__func__, name, res->ai_canonname, (u_long)clen);
|
||||||
|
if (clen > 0)
|
||||||
|
*cname = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether the cname is a permitted replacement for the hostname
|
||||||
|
* and perform the replacement if it is.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
check_follow_cname(char **namep, const char *cname)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct allowed_cname *rule;
|
||||||
|
|
||||||
|
if (*cname == '\0' || options.num_permitted_cnames == 0 ||
|
||||||
|
strcmp(*namep, cname) == 0)
|
||||||
|
return 0;
|
||||||
|
if (options.canonicalise_hostname == SSH_CANONICALISE_NO)
|
||||||
|
return 0;
|
||||||
|
/*
|
||||||
|
* Don't attempt to canonicalise names that will be interpreted by
|
||||||
|
* a proxy unless the user specifically requests so.
|
||||||
|
*/
|
||||||
|
if (options.proxy_command != NULL &&
|
||||||
|
options.canonicalise_hostname != SSH_CANONICALISE_ALWAYS)
|
||||||
|
return 0;
|
||||||
|
debug3("%s: check \"%s\" CNAME \"%s\"", __func__, *namep, cname);
|
||||||
|
for (i = 0; i < options.num_permitted_cnames; i++) {
|
||||||
|
rule = options.permitted_cnames + i;
|
||||||
|
if (match_pattern_list(*namep, rule->source_list,
|
||||||
|
strlen(rule->source_list), 1) != 1 ||
|
||||||
|
match_pattern_list(cname, rule->target_list,
|
||||||
|
strlen(rule->target_list), 1) != 1)
|
||||||
|
continue;
|
||||||
|
verbose("Canonicalised DNS aliased hostname "
|
||||||
|
"\"%s\" => \"%s\"", *namep, cname);
|
||||||
|
free(*namep);
|
||||||
|
*namep = xstrdup(cname);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Attempt to resolve the supplied hostname after applying the user's
|
||||||
|
* canonicalisation rules. Returns the address list for the host or NULL
|
||||||
|
* if no name was found after canonicalisation.
|
||||||
|
*/
|
||||||
|
static struct addrinfo *
|
||||||
|
resolve_canonicalise(char **hostp, u_int port)
|
||||||
|
{
|
||||||
|
int i, ndots;
|
||||||
|
char *cp, *fullhost, cname_target[NI_MAXHOST];
|
||||||
|
struct addrinfo *addrs;
|
||||||
|
|
||||||
|
if (options.canonicalise_hostname == SSH_CANONICALISE_NO)
|
||||||
|
return NULL;
|
||||||
|
/*
|
||||||
|
* Don't attempt to canonicalise names that will be interpreted by
|
||||||
|
* a proxy unless the user specifically requests so.
|
||||||
|
*/
|
||||||
|
if (options.proxy_command != NULL &&
|
||||||
|
options.canonicalise_hostname != SSH_CANONICALISE_ALWAYS)
|
||||||
|
return NULL;
|
||||||
|
/* Don't apply canonicalisation to sufficiently-qualified hostnames */
|
||||||
|
ndots = 0;
|
||||||
|
for (cp = *hostp; *cp != '\0'; cp++) {
|
||||||
|
if (*cp == '.')
|
||||||
|
ndots++;
|
||||||
|
}
|
||||||
|
if (ndots > options.canonicalise_max_dots) {
|
||||||
|
debug3("%s: not canonicalising hostname \"%s\" (max dots %d)",
|
||||||
|
__func__, *hostp, options.canonicalise_max_dots);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* Attempt each supplied suffix */
|
||||||
|
for (i = 0; i < options.num_canonical_domains; i++) {
|
||||||
|
*cname_target = '\0';
|
||||||
|
xasprintf(&fullhost, "%s.%s.", *hostp,
|
||||||
|
options.canonical_domains[i]);
|
||||||
|
if ((addrs = resolve_host(fullhost, options.port, 0,
|
||||||
|
cname_target, sizeof(cname_target))) == NULL) {
|
||||||
|
free(fullhost);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Remove trailing '.' */
|
||||||
|
fullhost[strlen(fullhost) - 1] = '\0';
|
||||||
|
/* Follow CNAME if requested */
|
||||||
|
if (!check_follow_cname(&fullhost, cname_target)) {
|
||||||
|
debug("Canonicalised hostname \"%s\" => \"%s\"",
|
||||||
|
*hostp, fullhost);
|
||||||
|
}
|
||||||
|
free(*hostp);
|
||||||
|
*hostp = fullhost;
|
||||||
|
return addrs;
|
||||||
|
}
|
||||||
|
if (!options.canonicalise_fallback_local)
|
||||||
|
fatal("%s: Could not resolve host \"%s\"", __progname, host);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Main program for the ssh client.
|
* Main program for the ssh client.
|
||||||
*/
|
*/
|
||||||
|
@ -240,12 +368,14 @@ main(int ac, char **av)
|
||||||
int i, r, opt, exit_status, use_syslog;
|
int i, r, opt, exit_status, use_syslog;
|
||||||
char *p, *cp, *line, *argv0, buf[MAXPATHLEN], *host_arg, *logfile;
|
char *p, *cp, *line, *argv0, buf[MAXPATHLEN], *host_arg, *logfile;
|
||||||
char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
|
char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
|
||||||
|
char cname[NI_MAXHOST];
|
||||||
struct stat st;
|
struct stat st;
|
||||||
struct passwd *pw;
|
struct passwd *pw;
|
||||||
int timeout_ms;
|
int timeout_ms;
|
||||||
extern int optind, optreset;
|
extern int optind, optreset;
|
||||||
extern char *optarg;
|
extern char *optarg;
|
||||||
Forward fwd;
|
Forward fwd;
|
||||||
|
struct addrinfo *addrs = NULL;
|
||||||
|
|
||||||
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
|
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
|
||||||
sanitise_stdfd();
|
sanitise_stdfd();
|
||||||
|
@ -630,9 +760,9 @@ main(int ac, char **av)
|
||||||
usage();
|
usage();
|
||||||
options.user = p;
|
options.user = p;
|
||||||
*cp = '\0';
|
*cp = '\0';
|
||||||
host = ++cp;
|
host = xstrdup(++cp);
|
||||||
} else
|
} else
|
||||||
host = *av;
|
host = xstrdup(*av);
|
||||||
if (ac > 1) {
|
if (ac > 1) {
|
||||||
optind = optreset = 1;
|
optind = optreset = 1;
|
||||||
goto again;
|
goto again;
|
||||||
|
@ -644,6 +774,9 @@ main(int ac, char **av)
|
||||||
if (!host)
|
if (!host)
|
||||||
usage();
|
usage();
|
||||||
|
|
||||||
|
lowercase(host);
|
||||||
|
host_arg = xstrdup(host);
|
||||||
|
|
||||||
OpenSSL_add_all_algorithms();
|
OpenSSL_add_all_algorithms();
|
||||||
ERR_load_crypto_strings();
|
ERR_load_crypto_strings();
|
||||||
|
|
||||||
|
@ -728,6 +861,10 @@ main(int ac, char **av)
|
||||||
strcmp(options.proxy_command, "-") == 0 &&
|
strcmp(options.proxy_command, "-") == 0 &&
|
||||||
options.proxy_use_fdpass)
|
options.proxy_use_fdpass)
|
||||||
fatal("ProxyCommand=- and ProxyUseFDPass are incompatible");
|
fatal("ProxyCommand=- and ProxyUseFDPass are incompatible");
|
||||||
|
#ifndef HAVE_CYGWIN
|
||||||
|
if (original_effective_uid != 0)
|
||||||
|
options.use_privileged_port = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* reinit */
|
/* reinit */
|
||||||
log_init(argv0, options.log_level, SYSLOG_FACILITY_USER, !use_syslog);
|
log_init(argv0, options.log_level, SYSLOG_FACILITY_USER, !use_syslog);
|
||||||
|
@ -762,10 +899,26 @@ main(int ac, char **av)
|
||||||
options.port = default_ssh_port();
|
options.port = default_ssh_port();
|
||||||
|
|
||||||
/* preserve host name given on command line for %n expansion */
|
/* preserve host name given on command line for %n expansion */
|
||||||
host_arg = host;
|
|
||||||
if (options.hostname != NULL) {
|
if (options.hostname != NULL) {
|
||||||
host = percent_expand(options.hostname,
|
cp = percent_expand(options.hostname,
|
||||||
"h", host, (char *)NULL);
|
"h", host, (char *)NULL);
|
||||||
|
free(host);
|
||||||
|
host = cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If canonicalisation requested then try to apply it */
|
||||||
|
if (options.canonicalise_hostname != SSH_CANONICALISE_NO)
|
||||||
|
addrs = resolve_canonicalise(&host, options.port);
|
||||||
|
/*
|
||||||
|
* If canonicalisation not requested, or if it failed then try to
|
||||||
|
* resolve the bare hostname name using the system resolver's usual
|
||||||
|
* search rules.
|
||||||
|
*/
|
||||||
|
if (addrs == NULL) {
|
||||||
|
if ((addrs = resolve_host(host, options.port, 1,
|
||||||
|
cname, sizeof(cname))) == NULL)
|
||||||
|
cleanup_exit(255); /* resolve_host logs the error */
|
||||||
|
check_follow_cname(&host, cname);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gethostname(thishost, sizeof(thishost)) == -1)
|
if (gethostname(thishost, sizeof(thishost)) == -1)
|
||||||
|
@ -803,16 +956,15 @@ main(int ac, char **av)
|
||||||
timeout_ms = options.connection_timeout * 1000;
|
timeout_ms = options.connection_timeout * 1000;
|
||||||
|
|
||||||
/* Open a connection to the remote host. */
|
/* Open a connection to the remote host. */
|
||||||
if (ssh_connect(host, &hostaddr, options.port,
|
if (ssh_connect(host, addrs, &hostaddr, options.port,
|
||||||
options.address_family, options.connection_attempts, &timeout_ms,
|
options.address_family, options.connection_attempts,
|
||||||
options.tcp_keep_alive,
|
&timeout_ms, options.tcp_keep_alive,
|
||||||
#ifdef HAVE_CYGWIN
|
options.use_privileged_port) != 0)
|
||||||
options.use_privileged_port,
|
exit(255);
|
||||||
#else
|
|
||||||
original_effective_uid == 0 && options.use_privileged_port,
|
freeaddrinfo(addrs);
|
||||||
#endif
|
packet_set_timeout(options.server_alive_interval,
|
||||||
options.proxy_command) != 0)
|
options.server_alive_count_max);
|
||||||
exit(255);
|
|
||||||
|
|
||||||
if (timeout_ms > 0)
|
if (timeout_ms > 0)
|
||||||
debug3("timeout: %d ms remain after connect", timeout_ms);
|
debug3("timeout: %d ms remain after connect", timeout_ms);
|
||||||
|
@ -1621,4 +1773,3 @@ main_sigchld_handler(int sig)
|
||||||
signal(sig, main_sigchld_handler);
|
signal(sig, main_sigchld_handler);
|
||||||
errno = save_errno;
|
errno = save_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
75
ssh_config.5
75
ssh_config.5
|
@ -33,8 +33,8 @@
|
||||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.\" $OpenBSD: ssh_config.5,v 1.170 2013/10/15 14:10:25 jmc Exp $
|
.\" $OpenBSD: ssh_config.5,v 1.171 2013/10/16 02:31:46 djm Exp $
|
||||||
.Dd $Mdocdate: October 15 2013 $
|
.Dd $Mdocdate: October 16 2013 $
|
||||||
.Dt SSH_CONFIG 5
|
.Dt SSH_CONFIG 5
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
@ -200,6 +200,77 @@ Note that this option does not work if
|
||||||
.Cm UsePrivilegedPort
|
.Cm UsePrivilegedPort
|
||||||
is set to
|
is set to
|
||||||
.Dq yes .
|
.Dq yes .
|
||||||
|
.It Cm CanonicalDomains
|
||||||
|
when
|
||||||
|
.Cm CanonicaliseHostname
|
||||||
|
is enabled, this option specifies the list of domain suffixes in which to
|
||||||
|
search for the specified destination host.
|
||||||
|
.It Cm CanonicaliseFallbackLocal
|
||||||
|
specified whether to fail with an error when hostname canonicalisation fails.
|
||||||
|
The default of
|
||||||
|
.Dq no
|
||||||
|
will attempt to lookup the unqualified hostname using the system resolver's
|
||||||
|
search rules.
|
||||||
|
A value of
|
||||||
|
.Dq yes
|
||||||
|
will cause
|
||||||
|
.Xr ssh 1
|
||||||
|
to fail instantly if
|
||||||
|
.Cm CanonicaliseHostname
|
||||||
|
is enabled and the target hostname cannot be found in any of the domains
|
||||||
|
specified by
|
||||||
|
.Cm CanonicalDomains .
|
||||||
|
.It Cm CanonicaliseHostname
|
||||||
|
controls whether explicit hostname canonicalisation is performed.
|
||||||
|
The default
|
||||||
|
.Dq no
|
||||||
|
is not to perform any name rewriting and let the system resolver handle all
|
||||||
|
hostname lookups.
|
||||||
|
If set to
|
||||||
|
.Dq yes
|
||||||
|
then, for connections that do not use a
|
||||||
|
.Cm ProxyCommand ,
|
||||||
|
.Xr ssh 1
|
||||||
|
will attempt to canonicalise the hostname specified on the command line
|
||||||
|
using the
|
||||||
|
.Cm CanonicalDomains
|
||||||
|
suffixes and
|
||||||
|
.Cm CanonicalisePermittedCNAMEs
|
||||||
|
rules.
|
||||||
|
If
|
||||||
|
.Cm CanonicaliseHostname
|
||||||
|
is set to
|
||||||
|
.Dq always ,
|
||||||
|
then canonicalisation is applied to proxied connections to.
|
||||||
|
.It Cm CanonicaliseMaxDots
|
||||||
|
specifies the maximum number of dot characters in a hostname name before
|
||||||
|
canonicalisation is disabled.
|
||||||
|
The default of
|
||||||
|
.Dq 1
|
||||||
|
allows a single dot (i.e. hostname.subdomain)
|
||||||
|
.It Cm CanonicalisePermittedCNAMEs
|
||||||
|
specifies rules to determine whether CNAMEs should be followed when
|
||||||
|
canonicalising hostnames.
|
||||||
|
The rules consist of one or more arguments of
|
||||||
|
.Sm off
|
||||||
|
.Ar source_domain_list : Ar target_domain_list
|
||||||
|
.Sm on
|
||||||
|
where
|
||||||
|
.Ar source_domain_list
|
||||||
|
is a pattern-list of domains that are may follow CNAMEs in canonicalisation
|
||||||
|
and
|
||||||
|
.Ar target_domain_list
|
||||||
|
is a pattern-list of domains that they may resove to.
|
||||||
|
.Pp
|
||||||
|
For example,
|
||||||
|
.Dq *.a.example.com:*.b.example.com,*.c.example.com
|
||||||
|
will allow hostnames matching
|
||||||
|
.Dq *.a.example.com
|
||||||
|
to be canonicalised to names in the
|
||||||
|
.Dq *.b.example.com
|
||||||
|
or
|
||||||
|
.Dq *.c.example.com
|
||||||
|
domains.
|
||||||
.It Cm ChallengeResponseAuthentication
|
.It Cm ChallengeResponseAuthentication
|
||||||
Specifies whether to use challenge-response authentication.
|
Specifies whether to use challenge-response authentication.
|
||||||
The argument to this keyword must be
|
The argument to this keyword must be
|
||||||
|
|
74
sshconnect.c
74
sshconnect.c
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: sshconnect.c,v 1.240 2013/09/19 01:26:29 djm Exp $ */
|
/* $OpenBSD: sshconnect.c,v 1.241 2013/10/16 02:31:46 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
|
@ -86,7 +86,7 @@ expand_proxy_command(const char *proxy_command, const char *user,
|
||||||
{
|
{
|
||||||
char *tmp, *ret, strport[NI_MAXSERV];
|
char *tmp, *ret, strport[NI_MAXSERV];
|
||||||
|
|
||||||
snprintf(strport, sizeof strport, "%hu", port);
|
snprintf(strport, sizeof strport, "%d", port);
|
||||||
xasprintf(&tmp, "exec %s", proxy_command);
|
xasprintf(&tmp, "exec %s", proxy_command);
|
||||||
ret = percent_expand(tmp, "h", host, "p", strport,
|
ret = percent_expand(tmp, "h", host, "p", strport,
|
||||||
"r", options.user, (char *)NULL);
|
"r", options.user, (char *)NULL);
|
||||||
|
@ -170,8 +170,6 @@ ssh_proxy_fdpass_connect(const char *host, u_short port,
|
||||||
|
|
||||||
/* Set the connection file descriptors. */
|
/* Set the connection file descriptors. */
|
||||||
packet_set_connection(sock, sock);
|
packet_set_connection(sock, sock);
|
||||||
packet_set_timeout(options.server_alive_interval,
|
|
||||||
options.server_alive_count_max);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -187,16 +185,6 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
char *shell;
|
char *shell;
|
||||||
|
|
||||||
if (!strcmp(proxy_command, "-")) {
|
|
||||||
packet_set_connection(STDIN_FILENO, STDOUT_FILENO);
|
|
||||||
packet_set_timeout(options.server_alive_interval,
|
|
||||||
options.server_alive_count_max);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.proxy_use_fdpass)
|
|
||||||
return ssh_proxy_fdpass_connect(host, port, proxy_command);
|
|
||||||
|
|
||||||
if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
|
if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
|
||||||
shell = _PATH_BSHELL;
|
shell = _PATH_BSHELL;
|
||||||
|
|
||||||
|
@ -258,8 +246,6 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
|
||||||
|
|
||||||
/* Set the connection file descriptors. */
|
/* Set the connection file descriptors. */
|
||||||
packet_set_connection(pout[0], pin[1]);
|
packet_set_connection(pout[0], pin[1]);
|
||||||
packet_set_timeout(options.server_alive_interval,
|
|
||||||
options.server_alive_count_max);
|
|
||||||
|
|
||||||
/* Indicate OK return */
|
/* Indicate OK return */
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -429,33 +415,18 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr,
|
||||||
* and %p substituted for host and port, respectively) to use to contact
|
* and %p substituted for host and port, respectively) to use to contact
|
||||||
* the daemon.
|
* the daemon.
|
||||||
*/
|
*/
|
||||||
int
|
static int
|
||||||
ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
|
ssh_connect_direct(const char *host, struct addrinfo *aitop,
|
||||||
u_short port, int family, int connection_attempts, int *timeout_ms,
|
struct sockaddr_storage *hostaddr, u_short port, int family,
|
||||||
int want_keepalive, int needpriv, const char *proxy_command)
|
int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv)
|
||||||
{
|
{
|
||||||
int gaierr;
|
|
||||||
int on = 1;
|
int on = 1;
|
||||||
int sock = -1, attempt;
|
int sock = -1, attempt;
|
||||||
char ntop[NI_MAXHOST], strport[NI_MAXSERV];
|
char ntop[NI_MAXHOST], strport[NI_MAXSERV];
|
||||||
struct addrinfo hints, *ai, *aitop;
|
struct addrinfo *ai;
|
||||||
|
|
||||||
debug2("ssh_connect: needpriv %d", needpriv);
|
debug2("ssh_connect: needpriv %d", needpriv);
|
||||||
|
|
||||||
/* If a proxy command is given, connect using it. */
|
|
||||||
if (proxy_command != NULL)
|
|
||||||
return ssh_proxy_connect(host, port, proxy_command);
|
|
||||||
|
|
||||||
/* No proxy command. */
|
|
||||||
|
|
||||||
memset(&hints, 0, sizeof(hints));
|
|
||||||
hints.ai_family = family;
|
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
|
||||||
snprintf(strport, sizeof strport, "%u", port);
|
|
||||||
if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
|
|
||||||
fatal("%s: Could not resolve hostname %.100s: %s", __progname,
|
|
||||||
host, ssh_gai_strerror(gaierr));
|
|
||||||
|
|
||||||
for (attempt = 0; attempt < connection_attempts; attempt++) {
|
for (attempt = 0; attempt < connection_attempts; attempt++) {
|
||||||
if (attempt > 0) {
|
if (attempt > 0) {
|
||||||
/* Sleep a moment before retrying. */
|
/* Sleep a moment before retrying. */
|
||||||
|
@ -467,7 +438,8 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
|
||||||
* sequence until the connection succeeds.
|
* sequence until the connection succeeds.
|
||||||
*/
|
*/
|
||||||
for (ai = aitop; ai; ai = ai->ai_next) {
|
for (ai = aitop; ai; ai = ai->ai_next) {
|
||||||
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
|
if (ai->ai_family != AF_INET &&
|
||||||
|
ai->ai_family != AF_INET6)
|
||||||
continue;
|
continue;
|
||||||
if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
|
if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
|
||||||
ntop, sizeof(ntop), strport, sizeof(strport),
|
ntop, sizeof(ntop), strport, sizeof(strport),
|
||||||
|
@ -500,8 +472,6 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
|
||||||
break; /* Successful connection. */
|
break; /* Successful connection. */
|
||||||
}
|
}
|
||||||
|
|
||||||
freeaddrinfo(aitop);
|
|
||||||
|
|
||||||
/* Return failure if we didn't get a successful connection. */
|
/* Return failure if we didn't get a successful connection. */
|
||||||
if (sock == -1) {
|
if (sock == -1) {
|
||||||
error("ssh: connect to host %s port %s: %s",
|
error("ssh: connect to host %s port %s: %s",
|
||||||
|
@ -519,12 +489,28 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
|
||||||
|
|
||||||
/* Set the connection. */
|
/* Set the connection. */
|
||||||
packet_set_connection(sock, sock);
|
packet_set_connection(sock, sock);
|
||||||
packet_set_timeout(options.server_alive_interval,
|
|
||||||
options.server_alive_count_max);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ssh_connect(const char *host, struct addrinfo *addrs,
|
||||||
|
struct sockaddr_storage *hostaddr, u_short port, int family,
|
||||||
|
int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv)
|
||||||
|
{
|
||||||
|
if (options.proxy_command == NULL) {
|
||||||
|
return ssh_connect_direct(host, addrs, hostaddr, port, family,
|
||||||
|
connection_attempts, timeout_ms, want_keepalive, needpriv);
|
||||||
|
} else if (strcmp(options.proxy_command, "-") == 0) {
|
||||||
|
packet_set_connection(STDIN_FILENO, STDOUT_FILENO);
|
||||||
|
return 0; /* Always succeeds */
|
||||||
|
} else if (options.proxy_use_fdpass) {
|
||||||
|
return ssh_proxy_fdpass_connect(host, port,
|
||||||
|
options.proxy_command);
|
||||||
|
}
|
||||||
|
return ssh_proxy_connect(host, port, options.proxy_command);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
send_client_banner(int connection_out, int minor1)
|
send_client_banner(int connection_out, int minor1)
|
||||||
{
|
{
|
||||||
|
@ -1265,7 +1251,7 @@ void
|
||||||
ssh_login(Sensitive *sensitive, const char *orighost,
|
ssh_login(Sensitive *sensitive, const char *orighost,
|
||||||
struct sockaddr *hostaddr, u_short port, struct passwd *pw, int timeout_ms)
|
struct sockaddr *hostaddr, u_short port, struct passwd *pw, int timeout_ms)
|
||||||
{
|
{
|
||||||
char *host, *cp;
|
char *host;
|
||||||
char *server_user, *local_user;
|
char *server_user, *local_user;
|
||||||
|
|
||||||
local_user = xstrdup(pw->pw_name);
|
local_user = xstrdup(pw->pw_name);
|
||||||
|
@ -1273,9 +1259,7 @@ ssh_login(Sensitive *sensitive, const char *orighost,
|
||||||
|
|
||||||
/* Convert the user-supplied hostname into all lowercase. */
|
/* Convert the user-supplied hostname into all lowercase. */
|
||||||
host = xstrdup(orighost);
|
host = xstrdup(orighost);
|
||||||
for (cp = host; *cp; cp++)
|
lowercase(host);
|
||||||
if (isupper(*cp))
|
|
||||||
*cp = (char)tolower(*cp);
|
|
||||||
|
|
||||||
/* Exchange protocol version identification strings with the server. */
|
/* Exchange protocol version identification strings with the server. */
|
||||||
ssh_exchange_identification(timeout_ms);
|
ssh_exchange_identification(timeout_ms);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: sshconnect.h,v 1.27 2010/11/29 23:45:51 djm Exp $ */
|
/* $OpenBSD: sshconnect.h,v 1.28 2013/10/16 02:31:47 djm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||||
|
@ -31,9 +31,9 @@ struct Sensitive {
|
||||||
int external_keysign;
|
int external_keysign;
|
||||||
};
|
};
|
||||||
|
|
||||||
int
|
struct addrinfo;
|
||||||
ssh_connect(const char *, struct sockaddr_storage *, u_short, int, int,
|
int ssh_connect(const char *, struct addrinfo *, struct sockaddr_storage *,
|
||||||
int *, int, int, const char *);
|
u_short, int, int, int *, int, int);
|
||||||
void ssh_kill_proxy_command(void);
|
void ssh_kill_proxy_command(void);
|
||||||
|
|
||||||
void ssh_login(Sensitive *, const char *, struct sockaddr *, u_short,
|
void ssh_login(Sensitive *, const char *, struct sockaddr *, u_short,
|
||||||
|
|
Loading…
Reference in New Issue