upstream: add a `sshd -G` option that parses and prints the

effective configuration without attempting to load private keys and perform
other checks. This allows usage of the option before keys have been
generated.

bz3460 feedback/ok dtucker@

OpenBSD-Commit-ID: 774504f629023fc25a559ab1d95401adb3a7fb29
This commit is contained in:
djm@openbsd.org 2023-02-10 04:47:19 +00:00 committed by Damien Miller
parent df7d3dbf71
commit 18938d11a9
No known key found for this signature in database
2 changed files with 45 additions and 19 deletions

20
sshd.8
View File

@ -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: sshd.8,v 1.322 2023/01/18 01:50:21 millert Exp $ .\" $OpenBSD: sshd.8,v 1.323 2023/02/10 04:47:19 djm Exp $
.Dd $Mdocdate: January 18 2023 $ .Dd $Mdocdate: February 10 2023 $
.Dt SSHD 8 .Dt SSHD 8
.Os .Os
.Sh NAME .Sh NAME
@ -43,7 +43,7 @@
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm sshd .Nm sshd
.Bk -words .Bk -words
.Op Fl 46DdeiqTtV .Op Fl 46DGdeiqTtV
.Op Fl C Ar connection_spec .Op Fl C Ar connection_spec
.Op Fl c Ar host_certificate_file .Op Fl c Ar host_certificate_file
.Op Fl E Ar log_file .Op Fl E Ar log_file
@ -154,6 +154,15 @@ The default is
.Pa /etc/ssh/sshd_config . .Pa /etc/ssh/sshd_config .
.Nm .Nm
refuses to start if there is no configuration file. refuses to start if there is no configuration file.
.It Fl G
Parse and print configuration file.
Check the validity of the configuration file, output the effective configuration
to stdout and then exit.
Optionally,
.Cm Match
rules may be applied by specifying the connection parameters using one or more
.Fl C
options.
.It Fl g Ar login_grace_time .It Fl g Ar login_grace_time
Gives the grace time for clients to authenticate themselves (default Gives the grace time for clients to authenticate themselves (default
120 seconds). 120 seconds).
@ -208,6 +217,11 @@ Optionally,
rules may be applied by specifying the connection parameters using one or more rules may be applied by specifying the connection parameters using one or more
.Fl C .Fl C
options. options.
This is similar to the
.Fl G
flag, but it includes the additional testing performed by the
.Fl t
flag.
.It Fl t .It Fl t
Test mode. Test mode.
Only check the validity of the configuration file and sanity of the keys. Only check the validity of the configuration file and sanity of the keys.

