[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Config file parsing order



----- Original Message -----
> From: "Tilo Eckert" <tilo.eckert@xxxxxxx>
> To: libssh@xxxxxxxxxx
> Sent: Friday, February 14, 2020 12:59:13 PM
> Subject: Config file parsing order
> 
> Hi everyone,
> 
> we are currently facing an issue with the order in which options from
> the OpenSSH config files are applied.
> 
> When setting up a connection, we call ssh_options_set() for all options
> we want to set, followed by ssh_connect(). Commit 89a8a6fc introduced
> automatic loading of user-specific and system-wide OpenSSH config files
> if no config file has been loaded explicitly. This overrides options
> previously set with ssh_options_set() if they also appear in one of the
> config files as mentioned in the commit message.
> 
> There are multiple problems with this behavior:
> 
> 1) It is counter-intuitive. Options set explicitly should override
> options set in automatically loaded config files. The default global
> OpenSSH config file is intended to contain reasonable defaults which may
> be overridden by the user-specific config file or via command line.
> From OpenSSH docs:
> > ssh(1) obtains configuration data from the following sources in the
> > following order:
> >       1.   command-line options
> >       2.   user's configuration file (~/.ssh/config)
> >       3.   system-wide configuration file (/etc/ssh/ssh_config)
> > For each parameter, the first obtained value will be used.
> 
> Imo, that is how it should work in libssh, too.

You can make libssh based client to behave like this by:

1- Parse local configuration file by manually calling ssh_options_parse_config(session, NULL).
   - This must be called after setting the host with ssh_options_set_host()
   - This will parse the local and global configuration, being local options prioritized
2- Set the command line options using ssh_options_set()
   - This will override any options set before.
3- Connect with ssh_connect()

The configuration file is parsed only once. When ssh_connect is called, it checks if the configuration was already parsed to avoid parsing twice.

The options inside the configuration will follow OpenSSH way: the first seen value will be kept (which I particularly don't like).

> 
> 2) Libssh implements the exact opposite order. This leads to conflicts
> if the user uses the OpenSSH client and a libssh-based client on the
> same machine/account. For example, if the user configures his
> non-default known_hosts path in ~/.ssh/config to avoid passing it to the
> OpenSSH CLI every time, there is no way to override this with
> ssh_options_set() if the user wants to use a different known_hosts file
> with libssh. The user of the libssh-based client would need to create a
> new config file that we have to load with ssh_options_parse_config()
> before connecting.

You can manually call ssh_options_parse_config() and then override the values with ssh_options_set().

> 
> 3) We could call ssh_options_parse_config(session, NULL) before setting
> our own options to work around it, but the user and system-wide config
> files would still be loaded in the wrong order, with system-wide config
> taking top priority.

The values in the local configuration have priority over the values in the global configuration.

In the client values set through configuration files will follow OpenSSH's way, where the first value seen is kept, independently on that being in a different configuration file.
This is implemented by keeping a table where the options seen are marked (search for 'seen' in src/config.c). But this also means that an option set by a configuration file can't be overridden later by another configuration file (only by setting manually through ssh_options_set()).

> 
> 4) There is no documentation about the overriding behavior of the
> ssh_connect() function.

I agree, we have to improve the documentation about how the configuration and options work.

> 
> TL;DR
> Is it intentional that libssh options priority is the exact opposite of
> what OpenSSH does? If yes, why?

Actually, in the client it was implemented trying to follow OpenSSH's way. The only difference it that if you need to override values from the configuration files, you have to call the parsing manually.

In the server side things are different. Values set through configuration files can be overridden later by another configuration file. This choice was made to allow values to be overridden using configuration files, which is not possible in the client side (exacly because of the seen table which is kept around).

> Wouldn't it be more reasonable if options from autoloaded config files
> are only applied if not already set?

For me the answer is yes: options set manually through ssh_options_set() should take precedence. But we can't simply change the behavior like this (it would be an ABI breakage).

> 
> Regards,
> Tilo Eckert
> 
> 


Follow-Ups:
Re: Config file parsing orderTilo Eckert <tilo.eckert@xxxxxxx>
References:
Config file parsing orderTilo Eckert <tilo.eckert@xxxxxxx>
Archive administrator: postmaster@lists.cynapses.org