[sshd.c channels.h channels.c log.c servconf.c log.h servconf.h sshd.8]
     Add extended test mode (-T) and connection parameters for test mode (-C).
     -T causes sshd to write its effective configuration to stdout and exit.
     -C causes any relevant Match rules to be applied before output.  The
     combination allows tesing of the parser and config files.  ok deraadt djm
This commit is contained in:
Darren Tucker 2008-06-10 23:01:51 +10:00
parent b06cc4abf8
commit e7140f20cb
9 changed files with 355 additions and 24 deletions

View File

@ -12,6 +12,12 @@
- djm@cvs.openbsd.org 2008/06/10 04:17:46
[sshd_config.5]
better reference for pattern-list
- dtucker@cvs.openbsd.org 2008/06/10 04:50:25
[sshd.c channels.h channels.c log.c servconf.c log.h servconf.h sshd.8]
Add extended test mode (-T) and connection parameters for test mode (-C).
-T causes sshd to write its effective configuration to stdout and exit.
-C causes any relevant Match rules to be applied before output. The
combination allows tesing of the parser and config files. ok deraadt djm
20080609
- (dtucker) OpenBSD CVS Sync
@ -4098,4 +4104,4 @@
OpenServer 6 and add osr5bigcrypt support so when someone migrates
passwords between UnixWare and OpenServer they will still work. OK dtucker@
$Id: ChangeLog,v 1.4950 2008/06/10 12:59:53 dtucker Exp $
$Id: ChangeLog,v 1.4951 2008/06/10 13:01:51 dtucker Exp $

View File

@ -1,4 +1,4 @@
/* $OpenBSD: channels.c,v 1.277 2008/05/09 16:17:51 markus Exp $ */
/* $OpenBSD: channels.c,v 1.278 2008/06/10 04:50:25 dtucker Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -2784,6 +2784,17 @@ channel_clear_adm_permitted_opens(void)
num_adm_permitted_opens = 0;
}
void
channel_print_adm_permitted_opens(void)
{
static int i;
for (i = 0; i < num_adm_permitted_opens; i++)
if (permitted_adm_opens[i].host_to_connect != NULL)
printf(" %s:%d", permitted_adm_opens[i].host_to_connect,
permitted_adm_opens[i].port_to_connect);
}
/* Try to start non-blocking connect to next host in cctx list */
static int
connect_next(struct channel_connect *cctx)

View File

@ -1,4 +1,4 @@
/* $OpenBSD: channels.h,v 1.92 2008/05/09 16:21:13 markus Exp $ */
/* $OpenBSD: channels.h,v 1.93 2008/06/10 04:50:25 dtucker Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -235,6 +235,7 @@ void channel_add_permitted_opens(char *, int);
int channel_add_adm_permitted_opens(char *, int);
void channel_clear_permitted_opens(void);
void channel_clear_adm_permitted_opens(void);
void channel_print_adm_permitted_opens(void);
int channel_input_port_forward_request(int, int);
Channel *channel_connect_to(const char *, u_short, char *, char *);
Channel *channel_connect_by_listen_address(u_short, char *, char *);

24
log.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: log.c,v 1.40 2007/05/17 07:50:31 djm Exp $ */
/* $OpenBSD: log.c,v 1.41 2008/06/10 04:50:25 dtucker Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -114,6 +114,17 @@ log_facility_number(char *name)
return SYSLOG_FACILITY_NOT_SET;
}
const char *
log_facility_name(SyslogFacility facility)
{
u_int i;
for (i = 0; log_facilities[i].name; i++)
if (log_facilities[i].val == facility)
return log_facilities[i].name;
return NULL;
}
LogLevel
log_level_number(char *name)
{
@ -126,6 +137,17 @@ log_level_number(char *name)
return SYSLOG_LEVEL_NOT_SET;
}
const char *
log_level_name(LogLevel level)
{
u_int i;
for (i = 0; log_levels[i].name != NULL; i++)
if (log_levels[i].val == level)
return log_levels[i].name;
return NULL;
}
/* Error messages that should be logged. */
void

6
log.h
View File