44
sshd.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshd.c,v 1.596 2023/01/18 01:50:21 millert Exp $ */ /* $OpenBSD: sshd.c,v 1.597 2023/02/10 04:47:19 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
@ -901,7 +901,7 @@ usage(void)
{ {
fprintf(stderr, "%s, %s\n", SSH_RELEASE, SSH_OPENSSL_VERSION); fprintf(stderr, "%s, %s\n", SSH_RELEASE, SSH_OPENSSL_VERSION);
fprintf(stderr, fprintf(stderr,
"usage: sshd [-46DdeiqTtV] [-C connection_spec] [-c host_cert_file]\n" "usage: sshd [-46DdeGiqTtV] [-C connection_spec] [-c host_cert_file]\n"
" [-E log_file] [-f config_file] [-g login_grace_time]\n" " [-E log_file] [-f config_file] [-g login_grace_time]\n"
" [-h host_key_file] [-o option] [-p port] [-u len]\n" " [-h host_key_file] [-o option] [-p port] [-u len]\n"
); );
@ -1524,6 +1524,21 @@ prepare_proctitle(int ac, char **av)
return ret; return ret;
} }
static void
print_config(struct ssh *ssh, struct connection_info *connection_info)
{
/*
* If no connection info was provided by -C then use
* use a blank one that will cause no predicate to match.
*/
if (connection_info == NULL)
connection_info = get_connection_info(ssh, 0, 0);
connection_info->test = 1;
parse_server_match_config(&options, &includes, connection_info);
dump_config(&options);
exit(0);
}
/* /*
* Main program for the daemon. * Main program for the daemon.
*/ */
@ -1533,7 +1548,7 @@ main(int ac, char **av)
struct ssh *ssh = NULL; struct ssh *ssh = NULL;
extern char *optarg; extern char *optarg;
extern int optind; extern int optind;
int r, opt, on = 1, already_daemon, remote_port; int r, opt, on = 1, do_dump_cfg = 0, already_daemon, remote_port;
int sock_in = -1, sock_out = -1, newsock = -1; int sock_in = -1, sock_out = -1, newsock = -1;
const char *remote_ip, *rdomain; const char *remote_ip, *rdomain;
char *fp, *line, *laddr, *logfile = NULL; char *fp, *line, *laddr, *logfile = NULL;
@ -1581,7 +1596,7 @@ main(int ac, char **av)
/* Parse command-line arguments. */ /* Parse command-line arguments. */
while ((opt = getopt(ac, av, while ((opt = getopt(ac, av,
"C:E:b:c:f:g:h:k:o:p:u:46DQRTdeiqrtV")) != -1) { "C:E:b:c:f:g:h:k:o:p:u:46DGQRTdeiqrtV")) != -1) {
switch (opt) { switch (opt) {
case '4': case '4':
options.address_family = AF_INET; options.address_family = AF_INET;
@ -1606,6 +1621,9 @@ main(int ac, char **av)
case 'D': case 'D':
no_daemon_flag = 1; no_daemon_flag = 1;
break; break;
case 'G':
do_dump_cfg = 1;
break;
case 'E': case 'E':
logfile = optarg; logfile = optarg;
/* FALLTHROUGH */ /* FALLTHROUGH */
@ -1693,7 +1711,7 @@ main(int ac, char **av)
} }
if (rexeced_flag || inetd_flag) if (rexeced_flag || inetd_flag)
rexec_flag = 0; rexec_flag = 0;
if (!test_flag && rexec_flag && !path_absolute(av[0])) if (!test_flag && !do_dump_cfg && rexec_flag && !path_absolute(av[0]))
fatal("sshd re-exec requires execution with an absolute path"); fatal("sshd re-exec requires execution with an absolute path");
if (rexeced_flag) if (rexeced_flag)
closefrom(REEXEC_MIN_FREE_FD); closefrom(REEXEC_MIN_FREE_FD);
@ -1799,6 +1817,9 @@ main(int ac, char **av)
debug("sshd version %s, %s", SSH_VERSION, SSH_OPENSSL_VERSION); debug("sshd version %s, %s", SSH_VERSION, SSH_OPENSSL_VERSION);
if (do_dump_cfg)
print_config(ssh, connection_info);
/* Store privilege separation user for later use if required. */ /* Store privilege separation user for later use if required. */
privsep_chroot = use_privsep && (getuid() == 0 || geteuid() == 0); privsep_chroot = use_privsep && (getuid() == 0 || geteuid() == 0);
if ((privsep_pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) { if ((privsep_pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) {
@ -1981,17 +2002,8 @@ main(int ac, char **av)
"world-writable.", _PATH_PRIVSEP_CHROOT_DIR); "world-writable.", _PATH_PRIVSEP_CHROOT_DIR);
} }
if (test_flag > 1) { if (test_flag > 1)
/* print_config(ssh, connection_info);
* If no connection info was provided by -C then use
* use a blank one that will cause no predicate to match.
*/
if (connection_info == NULL)
connection_info = get_connection_info(ssh, 0, 0);
connection_info->test = 1;
parse_server_match_config(&options, &includes, connection_info);
dump_config(&options);
}
/* Configuration looks good, so exit if in test mode. */ /* Configuration looks good, so exit if in test mode. */
if (test_flag) if (test_flag)