You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2365 lines
71 KiB
2365 lines
71 KiB
|
|
/* $OpenBSD: servconf.c,v 1.306 2017/03/14 07:19:07 djm Exp $ */ |
|
/* |
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
|
* All rights reserved |
|
* |
|
* As far as I am concerned, the code I have written for this software |
|
* can be used freely for any purpose. Any derived versions of this |
|
* software must be clearly marked as such, and if the derived work is |
|
* incompatible with the protocol description in the RFC file, it must be |
|
* called by a name other than "ssh" or "Secure Shell". |
|
*/ |
|
|
|
#include "includes.h" |
|
|
|
#include <sys/types.h> |
|
#include <sys/socket.h> |
|
|
|
#include <netinet/in.h> |
|
#include <netinet/in_systm.h> |
|
#include <netinet/ip.h> |
|
|
|
#include <ctype.h> |
|
#include <netdb.h> |
|
#include <pwd.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <signal.h> |
|
#include <unistd.h> |
|
#include <limits.h> |
|
#include <stdarg.h> |
|
#include <errno.h> |
|
#ifdef HAVE_UTIL_H |
|
#include <util.h> |
|
#endif |
|
|
|
#include "openbsd-compat/sys-queue.h" |
|
#include "xmalloc.h" |
|
#include "ssh.h" |
|
#include "log.h" |
|
#include "buffer.h" |
|
#include "misc.h" |
|
#include "servconf.h" |
|
#include "compat.h" |
|
#include "pathnames.h" |
|
#include "cipher.h" |
|
#include "key.h" |
|
#include "kex.h" |
|
#include "mac.h" |
|
#include "match.h" |
|
#include "channels.h" |
|
#include "groupaccess.h" |
|
#include "canohost.h" |
|
#include "packet.h" |
|
#include "hostfile.h" |
|
#include "auth.h" |
|
#include "myproposal.h" |
|
#include "digest.h" |
|
|
|
#ifdef ANDROID |
|
#include <cutils/properties.h> |
|
#endif |
|
|
|
static void add_listen_addr(ServerOptions *, char *, int); |
|
static void add_one_listen_addr(ServerOptions *, char *, int); |
|
|
|
/* Use of privilege separation or not */ |
|
extern int use_privsep; |
|
extern Buffer cfg; |
|
|
|
/* Initializes the server options to their default values. */ |
|
|
|
void |
|
initialize_server_options(ServerOptions *options) |
|
{ |
|
memset(options, 0, sizeof(*options)); |
|
|
|
/* Portable-specific options */ |
|
options->use_pam = -1; |
|
|
|
/* Standard Options */ |
|
options->num_ports = 0; |
|
options->ports_from_cmdline = 0; |
|
options->queued_listen_addrs = NULL; |
|
options->num_queued_listens = 0; |
|
options->listen_addrs = NULL; |
|
options->address_family = -1; |
|
options->num_host_key_files = 0; |
|
options->num_host_cert_files = 0; |
|
options->host_key_agent = NULL; |
|
options->pid_file = NULL; |
|
options->login_grace_time = -1; |
|
options->permit_root_login = PERMIT_NOT_SET; |
|
options->ignore_rhosts = -1; |
|
options->ignore_user_known_hosts = -1; |
|
options->print_motd = -1; |
|
options->print_lastlog = -1; |
|
options->x11_forwarding = -1; |
|
options->x11_display_offset = -1; |
|
options->x11_use_localhost = -1; |
|
options->permit_tty = -1; |
|
options->permit_user_rc = -1; |
|
options->xauth_location = NULL; |
|
options->strict_modes = -1; |
|
options->tcp_keep_alive = -1; |
|
options->log_facility = SYSLOG_FACILITY_NOT_SET; |
|
options->log_level = SYSLOG_LEVEL_NOT_SET; |
|
options->hostbased_authentication = -1; |
|
options->hostbased_uses_name_from_packet_only = -1; |
|
options->hostbased_key_types = NULL; |
|
options->hostkeyalgorithms = NULL; |
|
options->pubkey_authentication = -1; |
|
options->pubkey_key_types = NULL; |
|
options->kerberos_authentication = -1; |
|
options->kerberos_or_local_passwd = -1; |
|
options->kerberos_ticket_cleanup = -1; |
|
options->kerberos_get_afs_token = -1; |
|
options->gss_authentication=-1; |
|
options->gss_cleanup_creds = -1; |
|
options->gss_strict_acceptor = -1; |
|
options->password_authentication = -1; |
|
options->kbd_interactive_authentication = -1; |
|
options->challenge_response_authentication = -1; |
|
options->permit_empty_passwd = -1; |
|
options->permit_user_env = -1; |
|
options->compression = -1; |
|
options->rekey_limit = -1; |
|
options->rekey_interval = -1; |
|
options->allow_tcp_forwarding = -1; |
|
options->allow_streamlocal_forwarding = -1; |
|
options->allow_agent_forwarding = -1; |
|
options->num_allow_users = 0; |
|
options->num_deny_users = 0; |
|
options->num_allow_groups = 0; |
|
options->num_deny_groups = 0; |
|
options->ciphers = NULL; |
|
options->macs = NULL; |
|
options->kex_algorithms = NULL; |
|
options->fwd_opts.gateway_ports = -1; |
|
options->fwd_opts.streamlocal_bind_mask = (mode_t)-1; |
|
options->fwd_opts.streamlocal_bind_unlink = -1; |
|
options->num_subsystems = 0; |
|
options->max_startups_begin = -1; |
|
options->max_startups_rate = -1; |
|
options->max_startups = -1; |
|
options->max_authtries = -1; |
|
options->max_sessions = -1; |
|
options->banner = NULL; |
|
options->use_dns = -1; |
|
options->client_alive_interval = -1; |
|
options->client_alive_count_max = -1; |
|
options->num_authkeys_files = 0; |
|
options->num_accept_env = 0; |
|
options->permit_tun = -1; |
|
options->num_permitted_opens = -1; |
|
options->adm_forced_command = NULL; |
|
options->chroot_directory = NULL; |
|
options->authorized_keys_command = NULL; |
|
options->authorized_keys_command_user = NULL; |
|
options->revoked_keys_file = NULL; |
|
options->trusted_user_ca_keys = NULL; |
|
options->authorized_principals_file = NULL; |
|
options->authorized_principals_command = NULL; |
|
options->authorized_principals_command_user = NULL; |
|
options->ip_qos_interactive = -1; |
|
options->ip_qos_bulk = -1; |
|
options->version_addendum = NULL; |
|
options->fingerprint_hash = -1; |
|
options->disable_forwarding = -1; |
|
} |
|
|
|
/* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ |
|
static int |
|
option_clear_or_none(const char *o) |
|
{ |
|
return o == NULL || strcasecmp(o, "none") == 0; |
|
} |
|
|
|
static void |
|
assemble_algorithms(ServerOptions *o) |
|
{ |
|
if (kex_assemble_names(KEX_SERVER_ENCRYPT, &o->ciphers) != 0 || |
|
kex_assemble_names(KEX_SERVER_MAC, &o->macs) != 0 || |
|
kex_assemble_names(KEX_SERVER_KEX, &o->kex_algorithms) != 0 || |
|
kex_assemble_names(KEX_DEFAULT_PK_ALG, |
|
&o->hostkeyalgorithms) != 0 || |
|
kex_assemble_names(KEX_DEFAULT_PK_ALG, |
|
&o->hostbased_key_types) != 0 || |
|
kex_assemble_names(KEX_DEFAULT_PK_ALG, &o->pubkey_key_types) != 0) |
|
fatal("kex_assemble_names failed"); |
|
} |
|
|
|
void |
|
fill_default_server_options(ServerOptions *options) |
|
{ |
|
int i; |
|
|
|
/* Portable-specific options */ |
|
if (options->use_pam == -1) |
|
options->use_pam = 0; |
|
|
|
/* Standard Options */ |
|
if (options->num_host_key_files == 0) { |
|
/* fill default hostkeys for protocols */ |
|
options->host_key_files[options->num_host_key_files++] = |
|
_PATH_HOST_RSA_KEY_FILE; |
|
options->host_key_files[options->num_host_key_files++] = |
|
_PATH_HOST_DSA_KEY_FILE; |
|
#ifdef OPENSSL_HAS_ECC |
|
options->host_key_files[options->num_host_key_files++] = |
|
_PATH_HOST_ECDSA_KEY_FILE; |
|
#endif |
|
options->host_key_files[options->num_host_key_files++] = |
|
_PATH_HOST_ED25519_KEY_FILE; |
|
} |
|
/* No certificates by default */ |
|
if (options->num_ports == 0) |
|
options->ports[options->num_ports++] = SSH_DEFAULT_PORT; |
|
if (options->address_family == -1) |
|
options->address_family = AF_UNSPEC; |
|
if (options->listen_addrs == NULL) |
|
add_listen_addr(options, NULL, 0); |
|
if (options->pid_file == NULL) |
|
options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE); |
|
if (options->login_grace_time == -1) |
|
options->login_grace_time = 120; |
|
if (options->permit_root_login == PERMIT_NOT_SET) |
|
options->permit_root_login = PERMIT_NO_PASSWD; |
|
if (options->ignore_rhosts == -1) |
|
options->ignore_rhosts = 1; |
|
if (options->ignore_user_known_hosts == -1) |
|
options->ignore_user_known_hosts = 0; |
|
if (options->print_motd == -1) |
|
options->print_motd = 1; |
|
if (options->print_lastlog == -1) |
|
options->print_lastlog = 1; |
|
if (options->x11_forwarding == -1) |
|
options->x11_forwarding = 0; |
|
if (options->x11_display_offset == -1) |
|
options->x11_display_offset = 10; |
|
if (options->x11_use_localhost == -1) |
|
options->x11_use_localhost = 1; |
|
if (options->xauth_location == NULL) |
|
options->xauth_location = xstrdup(_PATH_XAUTH); |
|
if (options->permit_tty == -1) |
|
options->permit_tty = 1; |
|
if (options->permit_user_rc == -1) |
|
options->permit_user_rc = 1; |
|
if (options->strict_modes == -1) |
|
options->strict_modes = 1; |
|
if (options->tcp_keep_alive == -1) |
|
options->tcp_keep_alive = 1; |
|
if (options->log_facility == SYSLOG_FACILITY_NOT_SET) |
|
options->log_facility = SYSLOG_FACILITY_AUTH; |
|
if (options->log_level == SYSLOG_LEVEL_NOT_SET) |
|
options->log_level = SYSLOG_LEVEL_INFO; |
|
if (options->hostbased_authentication == -1) |
|
options->hostbased_authentication = 0; |
|
if (options->hostbased_uses_name_from_packet_only == -1) |
|
options->hostbased_uses_name_from_packet_only = 0; |
|
if (options->pubkey_authentication == -1) |
|
options->pubkey_authentication = 1; |
|
if (options->kerberos_authentication == -1) |
|
options->kerberos_authentication = 0; |
|
if (options->kerberos_or_local_passwd == -1) |
|
options->kerberos_or_local_passwd = 1; |
|
if (options->kerberos_ticket_cleanup == -1) |
|
options->kerberos_ticket_cleanup = 1; |
|
if (options->kerberos_get_afs_token == -1) |
|
options->kerberos_get_afs_token = 0; |
|
if (options->gss_authentication == -1) |
|
options->gss_authentication = 0; |
|
if (options->gss_cleanup_creds == -1) |
|
options->gss_cleanup_creds = 1; |
|
if (options->gss_strict_acceptor == -1) |
|
options->gss_strict_acceptor = 1; |
|
if (options->password_authentication == -1) |
|
options->password_authentication = 1; |
|
if (options->kbd_interactive_authentication == -1) |
|
options->kbd_interactive_authentication = 0; |
|
if (options->challenge_response_authentication == -1) |
|
options->challenge_response_authentication = 1; |
|
if (options->permit_empty_passwd == -1) |
|
options->permit_empty_passwd = 0; |
|
if (options->permit_user_env == -1) |
|
options->permit_user_env = 0; |
|
if (options->compression == -1) |
|
options->compression = COMP_DELAYED; |
|
if (options->rekey_limit == -1) |
|
options->rekey_limit = 0; |
|
if (options->rekey_interval == -1) |
|
options->rekey_interval = 0; |
|
if (options->allow_tcp_forwarding == -1) |
|
options->allow_tcp_forwarding = FORWARD_ALLOW; |
|
if (options->allow_streamlocal_forwarding == -1) |
|
options->allow_streamlocal_forwarding = FORWARD_ALLOW; |
|
if (options->allow_agent_forwarding == -1) |
|
options->allow_agent_forwarding = 1; |
|
if (options->fwd_opts.gateway_ports == -1) |
|
options->fwd_opts.gateway_ports = 0; |
|
if (options->max_startups == -1) |
|
options->max_startups = 100; |
|
if (options->max_startups_rate == -1) |
|
options->max_startups_rate = 30; /* 30% */ |
|
if (options->max_startups_begin == -1) |
|
options->max_startups_begin = 10; |
|
if (options->max_authtries == -1) |
|
options->max_authtries = DEFAULT_AUTH_FAIL_MAX; |
|
if (options->max_sessions == -1) |
|
options->max_sessions = DEFAULT_SESSIONS_MAX; |
|
if (options->use_dns == -1) |
|
options->use_dns = 0; |
|
if (options->client_alive_interval == -1) |
|
options->client_alive_interval = 0; |
|
if (options->client_alive_count_max == -1) |
|
options->client_alive_count_max = 3; |
|
if (options->num_authkeys_files == 0) { |
|
options->authorized_keys_files[options->num_authkeys_files++] = |
|
xstrdup(_PATH_SSH_USER_PERMITTED_KEYS); |
|
options->authorized_keys_files[options->num_authkeys_files++] = |
|
xstrdup(_PATH_SSH_USER_PERMITTED_KEYS2); |
|
} |
|
if (options->permit_tun == -1) |
|
options->permit_tun = SSH_TUNMODE_NO; |
|
if (options->ip_qos_interactive == -1) |
|
options->ip_qos_interactive = IPTOS_LOWDELAY; |
|
if (options->ip_qos_bulk == -1) |
|
options->ip_qos_bulk = IPTOS_THROUGHPUT; |
|
if (options->version_addendum == NULL) |
|
options->version_addendum = xstrdup(""); |
|
if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1) |
|
options->fwd_opts.streamlocal_bind_mask = 0177; |
|
if (options->fwd_opts.streamlocal_bind_unlink == -1) |
|
options->fwd_opts.streamlocal_bind_unlink = 0; |
|
if (options->fingerprint_hash == -1) |
|
options->fingerprint_hash = SSH_FP_HASH_DEFAULT; |
|
if (options->disable_forwarding == -1) |
|
options->disable_forwarding = 0; |
|
|
|
assemble_algorithms(options); |
|
|
|
/* Turn privilege separation and sandboxing on by default */ |
|
if (use_privsep == -1) |
|
use_privsep = PRIVSEP_ON; |
|
|
|
#define CLEAR_ON_NONE(v) \ |
|
do { \ |
|
if (option_clear_or_none(v)) { \ |
|
free(v); \ |
|
v = NULL; \ |
|
} \ |
|
} while(0) |
|
CLEAR_ON_NONE(options->pid_file); |
|
CLEAR_ON_NONE(options->xauth_location); |
|
CLEAR_ON_NONE(options->banner); |
|
CLEAR_ON_NONE(options->trusted_user_ca_keys); |
|
CLEAR_ON_NONE(options->revoked_keys_file); |
|
CLEAR_ON_NONE(options->authorized_principals_file); |
|
CLEAR_ON_NONE(options->adm_forced_command); |
|
CLEAR_ON_NONE(options->chroot_directory); |
|
for (i = 0; i < options->num_host_key_files; i++) |
|
CLEAR_ON_NONE(options->host_key_files[i]); |
|
for (i = 0; i < options->num_host_cert_files; i++) |
|
CLEAR_ON_NONE(options->host_cert_files[i]); |
|
#undef CLEAR_ON_NONE |
|
|
|
/* Similar handling for AuthenticationMethods=any */ |
|
if (options->num_auth_methods == 1 && |
|
strcmp(options->auth_methods[0], "any") == 0) { |
|
free(options->auth_methods[0]); |
|
options->auth_methods[0] = NULL; |
|
options->num_auth_methods = 0; |
|
} |
|
|
|
#ifndef HAVE_MMAP |
|
if (use_privsep && options->compression == 1) { |
|
error("This platform does not support both privilege " |
|
"separation and compression"); |
|
error("Compression disabled"); |
|
options->compression = 0; |
|
} |
|
#endif |
|
|
|
} |
|
|
|
/* Keyword tokens. */ |
|
typedef enum { |
|
sBadOption, /* == unknown option */ |
|
/* Portable-specific options */ |
|
sUsePAM, |
|
/* Standard Options */ |
|
sPort, sHostKeyFile, sLoginGraceTime, |
|
sPermitRootLogin, sLogFacility, sLogLevel, |
|
sRhostsRSAAuthentication, sRSAAuthentication, |
|
sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, |
|
sKerberosGetAFSToken, |
|
sKerberosTgtPassing, sChallengeResponseAuthentication, |
|
sPasswordAuthentication, sKbdInteractiveAuthentication, |
|
sListenAddress, sAddressFamily, |
|
sPrintMotd, sPrintLastLog, sIgnoreRhosts, |
|
sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost, |
|
sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive, |
|
sPermitUserEnvironment, sAllowTcpForwarding, sCompression, |
|
sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, |
|
sIgnoreUserKnownHosts, sCiphers, sMacs, sPidFile, |
|
sGatewayPorts, sPubkeyAuthentication, sPubkeyAcceptedKeyTypes, |
|
sXAuthLocation, sSubsystem, sMaxStartups, sMaxAuthTries, sMaxSessions, |
|
sBanner, sUseDNS, sHostbasedAuthentication, |
|
sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedKeyTypes, |
|
sHostKeyAlgorithms, |
|
sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, |
|
sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, |
|
sAcceptEnv, sPermitTunnel, |
|
sMatch, sPermitOpen, sForceCommand, sChrootDirectory, |
|
sUsePrivilegeSeparation, sAllowAgentForwarding, |
|
sHostCertificate, |
|
sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile, |
|
sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser, |
|
sKexAlgorithms, sIPQoS, sVersionAddendum, |
|
sAuthorizedKeysCommand, sAuthorizedKeysCommandUser, |
|
sAuthenticationMethods, sHostKeyAgent, sPermitUserRC, |
|
sStreamLocalBindMask, sStreamLocalBindUnlink, |
|
sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, |
|
sDeprecated, sIgnore, sUnsupported |
|
} ServerOpCodes; |
|
|
|
#define SSHCFG_GLOBAL 0x01 /* allowed in main section of sshd_config */ |
|
#define SSHCFG_MATCH 0x02 /* allowed inside a Match section */ |
|
#define SSHCFG_ALL (SSHCFG_GLOBAL|SSHCFG_MATCH) |
|
|
|
/* Textual representation of the tokens. */ |
|
static struct { |
|
const char *name; |
|
ServerOpCodes opcode; |
|
u_int flags; |
|
} keywords[] = { |
|
/* Portable-specific options */ |
|
#ifdef USE_PAM |
|
{ "usepam", sUsePAM, SSHCFG_GLOBAL }, |
|
#else |
|
{ "usepam", sUnsupported, SSHCFG_GLOBAL }, |
|
#endif |
|
{ "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL }, |
|
/* Standard Options */ |
|
{ "port", sPort, SSHCFG_GLOBAL }, |
|
{ "hostkey", sHostKeyFile, SSHCFG_GLOBAL }, |
|
{ "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL }, /* alias */ |
|
{ "hostkeyagent", sHostKeyAgent, SSHCFG_GLOBAL }, |
|
{ "pidfile", sPidFile, SSHCFG_GLOBAL }, |
|
{ "serverkeybits", sDeprecated, SSHCFG_GLOBAL }, |
|
{ "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL }, |
|
{ "keyregenerationinterval", sDeprecated, SSHCFG_GLOBAL }, |
|
{ "permitrootlogin", sPermitRootLogin, SSHCFG_ALL }, |
|
{ "syslogfacility", sLogFacility, SSHCFG_GLOBAL }, |
|
{ "loglevel", sLogLevel, SSHCFG_GLOBAL }, |
|
{ "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL }, |
|
{ "rhostsrsaauthentication", sDeprecated, SSHCFG_ALL }, |
|
{ "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL }, |
|
{ "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_ALL }, |
|
{ "hostbasedacceptedkeytypes", sHostbasedAcceptedKeyTypes, SSHCFG_ALL }, |
|
{ "hostkeyalgorithms", sHostKeyAlgorithms, SSHCFG_GLOBAL }, |
|
{ "rsaauthentication", sDeprecated, SSHCFG_ALL }, |
|
{ "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL }, |
|
{ "pubkeyacceptedkeytypes", sPubkeyAcceptedKeyTypes, SSHCFG_ALL }, |
|
{ "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */ |
|
#ifdef KRB5 |
|
{ "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL }, |
|
{ "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL }, |
|
{ "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL }, |
|
#ifdef USE_AFS |
|
{ "kerberosgetafstoken", sKerberosGetAFSToken, SSHCFG_GLOBAL }, |
|
#else |
|
{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, |
|
#endif |
|
#else |
|
{ "kerberosauthentication", sUnsupported, SSHCFG_ALL }, |
|
{ "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL }, |
|
{ "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL }, |
|
{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, |
|
#endif |
|
{ "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL }, |
|
{ "afstokenpassing", sUnsupported, SSHCFG_GLOBAL }, |
|
#ifdef GSSAPI |
|
{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, |
|
{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, |
|
{ "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, |
|
#else |
|
{ "gssapiauthentication", sUnsupported, SSHCFG_ALL }, |
|
{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, |
|
{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, |
|
#endif |
|
{ "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, |
|
{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, |
|
{ "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, |
|
{ "skeyauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, /* alias */ |
|
{ "checkmail", sDeprecated, SSHCFG_GLOBAL }, |
|
{ "listenaddress", sListenAddress, SSHCFG_GLOBAL }, |
|
{ "addressfamily", sAddressFamily, SSHCFG_GLOBAL }, |
|
{ "printmotd", sPrintMotd, SSHCFG_GLOBAL }, |
|
#ifdef DISABLE_LASTLOG |
|
{ "printlastlog", sUnsupported, SSHCFG_GLOBAL }, |
|
#else |
|
{ "printlastlog", sPrintLastLog, SSHCFG_GLOBAL }, |
|
#endif |
|
{ "ignorerhosts", sIgnoreRhosts, SSHCFG_GLOBAL }, |
|
{ "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL }, |
|
{ "x11forwarding", sX11Forwarding, SSHCFG_ALL }, |
|
{ "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL }, |
|
{ "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL }, |
|
{ "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL }, |
|
{ "strictmodes", sStrictModes, SSHCFG_GLOBAL }, |
|
{ "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL }, |
|
{ "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL }, |
|
{ "uselogin", sDeprecated, SSHCFG_GLOBAL }, |
|
{ "compression", sCompression, SSHCFG_GLOBAL }, |
|
{ "rekeylimit", sRekeyLimit, SSHCFG_ALL }, |
|
{ "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL }, |
|
{ "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL }, /* obsolete alias */ |
|
{ "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL }, |
|
{ "allowagentforwarding", sAllowAgentForwarding, SSHCFG_ALL }, |
|
{ "allowusers", sAllowUsers, SSHCFG_ALL }, |
|
{ "denyusers", sDenyUsers, SSHCFG_ALL }, |
|
{ "allowgroups", sAllowGroups, SSHCFG_ALL }, |
|
{ "denygroups", sDenyGroups, SSHCFG_ALL }, |
|
{ "ciphers", sCiphers, SSHCFG_GLOBAL }, |
|
{ "macs", sMacs, SSHCFG_GLOBAL }, |
|
{ "protocol", sIgnore, SSHCFG_GLOBAL }, |
|
{ "gatewayports", sGatewayPorts, SSHCFG_ALL }, |
|
{ "subsystem", sSubsystem, SSHCFG_GLOBAL }, |
|
{ "maxstartups", sMaxStartups, SSHCFG_GLOBAL }, |
|
{ "maxauthtries", sMaxAuthTries, SSHCFG_ALL }, |
|
{ "maxsessions", sMaxSessions, SSHCFG_ALL }, |
|
{ "banner", sBanner, SSHCFG_ALL }, |
|
{ "usedns", sUseDNS, SSHCFG_GLOBAL }, |
|
{ "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL }, |
|
{ "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL }, |
|
{ "clientaliveinterval", sClientAliveInterval, SSHCFG_ALL }, |
|
{ "clientalivecountmax", sClientAliveCountMax, SSHCFG_ALL }, |
|
{ "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_ALL }, |
|
{ "authorizedkeysfile2", sDeprecated, SSHCFG_ALL }, |
|
{ "useprivilegeseparation", sDeprecated, SSHCFG_GLOBAL}, |
|
{ "acceptenv", sAcceptEnv, SSHCFG_ALL }, |
|
{ "permittunnel", sPermitTunnel, SSHCFG_ALL }, |
|
{ "permittty", sPermitTTY, SSHCFG_ALL }, |
|
{ "permituserrc", sPermitUserRC, SSHCFG_ALL }, |
|
{ "match", sMatch, SSHCFG_ALL }, |
|
{ "permitopen", sPermitOpen, SSHCFG_ALL }, |
|
{ "forcecommand", sForceCommand, SSHCFG_ALL }, |
|
{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL }, |
|
{ "hostcertificate", sHostCertificate, SSHCFG_GLOBAL }, |
|
{ "revokedkeys", sRevokedKeys, SSHCFG_ALL }, |
|
{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL }, |
|
{ "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL }, |
|
{ "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL }, |
|
{ "ipqos", sIPQoS, SSHCFG_ALL }, |
|
{ "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL }, |
|
{ "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL }, |
|
{ "authorizedprincipalscommand", sAuthorizedPrincipalsCommand, SSHCFG_ALL }, |
|
{ "authorizedprincipalscommanduser", sAuthorizedPrincipalsCommandUser, SSHCFG_ALL }, |
|
{ "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL }, |
|
{ "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL }, |
|
{ "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_ALL }, |
|
{ "streamlocalbindunlink", sStreamLocalBindUnlink, SSHCFG_ALL }, |
|
{ "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL }, |
|
{ "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL }, |
|
{ "disableforwarding", sDisableForwarding, SSHCFG_ALL }, |
|
{ 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. |
|
*/ |
|
|
|
static ServerOpCodes |
|
parse_token(const char *cp, const char *filename, |
|
int linenum, u_int *flags) |
|
{ |
|
u_int i; |
|
|
|
for (i = 0; keywords[i].name; i++) |
|
if (strcasecmp(cp, keywords[i].name) == 0) { |
|
*flags = keywords[i].flags; |
|
return keywords[i].opcode; |
|
} |
|
|
|
error("%s: line %d: Bad configuration option: %s", |
|
filename, linenum, cp); |
|
return sBadOption; |
|
} |
|
|
|
char * |
|
derelativise_path(const char *path) |
|
{ |
|
char *expanded, *ret, cwd[PATH_MAX]; |
|
|
|
if (strcasecmp(path, "none") == 0) |
|
return xstrdup("none"); |
|
expanded = tilde_expand_filename(path, getuid()); |
|
if (*expanded == '/') |
|
return expanded; |
|
if (getcwd(cwd, sizeof(cwd)) == NULL) |
|
fatal("%s: getcwd: %s", __func__, strerror(errno)); |
|
xasprintf(&ret, "%s/%s", cwd, expanded); |
|
free(expanded); |
|
return ret; |
|
} |
|
|
|
static void |
|
add_listen_addr(ServerOptions *options, char *addr, int port) |
|
{ |
|
u_int i; |
|
|
|
if (port == 0) |
|
for (i = 0; i < options->num_ports; i++) |
|
add_one_listen_addr(options, addr, options->ports[i]); |
|
else |
|
add_one_listen_addr(options, addr, port); |
|
} |
|
|
|
static void |
|
add_one_listen_addr(ServerOptions *options, char *addr, int port) |
|
{ |
|
struct addrinfo hints, *ai, *aitop; |
|
char strport[NI_MAXSERV]; |
|
int gaierr; |
|
|
|
memset(&hints, 0, sizeof(hints)); |
|
hints.ai_family = options->address_family; |
|
hints.ai_socktype = SOCK_STREAM; |
|
hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0; |
|
snprintf(strport, sizeof strport, "%d", port); |
|
if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0) |
|
fatal("bad addr or host: %s (%s)", |
|
addr ? addr : "<NULL>", |
|
ssh_gai_strerror(gaierr)); |
|
for (ai = aitop; ai->ai_next; ai = ai->ai_next) |
|
; |
|
ai->ai_next = options->listen_addrs; |
|
options->listen_addrs = aitop; |
|
} |
|
|
|
/* |
|
* Queue a ListenAddress to be processed once we have all of the Ports |
|
* and AddressFamily options. |
|
*/ |
|
static void |
|
queue_listen_addr(ServerOptions *options, char *addr, int port) |
|
{ |
|
options->queued_listen_addrs = xreallocarray( |
|
options->queued_listen_addrs, options->num_queued_listens + 1, |
|
sizeof(addr)); |
|
options->queued_listen_ports = xreallocarray( |
|
options->queued_listen_ports, options->num_queued_listens + 1, |
|
sizeof(port)); |
|
options->queued_listen_addrs[options->num_queued_listens] = |
|
xstrdup(addr); |
|
options->queued_listen_ports[options->num_queued_listens] = port; |
|
options->num_queued_listens++; |
|
} |
|
|
|
/* |
|
* Process queued (text) ListenAddress entries. |
|
*/ |
|
static void |
|
process_queued_listen_addrs(ServerOptions *options) |
|
{ |
|
u_int i; |
|
|
|
if (options->num_ports == 0) |
|
options->ports[options->num_ports++] = SSH_DEFAULT_PORT; |
|
if (options->address_family == -1) |
|
options->address_family = AF_UNSPEC; |
|
|
|
for (i = 0; i < options->num_queued_listens; i++) { |
|
add_listen_addr(options, options->queued_listen_addrs[i], |
|
options->queued_listen_ports[i]); |
|
free(options->queued_listen_addrs[i]); |
|
options->queued_listen_addrs[i] = NULL; |
|
} |
|
free(options->queued_listen_addrs); |
|
options->queued_listen_addrs = NULL; |
|
free(options->queued_listen_ports); |
|
options->queued_listen_ports = NULL; |
|
options->num_queued_listens = 0; |
|
} |
|
|
|
struct connection_info * |
|
get_connection_info(int populate, int use_dns) |
|
{ |
|
struct ssh *ssh = active_state; /* XXX */ |
|
static struct connection_info ci; |
|
|
|
if (!populate) |
|
return &ci; |
|
ci.host = auth_get_canonical_hostname(ssh, use_dns); |
|
ci.address = ssh_remote_ipaddr(ssh); |
|
ci.laddress = ssh_local_ipaddr(ssh); |
|
ci.lport = ssh_local_port(ssh); |
|
return &ci; |
|
} |
|
|
|
/* |
|
* The strategy for the Match blocks is that the config file is parsed twice. |
|
* |
|
* The first time is at startup. activep is initialized to 1 and the |
|
* directives in the global context are processed and acted on. Hitting a |
|
* Match directive unsets activep and the directives inside the block are |
|
* checked for syntax only. |
|
* |
|
* The second time is after a connection has been established but before |
|
* authentication. activep is initialized to 2 and global config directives |
|
* are ignored since they have already been processed. If the criteria in a |
|
* Match block is met, activep is set and the subsequent directives |
|
* processed and actioned until EOF or another Match block unsets it. Any |
|
* options set are copied into the main server config. |
|
* |
|
* Potential additions/improvements: |
|
* - Add Match support for pre-kex directives, eg. Ciphers. |
|
* |
|
* - Add a Tag directive (idea from David Leonard) ala pf, eg: |
|
* Match Address 192.168.0.* |
|
* Tag trusted |
|
* Match Group wheel |
|
* Tag trusted |
|
* Match Tag trusted |
|
* AllowTcpForwarding yes |
|
* GatewayPorts clientspecified |
|
* [...] |
|
* |
|
* - Add a PermittedChannelRequests directive |
|
* Match Group shell |
|
* PermittedChannelRequests session,forwarded-tcpip |
|
*/ |
|
|
|
static int |
|
match_cfg_line_group(const char *grps, int line, const char *user) |
|
{ |
|
int result = 0; |
|
struct passwd *pw; |
|
|
|
if (user == NULL) |
|
goto out; |
|
|
|
if ((pw = getpwnam(user)) == NULL) { |
|
debug("Can't match group at line %d because user %.100s does " |
|
"not exist", line, user); |
|
} else if (ga_init(pw->pw_name, pw->pw_gid) == 0) { |
|
debug("Can't Match group because user %.100s not in any group " |
|
"at line %d", user, line); |
|
} else if (ga_match_pattern_list(grps) != 1) { |
|
debug("user %.100s does not match group list %.100s at line %d", |
|
user, grps, line); |
|
} else { |
|
debug("user %.100s matched group list %.100s at line %d", user, |
|
grps, line); |
|
result = 1; |
|
} |
|
out: |
|
ga_free(); |
|
return result; |
|
} |
|
|
|
/* |
|
* All of the attributes on a single Match line are ANDed together, so we need |
|
* to check every attribute and set the result to zero if any attribute does |
|
* not match. |
|
*/ |
|
static int |
|
match_cfg_line(char **condition, int line, struct connection_info *ci) |
|
{ |
|
int result = 1, attributes = 0, port; |
|
char *arg, *attrib, *cp = *condition; |
|
|
|
if (ci == NULL) |
|
debug3("checking syntax for 'Match %s'", cp); |
|
else |
|
debug3("checking match for '%s' user %s host %s addr %s " |
|
"laddr %s lport %d", cp, ci->user ? ci->user : "(null)", |
|
ci->host ? ci->host : "(null)", |
|
ci->address ? ci->address : "(null)", |
|
ci->laddress ? ci->laddress : "(null)", ci->lport); |
|
|
|
while ((attrib = strdelim(&cp)) && *attrib != '\0') { |
|
attributes++; |
|
if (strcasecmp(attrib, "all") == 0) { |
|
if (attributes != 1 || |
|
((arg = strdelim(&cp)) != NULL && *arg != '\0')) { |
|
error("'all' cannot be combined with other " |
|
"Match attributes"); |
|
return -1; |
|
} |
|
*condition = cp; |
|
return 1; |
|
} |
|
if ((arg = strdelim(&cp)) == NULL || *arg == '\0') { |
|
error("Missing Match criteria for %s", attrib); |
|
return -1; |
|
} |
|
if (strcasecmp(attrib, "user") == 0) { |
|
if (ci == NULL || ci->user == NULL) { |
|
result = 0; |
|
continue; |
|
} |
|
if (match_pattern_list(ci->user, arg, 0) != 1) |
|
result = 0; |
|
else |
|
debug("user %.100s matched 'User %.100s' at " |
|
"line %d", ci->user, arg, line); |
|
} else if (strcasecmp(attrib, "group") == 0) { |
|
if (ci == NULL || ci->user == NULL) { |
|
result = 0; |
|
continue; |
|
} |
|
switch (match_cfg_line_group(arg, line, ci->user)) { |
|
case -1: |
|
return -1; |
|
case 0: |
|
result = 0; |
|
} |
|
} else if (strcasecmp(attrib, "host") == 0) { |
|
if (ci == NULL || ci->host == NULL) { |
|
result = 0; |
|
continue; |
|
} |
|
if (match_hostname(ci->host, arg) != 1) |
|
result = 0; |
|
else |
|
debug("connection from %.100s matched 'Host " |
|
"%.100s' at line %d", ci->host, arg, line); |
|
} else if (strcasecmp(attrib, "address") == 0) { |
|
if (ci == NULL || ci->address == NULL) { |
|
result = 0; |
|
continue; |
|
} |
|
switch (addr_match_list(ci->address, arg)) { |
|
case 1: |
|
debug("connection from %.100s matched 'Address " |
|
"%.100s' at line %d", ci->address, arg, line); |
|
break; |
|
case 0: |
|
case -1: |
|
result = 0; |
|
break; |
|
case -2: |
|
return -1; |
|
} |
|
} else if (strcasecmp(attrib, "localaddress") == 0){ |
|
if (ci == NULL || ci->laddress == NULL) { |
|
result = 0; |
|
continue; |
|
} |
|
switch (addr_match_list(ci->laddress, arg)) { |
|
case 1: |
|
debug("connection from %.100s matched " |
|
"'LocalAddress %.100s' at line %d", |
|
ci->laddress, arg, line); |
|
break; |
|
case 0: |
|
case -1: |
|
result = 0; |
|
break; |
|
case -2: |
|
return -1; |
|
} |
|
} else if (strcasecmp(attrib, "localport") == 0) { |
|
if ((port = a2port(arg)) == -1) { |
|
error("Invalid LocalPort '%s' on Match line", |
|
arg); |
|
return -1; |
|
} |
|
if (ci == NULL || ci->lport == 0) { |
|
result = 0; |
|
continue; |
|
} |
|
/* TODO support port lists */ |
|
if (port == ci->lport) |
|
debug("connection from %.100s matched " |
|
"'LocalPort %d' at line %d", |
|
ci->laddress, port, line); |
|
else |
|
result = 0; |
|
} else { |
|
error("Unsupported Match attribute %s", attrib); |
|
return -1; |
|
} |
|
} |
|
if (attributes == 0) { |
|
error("One or more attributes required for Match"); |
|
return -1; |
|
} |
|
if (ci != NULL) |
|
debug3("match %sfound", result ? "" : "not "); |
|
*condition = cp; |
|
return result; |
|
} |
|
|
|
#define WHITESPACE " \t\r\n" |
|
|
|
/* Multistate option parsing */ |
|
struct multistate { |
|
char *key; |
|
int value; |
|
}; |
|
static const struct multistate multistate_addressfamily[] = { |
|
{ "inet", AF_INET }, |
|
{ "inet6", AF_INET6 }, |
|
{ "any", AF_UNSPEC }, |
|
{ NULL, -1 } |
|
}; |
|
static const struct multistate multistate_permitrootlogin[] = { |
|
{ "without-password", PERMIT_NO_PASSWD }, |
|
{ "prohibit-password", PERMIT_NO_PASSWD }, |
|
{ "forced-commands-only", PERMIT_FORCED_ONLY }, |
|
{ "yes", PERMIT_YES }, |
|
{ "no", PERMIT_NO }, |
|
{ NULL, -1 } |
|
}; |
|
static const struct multistate multistate_compression[] = { |
|
{ "yes", COMP_DELAYED }, |
|
{ "delayed", COMP_DELAYED }, |
|
{ "no", COMP_NONE }, |
|
{ NULL, -1 } |
|
}; |
|
static const struct multistate multistate_gatewayports[] = { |
|
{ "clientspecified", 2 }, |
|
{ "yes", 1 }, |
|
{ "no", 0 }, |
|
{ NULL, -1 } |
|
}; |
|
static const struct multistate multistate_privsep[] = { |
|
{ "yes", PRIVSEP_NOSANDBOX }, |
|
{ "sandbox", PRIVSEP_ON }, |
|
{ "nosandbox", PRIVSEP_NOSANDBOX }, |
|
{ "no", PRIVSEP_OFF }, |
|
{ NULL, -1 } |
|
}; |
|
static const struct multistate multistate_tcpfwd[] = { |
|
{ "yes", FORWARD_ALLOW }, |
|
{ "all", FORWARD_ALLOW }, |
|
{ "no", FORWARD_DENY }, |
|
{ "remote", FORWARD_REMOTE }, |
|
{ "local", FORWARD_LOCAL }, |
|
{ NULL, -1 } |
|
}; |
|
|
|
int |
|
process_server_config_line(ServerOptions *options, char *line, |
|
const char *filename, int linenum, int *activep, |
|
struct connection_info *connectinfo) |
|
{ |
|
char *cp, **charptr, *arg, *p; |
|
int cmdline = 0, *intptr, value, value2, n, port; |
|
SyslogFacility *log_facility_ptr; |
|
LogLevel *log_level_ptr; |
|
ServerOpCodes opcode; |
|
u_int i, flags = 0; |
|
size_t len; |
|
long long val64; |
|
const struct multistate *multistate_ptr; |
|
|
|
/* Strip trailing whitespace. Allow \f (form feed) at EOL only */ |
|
if ((len = strlen(line)) == 0) |
|
return 0; |
|
for (len--; len > 0; len--) { |
|
if (strchr(WHITESPACE "\f", line[len]) == NULL) |
|
break; |
|
line[len] = '\0'; |
|
} |
|
|
|
cp = line; |
|
if ((arg = strdelim(&cp)) == NULL) |
|
return 0; |
|
/* Ignore leading whitespace */ |
|
if (*arg == '\0') |
|
arg = strdelim(&cp); |
|
if (!arg || !*arg || *arg == '#') |
|
return 0; |
|
intptr = NULL; |
|
charptr = NULL; |
|
opcode = parse_token(arg, filename, linenum, &flags); |
|
|
|
if (activep == NULL) { /* We are processing a command line directive */ |
|
cmdline = 1; |
|
activep = &cmdline; |
|
} |
|
if (*activep && opcode != sMatch) |
|
debug3("%s:%d setting %s %s", filename, linenum, arg, cp); |
|
if (*activep == 0 && !(flags & SSHCFG_MATCH)) { |
|
if (connectinfo == NULL) { |
|
fatal("%s line %d: Directive '%s' is not allowed " |
|
"within a Match block", filename, linenum, arg); |
|
} else { /* this is a directive we have already processed */ |
|
while (arg) |
|
arg = strdelim(&cp); |
|
return 0; |
|
} |
|
} |
|
|
|
switch (opcode) { |
|
/* Portable-specific options */ |
|
case sUsePAM: |
|
intptr = &options->use_pam; |
|
goto parse_flag; |
|
|
|
/* Standard Options */ |
|
case sBadOption: |
|
return -1; |
|
case sPort: |
|
/* ignore ports from configfile if cmdline specifies ports */ |
|
if (options->ports_from_cmdline) |
|
return 0; |
|
if (options->num_ports >= MAX_PORTS) |
|
fatal("%s line %d: too many ports.", |
|
filename, linenum); |
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%s line %d: missing port number.", |
|
filename, linenum); |
|
options->ports[options->num_ports++] = a2port(arg); |
|
if (options->ports[options->num_ports-1] <= 0) |
|
fatal("%s line %d: Badly formatted port number.", |
|
filename, linenum); |
|
break; |
|
|
|
case sLoginGraceTime: |
|
intptr = &options->login_grace_time; |
|
parse_time: |
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%s line %d: missing time value.", |
|
filename, linenum); |
|
if ((value = convtime(arg)) == -1) |
|
fatal("%s line %d: invalid time value.", |
|
filename, linenum); |
|
if (*activep && *intptr == -1) |
|
*intptr = value; |
|
break; |
|
|
|
case sListenAddress: |
|
arg = strdelim(&cp); |
|
if (arg == NULL || *arg == '\0') |
|
fatal("%s line %d: missing address", |
|
filename, linenum); |
|
/* check for bare IPv6 address: no "[]" and 2 or more ":" */ |
|
if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL |
|
&& strchr(p+1, ':') != NULL) { |
|
queue_listen_addr(options, arg, 0); |
|
break; |
|
} |
|
p = hpdelim(&arg); |
|
if (p == NULL) |
|
fatal("%s line %d: bad address:port usage", |
|
filename, linenum); |
|
p = cleanhostname(p); |
|
if (arg == NULL) |
|
port = 0; |
|
else if ((port = a2port(arg)) <= 0) |
|
fatal("%s line %d: bad port number", filename, linenum); |
|
|
|
queue_listen_addr(options, p, port); |
|
|
|
break; |
|
|
|
case sAddressFamily: |
|
intptr = &options->address_family; |
|
multistate_ptr = multistate_addressfamily; |
|
parse_multistate: |
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%s line %d: missing argument.", |
|
filename, linenum); |
|
value = -1; |
|
for (i = 0; multistate_ptr[i].key != NULL; i++) { |
|
if (strcasecmp(arg, multistate_ptr[i].key) == 0) { |
|
value = multistate_ptr[i].value; |
|
break; |
|
} |
|
} |
|
if (value == -1) |
|
fatal("%s line %d: unsupported option \"%s\".", |
|
filename, linenum, arg); |
|
if (*activep && *intptr == -1) |
|
*intptr = value; |
|
break; |
|
|
|
case sHostKeyFile: |
|
intptr = &options->num_host_key_files; |
|
if (*intptr >= MAX_HOSTKEYS) |
|
fatal("%s line %d: too many host keys specified (max %d).", |
|
filename, linenum, MAX_HOSTKEYS); |
|
charptr = &options->host_key_files[*intptr]; |
|
parse_filename: |
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%s line %d: missing file name.", |
|
filename, linenum); |
|
if (*activep && *charptr == NULL) { |
|
*charptr = derelativise_path(arg); |
|
/* increase optional counter */ |
|
if (intptr != NULL) |
|
*intptr = *intptr + 1; |
|
} |
|
break; |
|
|
|
case sHostKeyAgent: |
|
charptr = &options->host_key_agent; |
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%s line %d: missing socket name.", |
|
filename, linenum); |
|
if (*activep && *charptr == NULL) |
|
*charptr = !strcmp(arg, SSH_AUTHSOCKET_ENV_NAME) ? |
|
xstrdup(arg) : derelativise_path(arg); |
|
break; |
|
|
|
case sHostCertificate: |
|
intptr = &options->num_host_cert_files; |
|
if (*intptr >= MAX_HOSTKEYS) |
|
fatal("%s line %d: too many host certificates " |
|
"specified (max %d).", filename, linenum, |
|
MAX_HOSTCERTS); |
|
charptr = &options->host_cert_files[*intptr]; |
|
goto parse_filename; |
|
|
|
case sPidFile: |
|
charptr = &options->pid_file; |
|
goto parse_filename; |
|
|
|
case sPermitRootLogin: |
|
intptr = &options->permit_root_login; |
|
multistate_ptr = multistate_permitrootlogin; |
|
goto parse_multistate; |
|
|
|
case sIgnoreRhosts: |
|
intptr = &options->ignore_rhosts; |
|
parse_flag: |
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%s line %d: missing yes/no argument.", |
|
filename, linenum); |
|
value = 0; /* silence compiler */ |
|
if (strcmp(arg, "yes") == 0) |
|
value = 1; |
|
else if (strcmp(arg, "no") == 0) |
|
value = 0; |
|
else |
|
fatal("%s line %d: Bad yes/no argument: %s", |
|
filename, linenum, arg); |
|
if (*activep && *intptr == -1) |
|
*intptr = value; |
|
break; |
|
|
|
case sIgnoreUserKnownHosts: |
|
intptr = &options->ignore_user_known_hosts; |
|
goto parse_flag; |
|
|
|
case sHostbasedAuthentication: |
|
intptr = &options->hostbased_authentication; |
|
goto parse_flag; |
|
|
|
case sHostbasedUsesNameFromPacketOnly: |
|
intptr = &options->hostbased_uses_name_from_packet_only; |
|
goto parse_flag; |
|
|
|
case sHostbasedAcceptedKeyTypes: |
|
charptr = &options->hostbased_key_types; |
|
parse_keytypes: |
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%s line %d: Missing argument.", |
|
filename, linenum); |
|
if (*arg != '-' && |
|
!sshkey_names_valid2(*arg == '+' ? arg + 1 : arg, 1)) |
|
fatal("%s line %d: Bad key types '%s'.", |
|
filename, linenum, arg ? arg : "<NONE>"); |
|
if (*activep && *charptr == NULL) |
|
*charptr = xstrdup(arg); |
|
break; |
|
|
|
case sHostKeyAlgorithms: |
|
charptr = &options->hostkeyalgorithms; |
|
goto parse_keytypes; |
|
|
|
case sPubkeyAuthentication: |
|
intptr = &options->pubkey_authentication; |
|
goto parse_flag; |
|
|
|
case sPubkeyAcceptedKeyTypes: |
|
charptr = &options->pubkey_key_types; |
|
goto parse_keytypes; |
|
|
|
case sKerberosAuthentication: |
|
intptr = &options->kerberos_authentication; |
|
goto parse_flag; |
|
|
|
case sKerberosOrLocalPasswd: |
|
intptr = &options->kerberos_or_local_passwd; |
|
goto parse_flag; |
|
|
|
case sKerberosTicketCleanup: |
|
intptr = &options->kerberos_ticket_cleanup; |
|
goto parse_flag; |
|
|
|
case sKerberosGetAFSToken: |
|
intptr = &options->kerberos_get_afs_token; |
|
goto parse_flag; |
|
|
|
case sGssAuthentication: |
|
intptr = &options->gss_authentication; |
|
goto parse_flag; |
|
|
|
case sGssCleanupCreds: |
|
intptr = &options->gss_cleanup_creds; |
|
goto parse_flag; |
|
|
|
case sGssStrictAcceptor: |
|
intptr = &options->gss_strict_acceptor; |
|
goto parse_flag; |
|
|
|
case sPasswordAuthentication: |
|
intptr = &options->password_authentication; |
|
goto parse_flag; |
|
|
|
case sKbdInteractiveAuthentication: |
|
intptr = &options->kbd_interactive_authentication; |
|
goto parse_flag; |
|
|
|
case sChallengeResponseAuthentication: |
|
intptr = &options->challenge_response_authentication; |
|
goto parse_flag; |
|
|
|
case sPrintMotd: |
|
intptr = &options->print_motd; |
|
goto parse_flag; |
|
|
|
case sPrintLastLog: |
|
intptr = &options->print_lastlog; |
|
goto parse_flag; |
|
|
|
case sX11Forwarding: |
|
intptr = &options->x11_forwarding; |
|
goto parse_flag; |
|
|
|
case sX11DisplayOffset: |
|
intptr = &options->x11_display_offset; |
|
parse_int: |
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%s line %d: missing integer value.", |
|
filename, linenum); |
|
value = atoi(arg); |
|
if (*activep && *intptr == -1) |
|
*intptr = value; |
|
break; |
|
|
|
case sX11UseLocalhost: |
|
intptr = &options->x11_use_localhost; |
|
goto parse_flag; |
|
|
|
case sXAuthLocation: |
|
charptr = &options->xauth_location; |
|
goto parse_filename; |
|
|
|
case sPermitTTY: |
|
intptr = &options->permit_tty; |
|
goto parse_flag; |
|
|
|
case sPermitUserRC: |
|
intptr = &options->permit_user_rc; |
|
goto parse_flag; |
|
|
|
case sStrictModes: |
|
intptr = &options->strict_modes; |
|
goto parse_flag; |
|
|
|
case sTCPKeepAlive: |
|
intptr = &options->tcp_keep_alive; |
|
goto parse_flag; |
|
|
|
case sEmptyPasswd: |
|
intptr = &options->permit_empty_passwd; |
|
goto parse_flag; |
|
|
|
case sPermitUserEnvironment: |
|
intptr = &options->permit_user_env; |
|
goto parse_flag; |
|
|
|
case sCompression: |
|
intptr = &options->compression; |
|
multistate_ptr = multistate_compression; |
|
goto parse_multistate; |
|
|
|
case sRekeyLimit: |
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%.200s line %d: Missing argument.", filename, |
|
linenum); |
|
if (strcmp(arg, "default") == 0) { |
|
val64 = 0; |
|
} else { |
|
if (scan_scaled(arg, &val64) == -1) |
|
fatal("%.200s line %d: Bad number '%s': %s", |
|
filename, linenum, arg, strerror(errno)); |
|
if (val64 != 0 && val64 < 16) |
|
fatal("%.200s line %d: RekeyLimit too small", |
|
filename, linenum); |
|
} |
|
if (*activep && options->rekey_limit == -1) |
|
options->rekey_limit = val64; |
|
if (cp != NULL) { /* optional rekey interval present */ |
|
if (strcmp(cp, "none") == 0) { |
|
(void)strdelim(&cp); /* discard */ |
|
break; |
|
} |
|
intptr = &options->rekey_interval; |
|
goto parse_time; |
|
} |
|
break; |
|
|
|
case sGatewayPorts: |
|
intptr = &options->fwd_opts.gateway_ports; |
|
multistate_ptr = multistate_gatewayports; |
|
goto parse_multistate; |
|
|
|
case sUseDNS: |
|
intptr = &options->use_dns; |
|
goto parse_flag; |
|
|
|
case sLogFacility: |
|
log_facility_ptr = &options->log_facility; |
|
arg = strdelim(&cp); |
|
value = log_facility_number(arg); |
|
if (value == SYSLOG_FACILITY_NOT_SET) |
|
fatal("%.200s line %d: unsupported log facility '%s'", |
|
filename, linenum, arg ? arg : "<NONE>"); |
|
if (*log_facility_ptr == -1) |
|
*log_facility_ptr = (SyslogFacility) value; |
|
break; |
|
|
|
case sLogLevel: |
|
log_level_ptr = &options->log_level; |
|
arg = strdelim(&cp); |
|
value = log_level_number(arg); |
|
if (value == SYSLOG_LEVEL_NOT_SET) |
|
fatal("%.200s line %d: unsupported log level '%s'", |
|
filename, linenum, arg ? arg : "<NONE>"); |
|
if (*log_level_ptr == -1) |
|
*log_level_ptr = (LogLevel) value; |
|
break; |
|
|
|
case sAllowTcpForwarding: |
|
intptr = &options->allow_tcp_forwarding; |
|
multistate_ptr = multistate_tcpfwd; |
|
goto parse_multistate; |
|
|
|
case sAllowStreamLocalForwarding: |
|
intptr = &options->allow_streamlocal_forwarding; |
|
multistate_ptr = multistate_tcpfwd; |
|
goto parse_multistate; |
|
|
|
case sAllowAgentForwarding: |
|
intptr = &options->allow_agent_forwarding; |
|
goto parse_flag; |
|
|
|
case sDisableForwarding: |
|
intptr = &options->disable_forwarding; |
|
goto parse_flag; |
|
|
|
case sAllowUsers: |
|
while ((arg = strdelim(&cp)) && *arg != '\0') { |
|
if (options->num_allow_users >= MAX_ALLOW_USERS) |
|
fatal("%s line %d: too many allow users.", |
|
filename, linenum); |
|
if (match_user(NULL, NULL, NULL, arg) == -1) |
|
fatal("%s line %d: invalid AllowUsers pattern: " |
|
"\"%.100s\"", filename, linenum, arg); |
|
if (!*activep) |
|
continue; |
|
options->allow_users[options->num_allow_users++] = |
|
xstrdup(arg); |
|
} |
|
break; |
|
|
|
case sDenyUsers: |
|
while ((arg = strdelim(&cp)) && *arg != '\0') { |
|
if (options->num_deny_users >= MAX_DENY_USERS) |
|
fatal("%s line %d: too many deny users.", |
|
filename, linenum); |
|
if (match_user(NULL, NULL, NULL, arg) == -1) |
|
fatal("%s line %d: invalid DenyUsers pattern: " |
|
"\"%.100s\"", filename, linenum, arg); |
|
if (!*activep) |
|
continue; |
|
options->deny_users[options->num_deny_users++] = |
|
xstrdup(arg); |
|
} |
|
break; |
|
|
|
case sAllowGroups: |
|
while ((arg = strdelim(&cp)) && *arg != '\0') { |
|
if (options->num_allow_groups >= MAX_ALLOW_GROUPS) |
|
fatal("%s line %d: too many allow groups.", |
|
filename, linenum); |
|
if (!*activep) |
|
continue; |
|
options->allow_groups[options->num_allow_groups++] = |
|
xstrdup(arg); |
|
} |
|
break; |
|
|
|
case sDenyGroups: |
|
while ((arg = strdelim(&cp)) && *arg != '\0') { |
|
if (options->num_deny_groups >= MAX_DENY_GROUPS) |
|
fatal("%s line %d: too many deny groups.", |
|
filename, linenum); |
|
if (!*activep) |
|
continue; |
|
options->deny_groups[options->num_deny_groups++] = |
|
xstrdup(arg); |
|
} |
|
break; |
|
|
|
case sCiphers: |
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%s line %d: Missing argument.", filename, linenum); |
|
if (*arg != '-' && !ciphers_valid(*arg == '+' ? arg + 1 : arg)) |
|
fatal("%s line %d: Bad SSH2 cipher spec '%s'.", |
|
filename, linenum, arg ? arg : "<NONE>"); |
|
if (options->ciphers == NULL) |
|
options->ciphers = xstrdup(arg); |
|
break; |
|
|
|
case sMacs: |
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%s line %d: Missing argument.", filename, linenum); |
|
if (*arg != '-' && !mac_valid(*arg == '+' ? arg + 1 : arg)) |
|
fatal("%s line %d: Bad SSH2 mac spec '%s'.", |
|
filename, linenum, arg ? arg : "<NONE>"); |
|
if (options->macs == NULL) |
|
options->macs = xstrdup(arg); |
|
break; |
|
|
|
case sKexAlgorithms: |
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%s line %d: Missing argument.", |
|
filename, linenum); |
|
if (*arg != '-' && |
|
!kex_names_valid(*arg == '+' ? arg + 1 : arg)) |
|
fatal("%s line %d: Bad SSH2 KexAlgorithms '%s'.", |
|
filename, linenum, arg ? arg : "<NONE>"); |
|
if (options->kex_algorithms == NULL) |
|
options->kex_algorithms = xstrdup(arg); |
|
break; |
|
|
|
case sSubsystem: |
|
if (options->num_subsystems >= MAX_SUBSYSTEMS) { |
|
fatal("%s line %d: too many subsystems defined.", |
|
filename, linenum); |
|
} |
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%s line %d: Missing subsystem name.", |
|
filename, linenum); |
|
if (!*activep) { |
|
arg = strdelim(&cp); |
|
break; |
|
} |
|
for (i = 0; i < options->num_subsystems; i++) |
|
if (strcmp(arg, options->subsystem_name[i]) == 0) |
|
fatal("%s line %d: Subsystem '%s' already defined.", |
|
filename, linenum, arg); |
|
options->subsystem_name[options->num_subsystems] = xstrdup(arg); |
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%s line %d: Missing subsystem command.", |
|
filename, linenum); |
|
options->subsystem_command[options->num_subsystems] = xstrdup(arg); |
|
|
|
/* Collect arguments (separate to executable) */ |
|
p = xstrdup(arg); |
|
len = strlen(p) + 1; |
|
while ((arg = strdelim(&cp)) != NULL && *arg != '\0') { |
|
len += 1 + strlen(arg); |
|
p = xreallocarray(p, 1, len); |
|
strlcat(p, " ", len); |
|
strlcat(p, arg, len); |
|
} |
|
options->subsystem_args[options->num_subsystems] = p; |
|
options->num_subsystems++; |
|
break; |
|
|
|
case sMaxStartups: |
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%s line %d: Missing MaxStartups spec.", |
|
filename, linenum); |
|
if ((n = sscanf(arg, "%d:%d:%d", |
|
&options->max_startups_begin, |
|
&options->max_startups_rate, |
|
&options->max_startups)) == 3) { |
|
if (options->max_startups_begin > |
|
options->max_startups || |
|
options->max_startups_rate > 100 || |
|
options->max_startups_rate < 1) |
|
fatal("%s line %d: Illegal MaxStartups spec.", |
|
filename, linenum); |
|
} else if (n != 1) |
|
fatal("%s line %d: Illegal MaxStartups spec.", |
|
filename, linenum); |
|
else |
|
options->max_startups = options->max_startups_begin; |
|
break; |
|
|
|
case sMaxAuthTries: |
|
intptr = &options->max_authtries; |
|
goto parse_int; |
|
|
|
case sMaxSessions: |
|
intptr = &options->max_sessions; |
|
goto parse_int; |
|
|
|
case sBanner: |
|
charptr = &options->banner; |
|
goto parse_filename; |
|
|
|
/* |
|
* These options can contain %X options expanded at |
|
* connect time, so that you can specify paths like: |
|
* |
|
* AuthorizedKeysFile /etc/ssh_keys/%u |
|
*/ |
|
case sAuthorizedKeysFile: |
|
if (*activep && options->num_authkeys_files == 0) { |
|
while ((arg = strdelim(&cp)) && *arg != '\0') { |
|
if (options->num_authkeys_files >= |
|
MAX_AUTHKEYS_FILES) |
|
fatal("%s line %d: " |
|
"too many authorized keys files.", |
|
filename, linenum); |
|
options->authorized_keys_files[ |
|
options->num_authkeys_files++] = |
|
tilde_expand_filename(arg, getuid()); |
|
} |
|
} |
|
return 0; |
|
|
|
case sAuthorizedPrincipalsFile: |
|
charptr = &options->authorized_principals_file; |
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%s line %d: missing file name.", |
|
filename, linenum); |
|
if (*activep && *charptr == NULL) { |
|
*charptr = tilde_expand_filename(arg, getuid()); |
|
/* increase optional counter */ |
|
if (intptr != NULL) |
|
*intptr = *intptr + 1; |
|
} |
|
break; |
|
|
|
case sClientAliveInterval: |
|
intptr = &options->client_alive_interval; |
|
goto parse_time; |
|
|
|
case sClientAliveCountMax: |
|
intptr = &options->client_alive_count_max; |
|
goto parse_int; |
|
|
|
case sAcceptEnv: |
|
while ((arg = strdelim(&cp)) && *arg != '\0') { |
|
if (strchr(arg, '=') != NULL) |
|
fatal("%s line %d: Invalid environment name.", |
|
filename, linenum); |
|
if (options->num_accept_env >= MAX_ACCEPT_ENV) |
|
fatal("%s line %d: too many allow env.", |
|
filename, linenum); |
|
if (!*activep) |
|
continue; |
|
options->accept_env[options->num_accept_env++] = |
|
xstrdup(arg); |
|
} |
|
break; |
|
|
|
case sPermitTunnel: |
|
intptr = &options->permit_tun; |
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%s line %d: Missing yes/point-to-point/" |
|
"ethernet/no argument.", filename, linenum); |
|
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 (*activep && *intptr == -1) |
|
*intptr = value; |
|
break; |
|
|
|
case sMatch: |
|
if (cmdline) |
|
fatal("Match directive not supported as a command-line " |
|
"option"); |
|
value = match_cfg_line(&cp, linenum, connectinfo); |
|
if (value < 0) |
|
fatal("%s line %d: Bad Match condition", filename, |
|
linenum); |
|
*activep = value; |
|
break; |
|
|
|
case sPermitOpen: |
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%s line %d: missing PermitOpen specification", |
|
filename, linenum); |
|
n = options->num_permitted_opens; /* modified later */ |
|
if (strcmp(arg, "any") == 0) { |
|
if (*activep && n == -1) { |
|
channel_clear_adm_permitted_opens(); |
|
options->num_permitted_opens = 0; |
|
} |
|
break; |
|
} |
|
if (strcmp(arg, "none") == 0) { |
|
if (*activep && n == -1) { |
|
options->num_permitted_opens = 1; |
|
channel_disable_adm_local_opens(); |
|
} |
|
break; |
|
} |
|
if (*activep && n == -1) |
|
channel_clear_adm_permitted_opens(); |
|
for (; arg != NULL && *arg != '\0'; arg = strdelim(&cp)) { |
|
p = hpdelim(&arg); |
|
if (p == NULL) |
|
fatal("%s line %d: missing host in PermitOpen", |
|
filename, linenum); |
|
p = cleanhostname(p); |
|
if (arg == NULL || ((port = permitopen_port(arg)) < 0)) |
|
fatal("%s line %d: bad port number in " |
|
"PermitOpen", filename, linenum); |
|
if (*activep && n == -1) |
|
options->num_permitted_opens = |
|
channel_add_adm_permitted_opens(p, port); |
|
} |
|
break; |
|
|
|
case sForceCommand: |
|
if (cp == NULL || *cp == '\0') |
|
fatal("%.200s line %d: Missing argument.", filename, |
|
linenum); |
|
len = strspn(cp, WHITESPACE); |
|
if (*activep && options->adm_forced_command == NULL) |
|
options->adm_forced_command = xstrdup(cp + len); |
|
return 0; |
|
|
|
case sChrootDirectory: |
|
charptr = &options->chroot_directory; |
|
|
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%s line %d: missing file name.", |
|
filename, linenum); |
|
if (*activep && *charptr == NULL) |
|
*charptr = xstrdup(arg); |
|
break; |
|
|
|
case sTrustedUserCAKeys: |
|
charptr = &options->trusted_user_ca_keys; |
|
goto parse_filename; |
|
|
|
case sRevokedKeys: |
|
charptr = &options->revoked_keys_file; |
|
goto parse_filename; |
|
|
|
case sIPQoS: |
|
arg = strdelim(&cp); |
|
if ((value = parse_ipqos(arg)) == -1) |
|
fatal("%s line %d: Bad IPQoS value: %s", |
|
filename, linenum, arg); |
|
arg = strdelim(&cp); |
|
if (arg == NULL) |
|
value2 = value; |
|
else if ((value2 = parse_ipqos(arg)) == -1) |
|
fatal("%s line %d: Bad IPQoS value: %s", |
|
filename, linenum, arg); |
|
if (*activep) { |
|
options->ip_qos_interactive = value; |
|
options->ip_qos_bulk = value2; |
|
} |
|
break; |
|
|
|
case sVersionAddendum: |
|
if (cp == NULL || *cp == '\0') |
|
fatal("%.200s line %d: Missing argument.", filename, |
|
linenum); |
|
len = strspn(cp, WHITESPACE); |
|
if (*activep && options->version_addendum == NULL) { |
|
if (strcasecmp(cp + len, "none") == 0) |
|
options->version_addendum = xstrdup(""); |
|
else if (strchr(cp + len, '\r') != NULL) |
|
fatal("%.200s line %d: Invalid argument", |
|
filename, linenum); |
|
else |
|
options->version_addendum = xstrdup(cp + len); |
|
} |
|
return 0; |
|
|
|
case sAuthorizedKeysCommand: |
|
if (cp == NULL) |
|
fatal("%.200s line %d: Missing argument.", filename, |
|
linenum); |
|
len = strspn(cp, WHITESPACE); |
|
if (*activep && options->authorized_keys_command == NULL) { |
|
if (cp[len] != '/' && strcasecmp(cp + len, "none") != 0) |
|
fatal("%.200s line %d: AuthorizedKeysCommand " |
|
"must be an absolute path", |
|
filename, linenum); |
|
options->authorized_keys_command = xstrdup(cp + len); |
|
} |
|
return 0; |
|
|
|
case sAuthorizedKeysCommandUser: |
|
charptr = &options->authorized_keys_command_user; |
|
|
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%s line %d: missing AuthorizedKeysCommandUser " |
|
"argument.", filename, linenum); |
|
if (*activep && *charptr == NULL) |
|
*charptr = xstrdup(arg); |
|
break; |
|
|
|
case sAuthorizedPrincipalsCommand: |
|
if (cp == NULL) |
|
fatal("%.200s line %d: Missing argument.", filename, |
|
linenum); |
|
len = strspn(cp, WHITESPACE); |
|
if (*activep && |
|
options->authorized_principals_command == NULL) { |
|
if (cp[len] != '/' && strcasecmp(cp + len, "none") != 0) |
|
fatal("%.200s line %d: " |
|
"AuthorizedPrincipalsCommand must be " |
|
"an absolute path", filename, linenum); |
|
options->authorized_principals_command = |
|
xstrdup(cp + len); |
|
} |
|
return 0; |
|
|
|
case sAuthorizedPrincipalsCommandUser: |
|
charptr = &options->authorized_principals_command_user; |
|
|
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%s line %d: missing " |
|
"AuthorizedPrincipalsCommandUser argument.", |
|
filename, linenum); |
|
if (*activep && *charptr == NULL) |
|
*charptr = xstrdup(arg); |
|
break; |
|
|
|
case sAuthenticationMethods: |
|
if (options->num_auth_methods == 0) { |
|
value = 0; /* seen "any" pseudo-method */ |
|
value2 = 0; /* sucessfully parsed any method */ |
|
while ((arg = strdelim(&cp)) && *arg != '\0') { |
|
if (options->num_auth_methods >= |
|
MAX_AUTH_METHODS) |
|
fatal("%s line %d: " |
|
"too many authentication methods.", |
|
filename, linenum); |
|
if (strcmp(arg, "any") == 0) { |
|
if (options->num_auth_methods > 0) { |
|
fatal("%s line %d: \"any\" " |
|
"must appear alone in " |
|
"AuthenticationMethods", |
|
filename, linenum); |
|
} |
|
value = 1; |
|
} else if (value) { |
|
fatal("%s line %d: \"any\" must appear " |
|
"alone in AuthenticationMethods", |
|
filename, linenum); |
|
} else if (auth2_methods_valid(arg, 0) != 0) { |
|
fatal("%s line %d: invalid " |
|
"authentication method list.", |
|
filename, linenum); |
|
} |
|
value2 = 1; |
|
if (!*activep) |
|
continue; |
|
options->auth_methods[ |
|
options->num_auth_methods++] = xstrdup(arg); |
|
} |
|
if (value2 == 0) { |
|
fatal("%s line %d: no AuthenticationMethods " |
|
"specified", filename, linenum); |
|
} |
|
} |
|
return 0; |
|
|
|
case sStreamLocalBindMask: |
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%s line %d: missing StreamLocalBindMask " |
|
"argument.", filename, linenum); |
|
/* Parse mode in octal format */ |
|
value = strtol(arg, &p, 8); |
|
if (arg == p || value < 0 || value > 0777) |
|
fatal("%s line %d: Bad mask.", filename, linenum); |
|
if (*activep) |
|
options->fwd_opts.streamlocal_bind_mask = (mode_t)value; |
|
break; |
|
|
|
case sStreamLocalBindUnlink: |
|
intptr = &options->fwd_opts.streamlocal_bind_unlink; |
|
goto parse_flag; |
|
|
|
case sFingerprintHash: |
|
arg = strdelim(&cp); |
|
if (!arg || *arg == '\0') |
|
fatal("%.200s line %d: Missing argument.", |
|
filename, linenum); |
|
if ((value = ssh_digest_alg_by_name(arg)) == -1) |
|
fatal("%.200s line %d: Invalid hash algorithm \"%s\".", |
|
filename, linenum, arg); |
|
if (*activep) |
|
options->fingerprint_hash = value; |
|
break; |
|
|
|
case sDeprecated: |
|
case sIgnore: |
|
case sUnsupported: |
|
do_log2(opcode == sIgnore ? |
|
SYSLOG_LEVEL_DEBUG2 : SYSLOG_LEVEL_INFO, |
|
"%s line %d: %s option %s", filename, linenum, |
|
opcode == sUnsupported ? "Unsupported" : "Deprecated", arg); |
|
while (arg) |
|
arg = strdelim(&cp); |
|
break; |
|
|
|
default: |
|
fatal("%s line %d: Missing handler for opcode %s (%d)", |
|
filename, linenum, arg, opcode); |
|
} |
|
if ((arg = strdelim(&cp)) != NULL && *arg != '\0') |
|
fatal("%s line %d: garbage at end of line; \"%.200s\".", |
|
filename, linenum, arg); |
|
return 0; |
|
} |
|
|
|
/* Reads the server configuration file. */ |
|
|
|
void |
|
load_server_config(const char *filename, Buffer *conf) |
|
{ |
|
char line[4096], *cp; |
|
FILE *f; |
|
int lineno = 0; |
|
|
|
debug2("%s: filename %s", __func__, filename); |
|
if ((f = fopen(filename, "r")) == NULL) { |
|
perror(filename); |
|
exit(1); |
|
} |
|
buffer_clear(conf); |
|
while (fgets(line, sizeof(line), f)) { |
|
lineno++; |
|
if (strlen(line) == sizeof(line) - 1) |
|
fatal("%s line %d too long", filename, lineno); |
|
/* |
|
* Trim out comments and strip whitespace |
|
* NB - preserve newlines, they are needed to reproduce |
|
* line numbers later for error messages |
|
*/ |
|
if ((cp = strchr(line, '#')) != NULL) |
|
memcpy(cp, "\n", 2); |
|
cp = line + strspn(line, " \t\r"); |
|
|
|
buffer_append(conf, cp, strlen(cp)); |
|
} |
|
buffer_append(conf, "\0", 1); |
|
fclose(f); |
|
debug2("%s: done config len = %d", __func__, buffer_len(conf)); |
|
} |
|
|
|
void |
|
parse_server_match_config(ServerOptions *options, |
|
struct connection_info *connectinfo) |
|
{ |
|
ServerOptions mo; |
|
#if defined(ANDROID) |
|
char value[PROPERTY_VALUE_MAX]; |
|
#endif |
|
|
|
initialize_server_options(&mo); |
|
parse_server_config(&mo, "reprocess config", &cfg, connectinfo); |
|
#if defined(ANDROID) |
|
/* Allow root login if ro.debuggable is set. */ |
|
property_get("ro.debuggable", value, ""); |
|
if (strcmp(value, "1") == 0) { |
|
mo.permit_root_login = PERMIT_YES; |
|
} |
|
#endif |
|
copy_set_server_options(options, &mo, 0); |
|
} |
|
|
|
int parse_server_match_testspec(struct connection_info *ci, char *spec) |
|
{ |
|
char *p; |
|
|
|
while ((p = strsep(&spec, ",")) && *p != '\0') { |
|
if (strncmp(p, "addr=", 5) == 0) { |
|
ci->address = xstrdup(p + 5); |
|
} else if (strncmp(p, "host=", 5) == 0) { |
|
ci->host = xstrdup(p + 5); |
|
} else if (strncmp(p, "user=", 5) == 0) { |
|
ci->user = xstrdup(p + 5); |
|
} else if (strncmp(p, "laddr=", 6) == 0) { |
|
ci->laddress = xstrdup(p + 6); |
|
} else if (strncmp(p, "lport=", 6) == 0) { |
|
ci->lport = a2port(p + 6); |
|
if (ci->lport == -1) { |
|
fprintf(stderr, "Invalid port '%s' in test mode" |
|
" specification %s\n", p+6, p); |
|
return -1; |
|
} |
|
} else { |
|
fprintf(stderr, "Invalid test mode specification %s\n", |
|
p); |
|
return -1; |
|
} |
|
} |
|
return 0; |
|
} |
|
|
|
/* |
|
* returns 1 for a complete spec, 0 for partial spec and -1 for an |
|
* empty spec. |
|
*/ |
|
int server_match_spec_complete(struct connection_info *ci) |
|
{ |
|
if (ci->user && ci->host && ci->address) |
|
return 1; /* complete */ |
|
if (!ci->user && !ci->host && !ci->address) |
|
return -1; /* empty */ |
|
return 0; /* partial */ |
|
} |
|
|
|
/* |
|
* Copy any supported values that are set. |
|
* |
|
* If the preauth flag is set, we do not bother copying the string or |
|
* array values that are not used pre-authentication, because any that we |
|
* do use must be explictly sent in mm_getpwnamallow(). |
|
*/ |
|
void |
|
copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) |
|
{ |
|
#define M_CP_INTOPT(n) do {\ |
|
if (src->n != -1) \ |
|
dst->n = src->n; \ |
|
} while (0) |
|
|
|
M_CP_INTOPT(password_authentication); |
|
M_CP_INTOPT(gss_authentication); |
|
M_CP_INTOPT(pubkey_authentication); |
|
M_CP_INTOPT(kerberos_authentication); |
|
M_CP_INTOPT(hostbased_authentication); |
|
M_CP_INTOPT(hostbased_uses_name_from_packet_only); |
|
M_CP_INTOPT(kbd_interactive_authentication); |
|
M_CP_INTOPT(permit_root_login); |
|
M_CP_INTOPT(permit_empty_passwd); |
|
|
|
M_CP_INTOPT(allow_tcp_forwarding); |
|
M_CP_INTOPT(allow_streamlocal_forwarding); |
|
M_CP_INTOPT(allow_agent_forwarding); |
|
M_CP_INTOPT(disable_forwarding); |
|
M_CP_INTOPT(permit_tun); |
|
M_CP_INTOPT(fwd_opts.gateway_ports); |
|
M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink); |
|
M_CP_INTOPT(x11_display_offset); |
|
M_CP_INTOPT(x11_forwarding); |
|
M_CP_INTOPT(x11_use_localhost); |
|
M_CP_INTOPT(permit_tty); |
|
M_CP_INTOPT(permit_user_rc); |
|
M_CP_INTOPT(max_sessions); |
|
M_CP_INTOPT(max_authtries); |
|
M_CP_INTOPT(client_alive_count_max); |
|
M_CP_INTOPT(client_alive_interval); |
|
M_CP_INTOPT(ip_qos_interactive); |
|
M_CP_INTOPT(ip_qos_bulk); |
|
M_CP_INTOPT(rekey_limit); |
|
M_CP_INTOPT(rekey_interval); |
|
|
|
/* |
|
* The bind_mask is a mode_t that may be unsigned, so we can't use |
|
* M_CP_INTOPT - it does a signed comparison that causes compiler |
|
* warnings. |
|
*/ |
|
if (src->fwd_opts.streamlocal_bind_mask != (mode_t)-1) { |
|
dst->fwd_opts.streamlocal_bind_mask = |
|
src->fwd_opts.streamlocal_bind_mask; |
|
} |
|
|
|
/* M_CP_STROPT and M_CP_STRARRAYOPT should not appear before here */ |
|
#define M_CP_STROPT(n) do {\ |
|
if (src->n != NULL && dst->n != src->n) { \ |
|
free(dst->n); \ |
|
dst->n = src->n; \ |
|
} \ |
|
} while(0) |
|
#define M_CP_STRARRAYOPT(n, num_n) do {\ |
|
if (src->num_n != 0) { \ |
|
for (dst->num_n = 0; dst->num_n < src->num_n; dst->num_n++) \ |
|
dst->n[dst->num_n] = xstrdup(src->n[dst->num_n]); \ |
|
} \ |
|
} while(0) |
|
|
|
/* See comment in servconf.h */ |
|
COPY_MATCH_STRING_OPTS(); |
|
|
|
/* Arguments that accept '+...' need to be expanded */ |
|
assemble_algorithms(dst); |
|
|
|
/* |
|
* The only things that should be below this point are string options |
|
* which are only used after authentication. |
|
*/ |
|
if (preauth) |
|
return; |
|
|
|
/* These options may be "none" to clear a global setting */ |
|
M_CP_STROPT(adm_forced_command); |
|
if (option_clear_or_none(dst->adm_forced_command)) { |
|
free(dst->adm_forced_command); |
|
dst->adm_forced_command = NULL; |
|
} |
|
M_CP_STROPT(chroot_directory); |
|
if (option_clear_or_none(dst->chroot_directory)) { |
|
free(dst->chroot_directory); |
|
dst->chroot_directory = NULL; |
|
} |
|
} |
|
|
|
#undef M_CP_INTOPT |
|
#undef M_CP_STROPT |
|
#undef M_CP_STRARRAYOPT |
|
|
|
void |
|
parse_server_config(ServerOptions *options, const char *filename, Buffer *conf, |
|
struct connection_info *connectinfo) |
|
{ |
|
int active, linenum, bad_options = 0; |
|
char *cp, *obuf, *cbuf; |
|
|
|
debug2("%s: config %s len %d", __func__, filename, buffer_len(conf)); |
|
|
|
if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL) |
|
fatal("%s: sshbuf_dup_string failed", __func__); |
|
active = connectinfo ? 0 : 1; |
|
linenum = 1; |
|
while ((cp = strsep(&cbuf, "\n")) != NULL) { |
|
if (process_server_config_line(options, cp, filename, |
|
linenum++, &active, connectinfo) != 0) |
|
bad_options++; |
|
} |
|
free(obuf); |
|
if (bad_options > 0) |
|
fatal("%s: terminating, %d bad configuration options", |
|
filename, bad_options); |
|
process_queued_listen_addrs(options); |
|
} |
|
|
|
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(ServerOpCodes code, int val) |
|
{ |
|
if (val == -1) |
|
return "unset"; |
|
switch (code) { |
|
case sAddressFamily: |
|
return fmt_multistate_int(val, multistate_addressfamily); |
|
case sPermitRootLogin: |
|
return fmt_multistate_int(val, multistate_permitrootlogin); |
|
case sGatewayPorts: |
|
return fmt_multistate_int(val, multistate_gatewayports); |
|
case sCompression: |
|
return fmt_multistate_int(val, multistate_compression); |
|
case sAllowTcpForwarding: |
|
return fmt_multistate_int(val, multistate_tcpfwd); |
|
case sAllowStreamLocalForwarding: |
|
return fmt_multistate_int(val, multistate_tcpfwd); |
|
case sFingerprintHash: |
|
return ssh_digest_alg_name(val); |
|
default: |
|
switch (val) { |
|
case 0: |
|
return "no"; |
|
case 1: |
|
return "yes"; |
|
default: |
|
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_oct(ServerOpCodes code, int val) |
|
{ |
|
printf("%s 0%o\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) |
|
{ |
|
printf("%s %s\n", lookup_opcode_name(code), |
|
val == NULL ? "none" : 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]); |
|
} |
|
|
|
static void |
|
dump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals) |
|
{ |
|
u_int i; |
|
|
|
if (count <= 0 && code != sAuthenticationMethods) |
|
return; |
|
printf("%s", lookup_opcode_name(code)); |
|
for (i = 0; i < count; i++) |
|
printf(" %s", vals[i]); |
|
if (code == sAuthenticationMethods && count == 0) |
|
printf(" any"); |
|
printf("\n"); |
|
} |
|
|
|
void |
|
dump_config(ServerOptions *o) |
|
{ |
|
u_int i; |
|
int ret; |
|
struct addrinfo *ai; |
|
char addr[NI_MAXHOST], port[NI_MAXSERV], *s = NULL; |
|
char *laddr1 = xstrdup(""), *laddr2 = 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(sAddressFamily, o->address_family); |
|
|
|
/* |
|
* ListenAddress must be after Port. add_one_listen_addr pushes |
|
* addresses onto a stack, so to maintain ordering we need to |
|
* print these in reverse order. |
|
*/ |
|
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 { |
|
laddr2 = laddr1; |
|
if (ai->ai_family == AF_INET6) |
|
xasprintf(&laddr1, "listenaddress [%s]:%s\n%s", |
|
addr, port, laddr2); |
|
else |
|
xasprintf(&laddr1, "listenaddress %s:%s\n%s", |
|
addr, port, laddr2); |
|
free(laddr2); |
|
} |
|
} |
|
printf("%s", laddr1); |
|
free(laddr1); |
|
|
|
/* integer arguments */ |
|
#ifdef USE_PAM |
|
dump_cfg_fmtint(sUsePAM, o->use_pam); |
|
#endif |
|
dump_cfg_int(sLoginGraceTime, o->login_grace_time); |
|
dump_cfg_int(sX11DisplayOffset, o->x11_display_offset); |
|
dump_cfg_int(sMaxAuthTries, o->max_authtries); |
|
dump_cfg_int(sMaxSessions, o->max_sessions); |
|
dump_cfg_int(sClientAliveInterval, o->client_alive_interval); |
|
dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max); |
|
dump_cfg_oct(sStreamLocalBindMask, o->fwd_opts.streamlocal_bind_mask); |
|
|
|
/* 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(sHostbasedAuthentication, o->hostbased_authentication); |
|
dump_cfg_fmtint(sHostbasedUsesNameFromPacketOnly, |
|
o->hostbased_uses_name_from_packet_only); |
|
dump_cfg_fmtint(sPubkeyAuthentication, o->pubkey_authentication); |
|
#ifdef KRB5 |
|
dump_cfg_fmtint(sKerberosAuthentication, o->kerberos_authentication); |
|
dump_cfg_fmtint(sKerberosOrLocalPasswd, o->kerberos_or_local_passwd); |
|
dump_cfg_fmtint(sKerberosTicketCleanup, o->kerberos_ticket_cleanup); |
|
# ifdef USE_AFS |
|
dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token); |
|
# endif |
|
#endif |
|
#ifdef GSSAPI |
|
dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); |
|
dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); |
|
#endif |
|
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); |
|
#ifndef DISABLE_LASTLOG |
|
dump_cfg_fmtint(sPrintLastLog, o->print_lastlog); |
|
#endif |
|
dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding); |
|
dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost); |
|
dump_cfg_fmtint(sPermitTTY, o->permit_tty); |
|
dump_cfg_fmtint(sPermitUserRC, o->permit_user_rc); |
|
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(sCompression, o->compression); |
|
dump_cfg_fmtint(sGatewayPorts, o->fwd_opts.gateway_ports); |
|
dump_cfg_fmtint(sUseDNS, o->use_dns); |
|
dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding); |
|
dump_cfg_fmtint(sAllowAgentForwarding, o->allow_agent_forwarding); |
|
dump_cfg_fmtint(sDisableForwarding, o->disable_forwarding); |
|
dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding); |
|
dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); |
|
dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash); |
|
|
|
/* string arguments */ |
|
dump_cfg_string(sPidFile, o->pid_file); |
|
dump_cfg_string(sXAuthLocation, o->xauth_location); |
|
dump_cfg_string(sCiphers, o->ciphers ? o->ciphers : KEX_SERVER_ENCRYPT); |
|
dump_cfg_string(sMacs, o->macs ? o->macs : KEX_SERVER_MAC); |
|
dump_cfg_string(sBanner, o->banner); |
|
dump_cfg_string(sForceCommand, o->adm_forced_command); |
|
dump_cfg_string(sChrootDirectory, o->chroot_directory); |
|
dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys); |
|
dump_cfg_string(sRevokedKeys, o->revoked_keys_file); |
|
dump_cfg_string(sAuthorizedPrincipalsFile, |
|
o->authorized_principals_file); |
|
dump_cfg_string(sVersionAddendum, *o->version_addendum == '\0' |
|
? "none" : o->version_addendum); |
|
dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command); |
|
dump_cfg_string(sAuthorizedKeysCommandUser, o->authorized_keys_command_user); |
|
dump_cfg_string(sAuthorizedPrincipalsCommand, o->authorized_principals_command); |
|
dump_cfg_string(sAuthorizedPrincipalsCommandUser, o->authorized_principals_command_user); |
|
dump_cfg_string(sHostKeyAgent, o->host_key_agent); |
|
dump_cfg_string(sKexAlgorithms, |
|
o->kex_algorithms ? o->kex_algorithms : KEX_SERVER_KEX); |
|
dump_cfg_string(sHostbasedAcceptedKeyTypes, o->hostbased_key_types ? |
|
o->hostbased_key_types : KEX_DEFAULT_PK_ALG); |
|
dump_cfg_string(sHostKeyAlgorithms, o->hostkeyalgorithms ? |
|
o->hostkeyalgorithms : KEX_DEFAULT_PK_ALG); |
|
dump_cfg_string(sPubkeyAcceptedKeyTypes, o->pubkey_key_types ? |
|
o->pubkey_key_types : KEX_DEFAULT_PK_ALG); |
|
|
|
/* 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_oneline(sAuthorizedKeysFile, o->num_authkeys_files, |
|
o->authorized_keys_files); |
|
dump_cfg_strarray(sHostKeyFile, o->num_host_key_files, |
|
o->host_key_files); |
|
dump_cfg_strarray(sHostCertificate, o->num_host_cert_files, |
|
o->host_cert_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); |
|
dump_cfg_strarray_oneline(sAuthenticationMethods, |
|
o->num_auth_methods, o->auth_methods); |
|
|
|
/* 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("ipqos %s ", iptos2str(o->ip_qos_interactive)); |
|
printf("%s\n", iptos2str(o->ip_qos_bulk)); |
|
|
|
printf("rekeylimit %llu %d\n", (unsigned long long)o->rekey_limit, |
|
o->rekey_interval); |
|
|
|
channel_print_adm_permitted_opens(); |
|
}
|
|
|