@ -1,4 +1,4 @@
/* $OpenBSD: log.h,v 1.15 2006/08/18 09:13:25 deraadt Exp $ */
/* $OpenBSD: log.h,v 1.16 2008/06/10 04:50:25 dtucker Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -49,7 +49,9 @@ typedef enum {
void log_init(char *, LogLevel, SyslogFacility, int);
SyslogFacility log_facility_number(char *);
LogLevel log_level_number(char *);
const char * log_facility_name(SyslogFacility);
LogLevel log_level_number(char *);
const char * log_level_name(LogLevel);
void fatal(const char *, ...) __dead __attribute__((format(printf, 1, 2)));
void error(const char *, ...) __attribute__((format(printf, 1, 2)));

View File

@ -1,4 +1,4 @@
/* $OpenBSD: servconf.c,v 1.181 2008/06/10 03:57:27 djm Exp $ */
/* $OpenBSD: servconf.c,v 1.182 2008/06/10 04:50:25 dtucker Exp $ */
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
@ -23,6 +23,7 @@
#include <signal.h>
#include <unistd.h>
#include <stdarg.h>
#include <errno.h>
#include "openbsd-compat/sys-queue.h"
#include "xmalloc.h"
@ -417,6 +418,17 @@ static struct {
{ NULL, sBadOption, 0 }
};
static struct {
int val;
char *text;
} tunmode_desc[] = {
{ SSH_TUNMODE_NO, "no" },
{ SSH_TUNMODE_POINTOPOINT, "point-to-point" },
{ SSH_TUNMODE_ETHERNET, "ethernet" },
{ SSH_TUNMODE_YES, "yes" },
{ -1, NULL }
};
/*
* Returns the number of the token pointed to by cp or sBadOption.
*/
@ -1211,16 +1223,13 @@ process_server_config_line(ServerOptions *options, char *line,
if (!arg || *arg == '\0')
fatal("%s line %d: Missing yes/point-to-point/"
"ethernet/no argument.", filename, linenum);
value = 0; /* silence compiler */
if (strcasecmp(arg, "ethernet") == 0)
value = SSH_TUNMODE_ETHERNET;
else if (strcasecmp(arg, "point-to-point") == 0)
value = SSH_TUNMODE_POINTOPOINT;
else if (strcasecmp(arg, "yes") == 0)
value = SSH_TUNMODE_YES;
else if (strcasecmp(arg, "no") == 0)
value = SSH_TUNMODE_NO;
else
value = -1;
for (i = 0; tunmode_desc[i].val != -1; i++)
if (strcmp(tunmode_desc[i].text, arg) == 0) {
value = tunmode_desc[i].val;
break;
}
if (value == -1)
fatal("%s line %d: Bad yes/point-to-point/ethernet/"
"no argument: %s", filename, linenum, arg);
if (*intptr == -1)
@ -1426,3 +1435,213 @@ parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
fatal("%s: terminating, %d bad configuration options",
filename, bad_options);
}
static const char *
fmt_intarg(ServerOpCodes code, int val)
{
if (code == sAddressFamily) {
switch (val) {
case AF_INET:
return "inet";
case AF_INET6:
return "inet6";
case AF_UNSPEC:
return "any";
default:
return "UNKNOWN";
}
}
if (code == sPermitRootLogin) {
switch (val) {
case PERMIT_NO_PASSWD:
return "without-passord";
case PERMIT_FORCED_ONLY:
return "forced-commands-only";
case PERMIT_YES:
return "yes";
}
}
if (code == sProtocol) {
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";
}
}
if (code == sGatewayPorts && val == 2)
return "clientspecified";
if (code == sCompression && val == COMP_DELAYED)
return "delayed";
switch (val) {
case -1:
return "unset";
case 0:
return "no";
case 1:
return "yes";
}
return "UNKNOWN";
}
static const char *
lookup_opcode_name(ServerOpCodes 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(ServerOpCodes code, int val)
{
printf("%s %d\n", lookup_opcode_name(code), val);
}
static void
dump_cfg_fmtint(ServerOpCodes code, int val)
{
printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
}
static void
dump_cfg_string(ServerOpCodes code, const char *val)
{
if (val == NULL)
return;
printf("%s %s\n", lookup_opcode_name(code), val);
}
static void
dump_cfg_strarray(ServerOpCodes 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]);
}
void
dump_config(ServerOptions *o)
{
u_int i;
int ret;
struct addrinfo *ai;
char addr[NI_MAXHOST], port[NI_MAXSERV], *s = NULL;
/* these are usually at the top of the config */
for (i = 0; i < o->num_ports; i++)
printf("port %d\n", o->ports[i]);
dump_cfg_fmtint(sProtocol, o->protocol);
dump_cfg_fmtint(sAddressFamily, o->address_family);
/* ListenAddress must be after Port */
for (ai = o->listen_addrs; ai; ai = ai->ai_next) {
if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
sizeof(addr), port, sizeof(port),
NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
error("getnameinfo failed: %.100s",
(ret != EAI_SYSTEM) ? gai_strerror(ret) :
strerror(errno));
} else {
if (ai->ai_family == AF_INET6)
printf("listenaddress [%s]:%s\n", addr, port);
else
printf("listenaddress %s:%s\n", addr, port);
}
}
/* integer arguments */
dump_cfg_int(sServerKeyBits, o->server_key_bits);
dump_cfg_int(sLoginGraceTime, o->login_grace_time);
dump_cfg_int(sKeyRegenerationTime, o->key_regeneration_time);
dump_cfg_int(sX11DisplayOffset, o->x11_display_offset);
dump_cfg_int(sMaxAuthTries, o->max_authtries);
dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
/* formatted integer arguments */
dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login);
dump_cfg_fmtint(sIgnoreRhosts, o->ignore_rhosts);
dump_cfg_fmtint(sIgnoreUserKnownHosts, o->ignore_user_known_hosts);
dump_cfg_fmtint(sRhostsRSAAuthentication, o->rhosts_rsa_authentication);
dump_cfg_fmtint(sHostbasedAuthentication, o->hostbased_authentication);
dump_cfg_fmtint(sHostbasedUsesNameFromPacketOnly,
o->hostbased_uses_name_from_packet_only);
dump_cfg_fmtint(sRSAAuthentication, o->rsa_authentication);
dump_cfg_fmtint(sPubkeyAuthentication, o->pubkey_authentication);
dump_cfg_fmtint(sKerberosAuthentication, o->kerberos_authentication);
dump_cfg_fmtint(sKerberosOrLocalPasswd, o->kerberos_or_local_passwd);
dump_cfg_fmtint(sKerberosTicketCleanup, o->kerberos_ticket_cleanup);
dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
dump_cfg_fmtint(sKbdInteractiveAuthentication,
o->kbd_interactive_authentication);
dump_cfg_fmtint(sChallengeResponseAuthentication,
o->challenge_response_authentication);
dump_cfg_fmtint(sPrintMotd, o->print_motd);
dump_cfg_fmtint(sPrintLastLog, o->print_lastlog);
dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding);
dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost);
dump_cfg_fmtint(sStrictModes, o->strict_modes);
dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive);
dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd);
dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
dump_cfg_fmtint(sUseLogin, o->use_login);
dump_cfg_fmtint(sCompression, o->compression);
dump_cfg_fmtint(sGatewayPorts, o->gateway_ports);
dump_cfg_fmtint(sUseDNS, o->use_dns);
dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep);
/* string arguments */
dump_cfg_string(sPidFile, o->pid_file);
dump_cfg_string(sXAuthLocation, o->xauth_location);
dump_cfg_string(sCiphers, o->ciphers);
dump_cfg_string(sMacs, o->macs);
dump_cfg_string(sBanner, o->banner);
dump_cfg_string(sAuthorizedKeysFile, o->authorized_keys_file);
dump_cfg_string(sAuthorizedKeysFile2, o->authorized_keys_file2);
dump_cfg_string(sForceCommand, o->adm_forced_command);
/* string arguments requiring a lookup */
dump_cfg_string(sLogLevel, log_level_name(o->log_level));
dump_cfg_string(sLogFacility, log_facility_name(o->log_facility));
/* string array arguments */
dump_cfg_strarray(sHostKeyFile, o->num_host_key_files,
o->host_key_files);
dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users);
dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users);
dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups);
dump_cfg_strarray(sDenyGroups, o->num_deny_groups, o->deny_groups);
dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env);
/* other arguments */
for (i = 0; i < o->num_subsystems; i++)
printf("subsystem %s %s\n", o->subsystem_name[i],
o->subsystem_args[i]);
printf("maxstartups %d:%d:%d\n", o->max_startups_begin,
o->max_startups_rate, o->max_startups);
for (i = 0; tunmode_desc[i].val != -1; i++)
if (tunmode_desc[i].val == o->permit_tun) {
s = tunmode_desc[i].text;
break;
}
dump_cfg_string(sPermitTunnel, s);
printf("permitopen");
channel_print_adm_permitted_opens();
printf("\n");
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: servconf.h,v 1.84 2008/05/08 12:21:16 djm Exp $ */
/* $OpenBSD: servconf.h,v 1.85 2008/06/10 04:50:25 dtucker Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -161,5 +161,6 @@ void parse_server_config(ServerOptions *, const char *, Buffer *,
void parse_server_match_config(ServerOptions *, const char *, const char *,
const char *);
void copy_set_server_options(ServerOptions *, ServerOptions *, int);
void dump_config(ServerOptions *);
#endif /* SERVCONF_H */

