upstream commit
Tweak config reparsing with host canonicalisation Make the second pass through the config files always run when hostname canonicalisation is enabled. Add a "Match canonical" criteria that allows ssh_config Match blocks to trigger only in the second config pass. Add a -G option to ssh that causes it to parse its configuration and dump the result to stdout, similar to "sshd -T" Allow ssh_config Port options set in the second config parse phase to be applied (they were being ignored). bz#2267 bz#2286; ok markus
This commit is contained in:
parent
5c0dafd38b
commit
957fbceb0f
450
readconf.c
450
readconf.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: readconf.c,v 1.220 2014/07/15 15:54:14 millert Exp $ */
|
||||
/* $OpenBSD: readconf.c,v 1.221 2014/10/08 22:20:25 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
|
@ -41,6 +41,9 @@
|
|||
#ifdef HAVE_UTIL_H
|
||||
#include <util.h>
|
||||
#endif
|
||||
#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
|
||||
# include <vis.h>
|
||||
#endif
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
|
@ -56,6 +59,7 @@
|
|||
#include "kex.h"
|
||||
#include "mac.h"
|
||||
#include "uidswap.h"
|
||||
#include "myproposal.h"
|
||||
|
||||
/* Format of the configuration file:
|
||||
|
||||
|
@ -135,7 +139,7 @@ typedef enum {
|
|||
oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
|
||||
oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
|
||||
oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
|
||||
oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
|
||||
oPubkeyAuthentication,
|
||||
oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
|
||||
oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
|
||||
oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
|
||||
|
@ -212,7 +216,7 @@ static struct {
|
|||
{ "globalknownhostsfile", oGlobalKnownHostsFile },
|
||||
{ "globalknownhostsfile2", oDeprecated },
|
||||
{ "userknownhostsfile", oUserKnownHostsFile },
|
||||
{ "userknownhostsfile2", oDeprecated },
|
||||
{ "userknownhostsfile2", oDeprecated },
|
||||
{ "connectionattempts", oConnectionAttempts },
|
||||
{ "batchmode", oBatchMode },
|
||||
{ "checkhostip", oCheckHostIP },
|
||||
|
@ -466,7 +470,7 @@ execute_in_shell(const char *cmd)
|
|||
if (!WIFEXITED(status)) {
|
||||
error("command '%.100s' exited abnormally", cmd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
debug3("command returned status %d", WEXITSTATUS(status));
|
||||
return WEXITSTATUS(status);
|
||||
}
|
||||
|
@ -476,11 +480,12 @@ execute_in_shell(const char *cmd)
|
|||
*/
|
||||
static int
|
||||
match_cfg_line(Options *options, char **condition, struct passwd *pw,
|
||||
const char *host_arg, const char *filename, int linenum)
|
||||
const char *host_arg, const char *original_host, int post_canon,
|
||||
const char *filename, int linenum)
|
||||
{
|
||||
char *arg, *attrib, *cmd, *cp = *condition, *host;
|
||||
char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria;
|
||||
const char *ruser;
|
||||
int r, port, result = 1, attributes = 0;
|
||||
int r, port, this_result, result = 1, attributes = 0, negate;
|
||||
size_t len;
|
||||
char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
|
||||
|
||||
|
@ -497,21 +502,38 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw,
|
|||
} else
|
||||
host = xstrdup(host_arg);
|
||||
|
||||
debug3("checking match for '%s' host %s", cp, host);
|
||||
while ((attrib = strdelim(&cp)) && *attrib != '\0') {
|
||||
attributes++;
|
||||
debug2("checking match for '%s' host %s originally %s",
|
||||
cp, host, original_host);
|
||||
while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') {
|
||||
criteria = NULL;
|
||||
this_result = 1;
|
||||
if ((negate = attrib[0] == '!'))
|
||||
attrib++;
|
||||
/* criteria "all" and "canonical" have no argument */
|
||||
if (strcasecmp(attrib, "all") == 0) {
|
||||
if (attributes != 1 ||
|
||||
if (attributes > 1 ||
|
||||
((arg = strdelim(&cp)) != NULL && *arg != '\0')) {
|
||||
error("'all' cannot be combined with other "
|
||||
"Match attributes");
|
||||
error("%.200s line %d: '%s' cannot be combined "
|
||||
"with other Match attributes",
|
||||
filename, linenum, oattrib);
|
||||
result = -1;
|
||||
goto out;
|
||||
}
|
||||
*condition = cp;
|
||||
result = 1;
|
||||
if (result)
|
||||
result = negate ? 0 : 1;
|
||||
goto out;
|
||||
}
|
||||
attributes++;
|
||||
if (strcasecmp(attrib, "canonical") == 0) {
|
||||
r = !!post_canon; /* force bitmask member to boolean */
|
||||
if (r == (negate ? 1 : 0))
|
||||
this_result = result = 0;
|
||||
debug3("%.200s line %d: %smatched '%s'",
|
||||
filename, linenum,
|
||||
this_result ? "" : "not ", oattrib);
|
||||
continue;
|
||||
}
|
||||
/* All other criteria require an argument */
|
||||
if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
|
||||
error("Missing Match criteria for %s", attrib);
|
||||
result = -1;
|
||||
|
@ -519,31 +541,25 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw,
|
|||
}
|
||||
len = strlen(arg);
|
||||
if (strcasecmp(attrib, "host") == 0) {
|
||||
if (match_hostname(host, arg, len) != 1)
|
||||
result = 0;
|
||||
else
|
||||
debug("%.200s line %d: matched 'Host %.100s' ",
|
||||
filename, linenum, host);
|
||||
criteria = xstrdup(host);
|
||||
r = match_hostname(host, arg, len) == 1;
|
||||
if (r == (negate ? 1 : 0))
|
||||
this_result = result = 0;
|
||||
} else if (strcasecmp(attrib, "originalhost") == 0) {
|
||||
if (match_hostname(host_arg, arg, len) != 1)
|
||||
result = 0;
|
||||
else
|
||||
debug("%.200s line %d: matched "
|
||||
"'OriginalHost %.100s' ",
|
||||
filename, linenum, host_arg);
|
||||
criteria = xstrdup(original_host);
|
||||
r = match_hostname(original_host, arg, len) == 1;
|
||||
if (r == (negate ? 1 : 0))
|
||||
this_result = result = 0;
|
||||
} else if (strcasecmp(attrib, "user") == 0) {
|
||||
if (match_pattern_list(ruser, arg, len, 0) != 1)
|
||||
result = 0;
|
||||
else
|
||||
debug("%.200s line %d: matched 'User %.100s' ",
|
||||
filename, linenum, ruser);
|
||||
criteria = xstrdup(ruser);
|
||||
r = match_pattern_list(ruser, arg, len, 0) == 1;
|
||||
if (r == (negate ? 1 : 0))
|
||||
this_result = result = 0;
|
||||
} else if (strcasecmp(attrib, "localuser") == 0) {
|
||||
if (match_pattern_list(pw->pw_name, arg, len, 0) != 1)
|
||||
result = 0;
|
||||
else
|
||||
debug("%.200s line %d: matched "
|
||||
"'LocalUser %.100s' ",
|
||||
filename, linenum, pw->pw_name);
|
||||
criteria = xstrdup(pw->pw_name);
|
||||
r = match_pattern_list(pw->pw_name, arg, len, 0) == 1;
|
||||
if (r == (negate ? 1 : 0))
|
||||
this_result = result = 0;
|
||||
} else if (strcasecmp(attrib, "exec") == 0) {
|
||||
if (gethostname(thishost, sizeof(thishost)) == -1)
|
||||
fatal("gethostname: %s", strerror(errno));
|
||||
|
@ -556,47 +572,49 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw,
|
|||
"d", pw->pw_dir,
|
||||
"h", host,
|
||||
"l", thishost,
|
||||
"n", host_arg,
|
||||
"n", original_host,
|
||||
"p", portstr,
|
||||
"r", ruser,
|
||||
"u", pw->pw_name,
|
||||
(char *)NULL);
|
||||
if (result != 1) {
|
||||
/* skip execution if prior predicate failed */
|
||||
debug("%.200s line %d: skipped exec \"%.100s\"",
|
||||
filename, linenum, cmd);
|
||||
} else {
|
||||
r = execute_in_shell(cmd);
|
||||
if (r == -1) {
|
||||
fatal("%.200s line %d: match exec "
|
||||
"'%.100s' error", filename,
|
||||
linenum, cmd);
|
||||
} else if (r == 0) {
|
||||
debug("%.200s line %d: matched "
|
||||
"'exec \"%.100s\"'", filename,
|
||||
linenum, cmd);
|
||||
} else {
|
||||
debug("%.200s line %d: no match "
|
||||
"'exec \"%.100s\"'", filename,
|
||||
linenum, cmd);
|
||||
result = 0;
|
||||
}
|
||||
debug3("%.200s line %d: skipped exec "
|
||||
"\"%.100s\"", filename, linenum, cmd);
|
||||
free(cmd);
|
||||
continue;
|
||||
}
|
||||
r = execute_in_shell(cmd);
|
||||
if (r == -1) {
|
||||
fatal("%.200s line %d: match exec "
|
||||
"'%.100s' error", filename,
|
||||
linenum, cmd);
|
||||
}
|
||||
criteria = xstrdup(cmd);
|
||||
free(cmd);
|
||||
/* Force exit status to boolean */
|
||||
r = r == 0;
|
||||
if (r == (negate ? 1 : 0))
|
||||
this_result = result = 0;
|
||||
} else {
|
||||
error("Unsupported Match attribute %s", attrib);
|
||||
result = -1;
|
||||
goto out;
|
||||
}
|
||||
debug3("%.200s line %d: %smatched '%s \"%.100s\"' ",
|
||||
filename, linenum, this_result ? "": "not ",
|
||||
oattrib, criteria);
|
||||
free(criteria);
|
||||
}
|
||||
if (attributes == 0) {
|
||||
error("One or more attributes required for Match");
|
||||
result = -1;
|
||||
goto out;
|
||||
}
|
||||
debug3("match %sfound", result ? "" : "not ");
|
||||
*condition = cp;
|
||||
out:
|
||||
if (result != -1)
|
||||
debug2("match %sfound", result ? "" : "not ");
|
||||
*condition = cp;
|
||||
free(host);
|
||||
return result;
|
||||
}
|
||||
|
@ -719,7 +737,8 @@ static const struct multistate multistate_canonicalizehostname[] = {
|
|||
#define WHITESPACE " \t\r\n"
|
||||
int
|
||||
process_config_line(Options *options, struct passwd *pw, const char *host,
|
||||
char *line, const char *filename, int linenum, int *activep, int userconfig)
|
||||
const char *original_host, char *line, const char *filename,
|
||||
int linenum, int *activep, int flags)
|
||||
{
|
||||
char *s, **charptr, *endofnumber, *keyword, *arg, *arg2;
|
||||
char **cpptr, fwdarg[256];
|
||||
|
@ -775,7 +794,9 @@ parse_time:
|
|||
if (!arg || *arg == '\0')
|
||||
fatal("%s line %d: missing time value.",
|
||||
filename, linenum);
|
||||
if ((value = convtime(arg)) == -1)
|
||||
if (strcmp(arg, "none") == 0)
|
||||
value = -1;
|
||||
else if ((value = convtime(arg)) == -1)
|
||||
fatal("%s line %d: invalid time value.",
|
||||
filename, linenum);
|
||||
if (*activep && *intptr == -1)
|
||||
|
@ -812,7 +833,7 @@ parse_time:
|
|||
case oForwardX11Trusted:
|
||||
intptr = &options->forward_x11_trusted;
|
||||
goto parse_flag;
|
||||
|
||||
|
||||
case oForwardX11Timeout:
|
||||
intptr = &options->forward_x11_timeout;
|
||||
goto parse_time;
|
||||
|
@ -947,7 +968,8 @@ parse_time:
|
|||
if (*intptr >= SSH_MAX_IDENTITY_FILES)
|
||||
fatal("%.200s line %d: Too many identity files specified (max %d).",
|
||||
filename, linenum, SSH_MAX_IDENTITY_FILES);
|
||||
add_identity_file(options, NULL, arg, userconfig);
|
||||
add_identity_file(options, NULL,
|
||||
arg, flags & SSHCONF_USERCONF);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1195,8 +1217,8 @@ parse_int:
|
|||
if (cmdline)
|
||||
fatal("Host directive not supported as a command-line "
|
||||
"option");
|
||||
value = match_cfg_line(options, &s, pw, host,
|
||||
filename, linenum);
|
||||
value = match_cfg_line(options, &s, pw, host, original_host,
|
||||
flags & SSHCONF_POSTCANON, filename, linenum);
|
||||
if (value < 0)
|
||||
fatal("%.200s line %d: Bad Match condition", filename,
|
||||
linenum);
|
||||
|
@ -1444,7 +1466,7 @@ parse_int:
|
|||
return 0;
|
||||
|
||||
default:
|
||||
fatal("process_config_line: Unimplemented opcode %d", opcode);
|
||||
fatal("%s: Unimplemented opcode %d", __func__, opcode);
|
||||
}
|
||||
|
||||
/* Check that there is no garbage at end of line. */
|
||||
|
@ -1464,7 +1486,7 @@ parse_int:
|
|||
|
||||
int
|
||||
read_config_file(const char *filename, struct passwd *pw, const char *host,
|
||||
Options *options, int flags)
|
||||
const char *original_host, Options *options, int flags)
|
||||
{
|
||||
FILE *f;
|
||||
char line[1024];
|
||||
|
@ -1495,8 +1517,8 @@ read_config_file(const char *filename, struct passwd *pw, const char *host,
|
|||
while (fgets(line, sizeof(line), f)) {
|
||||
/* Update line number counter. */
|
||||
linenum++;
|
||||
if (process_config_line(options, pw, host, line, filename,
|
||||
linenum, &active, flags & SSHCONF_USERCONF) != 0)
|
||||
if (process_config_line(options, pw, host, original_host,
|
||||
line, filename, linenum, &active, flags) != 0)
|
||||
bad_options++;
|
||||
}
|
||||
fclose(f);
|
||||
|
@ -2009,3 +2031,295 @@ parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remo
|
|||
fwd->listen_path = NULL;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* XXX the following is a near-vebatim copy from servconf.c; refactor */
|
||||
static const char *
|
||||
fmt_multistate_int(int val, const struct multistate *m)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
for (i = 0; m[i].key != NULL; i++) {
|
||||
if (m[i].value == val)
|
||||
return m[i].key;
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
static const char *
|
||||
fmt_intarg(OpCodes code, int val)
|
||||
{
|
||||
if (val == -1)
|
||||
return "unset";
|
||||
switch (code) {
|
||||
case oAddressFamily:
|
||||
return fmt_multistate_int(val, multistate_addressfamily);
|
||||
case oVerifyHostKeyDNS:
|
||||
case oStrictHostKeyChecking:
|
||||
return fmt_multistate_int(val, multistate_yesnoask);
|
||||
case oControlMaster:
|
||||
return fmt_multistate_int(val, multistate_controlmaster);
|
||||
case oTunnel:
|
||||
return fmt_multistate_int(val, multistate_tunnel);
|
||||
case oRequestTTY:
|
||||
return fmt_multistate_int(val, multistate_requesttty);
|
||||
case oCanonicalizeHostname:
|
||||
return fmt_multistate_int(val, multistate_canonicalizehostname);
|
||||
case oProtocol:
|
||||
switch (val) {
|
||||
case SSH_PROTO_1:
|
||||
return "1";
|
||||
case SSH_PROTO_2:
|
||||
return "2";
|
||||
case (SSH_PROTO_1|SSH_PROTO_2):
|
||||
return "2,1";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
default:
|
||||
switch (val) {
|
||||
case 0:
|
||||
return "no";
|
||||
case 1:
|
||||
return "yes";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char *
|
||||
lookup_opcode_name(OpCodes code)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
for (i = 0; keywords[i].name != NULL; i++)
|
||||
if (keywords[i].opcode == code)
|
||||
return(keywords[i].name);
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
static void
|
||||
dump_cfg_int(OpCodes code, int val)
|
||||
{
|
||||
printf("%s %d\n", lookup_opcode_name(code), val);
|
||||
}
|
||||
|
||||
static void
|
||||
dump_cfg_fmtint(OpCodes code, int val)
|
||||
{
|
||||
printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
|
||||
}
|
||||
|
||||
static void
|
||||
dump_cfg_string(OpCodes code, const char *val)
|
||||
{
|
||||
if (val == NULL)
|
||||
return;
|
||||
printf("%s %s\n", lookup_opcode_name(code), val);
|
||||
}
|
||||
|
||||
static void
|
||||
dump_cfg_strarray(OpCodes code, u_int count, char **vals)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
printf("%s %s\n", lookup_opcode_name(code), vals[i]);
|
||||
}
|
||||
|
||||
static void
|
||||
dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
printf("%s", lookup_opcode_name(code));
|
||||
for (i = 0; i < count; i++)
|
||||
printf(" %s", vals[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
|
||||
{
|
||||
const struct Forward *fwd;
|
||||
u_int i;
|
||||
|
||||
/* oDynamicForward */
|
||||
for (i = 0; i < count; i++) {
|
||||
fwd = &fwds[i];
|
||||
if (code == oDynamicForward &&
|
||||
strcmp(fwd->connect_host, "socks") != 0)
|
||||
continue;
|
||||
if (code == oLocalForward &&
|
||||
strcmp(fwd->connect_host, "socks") == 0)
|
||||
continue;
|
||||
printf("%s", lookup_opcode_name(code));
|
||||
if (fwd->listen_port == PORT_STREAMLOCAL)
|
||||
printf(" %s", fwd->listen_path);
|
||||
else if (fwd->listen_host == NULL)
|
||||
printf(" %d", fwd->listen_port);
|
||||
else {
|
||||
printf(" [%s]:%d",
|
||||
fwd->listen_host, fwd->listen_port);
|
||||
}
|
||||
if (code != oDynamicForward) {
|
||||
if (fwd->connect_port == PORT_STREAMLOCAL)
|
||||
printf(" %s", fwd->connect_path);
|
||||
else if (fwd->connect_host == NULL)
|
||||
printf(" %d", fwd->connect_port);
|
||||
else {
|
||||
printf(" [%s]:%d",
|
||||
fwd->connect_host, fwd->connect_port);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dump_client_config(Options *o, const char *host)
|
||||
{
|
||||
int i;
|
||||
char vbuf[5];
|
||||
|
||||
/* Most interesting options first: user, host, port */
|
||||
dump_cfg_string(oUser, o->user);
|
||||
dump_cfg_string(oHostName, host);
|
||||
dump_cfg_int(oPort, o->port);
|
||||
|
||||
/* Flag options */
|
||||
dump_cfg_fmtint(oAddressFamily, o->address_family);
|
||||
dump_cfg_fmtint(oBatchMode, o->batch_mode);
|
||||
dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local);
|
||||
dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname);
|
||||
dump_cfg_fmtint(oChallengeResponseAuthentication, o->challenge_response_authentication);
|
||||
dump_cfg_fmtint(oCheckHostIP, o->check_host_ip);
|
||||
dump_cfg_fmtint(oCompression, o->compression);
|
||||
dump_cfg_fmtint(oControlMaster, o->control_master);
|
||||
dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
|
||||
dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
|
||||
dump_cfg_fmtint(oForwardAgent, o->forward_agent);
|
||||
dump_cfg_fmtint(oForwardX11, o->forward_x11);
|
||||
dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
|
||||
dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
|
||||
#ifdef GSSAPI
|
||||
dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
|
||||
dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
|
||||
#endif /* GSSAPI */
|
||||
dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
|
||||
dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
|
||||
dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
|
||||
dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication);
|
||||
dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost);
|
||||
dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication);
|
||||
dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command);
|
||||
dump_cfg_fmtint(oProtocol, o->protocol);
|
||||
dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
|
||||
dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
|
||||
dump_cfg_fmtint(oRequestTTY, o->request_tty);
|
||||
dump_cfg_fmtint(oRhostsRSAAuthentication, o->rhosts_rsa_authentication);
|
||||
dump_cfg_fmtint(oRSAAuthentication, o->rsa_authentication);
|
||||
dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
|
||||
dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking);
|
||||
dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive);
|
||||
dump_cfg_fmtint(oTunnel, o->tun_open);
|
||||
dump_cfg_fmtint(oUsePrivilegedPort, o->use_privileged_port);
|
||||
dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns);
|
||||
dump_cfg_fmtint(oVisualHostKey, o->visual_host_key);
|
||||
|
||||
/* Integer options */
|
||||
dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots);
|
||||
dump_cfg_int(oCompressionLevel, o->compression_level);
|
||||
dump_cfg_int(oConnectionAttempts, o->connection_attempts);
|
||||
dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout);
|
||||
dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
|
||||
dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
|
||||
dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
|
||||
|
||||
/* String options */
|
||||
dump_cfg_string(oBindAddress, o->bind_address);
|
||||
dump_cfg_string(oCiphers, o->ciphers ? o->ciphers : KEX_CLIENT_ENCRYPT);
|
||||
dump_cfg_string(oControlPath, o->control_path);
|
||||
dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms ? o->hostkeyalgorithms : KEX_DEFAULT_PK_ALG);
|
||||
dump_cfg_string(oHostKeyAlias, o->host_key_alias);
|
||||
dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
|
||||
dump_cfg_string(oKexAlgorithms, o->kex_algorithms ? o->kex_algorithms : KEX_CLIENT_KEX);
|
||||
dump_cfg_string(oLocalCommand, o->local_command);
|
||||
dump_cfg_string(oLogLevel, log_level_name(o->log_level));
|
||||
dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC);
|
||||
dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
|
||||
dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
|
||||
dump_cfg_string(oProxyCommand, o->proxy_command);
|
||||
dump_cfg_string(oXAuthLocation, o->xauth_location);
|
||||
|
||||
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_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles);
|
||||
dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
|
||||
dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
|
||||
|
||||
/* Special cases */
|
||||
|
||||
/* oConnectTimeout */
|
||||
if (o->connection_timeout == -1)
|
||||
printf("connecttimeout none\n");
|
||||
else
|
||||
dump_cfg_int(oConnectTimeout, o->connection_timeout);
|
||||
|
||||
/* oTunnelDevice */
|
||||
printf("tunneldevice");
|
||||
if (o->tun_local == SSH_TUNID_ANY)
|
||||
printf(" any");
|
||||
else
|
||||
printf(" %d", o->tun_local);
|
||||
if (o->tun_remote == SSH_TUNID_ANY)
|
||||
printf(":any");
|
||||
else
|
||||
printf(":%d", o->tun_remote);
|
||||
printf("\n");
|
||||
|
||||
/* oCanonicalizePermittedCNAMEs */
|
||||
if ( o->num_permitted_cnames > 0) {
|
||||
printf("canonicalizePermittedcnames");
|
||||
for (i = 0; i < o->num_permitted_cnames; i++) {
|
||||
printf(" %s:%s", o->permitted_cnames[i].source_list,
|
||||
o->permitted_cnames[i].target_list);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* oCipher */
|
||||
if (o->cipher != SSH_CIPHER_NOT_SET)
|
||||
printf("Cipher %s\n", cipher_name(o->cipher));
|
||||
|
||||
/* oControlPersist */
|
||||
if (o->control_persist == 0 || o->control_persist_timeout == 0)
|
||||
dump_cfg_fmtint(oControlPersist, o->control_persist);
|
||||
else
|
||||
dump_cfg_int(oControlPersist, o->control_persist_timeout);
|
||||
|
||||
/* oEscapeChar */
|
||||
if (o->escape_char == SSH_ESCAPECHAR_NONE)
|
||||
printf("escapechar none\n");
|
||||
else {
|
||||
vis(vbuf, o->escape_char, VIS_WHITE, 0);
|
||||
printf("escapechar %s\n", vbuf);
|
||||
}
|
||||
|
||||
/* oIPQoS */
|
||||
printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
|
||||
printf("%s\n", iptos2str(o->ip_qos_bulk));
|
||||
|
||||
/* oRekeyLimit */
|
||||
printf("rekeylimit %lld %d\n",
|
||||
(long long)o->rekey_limit, o->rekey_interval);
|
||||
|
||||
/* oStreamLocalBindMask */
|
||||
printf("streamlocalbindmask 0%o\n",
|
||||
o->fwd_opts.streamlocal_bind_mask);
|
||||
}
|
||||
|
|
10
readconf.h
10
readconf.h
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: readconf.h,v 1.102 2014/07/15 15:54:14 millert Exp $ */
|
||||
/* $OpenBSD: readconf.h,v 1.103 2014/10/08 22:20:25 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
@ -164,17 +164,19 @@ typedef struct {
|
|||
|
||||
#define SSHCONF_CHECKPERM 1 /* check permissions on config file */
|
||||
#define SSHCONF_USERCONF 2 /* user provided config file not system */
|
||||
#define SSHCONF_POSTCANON 4 /* After hostname canonicalisation */
|
||||
|
||||
void initialize_options(Options *);
|
||||
void fill_default_options(Options *);
|
||||
void fill_default_options_for_canonicalization(Options *);
|
||||
int process_config_line(Options *, struct passwd *, const char *, char *,
|
||||
const char *, int, int *, int);
|
||||
int process_config_line(Options *, struct passwd *, const char *,
|
||||
const char *, char *, const char *, int, int *, int);
|
||||
int read_config_file(const char *, struct passwd *, const char *,
|
||||
Options *, int);
|
||||
const char *, Options *, int);
|
||||
int parse_forward(struct Forward *, const char *, int, int);
|
||||
int default_ssh_port(void);
|
||||
int option_clear_or_none(const char *);
|
||||
void dump_client_config(Options *o, const char *host);
|
||||
|
||||
void add_local_forward(Options *, const struct Forward *);
|
||||
void add_remote_forward(Options *, const struct Forward *);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ssh-keysign.c,v 1.42 2014/04/29 18:01:49 markus Exp $ */
|
||||
/* $OpenBSD: ssh-keysign.c,v 1.43 2014/10/08 22:20:25 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2002 Markus Friedl. All rights reserved.
|
||||
*
|
||||
|
@ -187,7 +187,7 @@ main(int argc, char **argv)
|
|||
|
||||
/* verify that ssh-keysign is enabled by the admin */
|
||||
initialize_options(&options);
|
||||
(void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, "", &options, 0);
|
||||
(void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, "", "", &options, 0);
|
||||
fill_default_options(&options);
|
||||
if (options.enable_ssh_keysign != 1)
|
||||
fatal("ssh-keysign not enabled in %s",
|
||||
|
|
14
ssh.1
14
ssh.1
|
@ -33,8 +33,8 @@
|
|||
.\" (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.1,v 1.349 2014/08/30 15:33:50 sobrado Exp $
|
||||
.Dd $Mdocdate: August 30 2014 $
|
||||
.\" $OpenBSD: ssh.1,v 1.350 2014/10/08 22:20:25 djm Exp $
|
||||
.Dd $Mdocdate: October 8 2014 $
|
||||
.Dt SSH 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -43,7 +43,7 @@
|
|||
.Sh SYNOPSIS
|
||||
.Nm ssh
|
||||
.Bk -words
|
||||
.Op Fl 1246AaCfgKkMNnqsTtVvXxYy
|
||||
.Op Fl 1246AaCfgGKkMNnqsTtVvXxYy
|
||||
.Op Fl b Ar bind_address
|
||||
.Op Fl c Ar cipher_spec
|
||||
.Op Fl D Oo Ar bind_address : Oc Ns Ar port
|
||||
|
@ -251,6 +251,14 @@ then a client started with
|
|||
.Fl f
|
||||
will wait for all remote port forwards to be successfully established
|
||||
before placing itself in the background.
|
||||
.It Fl G
|
||||
Causes
|
||||
.Nm
|
||||
to print its configuration after evaluating
|
||||
.Cm Host
|
||||
and
|
||||
.Cm Match
|
||||
blocks and exit.
|
||||
.It Fl g
|
||||
Allows remote hosts to connect to local forwarded ports.
|
||||
If used on a multiplexed connection, then this option must be specified
|
||||
|
|
80
ssh.c
80
ssh.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ssh.c,v 1.407 2014/07/17 07:22:19 djm Exp $ */
|
||||
/* $OpenBSD: ssh.c,v 1.408 2014/10/08 22:20:25 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
|
@ -384,27 +384,49 @@ resolve_canonicalize(char **hostp, int port)
|
|||
* file if the user specifies a config file on the command line.
|
||||
*/
|
||||
static void
|
||||
process_config_files(struct passwd *pw)
|
||||
process_config_files(const char *host_arg, struct passwd *pw, int post_canon)
|
||||
{
|
||||
char buf[MAXPATHLEN];
|
||||
int r;
|
||||
|
||||
if (config != NULL) {
|
||||
if (strcasecmp(config, "none") != 0 &&
|
||||
!read_config_file(config, pw, host, &options,
|
||||
SSHCONF_USERCONF))
|
||||
!read_config_file(config, pw, host, host_arg, &options,
|
||||
SSHCONF_USERCONF | (post_canon ? SSHCONF_POSTCANON : 0)))
|
||||
fatal("Can't open user config file %.100s: "
|
||||
"%.100s", config, strerror(errno));
|
||||
} else {
|
||||
r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir,
|
||||
_PATH_SSH_USER_CONFFILE);
|
||||
if (r > 0 && (size_t)r < sizeof(buf))
|
||||
(void)read_config_file(buf, pw, host, &options,
|
||||
SSHCONF_CHECKPERM|SSHCONF_USERCONF);
|
||||
(void)read_config_file(buf, pw, host, host_arg,
|
||||
&options, SSHCONF_CHECKPERM | SSHCONF_USERCONF |
|
||||
(post_canon ? SSHCONF_POSTCANON : 0));
|
||||
|
||||
/* Read systemwide configuration file after user config. */
|
||||
(void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, host,
|
||||
&options, 0);
|
||||
(void)read_config_file(_PATH_HOST_CONFIG_FILE, pw,
|
||||
host, host_arg, &options,
|
||||
post_canon ? SSHCONF_POSTCANON : 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Rewrite the port number in an addrinfo list of addresses */
|
||||
static void
|
||||
set_addrinfo_port(struct addrinfo *addrs, int port)
|
||||
{
|
||||
struct addrinfo *addr;
|
||||
|
||||
for (addr = addrs; addr != NULL; addr = addr->ai_next) {
|
||||
switch (addr->ai_family) {
|
||||
case AF_INET:
|
||||
((struct sockaddr_in *)addr->ai_addr)->
|
||||
sin_port = htons(port);
|
||||
break;
|
||||
case AF_INET6:
|
||||
((struct sockaddr_in6 *)addr->ai_addr)->
|
||||
sin6_port = htons(port);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -414,7 +436,7 @@ process_config_files(struct passwd *pw)
|
|||
int
|
||||
main(int ac, char **av)
|
||||
{
|
||||
int i, r, opt, exit_status, use_syslog;
|
||||
int i, r, opt, exit_status, use_syslog, config_test = 0;
|
||||
char *p, *cp, *line, *argv0, buf[MAXPATHLEN], *host_arg, *logfile;
|
||||
char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
|
||||
char cname[NI_MAXHOST];
|
||||
|
@ -507,7 +529,7 @@ main(int ac, char **av)
|
|||
|
||||
again:
|
||||
while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx"
|
||||
"ACD:E:F:I:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) {
|
||||
"ACD:E:F:GI:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) {
|
||||
switch (opt) {
|
||||
case '1':
|
||||
options.protocol = SSH_PROTO_1;
|
||||
|
@ -540,6 +562,9 @@ main(int ac, char **av)
|
|||
case 'E':
|
||||
logfile = xstrdup(optarg);
|
||||
break;
|
||||
case 'G':
|
||||
config_test = 1;
|
||||
break;
|
||||
case 'Y':
|
||||
options.forward_x11 = 1;
|
||||
options.forward_x11_trusted = 1;
|
||||
|
@ -788,9 +813,9 @@ main(int ac, char **av)
|
|||
break;
|
||||
case 'o':
|
||||
line = xstrdup(optarg);
|
||||
if (process_config_line(&options, pw, host ? host : "",
|
||||
line, "command-line", 0, NULL, SSHCONF_USERCONF)
|
||||
!= 0)
|
||||
if (process_config_line(&options, pw,
|
||||
host ? host : "", host ? host : "", line,
|
||||
"command-line", 0, NULL, SSHCONF_USERCONF) != 0)
|
||||
exit(255);
|
||||
free(line);
|
||||
break;
|
||||
|
@ -899,7 +924,7 @@ main(int ac, char **av)
|
|||
);
|
||||
|
||||
/* Parse the configuration files */
|
||||
process_config_files(pw);
|
||||
process_config_files(host_arg, pw, 0);
|
||||
|
||||
/* Hostname canonicalisation needs a few options filled. */
|
||||
fill_default_options_for_canonicalization(&options);
|
||||
|
@ -911,6 +936,8 @@ main(int ac, char **av)
|
|||
"h", host, (char *)NULL);
|
||||
free(host);
|
||||
host = cp;
|
||||
free(options.hostname);
|
||||
options.hostname = xstrdup(host);
|
||||
}
|
||||
|
||||
/* If canonicalization requested then try to apply it */
|
||||
|
@ -945,12 +972,22 @@ main(int ac, char **av)
|
|||
}
|
||||
|
||||
/*
|
||||
* If the target hostname has changed as a result of canonicalisation
|
||||
* then re-parse the configuration files as new stanzas may match.
|
||||
* If canonicalisation is enabled then re-parse the configuration
|
||||
* files as new stanzas may match.
|
||||
*/
|
||||
if (strcasecmp(host_arg, host) != 0) {
|
||||
debug("Hostname has changed; re-reading configuration");
|
||||
process_config_files(pw);
|
||||
if (options.canonicalize_hostname != 0) {
|
||||
debug("Re-reading configuration after hostname "
|
||||
"canonicalisation");
|
||||
free(options.hostname);
|
||||
options.hostname = xstrdup(host);
|
||||
process_config_files(host_arg, pw, 1);
|
||||
/*
|
||||
* Address resolution happens early with canonicalisation
|
||||
* enabled and the port number may have changed since, so
|
||||
* reset it in address list
|
||||
*/
|
||||
if (addrs != NULL && options.port > 0)
|
||||
set_addrinfo_port(addrs, options.port);
|
||||
}
|
||||
|
||||
/* Fill configuration defaults. */
|
||||
|
@ -1052,6 +1089,11 @@ main(int ac, char **av)
|
|||
}
|
||||
free(conn_hash_hex);
|
||||
|
||||
if (config_test) {
|
||||
dump_client_config(&options, host);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (muxclient_command != 0 && options.control_path == NULL)
|
||||
fatal("No ControlPath specified for \"-O\" command");
|
||||
if (options.control_path != NULL)
|
||||
|
|
55
ssh_config.5
55
ssh_config.5
|
@ -33,8 +33,8 @@
|
|||
.\" (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.192 2014/08/30 15:33:50 sobrado Exp $
|
||||
.Dd $Mdocdate: August 30 2014 $
|
||||
.\" $OpenBSD: ssh_config.5,v 1.193 2014/10/08 22:20:25 djm Exp $
|
||||
.Dd $Mdocdate: October 8 2014 $
|
||||
.Dt SSH_CONFIG 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -65,7 +65,10 @@ The configuration files contain sections separated by
|
|||
.Dq Host
|
||||
specifications, and that section is only applied for hosts that
|
||||
match one of the patterns given in the specification.
|
||||
The matched host name is the one given on the command line.
|
||||
The matched host name is usually the one given on the command line
|
||||
(see the
|
||||
.Cm CanonicalizeHostname
|
||||
option for exceptions.)
|
||||
.Pp
|
||||
Since the first obtained value for each parameter is used, more
|
||||
host-specific declarations should be given near the beginning of the
|
||||
|
@ -109,10 +112,12 @@ A single
|
|||
.Ql *
|
||||
as a pattern can be used to provide global
|
||||
defaults for all hosts.
|
||||
The host is the
|
||||
The host is usually the
|
||||
.Ar hostname
|
||||
argument given on the command line (i.e. the name is not converted to
|
||||
a canonicalized host name before matching).
|
||||
argument given on the command line
|
||||
(see the
|
||||
.Cm CanonicalizeHostname
|
||||
option for exceptions.)
|
||||
.Pp
|
||||
A pattern entry may be negated by prefixing it with an exclamation mark
|
||||
.Pq Sq !\& .
|
||||
|
@ -134,19 +139,40 @@ or
|
|||
keyword) to be used only when the conditions following the
|
||||
.Cm Match
|
||||
keyword are satisfied.
|
||||
Match conditions are specified using one or more keyword/criteria pairs
|
||||
Match conditions are specified using one or more critera
|
||||
or the single token
|
||||
.Cm all
|
||||
which matches all criteria.
|
||||
The available keywords are:
|
||||
which always matches.
|
||||
The available criteria keywords are:
|
||||
.Cm canonical ,
|
||||
.Cm exec ,
|
||||
.Cm host ,
|
||||
.Cm originalhost ,
|
||||
.Cm user ,
|
||||
and
|
||||
.Cm localuser .
|
||||
The
|
||||
.Cm all
|
||||
criteria must appear alone or immediately after
|
||||
.Cm canonical.
|
||||
Other criteria may be combined arbitrarily.
|
||||
All criteria but
|
||||
.Cm all
|
||||
and
|
||||
.Cm canonical
|
||||
require an argument.
|
||||
Criteria may be negated by prepending an exclamation mark
|
||||
.Pq Sq !\& .
|
||||
.Pp
|
||||
The
|
||||
.Cm canonical
|
||||
keywork matches only when the configuration file is being re-parsed
|
||||
after hostname canonicalization (see the
|
||||
.Cm CanonicalizeHostname
|
||||
option.)
|
||||
This may be useful to specify conditions that work with canonical host
|
||||
names only.
|
||||
The
|
||||
.Cm exec
|
||||
keyword executes the specified command under the user's shell.
|
||||
If the command returns a zero exit status then the condition is considered true.
|
||||
|
@ -179,7 +205,9 @@ The criteria for the
|
|||
keyword are matched against the target hostname, after any substitution
|
||||
by the
|
||||
.Cm Hostname
|
||||
option.
|
||||
or
|
||||
.Cm CanonicalizeHostname
|
||||
options.
|
||||
The
|
||||
.Cm originalhost
|
||||
keyword matches against the hostname as it was specified on the command-line.
|
||||
|
@ -264,10 +292,11 @@ is set to
|
|||
.Dq always ,
|
||||
then canonicalization is applied to proxied connections too.
|
||||
.Pp
|
||||
If this option is enabled and canonicalisation results in the target hostname
|
||||
changing, then the configuration files are processed again using the new
|
||||
target name to pick up any new configuration in matching
|
||||
If this option is enabled, then the configuration files are processed
|
||||
again using the new target name to pick up any new configuration in matching
|
||||
.Cm Host
|
||||
and
|
||||
.Cm Match
|
||||
stanzas.
|
||||
.It Cm CanonicalizeMaxDots
|
||||
Specifies the maximum number of dot characters in a hostname before
|
||||
|
|
Loading…
Reference in New Issue