From fe92421772243702ecb18b862dbeb51a9bdbbc6e Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Sun, 15 May 2011 08:44:45 +1000 Subject: - djm@cvs.openbsd.org 2011/05/06 21:31:38 [readconf.c ssh_config.5] support negated Host matching, e.g. Host *.example.org !c.example.org User mekmitasdigoat Will match "a.example.org", "b.example.org", but not "c.example.org" ok markus@ --- readconf.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'readconf.c') diff --git a/readconf.c b/readconf.c index eb4a8b9ee..927e7fefa 100644 --- a/readconf.c +++ b/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.190 2010/11/13 23:27:50 djm Exp $ */ +/* $OpenBSD: readconf.c,v 1.191 2011/05/06 21:31:38 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -354,7 +354,7 @@ process_config_line(Options *options, const char *host, int *activep) { char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256]; - int opcode, *intptr, value, value2, scale; + int negated, opcode, *intptr, value, value2, scale; LogLevel *log_level_ptr; long long orig, val64; size_t len; @@ -793,12 +793,28 @@ parse_int: case oHost: *activep = 0; - while ((arg = strdelim(&s)) != NULL && *arg != '\0') + arg2 = NULL; + while ((arg = strdelim(&s)) != NULL && *arg != '\0') { + negated = *arg == '!'; + if (negated) + arg++; if (match_pattern(host, arg)) { - debug("Applying options for %.100s", arg); + if (negated) { + debug("%.200s line %d: Skipping Host " + "block because of negated match " + "for %.100s", filename, linenum, + arg); + *activep = 0; + break; + } + if (!*activep) + arg2 = arg; /* logged below */ *activep = 1; - break; } + } + if (*activep) + debug("%.200s line %d: Applying options for %.100s", + filename, linenum, arg2); /* Avoid garbage check below, as strdelim is done. */ return 0; -- cgit v1.2.3 From 21771e22d3e23a10cb01983b2df83d47362eadda Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Sun, 15 May 2011 08:45:50 +1000 Subject: - djm@cvs.openbsd.org 2011/05/06 21:34:32 [clientloop.c mux.c readconf.c readconf.h ssh.c ssh_config.5] Add a RequestTTY ssh_config option to allow configuration-based control over tty allocation (like -t/-T); ok markus@ --- ChangeLog | 4 ++++ clientloop.c | 24 +++++++++++------------- mux.c | 7 +++---- readconf.c | 28 ++++++++++++++++++++++++++-- readconf.h | 8 +++++++- ssh.c | 41 ++++++++++++++++++++++------------------- ssh_config.5 | 19 ++++++++++++++++++- 7 files changed, 91 insertions(+), 40 deletions(-) (limited to 'readconf.c') diff --git a/ChangeLog b/ChangeLog index caec1dd27..67e651335 100644 --- a/ChangeLog +++ b/ChangeLog @@ -32,6 +32,10 @@ Will match "a.example.org", "b.example.org", but not "c.example.org" ok markus@ + - djm@cvs.openbsd.org 2011/05/06 21:34:32 + [clientloop.c mux.c readconf.c readconf.h ssh.c ssh_config.5] + Add a RequestTTY ssh_config option to allow configuration-based + control over tty allocation (like -t/-T); ok markus@ 20110510 - (dtucker) [openbsd-compat/openssl-compat.{c,h}] Bug #1882: fix diff --git a/clientloop.c b/clientloop.c index 502dd982c..5bd757dfb 100644 --- a/clientloop.c +++ b/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.232 2011/04/17 22:42:41 djm Exp $ */ +/* $OpenBSD: clientloop.c,v 1.233 2011/05/06 21:34:32 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -130,9 +130,6 @@ extern int muxserver_sock; /* XXX use mux_client_cleanup() instead */ */ extern char *host; -/* Force TTY allocation */ -extern int force_tty_flag; - /* * Flag to indicate that we have received a window change signal which has * not yet been processed. This will cause a message indicating the new @@ -662,7 +659,7 @@ client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr) atomicio(vwrite, fileno(stderr), buffer_ptr(berr), buffer_len(berr)); - leave_raw_mode(force_tty_flag); + leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); /* * Free (and clear) the buffer to reduce the amount of data that gets @@ -683,7 +680,7 @@ client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr) buffer_init(bout); buffer_init(berr); - enter_raw_mode(force_tty_flag); + enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); } static void @@ -826,7 +823,7 @@ process_cmdline(void) bzero(&fwd, sizeof(fwd)); fwd.listen_host = fwd.connect_host = NULL; - leave_raw_mode(force_tty_flag); + leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); handler = signal(SIGINT, SIG_IGN); cmd = s = read_passphrase("\r\nssh> ", RP_ECHO); if (s == NULL) @@ -930,7 +927,7 @@ process_cmdline(void) out: signal(SIGINT, handler); - enter_raw_mode(force_tty_flag); + enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); if (cmd) xfree(cmd); if (fwd.listen_host != NULL) @@ -1049,7 +1046,8 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, * more new connections). */ /* Restore tty modes. */ - leave_raw_mode(force_tty_flag); + leave_raw_mode( + options.request_tty == REQUEST_TTY_FORCE); /* Stop listening for new connections. */ channel_stop_listening(); @@ -1344,7 +1342,7 @@ client_channel_closed(int id, void *arg) { channel_cancel_cleanup(id); session_closed = 1; - leave_raw_mode(force_tty_flag); + leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); } /* @@ -1415,7 +1413,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) signal(SIGWINCH, window_change_handler); if (have_pty) - enter_raw_mode(force_tty_flag); + enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); if (compat20) { session_ident = ssh2_chan_id; @@ -1559,7 +1557,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) channel_free_all(); if (have_pty) - leave_raw_mode(force_tty_flag); + leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); /* restore blocking io */ if (!isatty(fileno(stdin))) @@ -2142,7 +2140,7 @@ client_stop_mux(void) void cleanup_exit(int i) { - leave_raw_mode(force_tty_flag); + leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); leave_non_blocking(); if (options.control_path != NULL && muxserver_sock != -1) unlink(options.control_path); diff --git a/mux.c b/mux.c index fb24c0f97..1afd1bdf3 100644 --- a/mux.c +++ b/mux.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mux.c,v 1.26 2011/05/05 05:12:08 djm Exp $ */ +/* $OpenBSD: mux.c,v 1.27 2011/05/06 21:34:32 djm Exp $ */ /* * Copyright (c) 2002-2008 Damien Miller * @@ -87,7 +87,6 @@ /* from ssh.c */ extern int tty_flag; -extern int force_tty_flag; extern Options options; extern int stdin_null_flag; extern char *host; @@ -1710,7 +1709,7 @@ mux_client_request_session(int fd) signal(SIGWINCH, control_client_sigrelay); if (tty_flag) - enter_raw_mode(force_tty_flag); + enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); /* * Stick around until the controlee closes the client_fd. @@ -1739,7 +1738,7 @@ mux_client_request_session(int fd) } close(fd); - leave_raw_mode(force_tty_flag); + leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); if (muxclient_terminate) { debug2("Exiting on signal %d", muxclient_terminate); diff --git a/readconf.c b/readconf.c index 927e7fefa..4780ae289 100644 --- a/readconf.c +++ b/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.191 2011/05/06 21:31:38 djm Exp $ */ +/* $OpenBSD: readconf.c,v 1.192 2011/05/06 21:34:32 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -134,7 +134,7 @@ typedef enum { oHashKnownHosts, oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication, - oKexAlgorithms, oIPQoS, + oKexAlgorithms, oIPQoS, oRequestTTY, oDeprecated, oUnsupported } OpCodes; @@ -245,6 +245,7 @@ static struct { #endif { "kexalgorithms", oKexAlgorithms }, { "ipqos", oIPQoS }, + { "requesttty", oRequestTTY }, { NULL, oBadOption } }; @@ -1013,6 +1014,26 @@ parse_int: intptr = &options->use_roaming; goto parse_flag; + case oRequestTTY: + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%s line %d: missing argument.", + filename, linenum); + intptr = &options->request_tty; + if (strcasecmp(arg, "yes") == 0) + value = REQUEST_TTY_YES; + else if (strcasecmp(arg, "no") == 0) + value = REQUEST_TTY_NO; + else if (strcasecmp(arg, "force") == 0) + value = REQUEST_TTY_FORCE; + else if (strcasecmp(arg, "auto") == 0) + value = REQUEST_TTY_AUTO; + else + fatal("Unsupported RequestTTY \"%s\"", arg); + if (*activep && *intptr == -1) + *intptr = value; + break; + case oDeprecated: debug("%s line %d: Deprecated option \"%s\"", filename, linenum, keyword); @@ -1173,6 +1194,7 @@ initialize_options(Options * options) options->zero_knowledge_password_authentication = -1; options->ip_qos_interactive = -1; options->ip_qos_bulk = -1; + options->request_tty = -1; } /* @@ -1331,6 +1353,8 @@ fill_default_options(Options * options) options->ip_qos_interactive = IPTOS_LOWDELAY; if (options->ip_qos_bulk == -1) options->ip_qos_bulk = IPTOS_THROUGHPUT; + if (options->request_tty == -1) + options->request_tty = REQUEST_TTY_AUTO; /* options->local_command should not be set by default */ /* options->proxy_command should not be set by default */ /* options->user will be set in the main program if appropriate */ diff --git a/readconf.h b/readconf.h index ee160dfe7..bc3e8c1bb 100644 --- a/readconf.h +++ b/readconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.h,v 1.88 2010/11/13 23:27:50 djm Exp $ */ +/* $OpenBSD: readconf.h,v 1.89 2011/05/06 21:34:32 djm Exp $ */ /* * Author: Tatu Ylonen @@ -132,6 +132,7 @@ typedef struct { int use_roaming; + int request_tty; } Options; #define SSHCTL_MASTER_NO 0 @@ -140,6 +141,11 @@ typedef struct { #define SSHCTL_MASTER_ASK 3 #define SSHCTL_MASTER_AUTO_ASK 4 +#define REQUEST_TTY_AUTO 0 +#define REQUEST_TTY_NO 1 +#define REQUEST_TTY_YES 2 +#define REQUEST_TTY_FORCE 3 + void initialize_options(Options *); void fill_default_options(Options *); int read_config_file(const char *, const char *, Options *, int); diff --git a/ssh.c b/ssh.c index 549dd5c22..7243fa2a6 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.358 2011/05/06 21:18:02 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.359 2011/05/06 21:34:32 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -114,10 +114,8 @@ extern char *__progname; /* Flag indicating whether debug mode is on. May be set on the command line. */ int debug_flag = 0; -/* Flag indicating whether a tty should be allocated */ +/* Flag indicating whether a tty should be requested */ int tty_flag = 0; -int no_tty_flag = 0; -int force_tty_flag = 0; /* don't exec a shell */ int no_shell_flag = 0; @@ -135,7 +133,7 @@ int stdin_null_flag = 0; int need_controlpersist_detach = 0; /* Copies of flags for ControlPersist foreground slave */ -int ostdin_null_flag, ono_shell_flag, ono_tty_flag, otty_flag; +int ostdin_null_flag, ono_shell_flag, otty_flag, orequest_tty; /* * Flag indicating that ssh should fork after authentication. This is useful @@ -389,9 +387,10 @@ main(int ac, char **av) #endif break; case 't': - if (tty_flag) - force_tty_flag = 1; - tty_flag = 1; + if (options.request_tty == REQUEST_TTY_YES) + options.request_tty = REQUEST_TTY_FORCE; + else + options.request_tty = REQUEST_TTY_YES; break; case 'v': if (debug_flag == 0) { @@ -434,7 +433,7 @@ main(int ac, char **av) optarg); exit(255); } - no_tty_flag = 1; + options.request_tty = REQUEST_TTY_NO; no_shell_flag = 1; options.clear_forwardings = 1; options.exit_on_forward_failure = 1; @@ -543,10 +542,10 @@ main(int ac, char **av) break; case 'N': no_shell_flag = 1; - no_tty_flag = 1; + options.request_tty = REQUEST_TTY_NO; break; case 'T': - no_tty_flag = 1; + options.request_tty = REQUEST_TTY_NO; break; case 'o': dummy = 1; @@ -606,6 +605,10 @@ main(int ac, char **av) /* Initialize the command to execute on remote host. */ buffer_init(&command); + if (options.request_tty == REQUEST_TTY_YES || + options.request_tty == REQUEST_TTY_FORCE) + tty_flag = 1; + /* * Save the command to execute on the remote host in a buffer. There * is no limit on the length of the command, except by the maximum @@ -613,7 +616,7 @@ main(int ac, char **av) */ if (!ac) { /* No command specified - execute shell on a tty. */ - tty_flag = 1; + tty_flag = options.request_tty != REQUEST_TTY_NO; if (subsystem_flag) { fprintf(stderr, "You must specify a subsystem to invoke.\n"); @@ -636,13 +639,14 @@ main(int ac, char **av) /* Allocate a tty by default if no command specified. */ if (buffer_len(&command) == 0) - tty_flag = 1; + tty_flag = options.request_tty != REQUEST_TTY_NO; /* Force no tty */ - if (no_tty_flag || muxclient_command != 0) + if (options.request_tty == REQUEST_TTY_NO || muxclient_command != 0) tty_flag = 0; /* Do not allocate a tty if stdin is not a tty. */ - if ((!isatty(fileno(stdin)) || stdin_null_flag) && !force_tty_flag) { + if ((!isatty(fileno(stdin)) || stdin_null_flag) && + options.request_tty != REQUEST_TTY_FORCE) { if (tty_flag) logit("Pseudo-terminal will not be allocated because " "stdin is not a terminal."); @@ -946,8 +950,7 @@ control_persist_detach(void) /* Parent: set up mux slave to connect to backgrounded master */ debug2("%s: background process is %ld", __func__, (long)pid); stdin_null_flag = ostdin_null_flag; - no_shell_flag = ono_shell_flag; - no_tty_flag = ono_tty_flag; + options.request_tty = orequest_tty; tty_flag = otty_flag; close(muxserver_sock); muxserver_sock = -1; @@ -1394,11 +1397,11 @@ ssh_session2(void) if (options.control_persist && muxserver_sock != -1) { ostdin_null_flag = stdin_null_flag; ono_shell_flag = no_shell_flag; - ono_tty_flag = no_tty_flag; + orequest_tty = options.request_tty; otty_flag = tty_flag; stdin_null_flag = 1; no_shell_flag = 1; - no_tty_flag = 1; + options.request_tty == REQUEST_TTY_NO; tty_flag = 0; if (!fork_after_authentication_flag) need_controlpersist_detach = 1; diff --git a/ssh_config.5 b/ssh_config.5 index 5bdc7fec1..83baa82b1 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -33,7 +33,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh_config.5,v 1.148 2011/05/06 21:31:38 djm Exp $ +.\" $OpenBSD: ssh_config.5,v 1.149 2011/05/06 21:34:32 djm Exp $ .Dd $Mdocdate: May 6 2011 $ .Dt SSH_CONFIG 5 .Os @@ -959,6 +959,23 @@ will only succeed if the server's .Cm GatewayPorts option is enabled (see .Xr sshd_config 5 ) . +.It Cm RequestTTY +Specifies whether to request a pseudo-tty for the session. +The argument may be one of: +.Dq no +(never request a TTY), +.Dq yes +(always request a TTY when standard input is a TTY), +.Dq force +(always request a TTY) or +.Dq auto +(request a TTY when opening a login session). +This option mirrors the +.Fl t +and +.Fl T +flags for +.Xr ssh 1 . .It Cm RhostsRSAAuthentication Specifies whether to try rhosts based authentication with RSA host authentication. -- cgit v1.2.3 From 295ee63ab2123899fb21f76616ef4dac51515236 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Sun, 29 May 2011 21:42:31 +1000 Subject: - djm@cvs.openbsd.org 2011/05/24 07:15:47 [readconf.c readconf.h ssh.c ssh_config.5 sshconnect.c sshconnect2.c] Remove undocumented legacy options UserKnownHostsFile2 and GlobalKnownHostsFile2 by making UserKnownHostsFile/GlobalKnownHostsFile accept multiple paths per line and making their defaults include known_hosts2; ok markus --- ChangeLog | 6 +++++ readconf.c | 69 ++++++++++++++++++++++++++++++++------------------------ readconf.h | 13 ++++++----- ssh.c | 28 ++++++++++++++--------- ssh_config.5 | 20 ++++++++++------- sshconnect.c | 72 +++++++++++++++++++++++++++++------------------------------ sshconnect2.c | 11 ++++----- 7 files changed, 125 insertions(+), 94 deletions(-) (limited to 'readconf.c') diff --git a/ChangeLog b/ChangeLog index f3f43a13f..c7db4a5df 100644 --- a/ChangeLog +++ b/ChangeLog @@ -24,6 +24,12 @@ read in key comments for v.2 keys (though note that these are not passed over the agent protocol); bz#439, based on patch from binder AT arago.de; ok markus@ + - djm@cvs.openbsd.org 2011/05/24 07:15:47 + [readconf.c readconf.h ssh.c ssh_config.5 sshconnect.c sshconnect2.c] + Remove undocumented legacy options UserKnownHostsFile2 and + GlobalKnownHostsFile2 by making UserKnownHostsFile/GlobalKnownHostsFile + accept multiple paths per line and making their defaults include + known_hosts2; ok markus 20110520 - (djm) [session.c] call setexeccon() before executing passwd for pw diff --git a/readconf.c b/readconf.c index 4780ae289..91dfa566f 100644 --- a/readconf.c +++ b/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.192 2011/05/06 21:34:32 djm Exp $ */ +/* $OpenBSD: readconf.c,v 1.193 2011/05/24 07:15:47 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -193,9 +193,9 @@ static struct { { "host", oHost }, { "escapechar", oEscapeChar }, { "globalknownhostsfile", oGlobalKnownHostsFile }, - { "globalknownhostsfile2", oGlobalKnownHostsFile2 }, /* obsolete */ + { "globalknownhostsfile2", oDeprecated }, { "userknownhostsfile", oUserKnownHostsFile }, - { "userknownhostsfile2", oUserKnownHostsFile2 }, /* obsolete */ + { "userknownhostsfile2", oDeprecated }, { "connectionattempts", oConnectionAttempts }, { "batchmode", oBatchMode }, { "checkhostip", oCheckHostIP }, @@ -354,7 +354,9 @@ process_config_line(Options *options, const char *host, char *line, const char *filename, int linenum, int *activep) { - char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256]; + char *s, **charptr, *endofnumber, *keyword, *arg, *arg2; + char **cpptr, fwdarg[256]; + u_int *uintptr, max_entries = 0; int negated, opcode, *intptr, value, value2, scale; LogLevel *log_level_ptr; long long orig, val64; @@ -598,26 +600,33 @@ parse_yesnoask: parse_string: arg = strdelim(&s); if (!arg || *arg == '\0') - fatal("%.200s line %d: Missing argument.", filename, linenum); + fatal("%.200s line %d: Missing argument.", + filename, linenum); if (*activep && *charptr == NULL) *charptr = xstrdup(arg); break; case oGlobalKnownHostsFile: - charptr = &options->system_hostfile; - goto parse_string; + cpptr = (char **)&options->system_hostfiles; + uintptr = &options->num_system_hostfiles; + max_entries = SSH_MAX_HOSTS_FILES; +parse_char_array: + if (*activep && *uintptr == 0) { + while ((arg = strdelim(&s)) != NULL && *arg != '\0') { + if ((*uintptr) >= max_entries) + fatal("%s line %d: " + "too many authorized keys files.", + filename, linenum); + cpptr[(*uintptr)++] = xstrdup(arg); + } + } + return 0; case oUserKnownHostsFile: - charptr = &options->user_hostfile; - goto parse_string; - - case oGlobalKnownHostsFile2: - charptr = &options->system_hostfile2; - goto parse_string; - - case oUserKnownHostsFile2: - charptr = &options->user_hostfile2; - goto parse_string; + cpptr = (char **)&options->user_hostfiles; + uintptr = &options->num_user_hostfiles; + max_entries = SSH_MAX_HOSTS_FILES; + goto parse_char_array; case oHostName: charptr = &options->hostname; @@ -1158,10 +1167,8 @@ initialize_options(Options * options) options->proxy_command = NULL; options->user = NULL; options->escape_char = -1; - options->system_hostfile = NULL; - options->user_hostfile = NULL; - options->system_hostfile2 = NULL; - options->user_hostfile2 = NULL; + options->num_system_hostfiles = 0; + options->num_user_hostfiles = 0; options->local_forwards = NULL; options->num_local_forwards = 0; options->remote_forwards = NULL; @@ -1301,14 +1308,18 @@ fill_default_options(Options * options) } if (options->escape_char == -1) options->escape_char = '~'; - if (options->system_hostfile == NULL) - options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE; - if (options->user_hostfile == NULL) - options->user_hostfile = _PATH_SSH_USER_HOSTFILE; - if (options->system_hostfile2 == NULL) - options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2; - if (options->user_hostfile2 == NULL) - options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2; + if (options->num_system_hostfiles == 0) { + options->system_hostfiles[options->num_system_hostfiles++] = + xstrdup(_PATH_SSH_SYSTEM_HOSTFILE); + options->system_hostfiles[options->num_system_hostfiles++] = + xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2); + } + if (options->num_user_hostfiles == 0) { + options->user_hostfiles[options->num_user_hostfiles++] = + xstrdup(_PATH_SSH_USER_HOSTFILE); + options->user_hostfiles[options->num_user_hostfiles++] = + xstrdup(_PATH_SSH_USER_HOSTFILE2); + } if (options->log_level == SYSLOG_LEVEL_NOT_SET) options->log_level = SYSLOG_LEVEL_INFO; if (options->clear_forwardings == 1) diff --git a/readconf.h b/readconf.h index bc3e8c1bb..5944cff93 100644 --- a/readconf.h +++ b/readconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.h,v 1.89 2011/05/06 21:34:32 djm Exp $ */ +/* $OpenBSD: readconf.h,v 1.90 2011/05/24 07:15:47 djm Exp $ */ /* * Author: Tatu Ylonen @@ -27,7 +27,8 @@ typedef struct { } Forward; /* Data structure for representing option data. */ -#define MAX_SEND_ENV 256 +#define MAX_SEND_ENV 256 +#define SSH_MAX_HOSTS_FILES 256 typedef struct { int forward_agent; /* Forward authentication agent. */ @@ -83,10 +84,10 @@ typedef struct { char *user; /* User to log in as. */ int escape_char; /* Escape character; -2 = none */ - char *system_hostfile;/* Path for /etc/ssh/ssh_known_hosts. */ - char *user_hostfile; /* Path for $HOME/.ssh/known_hosts. */ - char *system_hostfile2; - char *user_hostfile2; + u_int num_system_hostfiles; /* Paths for /etc/ssh/ssh_known_hosts */ + char *system_hostfiles[SSH_MAX_HOSTS_FILES]; + u_int num_user_hostfiles; /* Path for $HOME/.ssh/known_hosts */ + char *user_hostfiles[SSH_MAX_HOSTS_FILES]; char *preferred_authentications; char *bind_address; /* local socket address for connection to sshd */ char *pkcs11_provider; /* PKCS#11 provider */ diff --git a/ssh.c b/ssh.c index 6080c0c27..e7e15cd65 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.360 2011/05/06 21:38:58 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.361 2011/05/24 07:15:47 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -212,6 +212,20 @@ static void main_sigchld_handler(int); void muxclient(const char *); void muxserver_listen(void); +/* ~/ expand a list of paths. NB. assumes path[n] is heap-allocated. */ +static void +tilde_expand_paths(char **paths, u_int num_paths) +{ + u_int i; + char *cp; + + for (i = 0; i < num_paths; i++) { + cp = tilde_expand_filename(paths[i], original_real_uid); + xfree(paths[i]); + paths[i] = cp; + } +} + /* * Main program for the ssh client. */ @@ -869,15 +883,9 @@ main(int ac, char **av) load_public_identity_files(); /* Expand ~ in known host file names. */ - /* XXX mem-leaks: */ - options.system_hostfile = - tilde_expand_filename(options.system_hostfile, original_real_uid); - options.user_hostfile = - tilde_expand_filename(options.user_hostfile, original_real_uid); - options.system_hostfile2 = - tilde_expand_filename(options.system_hostfile2, original_real_uid); - options.user_hostfile2 = - tilde_expand_filename(options.user_hostfile2, original_real_uid); + tilde_expand_paths(options.system_hostfiles, + options.num_system_hostfiles); + tilde_expand_paths(options.user_hostfiles, options.num_user_hostfiles); signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */ signal(SIGCHLD, main_sigchld_handler); diff --git a/ssh_config.5 b/ssh_config.5 index 7a3b641ff..87574e381 100644 --- a/ssh_config.5 +++ b/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.150 2011/05/07 23:19:39 jmc Exp $ -.Dd $Mdocdate: May 7 2011 $ +.\" $OpenBSD: ssh_config.5,v 1.151 2011/05/24 07:15:47 djm Exp $ +.Dd $Mdocdate: May 24 2011 $ .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -517,9 +517,11 @@ or The default is .Dq no . .It Cm GlobalKnownHostsFile -Specifies a file to use for the global -host key database instead of -.Pa /etc/ssh/ssh_known_hosts . +Specifies one or more files to use for the global +host key database, separated by whitespace. +The default is +.Pa /etc/ssh/ssh_known_hosts , +.Pa /etc/ssh/ssh_known_hosts2 . .It Cm GSSAPIAuthentication Specifies whether user authentication based on GSSAPI is allowed. The default is @@ -1171,9 +1173,11 @@ This can be useful when a different user name is used on different machines. This saves the trouble of having to remember to give the user name on the command line. .It Cm UserKnownHostsFile -Specifies a file to use for the user -host key database instead of -.Pa ~/.ssh/known_hosts . +Specifies one or more files to use for the user +host key database, separated by whitespace. +The default is +.Pa ~/.ssh/known_hosts , +.Pa ~/.ssh/known_hosts2 . .It Cm VerifyHostKeyDNS Specifies whether to verify the remote key using DNS and SSHFP resource records. diff --git a/sshconnect.c b/sshconnect.c index 603445227..0ee726637 100644 --- a/sshconnect.c +++ b/sshconnect.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect.c,v 1.233 2011/05/23 03:52:55 djm Exp $ */ +/* $OpenBSD: sshconnect.c,v 1.234 2011/05/24 07:15:47 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -683,28 +683,30 @@ get_hostfile_hostname_ipaddr(char *hostname, struct sockaddr *hostaddr, /* * check whether the supplied host key is valid, return -1 if the key - * is not valid. the user_hostfile will not be updated if 'readonly' is true. + * is not valid. user_hostfile[0] will not be updated if 'readonly' is true. */ #define RDRW 0 #define RDONLY 1 #define ROQUIET 2 static int check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, - Key *host_key, int readonly, char *user_hostfile, - char *system_hostfile) + Key *host_key, int readonly, + char **user_hostfiles, u_int num_user_hostfiles, + char **system_hostfiles, u_int num_system_hostfiles) { + HostStatus host_status; + HostStatus ip_status; Key *raw_key = NULL; - const char *type; char *ip = NULL, *host = NULL; char hostline[1000], *hostp, *fp, *ra; - HostStatus host_status; - HostStatus ip_status; - int r, want_cert = key_is_cert(host_key), host_ip_differ = 0; - int local = sockaddr_is_local(hostaddr); char msg[1024]; + const char *type; + const struct hostkey_entry *host_found, *ip_found; int len, cancelled_forwarding = 0; + int local = sockaddr_is_local(hostaddr); + int r, want_cert = key_is_cert(host_key), host_ip_differ = 0; struct hostkeys *host_hostkeys, *ip_hostkeys; - const struct hostkey_entry *host_found, *ip_found; + u_int i; /* * Force accepting of the host key for loopback/localhost. The @@ -736,14 +738,18 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, options.check_host_ip = 0; host_hostkeys = init_hostkeys(); - load_hostkeys(host_hostkeys, host, user_hostfile); - load_hostkeys(host_hostkeys, host, system_hostfile); + for (i = 0; i < num_user_hostfiles; i++) + load_hostkeys(host_hostkeys, host, user_hostfiles[i]); + for (i = 0; i < num_system_hostfiles; i++) + load_hostkeys(host_hostkeys, host, system_hostfiles[i]); ip_hostkeys = NULL; if (!want_cert && options.check_host_ip) { ip_hostkeys = init_hostkeys(); - load_hostkeys(ip_hostkeys, ip, user_hostfile); - load_hostkeys(ip_hostkeys, ip, system_hostfile); + for (i = 0; i < num_user_hostfiles; i++) + load_hostkeys(ip_hostkeys, ip, user_hostfiles[i]); + for (i = 0; i < num_system_hostfiles; i++) + load_hostkeys(ip_hostkeys, ip, system_hostfiles[i]); } retry: @@ -788,11 +794,12 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, logit("%s host key for IP address " "'%.128s' not in list of known hosts.", type, ip); - else if (!add_host_to_hostfile(user_hostfile, ip, + else if (!add_host_to_hostfile(user_hostfiles[0], ip, host_key, options.hash_known_hosts)) logit("Failed to add the %s host key for IP " "address '%.128s' to the list of known " - "hosts (%.30s).", type, ip, user_hostfile); + "hosts (%.30s).", type, ip, + user_hostfiles[0]); else logit("Warning: Permanently added the %s host " "key for IP address '%.128s' to the list " @@ -811,7 +818,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, port != SSH_DEFAULT_PORT) { debug("checking without port identifier"); if (check_host_key(hostname, hostaddr, 0, host_key, - ROQUIET, user_hostfile, system_hostfile) == 0) { + ROQUIET, user_hostfiles, num_user_hostfiles, + system_hostfiles, num_system_hostfiles) == 0) { debug("found matching key w/out port"); break; } @@ -876,25 +884,25 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, hostp = hostline; if (options.hash_known_hosts) { /* Add hash of host and IP separately */ - r = add_host_to_hostfile(user_hostfile, host, - host_key, options.hash_known_hosts) && - add_host_to_hostfile(user_hostfile, ip, + r = add_host_to_hostfile(user_hostfiles[0], + host, host_key, options.hash_known_hosts) && + add_host_to_hostfile(user_hostfiles[0], ip, host_key, options.hash_known_hosts); } else { /* Add unhashed "host,ip" */ - r = add_host_to_hostfile(user_hostfile, + r = add_host_to_hostfile(user_hostfiles[0], hostline, host_key, options.hash_known_hosts); } } else { - r = add_host_to_hostfile(user_hostfile, host, host_key, - options.hash_known_hosts); + r = add_host_to_hostfile(user_hostfiles[0], host, + host_key, options.hash_known_hosts); hostp = host; } if (!r) logit("Failed to add the host to the list of known " - "hosts (%.500s).", user_hostfile); + "hosts (%.500s).", user_hostfiles[0]); else logit("Warning: Permanently added '%.200s' (%s) to the " "list of known hosts.", hostp, type); @@ -955,7 +963,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, /* The host key has changed. */ warn_changed_key(host_key); error("Add correct host key in %.100s to get rid of this message.", - user_hostfile); + user_hostfiles[0]); error("Offending %s key in %s:%lu", key_type(host_found->key), host_found->file, host_found->line); @@ -1100,7 +1108,6 @@ fail: int verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) { - struct stat st; int flags = 0; char *fp; @@ -1128,16 +1135,9 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) } } - /* return ok if the key can be found in an old keyfile */ - if (stat(options.system_hostfile2, &st) == 0 || - stat(options.user_hostfile2, &st) == 0) { - if (check_host_key(host, hostaddr, options.port, host_key, - RDONLY, options.user_hostfile2, - options.system_hostfile2) == 0) - return 0; - } - return check_host_key(host, hostaddr, options.port, host_key, - RDRW, options.user_hostfile, options.system_hostfile); + return check_host_key(host, hostaddr, options.port, host_key, RDRW, + options.user_hostfiles, options.num_user_hostfiles, + options.system_hostfiles, options.num_system_hostfiles); } /* diff --git a/sshconnect2.c b/sshconnect2.c index 673bf1a4f..c24b20278 100644 --- a/sshconnect2.c +++ b/sshconnect2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect2.c,v 1.187 2011/05/06 02:05:41 djm Exp $ */ +/* $OpenBSD: sshconnect2.c,v 1.188 2011/05/24 07:15:47 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2008 Damien Miller. All rights reserved. @@ -109,14 +109,15 @@ order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port) size_t maxlen; struct hostkeys *hostkeys; int ktype; + u_int i; /* Find all hostkeys for this hostname */ get_hostfile_hostname_ipaddr(host, hostaddr, port, &hostname, NULL); hostkeys = init_hostkeys(); - load_hostkeys(hostkeys, hostname, options.user_hostfile2); - load_hostkeys(hostkeys, hostname, options.system_hostfile2); - load_hostkeys(hostkeys, hostname, options.user_hostfile); - load_hostkeys(hostkeys, hostname, options.system_hostfile); + for (i = 0; i < options.num_user_hostfiles; i++) + load_hostkeys(hostkeys, hostname, options.user_hostfiles[i]); + for (i = 0; i < options.num_system_hostfiles; i++) + load_hostkeys(hostkeys, hostname, options.system_hostfiles[i]); oavail = avail = xstrdup(KEX_DEFAULT_PK_ALG); maxlen = strlen(avail) + 1; -- cgit v1.2.3