34
sshd.8
View File

@ -34,8 +34,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: sshd.8,v 1.241 2008/03/27 22:37:57 jmc Exp $
.Dd $Mdocdate: March 27 2008 $
.\" $OpenBSD: sshd.8,v 1.242 2008/06/10 04:50:25 dtucker Exp $
.Dd $Mdocdate: June 10 2008 $
.Dt SSHD 8
.Os
.Sh NAME
@ -44,8 +44,9 @@
.Sh SYNOPSIS
.Nm sshd
.Bk -words
.Op Fl 46Ddeiqt
.Op Fl 46DTdeiqt
.Op Fl b Ar bits
.Op Fl C Ar connection_spec
.Op Fl f Ar config_file
.Op Fl g Ar login_grace_time
.Op Fl h Ar host_key_file
@ -197,6 +198,33 @@ Only check the validity of the configuration file and sanity of the keys.
This is useful for updating
.Nm
reliably as configuration options may change.
.It Fl T
Extended test mode.
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 C
Specify the connection parameters to use for the the
.Fl T
extended test mode.
If provided, any
.Cm Match
directives in the configuration file
that would apply to the specified user, host and address will be set before
the configuration is written to standard output.
The connection parameters are supplied as keyword=value pairs.
The keywords are
.Dq user ,
.Dq host
and
.Dq addr
All are required and may be supplied in any order, either with multiple
.Fl C
options or as a comma-separated list.
.It Fl u Ar len
This option is used to specify the size of the field
in the

47
sshd.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshd.c,v 1.357 2008/05/08 12:02:23 djm Exp $ */
/* $OpenBSD: sshd.c,v 1.358 2008/06/10 04:50:25 dtucker Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -1240,8 +1240,9 @@ main(int ac, char **av)
int opt, i, on = 1;
int sock_in = -1, sock_out = -1, newsock = -1;
const char *remote_ip;
char *test_user = NULL, *test_host = NULL, *test_addr = NULL;
int remote_port;
char *line;
char *line, *p, *cp;
int config_s[2] = { -1 , -1 };
Key *key;
Authctxt *authctxt;
@ -1276,7 +1277,7 @@ main(int ac, char **av)
initialize_server_options(&options);
/* Parse command-line arguments. */
while ((opt = getopt(ac, av, "f:p:b:k:h:g:u:o:dDeiqrtQR46")) != -1) {
while ((opt = getopt(ac, av, "f:p:b:k:h:g:u:o:C:dDeiqrtQRT46")) != -1) {
switch (opt) {
case '4':
options.address_family = AF_INET;
@ -1354,6 +1355,25 @@ main(int ac, char **av)
case 't':
test_flag = 1;
break;
case 'T':
test_flag = 2;
break;
case 'C':
cp = optarg;
while ((p = strsep(&cp, ",")) && *p != '\0') {
if (strncmp(p, "addr=", 5) == 0)
test_addr = xstrdup(p + 5);
else if (strncmp(p, "host=", 5) == 0)
test_host = xstrdup(p + 5);
else if (strncmp(p, "user=", 5) == 0)
test_user = xstrdup(p + 5);
else {
fprintf(stderr, "Invalid test "
"mode specification %s\n", p);
exit(1);
}
}
break;
case 'u':
utmp_len = (u_int)strtonum(optarg, 0, MAXHOSTNAMELEN+1, NULL);
if (utmp_len > MAXHOSTNAMELEN) {
@ -1415,6 +1435,20 @@ main(int ac, char **av)
sensitive_data.have_ssh1_key = 0;
sensitive_data.have_ssh2_key = 0;
/*
* If we're doing an extended config test, make sure we have all of
* the parameters we need. If we're not doing an extended test,
* do not silently ignore connection test params.
*/
if (test_flag >= 2 && (test_user != NULL || test_host != NULL || test_addr != NULL)
&& (test_user == NULL || test_host == NULL || test_addr == NULL))
fatal("user, host and addr are all required when testing "
"Match configs");
if (test_flag < 2 && (test_user != NULL || test_host != NULL ||
test_addr != NULL))
fatal("Config test connection parameter (-C) provided without "
"test mode (-T)");
/* Fetch our configuration */
buffer_init(&cfg);
if (rexeced_flag)
@ -1543,6 +1577,13 @@ main(int ac, char **av)
"world-writable.", _PATH_PRIVSEP_CHROOT_DIR);
}
if (test_flag > 1) {
if (test_user != NULL && test_addr != NULL && test_host != NULL)
parse_server_match_config(&options, test_user,
test_host, test_addr);
dump_config(&options);
}
/* Configuration looks good, so exit if in test mode. */
if (test_flag)
exit(0);