xref: /freebsd/crypto/openssh/servconf.c (revision 535af610a4fdace6d50960c0ad9be0597eea7a1b)
1*535af610SEd Maste /* $OpenBSD: servconf.c,v 1.396 2023/07/17 05:26:38 djm Exp $ */
2511b41d2SMark Murray /*
3511b41d2SMark Murray  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4511b41d2SMark Murray  *                    All rights reserved
5511b41d2SMark Murray  *
6c2d3a559SKris Kennaway  * As far as I am concerned, the code I have written for this software
7c2d3a559SKris Kennaway  * can be used freely for any purpose.  Any derived versions of this
8c2d3a559SKris Kennaway  * software must be clearly marked as such, and if the derived work is
9c2d3a559SKris Kennaway  * incompatible with the protocol description in the RFC file, it must be
10c2d3a559SKris Kennaway  * called by a name other than "ssh" or "Secure Shell".
11511b41d2SMark Murray  */
12511b41d2SMark Murray 
13511b41d2SMark Murray #include "includes.h"
14511b41d2SMark Murray 
15333ee039SDag-Erling Smørgrav #include <sys/types.h>
16333ee039SDag-Erling Smørgrav #include <sys/socket.h>
1719261079SEd Maste #include <sys/stat.h>
1819261079SEd Maste #ifdef __OpenBSD__
1947dd1d1bSDag-Erling Smørgrav #include <sys/sysctl.h>
2047dd1d1bSDag-Erling Smørgrav #endif
21333ee039SDag-Erling Smørgrav 
224a421b63SDag-Erling Smørgrav #include <netinet/in.h>
234a421b63SDag-Erling Smørgrav #include <netinet/in_systm.h>
244a421b63SDag-Erling Smørgrav #include <netinet/ip.h>
2547dd1d1bSDag-Erling Smørgrav #ifdef HAVE_NET_ROUTE_H
2647dd1d1bSDag-Erling Smørgrav #include <net/route.h>
2747dd1d1bSDag-Erling Smørgrav #endif
284a421b63SDag-Erling Smørgrav 
29e4a9863fSDag-Erling Smørgrav #include <ctype.h>
30333ee039SDag-Erling Smørgrav #include <netdb.h>
31333ee039SDag-Erling Smørgrav #include <pwd.h>
32333ee039SDag-Erling Smørgrav #include <stdio.h>
33333ee039SDag-Erling Smørgrav #include <stdlib.h>
34333ee039SDag-Erling Smørgrav #include <string.h>
35333ee039SDag-Erling Smørgrav #include <signal.h>
36333ee039SDag-Erling Smørgrav #include <unistd.h>
37bc5531deSDag-Erling Smørgrav #include <limits.h>
38333ee039SDag-Erling Smørgrav #include <stdarg.h>
39d4af9e69SDag-Erling Smørgrav #include <errno.h>
40e4a9863fSDag-Erling Smørgrav #ifdef HAVE_UTIL_H
41e4a9863fSDag-Erling Smørgrav #include <util.h>
42e4a9863fSDag-Erling Smørgrav #endif
4319261079SEd Maste #ifdef USE_SYSTEM_GLOB
4419261079SEd Maste # include <glob.h>
4519261079SEd Maste #else
4619261079SEd Maste # include "openbsd-compat/glob.h"
4719261079SEd Maste #endif
48333ee039SDag-Erling Smørgrav 
49d4af9e69SDag-Erling Smørgrav #include "openbsd-compat/sys-queue.h"
50333ee039SDag-Erling Smørgrav #include "xmalloc.h"
51511b41d2SMark Murray #include "ssh.h"
52ca3176e7SBrian Feldman #include "log.h"
53190cef3dSDag-Erling Smørgrav #include "sshbuf.h"
54a0ee8cc6SDag-Erling Smørgrav #include "misc.h"
55511b41d2SMark Murray #include "servconf.h"
56ca3176e7SBrian Feldman #include "pathnames.h"
57ca3176e7SBrian Feldman #include "cipher.h"
58190cef3dSDag-Erling Smørgrav #include "sshkey.h"
59ca3176e7SBrian Feldman #include "kex.h"
60ca3176e7SBrian Feldman #include "mac.h"
61333ee039SDag-Erling Smørgrav #include "match.h"
62333ee039SDag-Erling Smørgrav #include "channels.h"
63333ee039SDag-Erling Smørgrav #include "groupaccess.h"
64462c32cbSDag-Erling Smørgrav #include "canohost.h"
65462c32cbSDag-Erling Smørgrav #include "packet.h"
66190cef3dSDag-Erling Smørgrav #include "ssherr.h"
676888a9beSDag-Erling Smørgrav #include "hostfile.h"
686888a9beSDag-Erling Smørgrav #include "auth.h"
69bc5531deSDag-Erling Smørgrav #include "myproposal.h"
70bc5531deSDag-Erling Smørgrav #include "digest.h"
71b15c8340SDag-Erling Smørgrav #include "version.h"
72511b41d2SMark Murray 
7347dd1d1bSDag-Erling Smørgrav static void add_listen_addr(ServerOptions *, const char *,
7447dd1d1bSDag-Erling Smørgrav     const char *, int);
7547dd1d1bSDag-Erling Smørgrav static void add_one_listen_addr(ServerOptions *, const char *,
7647dd1d1bSDag-Erling Smørgrav     const char *, int);
7719261079SEd Maste static void parse_server_config_depth(ServerOptions *options,
7819261079SEd Maste     const char *filename, struct sshbuf *conf, struct include_list *includes,
7919261079SEd Maste     struct connection_info *connectinfo, int flags, int *activep, int depth);
80ca3176e7SBrian Feldman 
8180628bacSDag-Erling Smørgrav /* Use of privilege separation or not */
8280628bacSDag-Erling Smørgrav extern int use_privsep;
83190cef3dSDag-Erling Smørgrav extern struct sshbuf *cfg;
84511b41d2SMark Murray 
85511b41d2SMark Murray /* Initializes the server options to their default values. */
86511b41d2SMark Murray 
87511b41d2SMark Murray void
88511b41d2SMark Murray initialize_server_options(ServerOptions *options)
89511b41d2SMark Murray {
90511b41d2SMark Murray 	memset(options, 0, sizeof(*options));
91989dd127SDag-Erling Smørgrav 
92989dd127SDag-Erling Smørgrav 	/* Portable-specific options */
93cf2b5f3bSDag-Erling Smørgrav 	options->use_pam = -1;
94989dd127SDag-Erling Smørgrav 
95989dd127SDag-Erling Smørgrav 	/* Standard Options */
96511b41d2SMark Murray 	options->num_ports = 0;
97511b41d2SMark Murray 	options->ports_from_cmdline = 0;
98557f75e5SDag-Erling Smørgrav 	options->queued_listen_addrs = NULL;
99557f75e5SDag-Erling Smørgrav 	options->num_queued_listens = 0;
100511b41d2SMark Murray 	options->listen_addrs = NULL;
10147dd1d1bSDag-Erling Smørgrav 	options->num_listen_addrs = 0;
102aa49c926SDag-Erling Smørgrav 	options->address_family = -1;
10347dd1d1bSDag-Erling Smørgrav 	options->routing_domain = NULL;
104ca3176e7SBrian Feldman 	options->num_host_key_files = 0;
105b15c8340SDag-Erling Smørgrav 	options->num_host_cert_files = 0;
106e4a9863fSDag-Erling Smørgrav 	options->host_key_agent = NULL;
107e8aafc91SKris Kennaway 	options->pid_file = NULL;
108511b41d2SMark Murray 	options->login_grace_time = -1;
109ca3176e7SBrian Feldman 	options->permit_root_login = PERMIT_NOT_SET;
110511b41d2SMark Murray 	options->ignore_rhosts = -1;
111511b41d2SMark Murray 	options->ignore_user_known_hosts = -1;
112511b41d2SMark Murray 	options->print_motd = -1;
113ca3176e7SBrian Feldman 	options->print_lastlog = -1;
114511b41d2SMark Murray 	options->x11_forwarding = -1;
115511b41d2SMark Murray 	options->x11_display_offset = -1;
116af12a3e7SDag-Erling Smørgrav 	options->x11_use_localhost = -1;
117f7167e0eSDag-Erling Smørgrav 	options->permit_tty = -1;
118a0ee8cc6SDag-Erling Smørgrav 	options->permit_user_rc = -1;
119c2d3a559SKris Kennaway 	options->xauth_location = NULL;
120511b41d2SMark Murray 	options->strict_modes = -1;
1211ec0d754SDag-Erling Smørgrav 	options->tcp_keep_alive = -1;
122af12a3e7SDag-Erling Smørgrav 	options->log_facility = SYSLOG_FACILITY_NOT_SET;
123af12a3e7SDag-Erling Smørgrav 	options->log_level = SYSLOG_LEVEL_NOT_SET;
12419261079SEd Maste 	options->num_log_verbose = 0;
12519261079SEd Maste 	options->log_verbose = NULL;
126ca3176e7SBrian Feldman 	options->hostbased_authentication = -1;
127ca3176e7SBrian Feldman 	options->hostbased_uses_name_from_packet_only = -1;
12819261079SEd Maste 	options->hostbased_accepted_algos = NULL;
129eccfee6eSDag-Erling Smørgrav 	options->hostkeyalgorithms = NULL;
130ca3176e7SBrian Feldman 	options->pubkey_authentication = -1;
13119261079SEd Maste 	options->pubkey_auth_options = -1;
13219261079SEd Maste 	options->pubkey_accepted_algos = NULL;
133cb96ab36SAssar Westerlund 	options->kerberos_authentication = -1;
134af12a3e7SDag-Erling Smørgrav 	options->kerberos_or_local_passwd = -1;
135af12a3e7SDag-Erling Smørgrav 	options->kerberos_ticket_cleanup = -1;
1361ec0d754SDag-Erling Smørgrav 	options->kerberos_get_afs_token = -1;
137cf2b5f3bSDag-Erling Smørgrav 	options->gss_authentication=-1;
138cf2b5f3bSDag-Erling Smørgrav 	options->gss_cleanup_creds = -1;
139557f75e5SDag-Erling Smørgrav 	options->gss_strict_acceptor = -1;
140511b41d2SMark Murray 	options->password_authentication = -1;
14109958426SBrian Feldman 	options->kbd_interactive_authentication = -1;
142511b41d2SMark Murray 	options->permit_empty_passwd = -1;
143f388f5efSDag-Erling Smørgrav 	options->permit_user_env = -1;
14419261079SEd Maste 	options->permit_user_env_allowlist = NULL;
14580628bacSDag-Erling Smørgrav 	options->compression = -1;
146e4a9863fSDag-Erling Smørgrav 	options->rekey_limit = -1;
147e4a9863fSDag-Erling Smørgrav 	options->rekey_interval = -1;
14809958426SBrian Feldman 	options->allow_tcp_forwarding = -1;
149a0ee8cc6SDag-Erling Smørgrav 	options->allow_streamlocal_forwarding = -1;
150d4af9e69SDag-Erling Smørgrav 	options->allow_agent_forwarding = -1;
151511b41d2SMark Murray 	options->num_allow_users = 0;
152511b41d2SMark Murray 	options->num_deny_users = 0;
153511b41d2SMark Murray 	options->num_allow_groups = 0;
154511b41d2SMark Murray 	options->num_deny_groups = 0;
155e8aafc91SKris Kennaway 	options->ciphers = NULL;
156ca3176e7SBrian Feldman 	options->macs = NULL;
1574a421b63SDag-Erling Smørgrav 	options->kex_algorithms = NULL;
1582f513db7SEd Maste 	options->ca_sign_algorithms = NULL;
159a0ee8cc6SDag-Erling Smørgrav 	options->fwd_opts.gateway_ports = -1;
160a0ee8cc6SDag-Erling Smørgrav 	options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
161a0ee8cc6SDag-Erling Smørgrav 	options->fwd_opts.streamlocal_bind_unlink = -1;
162c2d3a559SKris Kennaway 	options->num_subsystems = 0;
163c2d3a559SKris Kennaway 	options->max_startups_begin = -1;
164c2d3a559SKris Kennaway 	options->max_startups_rate = -1;
165c2d3a559SKris Kennaway 	options->max_startups = -1;
16619261079SEd Maste 	options->per_source_max_startups = -1;
16719261079SEd Maste 	options->per_source_masklen_ipv4 = -1;
16819261079SEd Maste 	options->per_source_masklen_ipv6 = -1;
16921e764dfSDag-Erling Smørgrav 	options->max_authtries = -1;
170d4af9e69SDag-Erling Smørgrav 	options->max_sessions = -1;
171ca3176e7SBrian Feldman 	options->banner = NULL;
172cf2b5f3bSDag-Erling Smørgrav 	options->use_dns = -1;
173ca3176e7SBrian Feldman 	options->client_alive_interval = -1;
174ca3176e7SBrian Feldman 	options->client_alive_count_max = -1;
175e146993eSDag-Erling Smørgrav 	options->num_authkeys_files = 0;
17621e764dfSDag-Erling Smørgrav 	options->num_accept_env = 0;
177190cef3dSDag-Erling Smørgrav 	options->num_setenv = 0;
178b74df5b2SDag-Erling Smørgrav 	options->permit_tun = -1;
1794f52dfbbSDag-Erling Smørgrav 	options->permitted_opens = NULL;
180190cef3dSDag-Erling Smørgrav 	options->permitted_listens = NULL;
181333ee039SDag-Erling Smørgrav 	options->adm_forced_command = NULL;
182d4af9e69SDag-Erling Smørgrav 	options->chroot_directory = NULL;
1836888a9beSDag-Erling Smørgrav 	options->authorized_keys_command = NULL;
1846888a9beSDag-Erling Smørgrav 	options->authorized_keys_command_user = NULL;
185b15c8340SDag-Erling Smørgrav 	options->revoked_keys_file = NULL;
18619261079SEd Maste 	options->sk_provider = NULL;
187b15c8340SDag-Erling Smørgrav 	options->trusted_user_ca_keys = NULL;
188e2f6069cSDag-Erling Smørgrav 	options->authorized_principals_file = NULL;
189557f75e5SDag-Erling Smørgrav 	options->authorized_principals_command = NULL;
190557f75e5SDag-Erling Smørgrav 	options->authorized_principals_command_user = NULL;
1914a421b63SDag-Erling Smørgrav 	options->ip_qos_interactive = -1;
1924a421b63SDag-Erling Smørgrav 	options->ip_qos_bulk = -1;
193462c32cbSDag-Erling Smørgrav 	options->version_addendum = NULL;
194bc5531deSDag-Erling Smørgrav 	options->fingerprint_hash = -1;
195ca86bcf2SDag-Erling Smørgrav 	options->disable_forwarding = -1;
1964f52dfbbSDag-Erling Smørgrav 	options->expose_userauth_info = -1;
19738a52bd3SEd Maste 	options->required_rsa_size = -1;
198f374ba41SEd Maste 	options->channel_timeouts = NULL;
199f374ba41SEd Maste 	options->num_channel_timeouts = 0;
200f374ba41SEd Maste 	options->unused_connection_timeout = -1;
201b2af61ecSKurt Lidl 	options->use_blacklist = -1;
202bc5531deSDag-Erling Smørgrav }
203bc5531deSDag-Erling Smørgrav 
204bc5531deSDag-Erling Smørgrav /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
205bc5531deSDag-Erling Smørgrav static int
206bc5531deSDag-Erling Smørgrav option_clear_or_none(const char *o)
207bc5531deSDag-Erling Smørgrav {
208bc5531deSDag-Erling Smørgrav 	return o == NULL || strcasecmp(o, "none") == 0;
209511b41d2SMark Murray }
210511b41d2SMark Murray 
211acc1a9efSDag-Erling Smørgrav static void
212acc1a9efSDag-Erling Smørgrav assemble_algorithms(ServerOptions *o)
213acc1a9efSDag-Erling Smørgrav {
2142f513db7SEd Maste 	char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
21519261079SEd Maste 	char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig;
216190cef3dSDag-Erling Smørgrav 	int r;
217190cef3dSDag-Erling Smørgrav 
218190cef3dSDag-Erling Smørgrav 	all_cipher = cipher_alg_list(',', 0);
219190cef3dSDag-Erling Smørgrav 	all_mac = mac_alg_list(',');
220190cef3dSDag-Erling Smørgrav 	all_kex = kex_alg_list(',');
221190cef3dSDag-Erling Smørgrav 	all_key = sshkey_alg_list(0, 0, 1, ',');
2222f513db7SEd Maste 	all_sig = sshkey_alg_list(0, 1, 1, ',');
22319261079SEd Maste 	/* remove unsupported algos from default lists */
22419261079SEd Maste 	def_cipher = match_filter_allowlist(KEX_SERVER_ENCRYPT, all_cipher);
22519261079SEd Maste 	def_mac = match_filter_allowlist(KEX_SERVER_MAC, all_mac);
22619261079SEd Maste 	def_kex = match_filter_allowlist(KEX_SERVER_KEX, all_kex);
22719261079SEd Maste 	def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
22819261079SEd Maste 	def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig);
229190cef3dSDag-Erling Smørgrav #define ASSEMBLE(what, defaults, all) \
230190cef3dSDag-Erling Smørgrav 	do { \
231190cef3dSDag-Erling Smørgrav 		if ((r = kex_assemble_names(&o->what, defaults, all)) != 0) \
23219261079SEd Maste 			fatal_fr(r, "%s", #what); \
233190cef3dSDag-Erling Smørgrav 	} while (0)
23419261079SEd Maste 	ASSEMBLE(ciphers, def_cipher, all_cipher);
23519261079SEd Maste 	ASSEMBLE(macs, def_mac, all_mac);
23619261079SEd Maste 	ASSEMBLE(kex_algorithms, def_kex, all_kex);
23719261079SEd Maste 	ASSEMBLE(hostkeyalgorithms, def_key, all_key);
23819261079SEd Maste 	ASSEMBLE(hostbased_accepted_algos, def_key, all_key);
23919261079SEd Maste 	ASSEMBLE(pubkey_accepted_algos, def_key, all_key);
24019261079SEd Maste 	ASSEMBLE(ca_sign_algorithms, def_sig, all_sig);
241190cef3dSDag-Erling Smørgrav #undef ASSEMBLE
242190cef3dSDag-Erling Smørgrav 	free(all_cipher);
243190cef3dSDag-Erling Smørgrav 	free(all_mac);
244190cef3dSDag-Erling Smørgrav 	free(all_kex);
245190cef3dSDag-Erling Smørgrav 	free(all_key);
2462f513db7SEd Maste 	free(all_sig);
24719261079SEd Maste 	free(def_cipher);
24819261079SEd Maste 	free(def_mac);
24919261079SEd Maste 	free(def_kex);
25019261079SEd Maste 	free(def_key);
25119261079SEd Maste 	free(def_sig);
25247dd1d1bSDag-Erling Smørgrav }
25347dd1d1bSDag-Erling Smørgrav 
25447dd1d1bSDag-Erling Smørgrav static const char *defaultkey = "[default]";
25547dd1d1bSDag-Erling Smørgrav 
25647dd1d1bSDag-Erling Smørgrav void
25747dd1d1bSDag-Erling Smørgrav servconf_add_hostkey(const char *file, const int line,
25819261079SEd Maste     ServerOptions *options, const char *path, int userprovided)
25947dd1d1bSDag-Erling Smørgrav {
26047dd1d1bSDag-Erling Smørgrav 	char *apath = derelativise_path(path);
26147dd1d1bSDag-Erling Smørgrav 
26247dd1d1bSDag-Erling Smørgrav 	if (file == defaultkey && access(path, R_OK) != 0)
26347dd1d1bSDag-Erling Smørgrav 		return;
26419261079SEd Maste 	opt_array_append2(file, line, "HostKey",
26519261079SEd Maste 	    &options->host_key_files, &options->host_key_file_userprovided,
26619261079SEd Maste 	    &options->num_host_key_files, apath, userprovided);
26747dd1d1bSDag-Erling Smørgrav 	free(apath);
26847dd1d1bSDag-Erling Smørgrav }
26947dd1d1bSDag-Erling Smørgrav 
27047dd1d1bSDag-Erling Smørgrav void
27147dd1d1bSDag-Erling Smørgrav servconf_add_hostcert(const char *file, const int line,
27247dd1d1bSDag-Erling Smørgrav     ServerOptions *options, const char *path)
27347dd1d1bSDag-Erling Smørgrav {
27447dd1d1bSDag-Erling Smørgrav 	char *apath = derelativise_path(path);
27547dd1d1bSDag-Erling Smørgrav 
27619261079SEd Maste 	opt_array_append(file, line, "HostCertificate",
27747dd1d1bSDag-Erling Smørgrav 	    &options->host_cert_files, &options->num_host_cert_files, apath);
27847dd1d1bSDag-Erling Smørgrav 	free(apath);
27947dd1d1bSDag-Erling Smørgrav }
28047dd1d1bSDag-Erling Smørgrav 
281511b41d2SMark Murray void
282511b41d2SMark Murray fill_default_server_options(ServerOptions *options)
283511b41d2SMark Murray {
28447dd1d1bSDag-Erling Smørgrav 	u_int i;
285bc5531deSDag-Erling Smørgrav 
286989dd127SDag-Erling Smørgrav 	/* Portable-specific options */
287cf2b5f3bSDag-Erling Smørgrav 	if (options->use_pam == -1)
288f0477b26SDag-Erling Smørgrav 		options->use_pam = 1;
289989dd127SDag-Erling Smørgrav 
290989dd127SDag-Erling Smørgrav 	/* Standard Options */
291ca3176e7SBrian Feldman 	if (options->num_host_key_files == 0) {
292ca3176e7SBrian Feldman 		/* fill default hostkeys for protocols */
29347dd1d1bSDag-Erling Smørgrav 		servconf_add_hostkey(defaultkey, 0, options,
29419261079SEd Maste 		    _PATH_HOST_RSA_KEY_FILE, 0);
2954a421b63SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC
29647dd1d1bSDag-Erling Smørgrav 		servconf_add_hostkey(defaultkey, 0, options,
29719261079SEd Maste 		    _PATH_HOST_ECDSA_KEY_FILE, 0);
2984a421b63SDag-Erling Smørgrav #endif
29947dd1d1bSDag-Erling Smørgrav 		servconf_add_hostkey(defaultkey, 0, options,
30019261079SEd Maste 		    _PATH_HOST_ED25519_KEY_FILE, 0);
30147dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
30247dd1d1bSDag-Erling Smørgrav 		servconf_add_hostkey(defaultkey, 0, options,
30319261079SEd Maste 		    _PATH_HOST_XMSS_KEY_FILE, 0);
30447dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
305af12a3e7SDag-Erling Smørgrav 	}
306144a80bdSDag-Erling Smørgrav 	if (options->num_host_key_files == 0)
307144a80bdSDag-Erling Smørgrav 		fatal("No host key files found");
308b15c8340SDag-Erling Smørgrav 	/* No certificates by default */
309511b41d2SMark Murray 	if (options->num_ports == 0)
310511b41d2SMark Murray 		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
311557f75e5SDag-Erling Smørgrav 	if (options->address_family == -1)
312557f75e5SDag-Erling Smørgrav 		options->address_family = AF_UNSPEC;
313511b41d2SMark Murray 	if (options->listen_addrs == NULL)
31447dd1d1bSDag-Erling Smørgrav 		add_listen_addr(options, NULL, NULL, 0);
315e8aafc91SKris Kennaway 	if (options->pid_file == NULL)
316bc5531deSDag-Erling Smørgrav 		options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE);
31719261079SEd Maste 	if (options->moduli_file == NULL)
31819261079SEd Maste 		options->moduli_file = xstrdup(_PATH_DH_MODULI);
319511b41d2SMark Murray 	if (options->login_grace_time == -1)
320975616f0SDag-Erling Smørgrav 		options->login_grace_time = 120;
321ca3176e7SBrian Feldman 	if (options->permit_root_login == PERMIT_NOT_SET)
322975616f0SDag-Erling Smørgrav 		options->permit_root_login = PERMIT_NO;
323511b41d2SMark Murray 	if (options->ignore_rhosts == -1)
324fe5fd017SMark Murray 		options->ignore_rhosts = 1;
325511b41d2SMark Murray 	if (options->ignore_user_known_hosts == -1)
326511b41d2SMark Murray 		options->ignore_user_known_hosts = 0;
327511b41d2SMark Murray 	if (options->print_motd == -1)
328511b41d2SMark Murray 		options->print_motd = 1;
329ca3176e7SBrian Feldman 	if (options->print_lastlog == -1)
330ca3176e7SBrian Feldman 		options->print_lastlog = 1;
331511b41d2SMark Murray 	if (options->x11_forwarding == -1)
33277934b7aSEd Maste 		options->x11_forwarding = 0;
333511b41d2SMark Murray 	if (options->x11_display_offset == -1)
334fe5fd017SMark Murray 		options->x11_display_offset = 10;
335af12a3e7SDag-Erling Smørgrav 	if (options->x11_use_localhost == -1)
336af12a3e7SDag-Erling Smørgrav 		options->x11_use_localhost = 1;
337c2d3a559SKris Kennaway 	if (options->xauth_location == NULL)
338bc5531deSDag-Erling Smørgrav 		options->xauth_location = xstrdup(_PATH_XAUTH);
339f7167e0eSDag-Erling Smørgrav 	if (options->permit_tty == -1)
340f7167e0eSDag-Erling Smørgrav 		options->permit_tty = 1;
341a0ee8cc6SDag-Erling Smørgrav 	if (options->permit_user_rc == -1)
342a0ee8cc6SDag-Erling Smørgrav 		options->permit_user_rc = 1;
343511b41d2SMark Murray 	if (options->strict_modes == -1)
344511b41d2SMark Murray 		options->strict_modes = 1;
3451ec0d754SDag-Erling Smørgrav 	if (options->tcp_keep_alive == -1)
3461ec0d754SDag-Erling Smørgrav 		options->tcp_keep_alive = 1;
347af12a3e7SDag-Erling Smørgrav 	if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
348511b41d2SMark Murray 		options->log_facility = SYSLOG_FACILITY_AUTH;
349af12a3e7SDag-Erling Smørgrav 	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
350511b41d2SMark Murray 		options->log_level = SYSLOG_LEVEL_INFO;
351ca3176e7SBrian Feldman 	if (options->hostbased_authentication == -1)
352ca3176e7SBrian Feldman 		options->hostbased_authentication = 0;
353ca3176e7SBrian Feldman 	if (options->hostbased_uses_name_from_packet_only == -1)
354ca3176e7SBrian Feldman 		options->hostbased_uses_name_from_packet_only = 0;
355ca3176e7SBrian Feldman 	if (options->pubkey_authentication == -1)
356ca3176e7SBrian Feldman 		options->pubkey_authentication = 1;
35719261079SEd Maste 	if (options->pubkey_auth_options == -1)
35819261079SEd Maste 		options->pubkey_auth_options = 0;
359989dd127SDag-Erling Smørgrav 	if (options->kerberos_authentication == -1)
360cf2b5f3bSDag-Erling Smørgrav 		options->kerberos_authentication = 0;
361af12a3e7SDag-Erling Smørgrav 	if (options->kerberos_or_local_passwd == -1)
362af12a3e7SDag-Erling Smørgrav 		options->kerberos_or_local_passwd = 1;
363af12a3e7SDag-Erling Smørgrav 	if (options->kerberos_ticket_cleanup == -1)
364af12a3e7SDag-Erling Smørgrav 		options->kerberos_ticket_cleanup = 1;
3651ec0d754SDag-Erling Smørgrav 	if (options->kerberos_get_afs_token == -1)
3661ec0d754SDag-Erling Smørgrav 		options->kerberos_get_afs_token = 0;
367cf2b5f3bSDag-Erling Smørgrav 	if (options->gss_authentication == -1)
368cf2b5f3bSDag-Erling Smørgrav 		options->gss_authentication = 0;
369cf2b5f3bSDag-Erling Smørgrav 	if (options->gss_cleanup_creds == -1)
370cf2b5f3bSDag-Erling Smørgrav 		options->gss_cleanup_creds = 1;
371557f75e5SDag-Erling Smørgrav 	if (options->gss_strict_acceptor == -1)
372d93a896eSDag-Erling Smørgrav 		options->gss_strict_acceptor = 1;
373511b41d2SMark Murray 	if (options->password_authentication == -1)
374b909c84bSDag-Erling Smørgrav 		options->password_authentication = 0;
37509958426SBrian Feldman 	if (options->kbd_interactive_authentication == -1)
37619261079SEd Maste 		options->kbd_interactive_authentication = 1;
377511b41d2SMark Murray 	if (options->permit_empty_passwd == -1)
378fe5fd017SMark Murray 		options->permit_empty_passwd = 0;
379190cef3dSDag-Erling Smørgrav 	if (options->permit_user_env == -1) {
380f388f5efSDag-Erling Smørgrav 		options->permit_user_env = 0;
38119261079SEd Maste 		options->permit_user_env_allowlist = NULL;
382190cef3dSDag-Erling Smørgrav 	}
38380628bacSDag-Erling Smørgrav 	if (options->compression == -1)
38419261079SEd Maste #ifdef WITH_ZLIB
385d4ecd108SDag-Erling Smørgrav 		options->compression = COMP_DELAYED;
38619261079SEd Maste #else
38719261079SEd Maste 		options->compression = COMP_NONE;
38819261079SEd Maste #endif
38919261079SEd Maste 
390e4a9863fSDag-Erling Smørgrav 	if (options->rekey_limit == -1)
391e4a9863fSDag-Erling Smørgrav 		options->rekey_limit = 0;
392e4a9863fSDag-Erling Smørgrav 	if (options->rekey_interval == -1)
393e4a9863fSDag-Erling Smørgrav 		options->rekey_interval = 0;
39409958426SBrian Feldman 	if (options->allow_tcp_forwarding == -1)
3956888a9beSDag-Erling Smørgrav 		options->allow_tcp_forwarding = FORWARD_ALLOW;
396a0ee8cc6SDag-Erling Smørgrav 	if (options->allow_streamlocal_forwarding == -1)
397a0ee8cc6SDag-Erling Smørgrav 		options->allow_streamlocal_forwarding = FORWARD_ALLOW;
398d4af9e69SDag-Erling Smørgrav 	if (options->allow_agent_forwarding == -1)
399d4af9e69SDag-Erling Smørgrav 		options->allow_agent_forwarding = 1;
400a0ee8cc6SDag-Erling Smørgrav 	if (options->fwd_opts.gateway_ports == -1)
401a0ee8cc6SDag-Erling Smørgrav 		options->fwd_opts.gateway_ports = 0;
402c2d3a559SKris Kennaway 	if (options->max_startups == -1)
4036888a9beSDag-Erling Smørgrav 		options->max_startups = 100;
404c2d3a559SKris Kennaway 	if (options->max_startups_rate == -1)
4056888a9beSDag-Erling Smørgrav 		options->max_startups_rate = 30;		/* 30% */
406c2d3a559SKris Kennaway 	if (options->max_startups_begin == -1)
4076888a9beSDag-Erling Smørgrav 		options->max_startups_begin = 10;
40819261079SEd Maste 	if (options->per_source_max_startups == -1)
40919261079SEd Maste 		options->per_source_max_startups = INT_MAX;
41019261079SEd Maste 	if (options->per_source_masklen_ipv4 == -1)
41119261079SEd Maste 		options->per_source_masklen_ipv4 = 32;
41219261079SEd Maste 	if (options->per_source_masklen_ipv6 == -1)
41319261079SEd Maste 		options->per_source_masklen_ipv6 = 128;
41421e764dfSDag-Erling Smørgrav 	if (options->max_authtries == -1)
41521e764dfSDag-Erling Smørgrav 		options->max_authtries = DEFAULT_AUTH_FAIL_MAX;
416d4af9e69SDag-Erling Smørgrav 	if (options->max_sessions == -1)
417d4af9e69SDag-Erling Smørgrav 		options->max_sessions = DEFAULT_SESSIONS_MAX;
418cf2b5f3bSDag-Erling Smørgrav 	if (options->use_dns == -1)
419c4cd1fa4SDag-Erling Smørgrav 		options->use_dns = 1;
420ca3176e7SBrian Feldman 	if (options->client_alive_interval == -1)
421ca3176e7SBrian Feldman 		options->client_alive_interval = 0;
422ca3176e7SBrian Feldman 	if (options->client_alive_count_max == -1)
423ca3176e7SBrian Feldman 		options->client_alive_count_max = 3;
424e146993eSDag-Erling Smørgrav 	if (options->num_authkeys_files == 0) {
42519261079SEd Maste 		opt_array_append(defaultkey, 0, "AuthorizedKeysFiles",
42647dd1d1bSDag-Erling Smørgrav 		    &options->authorized_keys_files,
42747dd1d1bSDag-Erling Smørgrav 		    &options->num_authkeys_files,
42847dd1d1bSDag-Erling Smørgrav 		    _PATH_SSH_USER_PERMITTED_KEYS);
42919261079SEd Maste 		opt_array_append(defaultkey, 0, "AuthorizedKeysFiles",
43047dd1d1bSDag-Erling Smørgrav 		    &options->authorized_keys_files,
43147dd1d1bSDag-Erling Smørgrav 		    &options->num_authkeys_files,
43247dd1d1bSDag-Erling Smørgrav 		    _PATH_SSH_USER_PERMITTED_KEYS2);
433af12a3e7SDag-Erling Smørgrav 	}
434b74df5b2SDag-Erling Smørgrav 	if (options->permit_tun == -1)
435b74df5b2SDag-Erling Smørgrav 		options->permit_tun = SSH_TUNMODE_NO;
4364a421b63SDag-Erling Smørgrav 	if (options->ip_qos_interactive == -1)
437190cef3dSDag-Erling Smørgrav 		options->ip_qos_interactive = IPTOS_DSCP_AF21;
4384a421b63SDag-Erling Smørgrav 	if (options->ip_qos_bulk == -1)
439190cef3dSDag-Erling Smørgrav 		options->ip_qos_bulk = IPTOS_DSCP_CS1;
440462c32cbSDag-Erling Smørgrav 	if (options->version_addendum == NULL)
441462c32cbSDag-Erling Smørgrav 		options->version_addendum = xstrdup(SSH_VERSION_FREEBSD);
442a0ee8cc6SDag-Erling Smørgrav 	if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
443a0ee8cc6SDag-Erling Smørgrav 		options->fwd_opts.streamlocal_bind_mask = 0177;
444a0ee8cc6SDag-Erling Smørgrav 	if (options->fwd_opts.streamlocal_bind_unlink == -1)
445a0ee8cc6SDag-Erling Smørgrav 		options->fwd_opts.streamlocal_bind_unlink = 0;
446bc5531deSDag-Erling Smørgrav 	if (options->fingerprint_hash == -1)
447bc5531deSDag-Erling Smørgrav 		options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
448ca86bcf2SDag-Erling Smørgrav 	if (options->disable_forwarding == -1)
449ca86bcf2SDag-Erling Smørgrav 		options->disable_forwarding = 0;
4504f52dfbbSDag-Erling Smørgrav 	if (options->expose_userauth_info == -1)
4514f52dfbbSDag-Erling Smørgrav 		options->expose_userauth_info = 0;
45219261079SEd Maste 	if (options->sk_provider == NULL)
45319261079SEd Maste 		options->sk_provider = xstrdup("internal");
45438a52bd3SEd Maste 	if (options->required_rsa_size == -1)
45538a52bd3SEd Maste 		options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
456f374ba41SEd Maste 	if (options->unused_connection_timeout == -1)
457f374ba41SEd Maste 		options->unused_connection_timeout = 0;
458b2af61ecSKurt Lidl 	if (options->use_blacklist == -1)
459b2af61ecSKurt Lidl 		options->use_blacklist = 0;
460eccfee6eSDag-Erling Smørgrav 
461acc1a9efSDag-Erling Smørgrav 	assemble_algorithms(options);
462eccfee6eSDag-Erling Smørgrav 
463acc1a9efSDag-Erling Smørgrav 	/* Turn privilege separation and sandboxing on by default */
464462c32cbSDag-Erling Smørgrav 	if (use_privsep == -1)
4652b1970f3SDag-Erling Smørgrav 		use_privsep = PRIVSEP_ON;
466462c32cbSDag-Erling Smørgrav 
467bc5531deSDag-Erling Smørgrav #define CLEAR_ON_NONE(v) \
468bc5531deSDag-Erling Smørgrav 	do { \
469bc5531deSDag-Erling Smørgrav 		if (option_clear_or_none(v)) { \
470bc5531deSDag-Erling Smørgrav 			free(v); \
471bc5531deSDag-Erling Smørgrav 			v = NULL; \
472bc5531deSDag-Erling Smørgrav 		} \
473bc5531deSDag-Erling Smørgrav 	} while(0)
474f374ba41SEd Maste #define CLEAR_ON_NONE_ARRAY(v, nv, none) \
475f374ba41SEd Maste 	do { \
476f374ba41SEd Maste 		if (options->nv == 1 && \
477f374ba41SEd Maste 		    strcasecmp(options->v[0], none) == 0) { \
478f374ba41SEd Maste 			free(options->v[0]); \
479f374ba41SEd Maste 			free(options->v); \
480f374ba41SEd Maste 			options->v = NULL; \
481f374ba41SEd Maste 			options->nv = 0; \
482f374ba41SEd Maste 		} \
483f374ba41SEd Maste 	} while (0)
484bc5531deSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->pid_file);
485bc5531deSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->xauth_location);
486bc5531deSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->banner);
487bc5531deSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->trusted_user_ca_keys);
488bc5531deSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->revoked_keys_file);
48919261079SEd Maste 	CLEAR_ON_NONE(options->sk_provider);
490557f75e5SDag-Erling Smørgrav 	CLEAR_ON_NONE(options->authorized_principals_file);
491acc1a9efSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->adm_forced_command);
492acc1a9efSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->chroot_directory);
49347dd1d1bSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->routing_domain);
49419261079SEd Maste 	CLEAR_ON_NONE(options->host_key_agent);
495f374ba41SEd Maste 
496bc5531deSDag-Erling Smørgrav 	for (i = 0; i < options->num_host_key_files; i++)
497bc5531deSDag-Erling Smørgrav 		CLEAR_ON_NONE(options->host_key_files[i]);
498bc5531deSDag-Erling Smørgrav 	for (i = 0; i < options->num_host_cert_files; i++)
499bc5531deSDag-Erling Smørgrav 		CLEAR_ON_NONE(options->host_cert_files[i]);
500bc5531deSDag-Erling Smørgrav 
501f374ba41SEd Maste 	CLEAR_ON_NONE_ARRAY(channel_timeouts, num_channel_timeouts, "none");
502f374ba41SEd Maste 	CLEAR_ON_NONE_ARRAY(auth_methods, num_auth_methods, "any");
503f374ba41SEd Maste #undef CLEAR_ON_NONE
504f374ba41SEd Maste #undef CLEAR_ON_NONE_ARRAY
505511b41d2SMark Murray }
506511b41d2SMark Murray 
507511b41d2SMark Murray /* Keyword tokens. */
508511b41d2SMark Murray typedef enum {
509511b41d2SMark Murray 	sBadOption,		/* == unknown option */
510989dd127SDag-Erling Smørgrav 	/* Portable-specific options */
511cf2b5f3bSDag-Erling Smørgrav 	sUsePAM,
512989dd127SDag-Erling Smørgrav 	/* Standard Options */
513ca86bcf2SDag-Erling Smørgrav 	sPort, sHostKeyFile, sLoginGraceTime,
51419261079SEd Maste 	sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose,
515af12a3e7SDag-Erling Smørgrav 	sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
516e9e8876aSEd Maste 	sKerberosGetAFSToken, sPasswordAuthentication,
517e9e8876aSEd Maste 	sKbdInteractiveAuthentication, sListenAddress, sAddressFamily,
518ca3176e7SBrian Feldman 	sPrintMotd, sPrintLastLog, sIgnoreRhosts,
519af12a3e7SDag-Erling Smørgrav 	sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
520f7167e0eSDag-Erling Smørgrav 	sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive,
521ca86bcf2SDag-Erling Smørgrav 	sPermitUserEnvironment, sAllowTcpForwarding, sCompression,
522e4a9863fSDag-Erling Smørgrav 	sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
52319261079SEd Maste 	sIgnoreUserKnownHosts, sCiphers, sMacs, sPidFile, sModuliFile,
52419261079SEd Maste 	sGatewayPorts, sPubkeyAuthentication, sPubkeyAcceptedAlgorithms,
525bc5531deSDag-Erling Smørgrav 	sXAuthLocation, sSubsystem, sMaxStartups, sMaxAuthTries, sMaxSessions,
526cf2b5f3bSDag-Erling Smørgrav 	sBanner, sUseDNS, sHostbasedAuthentication,
52719261079SEd Maste 	sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedAlgorithms,
52819261079SEd Maste 	sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize,
529bc5531deSDag-Erling Smørgrav 	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
530557f75e5SDag-Erling Smørgrav 	sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
531190cef3dSDag-Erling Smørgrav 	sAcceptEnv, sSetEnv, sPermitTunnel,
532190cef3dSDag-Erling Smørgrav 	sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory,
533d4af9e69SDag-Erling Smørgrav 	sUsePrivilegeSeparation, sAllowAgentForwarding,
53419261079SEd Maste 	sHostCertificate, sInclude,
535e2f6069cSDag-Erling Smørgrav 	sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
536557f75e5SDag-Erling Smørgrav 	sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser,
5372f513db7SEd Maste 	sKexAlgorithms, sCASignatureAlgorithms, sIPQoS, sVersionAddendum,
5386888a9beSDag-Erling Smørgrav 	sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
539a0ee8cc6SDag-Erling Smørgrav 	sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
540a0ee8cc6SDag-Erling Smørgrav 	sStreamLocalBindMask, sStreamLocalBindUnlink,
541ca86bcf2SDag-Erling Smørgrav 	sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
54219261079SEd Maste 	sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider,
543f374ba41SEd Maste 	sRequiredRSASize, sChannelTimeout, sUnusedConnectionTimeout,
544b2af61ecSKurt Lidl 	sUseBlacklist,
545ca86bcf2SDag-Erling Smørgrav 	sDeprecated, sIgnore, sUnsupported
546511b41d2SMark Murray } ServerOpCodes;
547511b41d2SMark Murray 
54819261079SEd Maste #define SSHCFG_GLOBAL		0x01	/* allowed in main section of config */
549333ee039SDag-Erling Smørgrav #define SSHCFG_MATCH		0x02	/* allowed inside a Match section */
550333ee039SDag-Erling Smørgrav #define SSHCFG_ALL		(SSHCFG_GLOBAL|SSHCFG_MATCH)
55119261079SEd Maste #define SSHCFG_NEVERMATCH	0x04  /* Match never matches; internal only */
55219261079SEd Maste #define SSHCFG_MATCH_ONLY	0x08  /* Match only in conditional blocks; internal only */
553333ee039SDag-Erling Smørgrav 
554511b41d2SMark Murray /* Textual representation of the tokens. */
555511b41d2SMark Murray static struct {
556511b41d2SMark Murray 	const char *name;
557511b41d2SMark Murray 	ServerOpCodes opcode;
558333ee039SDag-Erling Smørgrav 	u_int flags;
559511b41d2SMark Murray } keywords[] = {
560989dd127SDag-Erling Smørgrav 	/* Portable-specific options */
561cf2b5f3bSDag-Erling Smørgrav #ifdef USE_PAM
562333ee039SDag-Erling Smørgrav 	{ "usepam", sUsePAM, SSHCFG_GLOBAL },
563cf2b5f3bSDag-Erling Smørgrav #else
564333ee039SDag-Erling Smørgrav 	{ "usepam", sUnsupported, SSHCFG_GLOBAL },
565975616f0SDag-Erling Smørgrav #endif
566333ee039SDag-Erling Smørgrav 	{ "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
567989dd127SDag-Erling Smørgrav 	/* Standard Options */
568333ee039SDag-Erling Smørgrav 	{ "port", sPort, SSHCFG_GLOBAL },
569333ee039SDag-Erling Smørgrav 	{ "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
570333ee039SDag-Erling Smørgrav 	{ "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL },		/* alias */
571e4a9863fSDag-Erling Smørgrav 	{ "hostkeyagent", sHostKeyAgent, SSHCFG_GLOBAL },
572333ee039SDag-Erling Smørgrav 	{ "pidfile", sPidFile, SSHCFG_GLOBAL },
57319261079SEd Maste 	{ "modulifile", sModuliFile, SSHCFG_GLOBAL },
574ca86bcf2SDag-Erling Smørgrav 	{ "serverkeybits", sDeprecated, SSHCFG_GLOBAL },
575333ee039SDag-Erling Smørgrav 	{ "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL },
576ca86bcf2SDag-Erling Smørgrav 	{ "keyregenerationinterval", sDeprecated, SSHCFG_GLOBAL },
577d4af9e69SDag-Erling Smørgrav 	{ "permitrootlogin", sPermitRootLogin, SSHCFG_ALL },
578333ee039SDag-Erling Smørgrav 	{ "syslogfacility", sLogFacility, SSHCFG_GLOBAL },
5794f52dfbbSDag-Erling Smørgrav 	{ "loglevel", sLogLevel, SSHCFG_ALL },
58019261079SEd Maste 	{ "logverbose", sLogVerbose, SSHCFG_ALL },
581333ee039SDag-Erling Smørgrav 	{ "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL },
582ca86bcf2SDag-Erling Smørgrav 	{ "rhostsrsaauthentication", sDeprecated, SSHCFG_ALL },
583d4af9e69SDag-Erling Smørgrav 	{ "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL },
584e2f6069cSDag-Erling Smørgrav 	{ "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_ALL },
58519261079SEd Maste 	{ "hostbasedacceptedalgorithms", sHostbasedAcceptedAlgorithms, SSHCFG_ALL },
58619261079SEd Maste 	{ "hostbasedacceptedkeytypes", sHostbasedAcceptedAlgorithms, SSHCFG_ALL }, /* obsolete */
587eccfee6eSDag-Erling Smørgrav 	{ "hostkeyalgorithms", sHostKeyAlgorithms, SSHCFG_GLOBAL },
588ca86bcf2SDag-Erling Smørgrav 	{ "rsaauthentication", sDeprecated, SSHCFG_ALL },
589d4af9e69SDag-Erling Smørgrav 	{ "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL },
59019261079SEd Maste 	{ "pubkeyacceptedalgorithms", sPubkeyAcceptedAlgorithms, SSHCFG_ALL },
59119261079SEd Maste 	{ "pubkeyacceptedkeytypes", sPubkeyAcceptedAlgorithms, SSHCFG_ALL }, /* obsolete */
59219261079SEd Maste 	{ "pubkeyauthoptions", sPubkeyAuthOptions, SSHCFG_ALL },
593333ee039SDag-Erling Smørgrav 	{ "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */
594cf2b5f3bSDag-Erling Smørgrav #ifdef KRB5
595d4af9e69SDag-Erling Smørgrav 	{ "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL },
596333ee039SDag-Erling Smørgrav 	{ "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL },
597333ee039SDag-Erling Smørgrav 	{ "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL },
5981ec0d754SDag-Erling Smørgrav #ifdef USE_AFS
599333ee039SDag-Erling Smørgrav 	{ "kerberosgetafstoken", sKerberosGetAFSToken, SSHCFG_GLOBAL },
6001ec0d754SDag-Erling Smørgrav #else
601333ee039SDag-Erling Smørgrav 	{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
6021ec0d754SDag-Erling Smørgrav #endif
603cf2b5f3bSDag-Erling Smørgrav #else
604d4af9e69SDag-Erling Smørgrav 	{ "kerberosauthentication", sUnsupported, SSHCFG_ALL },
605333ee039SDag-Erling Smørgrav 	{ "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
606333ee039SDag-Erling Smørgrav 	{ "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
607333ee039SDag-Erling Smørgrav 	{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
608cb96ab36SAssar Westerlund #endif
609333ee039SDag-Erling Smørgrav 	{ "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
610333ee039SDag-Erling Smørgrav 	{ "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
611cf2b5f3bSDag-Erling Smørgrav #ifdef GSSAPI
612d4af9e69SDag-Erling Smørgrav 	{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
613333ee039SDag-Erling Smørgrav 	{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
614557f75e5SDag-Erling Smørgrav 	{ "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
615cf2b5f3bSDag-Erling Smørgrav #else
616d4af9e69SDag-Erling Smørgrav 	{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
617333ee039SDag-Erling Smørgrav 	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
618557f75e5SDag-Erling Smørgrav 	{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
619511b41d2SMark Murray #endif
620d4af9e69SDag-Erling Smørgrav 	{ "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
621d4af9e69SDag-Erling Smørgrav 	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
62219261079SEd Maste 	{ "challengeresponseauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */
62319261079SEd Maste 	{ "skeyauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */
624333ee039SDag-Erling Smørgrav 	{ "checkmail", sDeprecated, SSHCFG_GLOBAL },
625333ee039SDag-Erling Smørgrav 	{ "listenaddress", sListenAddress, SSHCFG_GLOBAL },
626333ee039SDag-Erling Smørgrav 	{ "addressfamily", sAddressFamily, SSHCFG_GLOBAL },
627333ee039SDag-Erling Smørgrav 	{ "printmotd", sPrintMotd, SSHCFG_GLOBAL },
628acc1a9efSDag-Erling Smørgrav #ifdef DISABLE_LASTLOG
629acc1a9efSDag-Erling Smørgrav 	{ "printlastlog", sUnsupported, SSHCFG_GLOBAL },
630acc1a9efSDag-Erling Smørgrav #else
631333ee039SDag-Erling Smørgrav 	{ "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
632acc1a9efSDag-Erling Smørgrav #endif
63319261079SEd Maste 	{ "ignorerhosts", sIgnoreRhosts, SSHCFG_ALL },
634333ee039SDag-Erling Smørgrav 	{ "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
635333ee039SDag-Erling Smørgrav 	{ "x11forwarding", sX11Forwarding, SSHCFG_ALL },
636333ee039SDag-Erling Smørgrav 	{ "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
637333ee039SDag-Erling Smørgrav 	{ "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
638333ee039SDag-Erling Smørgrav 	{ "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
639333ee039SDag-Erling Smørgrav 	{ "strictmodes", sStrictModes, SSHCFG_GLOBAL },
640cce7d346SDag-Erling Smørgrav 	{ "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL },
641333ee039SDag-Erling Smørgrav 	{ "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
642ca86bcf2SDag-Erling Smørgrav 	{ "uselogin", sDeprecated, SSHCFG_GLOBAL },
643333ee039SDag-Erling Smørgrav 	{ "compression", sCompression, SSHCFG_GLOBAL },
644e4a9863fSDag-Erling Smørgrav 	{ "rekeylimit", sRekeyLimit, SSHCFG_ALL },
645333ee039SDag-Erling Smørgrav 	{ "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
646333ee039SDag-Erling Smørgrav 	{ "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL },	/* obsolete alias */
647333ee039SDag-Erling Smørgrav 	{ "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
648d4af9e69SDag-Erling Smørgrav 	{ "allowagentforwarding", sAllowAgentForwarding, SSHCFG_ALL },
649462c32cbSDag-Erling Smørgrav 	{ "allowusers", sAllowUsers, SSHCFG_ALL },
650462c32cbSDag-Erling Smørgrav 	{ "denyusers", sDenyUsers, SSHCFG_ALL },
651462c32cbSDag-Erling Smørgrav 	{ "allowgroups", sAllowGroups, SSHCFG_ALL },
652462c32cbSDag-Erling Smørgrav 	{ "denygroups", sDenyGroups, SSHCFG_ALL },
653333ee039SDag-Erling Smørgrav 	{ "ciphers", sCiphers, SSHCFG_GLOBAL },
654333ee039SDag-Erling Smørgrav 	{ "macs", sMacs, SSHCFG_GLOBAL },
655ca86bcf2SDag-Erling Smørgrav 	{ "protocol", sIgnore, SSHCFG_GLOBAL },
656333ee039SDag-Erling Smørgrav 	{ "gatewayports", sGatewayPorts, SSHCFG_ALL },
657333ee039SDag-Erling Smørgrav 	{ "subsystem", sSubsystem, SSHCFG_GLOBAL },
658333ee039SDag-Erling Smørgrav 	{ "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
65919261079SEd Maste 	{ "persourcemaxstartups", sPerSourceMaxStartups, SSHCFG_GLOBAL },
66019261079SEd Maste 	{ "persourcenetblocksize", sPerSourceNetBlockSize, SSHCFG_GLOBAL },
661d4af9e69SDag-Erling Smørgrav 	{ "maxauthtries", sMaxAuthTries, SSHCFG_ALL },
662d4af9e69SDag-Erling Smørgrav 	{ "maxsessions", sMaxSessions, SSHCFG_ALL },
663d4af9e69SDag-Erling Smørgrav 	{ "banner", sBanner, SSHCFG_ALL },
664333ee039SDag-Erling Smørgrav 	{ "usedns", sUseDNS, SSHCFG_GLOBAL },
665333ee039SDag-Erling Smørgrav 	{ "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
666333ee039SDag-Erling Smørgrav 	{ "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL },
667ca86bcf2SDag-Erling Smørgrav 	{ "clientaliveinterval", sClientAliveInterval, SSHCFG_ALL },
668ca86bcf2SDag-Erling Smørgrav 	{ "clientalivecountmax", sClientAliveCountMax, SSHCFG_ALL },
669e2f6069cSDag-Erling Smørgrav 	{ "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_ALL },
670e146993eSDag-Erling Smørgrav 	{ "authorizedkeysfile2", sDeprecated, SSHCFG_ALL },
671d93a896eSDag-Erling Smørgrav 	{ "useprivilegeseparation", sDeprecated, SSHCFG_GLOBAL},
672462c32cbSDag-Erling Smørgrav 	{ "acceptenv", sAcceptEnv, SSHCFG_ALL },
673190cef3dSDag-Erling Smørgrav 	{ "setenv", sSetEnv, SSHCFG_ALL },
674e2f6069cSDag-Erling Smørgrav 	{ "permittunnel", sPermitTunnel, SSHCFG_ALL },
675f7167e0eSDag-Erling Smørgrav 	{ "permittty", sPermitTTY, SSHCFG_ALL },
676a0ee8cc6SDag-Erling Smørgrav 	{ "permituserrc", sPermitUserRC, SSHCFG_ALL },
677333ee039SDag-Erling Smørgrav 	{ "match", sMatch, SSHCFG_ALL },
678333ee039SDag-Erling Smørgrav 	{ "permitopen", sPermitOpen, SSHCFG_ALL },
679190cef3dSDag-Erling Smørgrav 	{ "permitlisten", sPermitListen, SSHCFG_ALL },
680333ee039SDag-Erling Smørgrav 	{ "forcecommand", sForceCommand, SSHCFG_ALL },
681d4af9e69SDag-Erling Smørgrav 	{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
682b15c8340SDag-Erling Smørgrav 	{ "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
683b15c8340SDag-Erling Smørgrav 	{ "revokedkeys", sRevokedKeys, SSHCFG_ALL },
684b15c8340SDag-Erling Smørgrav 	{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
685e2f6069cSDag-Erling Smørgrav 	{ "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
6864a421b63SDag-Erling Smørgrav 	{ "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
68719261079SEd Maste 	{ "include", sInclude, SSHCFG_ALL },
6884a421b63SDag-Erling Smørgrav 	{ "ipqos", sIPQoS, SSHCFG_ALL },
6896888a9beSDag-Erling Smørgrav 	{ "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
6906888a9beSDag-Erling Smørgrav 	{ "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
691557f75e5SDag-Erling Smørgrav 	{ "authorizedprincipalscommand", sAuthorizedPrincipalsCommand, SSHCFG_ALL },
692557f75e5SDag-Erling Smørgrav 	{ "authorizedprincipalscommanduser", sAuthorizedPrincipalsCommandUser, SSHCFG_ALL },
693462c32cbSDag-Erling Smørgrav 	{ "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL },
6946888a9beSDag-Erling Smørgrav 	{ "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL },
695a0ee8cc6SDag-Erling Smørgrav 	{ "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_ALL },
696a0ee8cc6SDag-Erling Smørgrav 	{ "streamlocalbindunlink", sStreamLocalBindUnlink, SSHCFG_ALL },
697a0ee8cc6SDag-Erling Smørgrav 	{ "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL },
698bc5531deSDag-Erling Smørgrav 	{ "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL },
699ca86bcf2SDag-Erling Smørgrav 	{ "disableforwarding", sDisableForwarding, SSHCFG_ALL },
7004f52dfbbSDag-Erling Smørgrav 	{ "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL },
70147dd1d1bSDag-Erling Smørgrav 	{ "rdomain", sRDomain, SSHCFG_ALL },
7022f513db7SEd Maste 	{ "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL },
70319261079SEd Maste 	{ "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL },
70438a52bd3SEd Maste 	{ "requiredrsasize", sRequiredRSASize, SSHCFG_ALL },
705f374ba41SEd Maste 	{ "channeltimeout", sChannelTimeout, SSHCFG_ALL },
706f374ba41SEd Maste 	{ "unusedconnectiontimeout", sUnusedConnectionTimeout, SSHCFG_ALL },
707b2af61ecSKurt Lidl 	{ "useblacklist", sUseBlacklist, SSHCFG_GLOBAL },
708e426c743SEd Maste 	{ "useblocklist", sUseBlacklist, SSHCFG_GLOBAL }, /* alias */
709a93cbba2SEd Maste 
710333ee039SDag-Erling Smørgrav 	{ NULL, sBadOption, 0 }
711511b41d2SMark Murray };
712511b41d2SMark Murray 
713d4af9e69SDag-Erling Smørgrav static struct {
714d4af9e69SDag-Erling Smørgrav 	int val;
715d4af9e69SDag-Erling Smørgrav 	char *text;
716d4af9e69SDag-Erling Smørgrav } tunmode_desc[] = {
717d4af9e69SDag-Erling Smørgrav 	{ SSH_TUNMODE_NO, "no" },
718d4af9e69SDag-Erling Smørgrav 	{ SSH_TUNMODE_POINTOPOINT, "point-to-point" },
719d4af9e69SDag-Erling Smørgrav 	{ SSH_TUNMODE_ETHERNET, "ethernet" },
720d4af9e69SDag-Erling Smørgrav 	{ SSH_TUNMODE_YES, "yes" },
721d4af9e69SDag-Erling Smørgrav 	{ -1, NULL }
722d4af9e69SDag-Erling Smørgrav };
723d4af9e69SDag-Erling Smørgrav 
724190cef3dSDag-Erling Smørgrav /* Returns an opcode name from its number */
725190cef3dSDag-Erling Smørgrav 
726190cef3dSDag-Erling Smørgrav static const char *
727190cef3dSDag-Erling Smørgrav lookup_opcode_name(ServerOpCodes code)
728190cef3dSDag-Erling Smørgrav {
729190cef3dSDag-Erling Smørgrav 	u_int i;
730190cef3dSDag-Erling Smørgrav 
731190cef3dSDag-Erling Smørgrav 	for (i = 0; keywords[i].name != NULL; i++)
732190cef3dSDag-Erling Smørgrav 		if (keywords[i].opcode == code)
733190cef3dSDag-Erling Smørgrav 			return(keywords[i].name);
734190cef3dSDag-Erling Smørgrav 	return "UNKNOWN";
735190cef3dSDag-Erling Smørgrav }
736190cef3dSDag-Erling Smørgrav 
737190cef3dSDag-Erling Smørgrav 
738511b41d2SMark Murray /*
739ca3176e7SBrian Feldman  * Returns the number of the token pointed to by cp or sBadOption.
740511b41d2SMark Murray  */
741511b41d2SMark Murray 
742511b41d2SMark Murray static ServerOpCodes
743511b41d2SMark Murray parse_token(const char *cp, const char *filename,
744333ee039SDag-Erling Smørgrav 	    int linenum, u_int *flags)
745511b41d2SMark Murray {
746ca3176e7SBrian Feldman 	u_int i;
747511b41d2SMark Murray 
748511b41d2SMark Murray 	for (i = 0; keywords[i].name; i++)
749333ee039SDag-Erling Smørgrav 		if (strcasecmp(cp, keywords[i].name) == 0) {
750333ee039SDag-Erling Smørgrav 			*flags = keywords[i].flags;
751511b41d2SMark Murray 			return keywords[i].opcode;
752333ee039SDag-Erling Smørgrav 		}
753511b41d2SMark Murray 
754ca3176e7SBrian Feldman 	error("%s: line %d: Bad configuration option: %s",
755511b41d2SMark Murray 	    filename, linenum, cp);
756511b41d2SMark Murray 	return sBadOption;
757511b41d2SMark Murray }
758511b41d2SMark Murray 
759b15c8340SDag-Erling Smørgrav char *
760b15c8340SDag-Erling Smørgrav derelativise_path(const char *path)
761b15c8340SDag-Erling Smørgrav {
762bc5531deSDag-Erling Smørgrav 	char *expanded, *ret, cwd[PATH_MAX];
763b15c8340SDag-Erling Smørgrav 
764bc5531deSDag-Erling Smørgrav 	if (strcasecmp(path, "none") == 0)
765bc5531deSDag-Erling Smørgrav 		return xstrdup("none");
766b15c8340SDag-Erling Smørgrav 	expanded = tilde_expand_filename(path, getuid());
76719261079SEd Maste 	if (path_absolute(expanded))
768b15c8340SDag-Erling Smørgrav 		return expanded;
7698ad9b54aSDag-Erling Smørgrav 	if (getcwd(cwd, sizeof(cwd)) == NULL)
77019261079SEd Maste 		fatal_f("getcwd: %s", strerror(errno));
771b15c8340SDag-Erling Smørgrav 	xasprintf(&ret, "%s/%s", cwd, expanded);
772e4a9863fSDag-Erling Smørgrav 	free(expanded);
773b15c8340SDag-Erling Smørgrav 	return ret;
774b15c8340SDag-Erling Smørgrav }
775b15c8340SDag-Erling Smørgrav 
776af12a3e7SDag-Erling Smørgrav static void
77747dd1d1bSDag-Erling Smørgrav add_listen_addr(ServerOptions *options, const char *addr,
77847dd1d1bSDag-Erling Smørgrav     const char *rdomain, int port)
779511b41d2SMark Murray {
780d4ecd108SDag-Erling Smørgrav 	u_int i;
781511b41d2SMark Murray 
78247dd1d1bSDag-Erling Smørgrav 	if (port > 0)
78347dd1d1bSDag-Erling Smørgrav 		add_one_listen_addr(options, addr, rdomain, port);
78447dd1d1bSDag-Erling Smørgrav 	else {
78547dd1d1bSDag-Erling Smørgrav 		for (i = 0; i < options->num_ports; i++) {
78647dd1d1bSDag-Erling Smørgrav 			add_one_listen_addr(options, addr, rdomain,
78747dd1d1bSDag-Erling Smørgrav 			    options->ports[i]);
78847dd1d1bSDag-Erling Smørgrav 		}
78947dd1d1bSDag-Erling Smørgrav 	}
790ca3176e7SBrian Feldman }
791ca3176e7SBrian Feldman 
792af12a3e7SDag-Erling Smørgrav static void
79347dd1d1bSDag-Erling Smørgrav add_one_listen_addr(ServerOptions *options, const char *addr,
79447dd1d1bSDag-Erling Smørgrav     const char *rdomain, int port)
795ca3176e7SBrian Feldman {
796ca3176e7SBrian Feldman 	struct addrinfo hints, *ai, *aitop;
797ca3176e7SBrian Feldman 	char strport[NI_MAXSERV];
798ca3176e7SBrian Feldman 	int gaierr;
79947dd1d1bSDag-Erling Smørgrav 	u_int i;
80047dd1d1bSDag-Erling Smørgrav 
80147dd1d1bSDag-Erling Smørgrav 	/* Find listen_addrs entry for this rdomain */
80247dd1d1bSDag-Erling Smørgrav 	for (i = 0; i < options->num_listen_addrs; i++) {
80347dd1d1bSDag-Erling Smørgrav 		if (rdomain == NULL && options->listen_addrs[i].rdomain == NULL)
80447dd1d1bSDag-Erling Smørgrav 			break;
80547dd1d1bSDag-Erling Smørgrav 		if (rdomain == NULL || options->listen_addrs[i].rdomain == NULL)
80647dd1d1bSDag-Erling Smørgrav 			continue;
80747dd1d1bSDag-Erling Smørgrav 		if (strcmp(rdomain, options->listen_addrs[i].rdomain) == 0)
80847dd1d1bSDag-Erling Smørgrav 			break;
80947dd1d1bSDag-Erling Smørgrav 	}
81047dd1d1bSDag-Erling Smørgrav 	if (i >= options->num_listen_addrs) {
81147dd1d1bSDag-Erling Smørgrav 		/* No entry for this rdomain; allocate one */
81247dd1d1bSDag-Erling Smørgrav 		if (i >= INT_MAX)
81319261079SEd Maste 			fatal_f("too many listen addresses");
81447dd1d1bSDag-Erling Smørgrav 		options->listen_addrs = xrecallocarray(options->listen_addrs,
81547dd1d1bSDag-Erling Smørgrav 		    options->num_listen_addrs, options->num_listen_addrs + 1,
81647dd1d1bSDag-Erling Smørgrav 		    sizeof(*options->listen_addrs));
81747dd1d1bSDag-Erling Smørgrav 		i = options->num_listen_addrs++;
81847dd1d1bSDag-Erling Smørgrav 		if (rdomain != NULL)
81947dd1d1bSDag-Erling Smørgrav 			options->listen_addrs[i].rdomain = xstrdup(rdomain);
82047dd1d1bSDag-Erling Smørgrav 	}
82147dd1d1bSDag-Erling Smørgrav 	/* options->listen_addrs[i] points to the addresses for this rdomain */
822ca3176e7SBrian Feldman 
823511b41d2SMark Murray 	memset(&hints, 0, sizeof(hints));
824aa49c926SDag-Erling Smørgrav 	hints.ai_family = options->address_family;
825511b41d2SMark Murray 	hints.ai_socktype = SOCK_STREAM;
826511b41d2SMark Murray 	hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
827cce7d346SDag-Erling Smørgrav 	snprintf(strport, sizeof strport, "%d", port);
828511b41d2SMark Murray 	if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
829ca3176e7SBrian Feldman 		fatal("bad addr or host: %s (%s)",
830511b41d2SMark Murray 		    addr ? addr : "<NULL>",
831d4af9e69SDag-Erling Smørgrav 		    ssh_gai_strerror(gaierr));
832511b41d2SMark Murray 	for (ai = aitop; ai->ai_next; ai = ai->ai_next)
833511b41d2SMark Murray 		;
83447dd1d1bSDag-Erling Smørgrav 	ai->ai_next = options->listen_addrs[i].addrs;
83547dd1d1bSDag-Erling Smørgrav 	options->listen_addrs[i].addrs = aitop;
83647dd1d1bSDag-Erling Smørgrav }
83747dd1d1bSDag-Erling Smørgrav 
83847dd1d1bSDag-Erling Smørgrav /* Returns nonzero if the routing domain name is valid */
83947dd1d1bSDag-Erling Smørgrav static int
84047dd1d1bSDag-Erling Smørgrav valid_rdomain(const char *name)
84147dd1d1bSDag-Erling Smørgrav {
84247dd1d1bSDag-Erling Smørgrav #if defined(HAVE_SYS_VALID_RDOMAIN)
84347dd1d1bSDag-Erling Smørgrav 	return sys_valid_rdomain(name);
84447dd1d1bSDag-Erling Smørgrav #elif defined(__OpenBSD__)
84547dd1d1bSDag-Erling Smørgrav 	const char *errstr;
84647dd1d1bSDag-Erling Smørgrav 	long long num;
84747dd1d1bSDag-Erling Smørgrav 	struct rt_tableinfo info;
84847dd1d1bSDag-Erling Smørgrav 	int mib[6];
84947dd1d1bSDag-Erling Smørgrav 	size_t miblen = sizeof(mib);
85047dd1d1bSDag-Erling Smørgrav 
85147dd1d1bSDag-Erling Smørgrav 	if (name == NULL)
85247dd1d1bSDag-Erling Smørgrav 		return 1;
85347dd1d1bSDag-Erling Smørgrav 
85447dd1d1bSDag-Erling Smørgrav 	num = strtonum(name, 0, 255, &errstr);
85547dd1d1bSDag-Erling Smørgrav 	if (errstr != NULL)
85647dd1d1bSDag-Erling Smørgrav 		return 0;
85747dd1d1bSDag-Erling Smørgrav 
85847dd1d1bSDag-Erling Smørgrav 	/* Check whether the table actually exists */
85947dd1d1bSDag-Erling Smørgrav 	memset(mib, 0, sizeof(mib));
86047dd1d1bSDag-Erling Smørgrav 	mib[0] = CTL_NET;
86147dd1d1bSDag-Erling Smørgrav 	mib[1] = PF_ROUTE;
86247dd1d1bSDag-Erling Smørgrav 	mib[4] = NET_RT_TABLE;
86347dd1d1bSDag-Erling Smørgrav 	mib[5] = (int)num;
86447dd1d1bSDag-Erling Smørgrav 	if (sysctl(mib, 6, &info, &miblen, NULL, 0) == -1)
86547dd1d1bSDag-Erling Smørgrav 		return 0;
86647dd1d1bSDag-Erling Smørgrav 
86747dd1d1bSDag-Erling Smørgrav 	return 1;
86847dd1d1bSDag-Erling Smørgrav #else /* defined(__OpenBSD__) */
86947dd1d1bSDag-Erling Smørgrav 	error("Routing domains are not supported on this platform");
87047dd1d1bSDag-Erling Smørgrav 	return 0;
87147dd1d1bSDag-Erling Smørgrav #endif
872511b41d2SMark Murray }
873511b41d2SMark Murray 
874557f75e5SDag-Erling Smørgrav /*
875557f75e5SDag-Erling Smørgrav  * Queue a ListenAddress to be processed once we have all of the Ports
876557f75e5SDag-Erling Smørgrav  * and AddressFamily options.
877557f75e5SDag-Erling Smørgrav  */
878557f75e5SDag-Erling Smørgrav static void
87947dd1d1bSDag-Erling Smørgrav queue_listen_addr(ServerOptions *options, const char *addr,
88047dd1d1bSDag-Erling Smørgrav     const char *rdomain, int port)
881557f75e5SDag-Erling Smørgrav {
88247dd1d1bSDag-Erling Smørgrav 	struct queued_listenaddr *qla;
88347dd1d1bSDag-Erling Smørgrav 
88447dd1d1bSDag-Erling Smørgrav 	options->queued_listen_addrs = xrecallocarray(
88547dd1d1bSDag-Erling Smørgrav 	    options->queued_listen_addrs,
88647dd1d1bSDag-Erling Smørgrav 	    options->num_queued_listens, options->num_queued_listens + 1,
88747dd1d1bSDag-Erling Smørgrav 	    sizeof(*options->queued_listen_addrs));
88847dd1d1bSDag-Erling Smørgrav 	qla = &options->queued_listen_addrs[options->num_queued_listens++];
88947dd1d1bSDag-Erling Smørgrav 	qla->addr = xstrdup(addr);
89047dd1d1bSDag-Erling Smørgrav 	qla->port = port;
89147dd1d1bSDag-Erling Smørgrav 	qla->rdomain = rdomain == NULL ? NULL : xstrdup(rdomain);
892557f75e5SDag-Erling Smørgrav }
893557f75e5SDag-Erling Smørgrav 
894557f75e5SDag-Erling Smørgrav /*
895557f75e5SDag-Erling Smørgrav  * Process queued (text) ListenAddress entries.
896557f75e5SDag-Erling Smørgrav  */
897557f75e5SDag-Erling Smørgrav static void
898557f75e5SDag-Erling Smørgrav process_queued_listen_addrs(ServerOptions *options)
899557f75e5SDag-Erling Smørgrav {
900557f75e5SDag-Erling Smørgrav 	u_int i;
90147dd1d1bSDag-Erling Smørgrav 	struct queued_listenaddr *qla;
902557f75e5SDag-Erling Smørgrav 
903557f75e5SDag-Erling Smørgrav 	if (options->num_ports == 0)
904557f75e5SDag-Erling Smørgrav 		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
905557f75e5SDag-Erling Smørgrav 	if (options->address_family == -1)
906557f75e5SDag-Erling Smørgrav 		options->address_family = AF_UNSPEC;
907557f75e5SDag-Erling Smørgrav 
908557f75e5SDag-Erling Smørgrav 	for (i = 0; i < options->num_queued_listens; i++) {
90947dd1d1bSDag-Erling Smørgrav 		qla = &options->queued_listen_addrs[i];
91047dd1d1bSDag-Erling Smørgrav 		add_listen_addr(options, qla->addr, qla->rdomain, qla->port);
91147dd1d1bSDag-Erling Smørgrav 		free(qla->addr);
91247dd1d1bSDag-Erling Smørgrav 		free(qla->rdomain);
913557f75e5SDag-Erling Smørgrav 	}
914557f75e5SDag-Erling Smørgrav 	free(options->queued_listen_addrs);
915557f75e5SDag-Erling Smørgrav 	options->queued_listen_addrs = NULL;
916557f75e5SDag-Erling Smørgrav 	options->num_queued_listens = 0;
917557f75e5SDag-Erling Smørgrav }
918557f75e5SDag-Erling Smørgrav 
9194f52dfbbSDag-Erling Smørgrav /*
920190cef3dSDag-Erling Smørgrav  * Inform channels layer of permitopen options for a single forwarding
921190cef3dSDag-Erling Smørgrav  * direction (local/remote).
922190cef3dSDag-Erling Smørgrav  */
923190cef3dSDag-Erling Smørgrav static void
924190cef3dSDag-Erling Smørgrav process_permitopen_list(struct ssh *ssh, ServerOpCodes opcode,
925190cef3dSDag-Erling Smørgrav     char **opens, u_int num_opens)
926190cef3dSDag-Erling Smørgrav {
927190cef3dSDag-Erling Smørgrav 	u_int i;
928190cef3dSDag-Erling Smørgrav 	int port;
9291323ec57SEd Maste 	char *host, *arg, *oarg;
930190cef3dSDag-Erling Smørgrav 	int where = opcode == sPermitOpen ? FORWARD_LOCAL : FORWARD_REMOTE;
931190cef3dSDag-Erling Smørgrav 	const char *what = lookup_opcode_name(opcode);
932190cef3dSDag-Erling Smørgrav 
933190cef3dSDag-Erling Smørgrav 	channel_clear_permission(ssh, FORWARD_ADM, where);
934190cef3dSDag-Erling Smørgrav 	if (num_opens == 0)
935190cef3dSDag-Erling Smørgrav 		return; /* permit any */
936190cef3dSDag-Erling Smørgrav 
937190cef3dSDag-Erling Smørgrav 	/* handle keywords: "any" / "none" */
938190cef3dSDag-Erling Smørgrav 	if (num_opens == 1 && strcmp(opens[0], "any") == 0)
939190cef3dSDag-Erling Smørgrav 		return;
940190cef3dSDag-Erling Smørgrav 	if (num_opens == 1 && strcmp(opens[0], "none") == 0) {
941190cef3dSDag-Erling Smørgrav 		channel_disable_admin(ssh, where);
942190cef3dSDag-Erling Smørgrav 		return;
943190cef3dSDag-Erling Smørgrav 	}
944190cef3dSDag-Erling Smørgrav 	/* Otherwise treat it as a list of permitted host:port */
945190cef3dSDag-Erling Smørgrav 	for (i = 0; i < num_opens; i++) {
946190cef3dSDag-Erling Smørgrav 		oarg = arg = xstrdup(opens[i]);
9471323ec57SEd Maste 		host = hpdelim(&arg);
9481323ec57SEd Maste 		if (host == NULL)
94919261079SEd Maste 			fatal_f("missing host in %s", what);
950190cef3dSDag-Erling Smørgrav 		host = cleanhostname(host);
951190cef3dSDag-Erling Smørgrav 		if (arg == NULL || ((port = permitopen_port(arg)) < 0))
95219261079SEd Maste 			fatal_f("bad port number in %s", what);
953190cef3dSDag-Erling Smørgrav 		/* Send it to channels layer */
954190cef3dSDag-Erling Smørgrav 		channel_add_permission(ssh, FORWARD_ADM,
955190cef3dSDag-Erling Smørgrav 		    where, host, port);
956190cef3dSDag-Erling Smørgrav 		free(oarg);
957190cef3dSDag-Erling Smørgrav 	}
958190cef3dSDag-Erling Smørgrav }
959190cef3dSDag-Erling Smørgrav 
960190cef3dSDag-Erling Smørgrav /*
9614f52dfbbSDag-Erling Smørgrav  * Inform channels layer of permitopen options from configuration.
9624f52dfbbSDag-Erling Smørgrav  */
9634f52dfbbSDag-Erling Smørgrav void
9644f52dfbbSDag-Erling Smørgrav process_permitopen(struct ssh *ssh, ServerOptions *options)
9654f52dfbbSDag-Erling Smørgrav {
966190cef3dSDag-Erling Smørgrav 	process_permitopen_list(ssh, sPermitOpen,
967190cef3dSDag-Erling Smørgrav 	    options->permitted_opens, options->num_permitted_opens);
968190cef3dSDag-Erling Smørgrav 	process_permitopen_list(ssh, sPermitListen,
969190cef3dSDag-Erling Smørgrav 	    options->permitted_listens,
970190cef3dSDag-Erling Smørgrav 	    options->num_permitted_listens);
9714f52dfbbSDag-Erling Smørgrav }
9724f52dfbbSDag-Erling Smørgrav 
973f374ba41SEd Maste /* Parse a ChannelTimeout clause "pattern=interval" */
974f374ba41SEd Maste static int
975*535af610SEd Maste parse_timeout(const char *s, char **typep, int *secsp)
976f374ba41SEd Maste {
977f374ba41SEd Maste 	char *cp, *sdup;
978f374ba41SEd Maste 	int secs;
979f374ba41SEd Maste 
980f374ba41SEd Maste 	if (typep != NULL)
981f374ba41SEd Maste 		*typep = NULL;
982f374ba41SEd Maste 	if (secsp != NULL)
983f374ba41SEd Maste 		*secsp = 0;
984f374ba41SEd Maste 	if (s == NULL)
985f374ba41SEd Maste 		return -1;
986f374ba41SEd Maste 	sdup = xstrdup(s);
987f374ba41SEd Maste 
988f374ba41SEd Maste 	if ((cp = strchr(sdup, '=')) == NULL || cp == sdup) {
989f374ba41SEd Maste 		free(sdup);
990f374ba41SEd Maste 		return -1;
991f374ba41SEd Maste 	}
992f374ba41SEd Maste 	*cp++ = '\0';
993f374ba41SEd Maste 	if ((secs = convtime(cp)) < 0) {
994f374ba41SEd Maste 		free(sdup);
995f374ba41SEd Maste 		return -1;
996f374ba41SEd Maste 	}
997f374ba41SEd Maste 	/* success */
998f374ba41SEd Maste 	if (typep != NULL)
999f374ba41SEd Maste 		*typep = xstrdup(sdup);
1000f374ba41SEd Maste 	if (secsp != NULL)
1001*535af610SEd Maste 		*secsp = secs;
1002f374ba41SEd Maste 	free(sdup);
1003f374ba41SEd Maste 	return 0;
1004f374ba41SEd Maste }
1005f374ba41SEd Maste 
1006f374ba41SEd Maste void
1007f374ba41SEd Maste process_channel_timeouts(struct ssh *ssh, ServerOptions *options)
1008f374ba41SEd Maste {
1009*535af610SEd Maste 	int secs;
1010*535af610SEd Maste 	u_int i;
1011f374ba41SEd Maste 	char *type;
1012f374ba41SEd Maste 
1013f374ba41SEd Maste 	debug3_f("setting %u timeouts", options->num_channel_timeouts);
1014f374ba41SEd Maste 	channel_clear_timeouts(ssh);
1015f374ba41SEd Maste 	for (i = 0; i < options->num_channel_timeouts; i++) {
1016f374ba41SEd Maste 		if (parse_timeout(options->channel_timeouts[i],
1017f374ba41SEd Maste 		    &type, &secs) != 0) {
1018f374ba41SEd Maste 			fatal_f("internal error: bad timeout %s",
1019f374ba41SEd Maste 			    options->channel_timeouts[i]);
1020f374ba41SEd Maste 		}
1021f374ba41SEd Maste 		channel_add_timeout(ssh, type, secs);
1022f374ba41SEd Maste 		free(type);
1023f374ba41SEd Maste 	}
1024f374ba41SEd Maste }
1025f374ba41SEd Maste 
1026462c32cbSDag-Erling Smørgrav struct connection_info *
102719261079SEd Maste get_connection_info(struct ssh *ssh, int populate, int use_dns)
1028462c32cbSDag-Erling Smørgrav {
1029462c32cbSDag-Erling Smørgrav 	static struct connection_info ci;
1030462c32cbSDag-Erling Smørgrav 
103119261079SEd Maste 	if (ssh == NULL || !populate)
1032462c32cbSDag-Erling Smørgrav 		return &ci;
1033076ad2f8SDag-Erling Smørgrav 	ci.host = auth_get_canonical_hostname(ssh, use_dns);
1034076ad2f8SDag-Erling Smørgrav 	ci.address = ssh_remote_ipaddr(ssh);
1035076ad2f8SDag-Erling Smørgrav 	ci.laddress = ssh_local_ipaddr(ssh);
1036076ad2f8SDag-Erling Smørgrav 	ci.lport = ssh_local_port(ssh);
103747dd1d1bSDag-Erling Smørgrav 	ci.rdomain = ssh_packet_rdomain_in(ssh);
1038462c32cbSDag-Erling Smørgrav 	return &ci;
1039462c32cbSDag-Erling Smørgrav }
1040462c32cbSDag-Erling Smørgrav 
1041333ee039SDag-Erling Smørgrav /*
1042333ee039SDag-Erling Smørgrav  * The strategy for the Match blocks is that the config file is parsed twice.
1043333ee039SDag-Erling Smørgrav  *
1044333ee039SDag-Erling Smørgrav  * The first time is at startup.  activep is initialized to 1 and the
1045333ee039SDag-Erling Smørgrav  * directives in the global context are processed and acted on.  Hitting a
1046333ee039SDag-Erling Smørgrav  * Match directive unsets activep and the directives inside the block are
1047333ee039SDag-Erling Smørgrav  * checked for syntax only.
1048333ee039SDag-Erling Smørgrav  *
1049333ee039SDag-Erling Smørgrav  * The second time is after a connection has been established but before
1050333ee039SDag-Erling Smørgrav  * authentication.  activep is initialized to 2 and global config directives
1051333ee039SDag-Erling Smørgrav  * are ignored since they have already been processed.  If the criteria in a
1052333ee039SDag-Erling Smørgrav  * Match block is met, activep is set and the subsequent directives
1053333ee039SDag-Erling Smørgrav  * processed and actioned until EOF or another Match block unsets it.  Any
1054333ee039SDag-Erling Smørgrav  * options set are copied into the main server config.
1055333ee039SDag-Erling Smørgrav  *
1056333ee039SDag-Erling Smørgrav  * Potential additions/improvements:
1057ca86bcf2SDag-Erling Smørgrav  *  - Add Match support for pre-kex directives, eg. Ciphers.
1058333ee039SDag-Erling Smørgrav  *
1059333ee039SDag-Erling Smørgrav  *  - Add a Tag directive (idea from David Leonard) ala pf, eg:
1060333ee039SDag-Erling Smørgrav  *	Match Address 192.168.0.*
1061333ee039SDag-Erling Smørgrav  *		Tag trusted
1062333ee039SDag-Erling Smørgrav  *	Match Group wheel
1063333ee039SDag-Erling Smørgrav  *		Tag trusted
1064333ee039SDag-Erling Smørgrav  *	Match Tag trusted
1065333ee039SDag-Erling Smørgrav  *		AllowTcpForwarding yes
1066333ee039SDag-Erling Smørgrav  *		GatewayPorts clientspecified
1067333ee039SDag-Erling Smørgrav  *		[...]
1068333ee039SDag-Erling Smørgrav  *
1069333ee039SDag-Erling Smørgrav  *  - Add a PermittedChannelRequests directive
1070333ee039SDag-Erling Smørgrav  *	Match Group shell
1071333ee039SDag-Erling Smørgrav  *		PermittedChannelRequests session,forwarded-tcpip
1072333ee039SDag-Erling Smørgrav  */
1073333ee039SDag-Erling Smørgrav 
1074333ee039SDag-Erling Smørgrav static int
1075333ee039SDag-Erling Smørgrav match_cfg_line_group(const char *grps, int line, const char *user)
1076333ee039SDag-Erling Smørgrav {
1077333ee039SDag-Erling Smørgrav 	int result = 0;
1078333ee039SDag-Erling Smørgrav 	struct passwd *pw;
1079333ee039SDag-Erling Smørgrav 
1080333ee039SDag-Erling Smørgrav 	if (user == NULL)
1081333ee039SDag-Erling Smørgrav 		goto out;
1082333ee039SDag-Erling Smørgrav 
1083333ee039SDag-Erling Smørgrav 	if ((pw = getpwnam(user)) == NULL) {
1084333ee039SDag-Erling Smørgrav 		debug("Can't match group at line %d because user %.100s does "
1085333ee039SDag-Erling Smørgrav 		    "not exist", line, user);
1086333ee039SDag-Erling Smørgrav 	} else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
1087333ee039SDag-Erling Smørgrav 		debug("Can't Match group because user %.100s not in any group "
1088333ee039SDag-Erling Smørgrav 		    "at line %d", user, line);
1089d4af9e69SDag-Erling Smørgrav 	} else if (ga_match_pattern_list(grps) != 1) {
1090d4af9e69SDag-Erling Smørgrav 		debug("user %.100s does not match group list %.100s at line %d",
1091d4af9e69SDag-Erling Smørgrav 		    user, grps, line);
1092333ee039SDag-Erling Smørgrav 	} else {
1093d4af9e69SDag-Erling Smørgrav 		debug("user %.100s matched group list %.100s at line %d", user,
1094d4af9e69SDag-Erling Smørgrav 		    grps, line);
1095333ee039SDag-Erling Smørgrav 		result = 1;
1096333ee039SDag-Erling Smørgrav 	}
1097333ee039SDag-Erling Smørgrav out:
1098333ee039SDag-Erling Smørgrav 	ga_free();
1099333ee039SDag-Erling Smørgrav 	return result;
1100333ee039SDag-Erling Smørgrav }
1101333ee039SDag-Erling Smørgrav 
110247dd1d1bSDag-Erling Smørgrav static void
110347dd1d1bSDag-Erling Smørgrav match_test_missing_fatal(const char *criteria, const char *attrib)
110447dd1d1bSDag-Erling Smørgrav {
110547dd1d1bSDag-Erling Smørgrav 	fatal("'Match %s' in configuration but '%s' not in connection "
110647dd1d1bSDag-Erling Smørgrav 	    "test specification.", criteria, attrib);
110747dd1d1bSDag-Erling Smørgrav }
110847dd1d1bSDag-Erling Smørgrav 
1109462c32cbSDag-Erling Smørgrav /*
11106888a9beSDag-Erling Smørgrav  * All of the attributes on a single Match line are ANDed together, so we need
1111f7167e0eSDag-Erling Smørgrav  * to check every attribute and set the result to zero if any attribute does
11126888a9beSDag-Erling Smørgrav  * not match.
1113462c32cbSDag-Erling Smørgrav  */
1114333ee039SDag-Erling Smørgrav static int
1115462c32cbSDag-Erling Smørgrav match_cfg_line(char **condition, int line, struct connection_info *ci)
1116333ee039SDag-Erling Smørgrav {
1117f7167e0eSDag-Erling Smørgrav 	int result = 1, attributes = 0, port;
1118333ee039SDag-Erling Smørgrav 	char *arg, *attrib, *cp = *condition;
1119333ee039SDag-Erling Smørgrav 
1120462c32cbSDag-Erling Smørgrav 	if (ci == NULL)
1121333ee039SDag-Erling Smørgrav 		debug3("checking syntax for 'Match %s'", cp);
1122333ee039SDag-Erling Smørgrav 	else
1123462c32cbSDag-Erling Smørgrav 		debug3("checking match for '%s' user %s host %s addr %s "
1124462c32cbSDag-Erling Smørgrav 		    "laddr %s lport %d", cp, ci->user ? ci->user : "(null)",
1125462c32cbSDag-Erling Smørgrav 		    ci->host ? ci->host : "(null)",
1126462c32cbSDag-Erling Smørgrav 		    ci->address ? ci->address : "(null)",
1127462c32cbSDag-Erling Smørgrav 		    ci->laddress ? ci->laddress : "(null)", ci->lport);
1128333ee039SDag-Erling Smørgrav 
1129333ee039SDag-Erling Smørgrav 	while ((attrib = strdelim(&cp)) && *attrib != '\0') {
113019261079SEd Maste 		/* Terminate on comment */
113119261079SEd Maste 		if (*attrib == '#') {
113219261079SEd Maste 			cp = NULL; /* mark all arguments consumed */
113319261079SEd Maste 			break;
113419261079SEd Maste 		}
113519261079SEd Maste 		arg = NULL;
1136f7167e0eSDag-Erling Smørgrav 		attributes++;
113719261079SEd Maste 		/* Criterion "all" has no argument and must appear alone */
1138f7167e0eSDag-Erling Smørgrav 		if (strcasecmp(attrib, "all") == 0) {
113919261079SEd Maste 			if (attributes > 1 || ((arg = strdelim(&cp)) != NULL &&
114019261079SEd Maste 			    *arg != '\0' && *arg != '#')) {
1141f7167e0eSDag-Erling Smørgrav 				error("'all' cannot be combined with other "
1142f7167e0eSDag-Erling Smørgrav 				    "Match attributes");
1143f7167e0eSDag-Erling Smørgrav 				return -1;
1144f7167e0eSDag-Erling Smørgrav 			}
114519261079SEd Maste 			if (arg != NULL && *arg == '#')
114619261079SEd Maste 				cp = NULL; /* mark all arguments consumed */
1147f7167e0eSDag-Erling Smørgrav 			*condition = cp;
1148f7167e0eSDag-Erling Smørgrav 			return 1;
1149f7167e0eSDag-Erling Smørgrav 		}
115019261079SEd Maste 		/* All other criteria require an argument */
115119261079SEd Maste 		if ((arg = strdelim(&cp)) == NULL ||
115219261079SEd Maste 		    *arg == '\0' || *arg == '#') {
1153333ee039SDag-Erling Smørgrav 			error("Missing Match criteria for %s", attrib);
1154333ee039SDag-Erling Smørgrav 			return -1;
1155333ee039SDag-Erling Smørgrav 		}
1156333ee039SDag-Erling Smørgrav 		if (strcasecmp(attrib, "user") == 0) {
115719261079SEd Maste 			if (ci == NULL || (ci->test && ci->user == NULL)) {
1158333ee039SDag-Erling Smørgrav 				result = 0;
1159333ee039SDag-Erling Smørgrav 				continue;
1160333ee039SDag-Erling Smørgrav 			}
116147dd1d1bSDag-Erling Smørgrav 			if (ci->user == NULL)
116247dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("User", "user");
116319261079SEd Maste 			if (match_usergroup_pattern_list(ci->user, arg) != 1)
1164333ee039SDag-Erling Smørgrav 				result = 0;
1165333ee039SDag-Erling Smørgrav 			else
1166333ee039SDag-Erling Smørgrav 				debug("user %.100s matched 'User %.100s' at "
1167462c32cbSDag-Erling Smørgrav 				    "line %d", ci->user, arg, line);
1168333ee039SDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "group") == 0) {
116919261079SEd Maste 			if (ci == NULL || (ci->test && ci->user == NULL)) {
1170462c32cbSDag-Erling Smørgrav 				result = 0;
1171462c32cbSDag-Erling Smørgrav 				continue;
1172462c32cbSDag-Erling Smørgrav 			}
117347dd1d1bSDag-Erling Smørgrav 			if (ci->user == NULL)
117447dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("Group", "user");
1175462c32cbSDag-Erling Smørgrav 			switch (match_cfg_line_group(arg, line, ci->user)) {
1176333ee039SDag-Erling Smørgrav 			case -1:
1177333ee039SDag-Erling Smørgrav 				return -1;
1178333ee039SDag-Erling Smørgrav 			case 0:
1179333ee039SDag-Erling Smørgrav 				result = 0;
1180333ee039SDag-Erling Smørgrav 			}
1181333ee039SDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "host") == 0) {
118219261079SEd Maste 			if (ci == NULL || (ci->test && ci->host == NULL)) {
1183333ee039SDag-Erling Smørgrav 				result = 0;
1184333ee039SDag-Erling Smørgrav 				continue;
1185333ee039SDag-Erling Smørgrav 			}
118647dd1d1bSDag-Erling Smørgrav 			if (ci->host == NULL)
118747dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("Host", "host");
1188557f75e5SDag-Erling Smørgrav 			if (match_hostname(ci->host, arg) != 1)
1189333ee039SDag-Erling Smørgrav 				result = 0;
1190333ee039SDag-Erling Smørgrav 			else
1191333ee039SDag-Erling Smørgrav 				debug("connection from %.100s matched 'Host "
1192462c32cbSDag-Erling Smørgrav 				    "%.100s' at line %d", ci->host, arg, line);
1193333ee039SDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "address") == 0) {
119419261079SEd Maste 			if (ci == NULL || (ci->test && ci->address == NULL)) {
119519261079SEd Maste 				if (addr_match_list(NULL, arg) != 0)
119619261079SEd Maste 					fatal("Invalid Match address argument "
119719261079SEd Maste 					    "'%s' at line %d", arg, line);
1198462c32cbSDag-Erling Smørgrav 				result = 0;
1199462c32cbSDag-Erling Smørgrav 				continue;
1200462c32cbSDag-Erling Smørgrav 			}
120147dd1d1bSDag-Erling Smørgrav 			if (ci->address == NULL)
120247dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("Address", "addr");
1203462c32cbSDag-Erling Smørgrav 			switch (addr_match_list(ci->address, arg)) {
1204d4af9e69SDag-Erling Smørgrav 			case 1:
1205333ee039SDag-Erling Smørgrav 				debug("connection from %.100s matched 'Address "
1206462c32cbSDag-Erling Smørgrav 				    "%.100s' at line %d", ci->address, arg, line);
1207d4af9e69SDag-Erling Smørgrav 				break;
1208d4af9e69SDag-Erling Smørgrav 			case 0:
1209d4af9e69SDag-Erling Smørgrav 			case -1:
1210d4af9e69SDag-Erling Smørgrav 				result = 0;
1211d4af9e69SDag-Erling Smørgrav 				break;
1212d4af9e69SDag-Erling Smørgrav 			case -2:
1213d4af9e69SDag-Erling Smørgrav 				return -1;
1214d4af9e69SDag-Erling Smørgrav 			}
1215462c32cbSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "localaddress") == 0){
121619261079SEd Maste 			if (ci == NULL || (ci->test && ci->laddress == NULL)) {
121719261079SEd Maste 				if (addr_match_list(NULL, arg) != 0)
121819261079SEd Maste 					fatal("Invalid Match localaddress "
121919261079SEd Maste 					    "argument '%s' at line %d", arg,
122019261079SEd Maste 					    line);
1221462c32cbSDag-Erling Smørgrav 				result = 0;
1222462c32cbSDag-Erling Smørgrav 				continue;
1223462c32cbSDag-Erling Smørgrav 			}
122447dd1d1bSDag-Erling Smørgrav 			if (ci->laddress == NULL)
122547dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("LocalAddress",
122647dd1d1bSDag-Erling Smørgrav 				    "laddr");
1227462c32cbSDag-Erling Smørgrav 			switch (addr_match_list(ci->laddress, arg)) {
1228462c32cbSDag-Erling Smørgrav 			case 1:
1229462c32cbSDag-Erling Smørgrav 				debug("connection from %.100s matched "
1230462c32cbSDag-Erling Smørgrav 				    "'LocalAddress %.100s' at line %d",
1231462c32cbSDag-Erling Smørgrav 				    ci->laddress, arg, line);
1232462c32cbSDag-Erling Smørgrav 				break;
1233462c32cbSDag-Erling Smørgrav 			case 0:
1234462c32cbSDag-Erling Smørgrav 			case -1:
1235462c32cbSDag-Erling Smørgrav 				result = 0;
1236462c32cbSDag-Erling Smørgrav 				break;
1237462c32cbSDag-Erling Smørgrav 			case -2:
1238462c32cbSDag-Erling Smørgrav 				return -1;
1239462c32cbSDag-Erling Smørgrav 			}
1240462c32cbSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "localport") == 0) {
1241462c32cbSDag-Erling Smørgrav 			if ((port = a2port(arg)) == -1) {
1242462c32cbSDag-Erling Smørgrav 				error("Invalid LocalPort '%s' on Match line",
1243462c32cbSDag-Erling Smørgrav 				    arg);
1244462c32cbSDag-Erling Smørgrav 				return -1;
1245462c32cbSDag-Erling Smørgrav 			}
124619261079SEd Maste 			if (ci == NULL || (ci->test && ci->lport == -1)) {
1247462c32cbSDag-Erling Smørgrav 				result = 0;
1248462c32cbSDag-Erling Smørgrav 				continue;
1249462c32cbSDag-Erling Smørgrav 			}
125047dd1d1bSDag-Erling Smørgrav 			if (ci->lport == 0)
125147dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("LocalPort", "lport");
1252462c32cbSDag-Erling Smørgrav 			/* TODO support port lists */
1253462c32cbSDag-Erling Smørgrav 			if (port == ci->lport)
1254462c32cbSDag-Erling Smørgrav 				debug("connection from %.100s matched "
1255462c32cbSDag-Erling Smørgrav 				    "'LocalPort %d' at line %d",
1256462c32cbSDag-Erling Smørgrav 				    ci->laddress, port, line);
1257462c32cbSDag-Erling Smørgrav 			else
1258462c32cbSDag-Erling Smørgrav 				result = 0;
125947dd1d1bSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "rdomain") == 0) {
126019261079SEd Maste 			if (ci == NULL || (ci->test && ci->rdomain == NULL)) {
126147dd1d1bSDag-Erling Smørgrav 				result = 0;
126247dd1d1bSDag-Erling Smørgrav 				continue;
126347dd1d1bSDag-Erling Smørgrav 			}
126419261079SEd Maste 			if (ci->rdomain == NULL)
126519261079SEd Maste 				match_test_missing_fatal("RDomain", "rdomain");
126647dd1d1bSDag-Erling Smørgrav 			if (match_pattern_list(ci->rdomain, arg, 0) != 1)
126747dd1d1bSDag-Erling Smørgrav 				result = 0;
126847dd1d1bSDag-Erling Smørgrav 			else
126947dd1d1bSDag-Erling Smørgrav 				debug("user %.100s matched 'RDomain %.100s' at "
127047dd1d1bSDag-Erling Smørgrav 				    "line %d", ci->rdomain, arg, line);
1271333ee039SDag-Erling Smørgrav 		} else {
1272333ee039SDag-Erling Smørgrav 			error("Unsupported Match attribute %s", attrib);
1273333ee039SDag-Erling Smørgrav 			return -1;
1274333ee039SDag-Erling Smørgrav 		}
1275333ee039SDag-Erling Smørgrav 	}
1276f7167e0eSDag-Erling Smørgrav 	if (attributes == 0) {
1277f7167e0eSDag-Erling Smørgrav 		error("One or more attributes required for Match");
1278f7167e0eSDag-Erling Smørgrav 		return -1;
1279f7167e0eSDag-Erling Smørgrav 	}
1280462c32cbSDag-Erling Smørgrav 	if (ci != NULL)
1281333ee039SDag-Erling Smørgrav 		debug3("match %sfound", result ? "" : "not ");
1282333ee039SDag-Erling Smørgrav 	*condition = cp;
1283333ee039SDag-Erling Smørgrav 	return result;
1284333ee039SDag-Erling Smørgrav }
1285333ee039SDag-Erling Smørgrav 
1286333ee039SDag-Erling Smørgrav #define WHITESPACE " \t\r\n"
1287333ee039SDag-Erling Smørgrav 
1288e146993eSDag-Erling Smørgrav /* Multistate option parsing */
1289e146993eSDag-Erling Smørgrav struct multistate {
1290e146993eSDag-Erling Smørgrav 	char *key;
1291e146993eSDag-Erling Smørgrav 	int value;
1292e146993eSDag-Erling Smørgrav };
129347dd1d1bSDag-Erling Smørgrav static const struct multistate multistate_flag[] = {
129447dd1d1bSDag-Erling Smørgrav 	{ "yes",			1 },
129547dd1d1bSDag-Erling Smørgrav 	{ "no",				0 },
129647dd1d1bSDag-Erling Smørgrav 	{ NULL, -1 }
129747dd1d1bSDag-Erling Smørgrav };
129819261079SEd Maste static const struct multistate multistate_ignore_rhosts[] = {
129919261079SEd Maste 	{ "yes",			IGNORE_RHOSTS_YES },
130019261079SEd Maste 	{ "no",				IGNORE_RHOSTS_NO },
130119261079SEd Maste 	{ "shosts-only",		IGNORE_RHOSTS_SHOSTS },
130219261079SEd Maste 	{ NULL, -1 }
130319261079SEd Maste };
1304e146993eSDag-Erling Smørgrav static const struct multistate multistate_addressfamily[] = {
1305e146993eSDag-Erling Smørgrav 	{ "inet",			AF_INET },
1306e146993eSDag-Erling Smørgrav 	{ "inet6",			AF_INET6 },
1307e146993eSDag-Erling Smørgrav 	{ "any",			AF_UNSPEC },
1308e146993eSDag-Erling Smørgrav 	{ NULL, -1 }
1309e146993eSDag-Erling Smørgrav };
1310e146993eSDag-Erling Smørgrav static const struct multistate multistate_permitrootlogin[] = {
1311e146993eSDag-Erling Smørgrav 	{ "without-password",		PERMIT_NO_PASSWD },
1312eccfee6eSDag-Erling Smørgrav 	{ "prohibit-password",		PERMIT_NO_PASSWD },
1313e146993eSDag-Erling Smørgrav 	{ "forced-commands-only",	PERMIT_FORCED_ONLY },
1314e146993eSDag-Erling Smørgrav 	{ "yes",			PERMIT_YES },
1315e146993eSDag-Erling Smørgrav 	{ "no",				PERMIT_NO },
1316e146993eSDag-Erling Smørgrav 	{ NULL, -1 }
1317e146993eSDag-Erling Smørgrav };
1318e146993eSDag-Erling Smørgrav static const struct multistate multistate_compression[] = {
131919261079SEd Maste #ifdef WITH_ZLIB
1320ca86bcf2SDag-Erling Smørgrav 	{ "yes",			COMP_DELAYED },
1321e146993eSDag-Erling Smørgrav 	{ "delayed",			COMP_DELAYED },
132219261079SEd Maste #endif
1323e146993eSDag-Erling Smørgrav 	{ "no",				COMP_NONE },
1324e146993eSDag-Erling Smørgrav 	{ NULL, -1 }
1325e146993eSDag-Erling Smørgrav };
1326e146993eSDag-Erling Smørgrav static const struct multistate multistate_gatewayports[] = {
1327e146993eSDag-Erling Smørgrav 	{ "clientspecified",		2 },
1328e146993eSDag-Erling Smørgrav 	{ "yes",			1 },
1329e146993eSDag-Erling Smørgrav 	{ "no",				0 },
1330e146993eSDag-Erling Smørgrav 	{ NULL, -1 }
1331e146993eSDag-Erling Smørgrav };
13326888a9beSDag-Erling Smørgrav static const struct multistate multistate_tcpfwd[] = {
13336888a9beSDag-Erling Smørgrav 	{ "yes",			FORWARD_ALLOW },
13346888a9beSDag-Erling Smørgrav 	{ "all",			FORWARD_ALLOW },
13356888a9beSDag-Erling Smørgrav 	{ "no",				FORWARD_DENY },
13366888a9beSDag-Erling Smørgrav 	{ "remote",			FORWARD_REMOTE },
13376888a9beSDag-Erling Smørgrav 	{ "local",			FORWARD_LOCAL },
13386888a9beSDag-Erling Smørgrav 	{ NULL, -1 }
13396888a9beSDag-Erling Smørgrav };
1340e146993eSDag-Erling Smørgrav 
134119261079SEd Maste static int
134219261079SEd Maste process_server_config_line_depth(ServerOptions *options, char *line,
1343462c32cbSDag-Erling Smørgrav     const char *filename, int linenum, int *activep,
134419261079SEd Maste     struct connection_info *connectinfo, int *inc_flags, int depth,
134519261079SEd Maste     struct include_list *includes)
1346511b41d2SMark Murray {
13471323ec57SEd Maste 	char *str, ***chararrayptr, **charptr, *arg, *arg2, *p, *keyword;
134819261079SEd Maste 	int cmdline = 0, *intptr, value, value2, n, port, oactive, r, found;
1349*535af610SEd Maste 	int ca_only = 0;
1350d4af9e69SDag-Erling Smørgrav 	SyslogFacility *log_facility_ptr;
1351d4af9e69SDag-Erling Smørgrav 	LogLevel *log_level_ptr;
1352511b41d2SMark Murray 	ServerOpCodes opcode;
1353190cef3dSDag-Erling Smørgrav 	u_int i, *uintptr, uvalue, flags = 0;
1354333ee039SDag-Erling Smørgrav 	size_t len;
1355e4a9863fSDag-Erling Smørgrav 	long long val64;
1356e146993eSDag-Erling Smørgrav 	const struct multistate *multistate_ptr;
135747dd1d1bSDag-Erling Smørgrav 	const char *errstr;
135819261079SEd Maste 	struct include_item *item;
135919261079SEd Maste 	glob_t gbuf;
136019261079SEd Maste 	char **oav = NULL, **av;
136119261079SEd Maste 	int oac = 0, ac;
136219261079SEd Maste 	int ret = -1;
1363511b41d2SMark Murray 
1364d93a896eSDag-Erling Smørgrav 	/* Strip trailing whitespace. Allow \f (form feed) at EOL only */
1365d93a896eSDag-Erling Smørgrav 	if ((len = strlen(line)) == 0)
1366d93a896eSDag-Erling Smørgrav 		return 0;
1367d93a896eSDag-Erling Smørgrav 	for (len--; len > 0; len--) {
1368d93a896eSDag-Erling Smørgrav 		if (strchr(WHITESPACE "\f", line[len]) == NULL)
1369d93a896eSDag-Erling Smørgrav 			break;
1370d93a896eSDag-Erling Smørgrav 		line[len] = '\0';
1371d93a896eSDag-Erling Smørgrav 	}
1372d93a896eSDag-Erling Smørgrav 
137319261079SEd Maste 	str = line;
137419261079SEd Maste 	if ((keyword = strdelim(&str)) == NULL)
1375333ee039SDag-Erling Smørgrav 		return 0;
1376c2d3a559SKris Kennaway 	/* Ignore leading whitespace */
137719261079SEd Maste 	if (*keyword == '\0')
137819261079SEd Maste 		keyword = strdelim(&str);
137919261079SEd Maste 	if (!keyword || !*keyword || *keyword == '#')
1380af12a3e7SDag-Erling Smørgrav 		return 0;
138119261079SEd Maste 	if (str == NULL || *str == '\0') {
138219261079SEd Maste 		error("%s line %d: no argument after keyword \"%s\"",
138319261079SEd Maste 		    filename, linenum, keyword);
138419261079SEd Maste 		return -1;
138519261079SEd Maste 	}
1386ca3176e7SBrian Feldman 	intptr = NULL;
1387ca3176e7SBrian Feldman 	charptr = NULL;
138819261079SEd Maste 	opcode = parse_token(keyword, filename, linenum, &flags);
138919261079SEd Maste 
139019261079SEd Maste 	if (argv_split(str, &oac, &oav, 1) != 0) {
139119261079SEd Maste 		error("%s line %d: invalid quotes", filename, linenum);
139219261079SEd Maste 		return -1;
139319261079SEd Maste 	}
139419261079SEd Maste 	ac = oac;
139519261079SEd Maste 	av = oav;
1396333ee039SDag-Erling Smørgrav 
1397333ee039SDag-Erling Smørgrav 	if (activep == NULL) { /* We are processing a command line directive */
1398333ee039SDag-Erling Smørgrav 		cmdline = 1;
1399333ee039SDag-Erling Smørgrav 		activep = &cmdline;
1400333ee039SDag-Erling Smørgrav 	}
140119261079SEd Maste 	if (*activep && opcode != sMatch && opcode != sInclude)
140219261079SEd Maste 		debug3("%s:%d setting %s %s", filename, linenum, keyword, str);
1403333ee039SDag-Erling Smørgrav 	if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
1404462c32cbSDag-Erling Smørgrav 		if (connectinfo == NULL) {
1405333ee039SDag-Erling Smørgrav 			fatal("%s line %d: Directive '%s' is not allowed "
140619261079SEd Maste 			    "within a Match block", filename, linenum, keyword);
1407333ee039SDag-Erling Smørgrav 		} else { /* this is a directive we have already processed */
140819261079SEd Maste 			ret = 0;
140919261079SEd Maste 			goto out;
1410333ee039SDag-Erling Smørgrav 		}
1411333ee039SDag-Erling Smørgrav 	}
1412333ee039SDag-Erling Smørgrav 
1413511b41d2SMark Murray 	switch (opcode) {
1414989dd127SDag-Erling Smørgrav 	/* Portable-specific options */
1415cf2b5f3bSDag-Erling Smørgrav 	case sUsePAM:
1416cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->use_pam;
1417989dd127SDag-Erling Smørgrav 		goto parse_flag;
1418989dd127SDag-Erling Smørgrav 
1419989dd127SDag-Erling Smørgrav 	/* Standard Options */
1420511b41d2SMark Murray 	case sBadOption:
142119261079SEd Maste 		goto out;
1422511b41d2SMark Murray 	case sPort:
1423511b41d2SMark Murray 		/* ignore ports from configfile if cmdline specifies ports */
142419261079SEd Maste 		if (options->ports_from_cmdline) {
142519261079SEd Maste 			argv_consume(&ac);
142619261079SEd Maste 			break;
142719261079SEd Maste 		}
1428511b41d2SMark Murray 		if (options->num_ports >= MAX_PORTS)
1429ca3176e7SBrian Feldman 			fatal("%s line %d: too many ports.",
1430511b41d2SMark Murray 			    filename, linenum);
143119261079SEd Maste 		arg = argv_next(&ac, &av);
1432c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1433ca3176e7SBrian Feldman 			fatal("%s line %d: missing port number.",
1434511b41d2SMark Murray 			    filename, linenum);
1435ca3176e7SBrian Feldman 		options->ports[options->num_ports++] = a2port(arg);
1436cce7d346SDag-Erling Smørgrav 		if (options->ports[options->num_ports-1] <= 0)
1437ca3176e7SBrian Feldman 			fatal("%s line %d: Badly formatted port number.",
1438ca3176e7SBrian Feldman 			    filename, linenum);
1439511b41d2SMark Murray 		break;
1440511b41d2SMark Murray 
1441511b41d2SMark Murray 	case sLoginGraceTime:
1442511b41d2SMark Murray 		intptr = &options->login_grace_time;
1443af12a3e7SDag-Erling Smørgrav  parse_time:
144419261079SEd Maste 		arg = argv_next(&ac, &av);
1445af12a3e7SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1446af12a3e7SDag-Erling Smørgrav 			fatal("%s line %d: missing time value.",
1447af12a3e7SDag-Erling Smørgrav 			    filename, linenum);
1448af12a3e7SDag-Erling Smørgrav 		if ((value = convtime(arg)) == -1)
1449af12a3e7SDag-Erling Smørgrav 			fatal("%s line %d: invalid time value.",
1450af12a3e7SDag-Erling Smørgrav 			    filename, linenum);
1451557f75e5SDag-Erling Smørgrav 		if (*activep && *intptr == -1)
1452af12a3e7SDag-Erling Smørgrav 			*intptr = value;
1453af12a3e7SDag-Erling Smørgrav 		break;
1454511b41d2SMark Murray 
1455511b41d2SMark Murray 	case sListenAddress:
145619261079SEd Maste 		arg = argv_next(&ac, &av);
1457aa49c926SDag-Erling Smørgrav 		if (arg == NULL || *arg == '\0')
1458aa49c926SDag-Erling Smørgrav 			fatal("%s line %d: missing address",
1459511b41d2SMark Murray 			    filename, linenum);
1460d4ecd108SDag-Erling Smørgrav 		/* check for bare IPv6 address: no "[]" and 2 or more ":" */
1461d4ecd108SDag-Erling Smørgrav 		if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL
1462d4ecd108SDag-Erling Smørgrav 		    && strchr(p+1, ':') != NULL) {
146347dd1d1bSDag-Erling Smørgrav 			port = 0;
146447dd1d1bSDag-Erling Smørgrav 			p = arg;
146547dd1d1bSDag-Erling Smørgrav 		} else {
146619261079SEd Maste 			arg2 = NULL;
14671323ec57SEd Maste 			p = hpdelim(&arg);
14681323ec57SEd Maste 			if (p == NULL)
1469aa49c926SDag-Erling Smørgrav 				fatal("%s line %d: bad address:port usage",
1470ca3176e7SBrian Feldman 				    filename, linenum);
1471aa49c926SDag-Erling Smørgrav 			p = cleanhostname(p);
1472aa49c926SDag-Erling Smørgrav 			if (arg == NULL)
1473aa49c926SDag-Erling Smørgrav 				port = 0;
1474cce7d346SDag-Erling Smørgrav 			else if ((port = a2port(arg)) <= 0)
147547dd1d1bSDag-Erling Smørgrav 				fatal("%s line %d: bad port number",
147647dd1d1bSDag-Erling Smørgrav 				    filename, linenum);
147747dd1d1bSDag-Erling Smørgrav 		}
147847dd1d1bSDag-Erling Smørgrav 		/* Optional routing table */
147947dd1d1bSDag-Erling Smørgrav 		arg2 = NULL;
148019261079SEd Maste 		if ((arg = argv_next(&ac, &av)) != NULL) {
148147dd1d1bSDag-Erling Smørgrav 			if (strcmp(arg, "rdomain") != 0 ||
148219261079SEd Maste 			    (arg2 = argv_next(&ac, &av)) == NULL)
148347dd1d1bSDag-Erling Smørgrav 				fatal("%s line %d: bad ListenAddress syntax",
148447dd1d1bSDag-Erling Smørgrav 				    filename, linenum);
148547dd1d1bSDag-Erling Smørgrav 			if (!valid_rdomain(arg2))
148647dd1d1bSDag-Erling Smørgrav 				fatal("%s line %d: bad routing domain",
148747dd1d1bSDag-Erling Smørgrav 				    filename, linenum);
148847dd1d1bSDag-Erling Smørgrav 		}
148947dd1d1bSDag-Erling Smørgrav 		queue_listen_addr(options, p, arg2, port);
1490aa49c926SDag-Erling Smørgrav 
1491aa49c926SDag-Erling Smørgrav 		break;
1492aa49c926SDag-Erling Smørgrav 
1493aa49c926SDag-Erling Smørgrav 	case sAddressFamily:
1494e146993eSDag-Erling Smørgrav 		intptr = &options->address_family;
1495e146993eSDag-Erling Smørgrav 		multistate_ptr = multistate_addressfamily;
1496e146993eSDag-Erling Smørgrav  parse_multistate:
149719261079SEd Maste 		arg = argv_next(&ac, &av);
1498d4ecd108SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1499e146993eSDag-Erling Smørgrav 			fatal("%s line %d: missing argument.",
1500d4ecd108SDag-Erling Smørgrav 			    filename, linenum);
1501e146993eSDag-Erling Smørgrav 		value = -1;
1502e146993eSDag-Erling Smørgrav 		for (i = 0; multistate_ptr[i].key != NULL; i++) {
1503e146993eSDag-Erling Smørgrav 			if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
1504e146993eSDag-Erling Smørgrav 				value = multistate_ptr[i].value;
1505e146993eSDag-Erling Smørgrav 				break;
1506e146993eSDag-Erling Smørgrav 			}
1507e146993eSDag-Erling Smørgrav 		}
1508e146993eSDag-Erling Smørgrav 		if (value == -1)
1509e146993eSDag-Erling Smørgrav 			fatal("%s line %d: unsupported option \"%s\".",
1510aa49c926SDag-Erling Smørgrav 			    filename, linenum, arg);
1511e146993eSDag-Erling Smørgrav 		if (*activep && *intptr == -1)
1512aa49c926SDag-Erling Smørgrav 			*intptr = value;
1513511b41d2SMark Murray 		break;
1514511b41d2SMark Murray 
1515511b41d2SMark Murray 	case sHostKeyFile:
151619261079SEd Maste 		arg = argv_next(&ac, &av);
1517ca3176e7SBrian Feldman 		if (!arg || *arg == '\0')
1518ca3176e7SBrian Feldman 			fatal("%s line %d: missing file name.",
1519e8aafc91SKris Kennaway 			    filename, linenum);
152019261079SEd Maste 		if (*activep) {
152119261079SEd Maste 			servconf_add_hostkey(filename, linenum,
152219261079SEd Maste 			    options, arg, 1);
152319261079SEd Maste 		}
1524e8aafc91SKris Kennaway 		break;
1525e8aafc91SKris Kennaway 
1526e4a9863fSDag-Erling Smørgrav 	case sHostKeyAgent:
1527e4a9863fSDag-Erling Smørgrav 		charptr = &options->host_key_agent;
152819261079SEd Maste 		arg = argv_next(&ac, &av);
1529e4a9863fSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1530e4a9863fSDag-Erling Smørgrav 			fatal("%s line %d: missing socket name.",
1531e4a9863fSDag-Erling Smørgrav 			    filename, linenum);
1532e4a9863fSDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
1533e4a9863fSDag-Erling Smørgrav 			*charptr = !strcmp(arg, SSH_AUTHSOCKET_ENV_NAME) ?
1534e4a9863fSDag-Erling Smørgrav 			    xstrdup(arg) : derelativise_path(arg);
1535e4a9863fSDag-Erling Smørgrav 		break;
1536e4a9863fSDag-Erling Smørgrav 
1537b15c8340SDag-Erling Smørgrav 	case sHostCertificate:
153819261079SEd Maste 		arg = argv_next(&ac, &av);
153947dd1d1bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
154047dd1d1bSDag-Erling Smørgrav 			fatal("%s line %d: missing file name.",
154147dd1d1bSDag-Erling Smørgrav 			    filename, linenum);
154247dd1d1bSDag-Erling Smørgrav 		if (*activep)
154347dd1d1bSDag-Erling Smørgrav 			servconf_add_hostcert(filename, linenum, options, arg);
154447dd1d1bSDag-Erling Smørgrav 		break;
1545b15c8340SDag-Erling Smørgrav 
1546e8aafc91SKris Kennaway 	case sPidFile:
1547e8aafc91SKris Kennaway 		charptr = &options->pid_file;
154847dd1d1bSDag-Erling Smørgrav  parse_filename:
154919261079SEd Maste 		arg = argv_next(&ac, &av);
155047dd1d1bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
155147dd1d1bSDag-Erling Smørgrav 			fatal("%s line %d: missing file name.",
155247dd1d1bSDag-Erling Smørgrav 			    filename, linenum);
155347dd1d1bSDag-Erling Smørgrav 		if (*activep && *charptr == NULL) {
155447dd1d1bSDag-Erling Smørgrav 			*charptr = derelativise_path(arg);
155547dd1d1bSDag-Erling Smørgrav 			/* increase optional counter */
155647dd1d1bSDag-Erling Smørgrav 			if (intptr != NULL)
155747dd1d1bSDag-Erling Smørgrav 				*intptr = *intptr + 1;
155847dd1d1bSDag-Erling Smørgrav 		}
155947dd1d1bSDag-Erling Smørgrav 		break;
1560511b41d2SMark Murray 
156119261079SEd Maste 	case sModuliFile:
156219261079SEd Maste 		charptr = &options->moduli_file;
156319261079SEd Maste 		goto parse_filename;
156419261079SEd Maste 
1565511b41d2SMark Murray 	case sPermitRootLogin:
1566511b41d2SMark Murray 		intptr = &options->permit_root_login;
1567e146993eSDag-Erling Smørgrav 		multistate_ptr = multistate_permitrootlogin;
1568e146993eSDag-Erling Smørgrav 		goto parse_multistate;
1569511b41d2SMark Murray 
1570511b41d2SMark Murray 	case sIgnoreRhosts:
1571511b41d2SMark Murray 		intptr = &options->ignore_rhosts;
157219261079SEd Maste 		multistate_ptr = multistate_ignore_rhosts;
157347dd1d1bSDag-Erling Smørgrav 		goto parse_multistate;
1574511b41d2SMark Murray 
1575511b41d2SMark Murray 	case sIgnoreUserKnownHosts:
1576511b41d2SMark Murray 		intptr = &options->ignore_user_known_hosts;
157719261079SEd Maste  parse_flag:
157819261079SEd Maste 		multistate_ptr = multistate_flag;
157919261079SEd Maste 		goto parse_multistate;
1580511b41d2SMark Murray 
1581ca3176e7SBrian Feldman 	case sHostbasedAuthentication:
1582ca3176e7SBrian Feldman 		intptr = &options->hostbased_authentication;
1583ca3176e7SBrian Feldman 		goto parse_flag;
1584ca3176e7SBrian Feldman 
1585ca3176e7SBrian Feldman 	case sHostbasedUsesNameFromPacketOnly:
1586ca3176e7SBrian Feldman 		intptr = &options->hostbased_uses_name_from_packet_only;
1587ca3176e7SBrian Feldman 		goto parse_flag;
1588ca3176e7SBrian Feldman 
158919261079SEd Maste 	case sHostbasedAcceptedAlgorithms:
159019261079SEd Maste 		charptr = &options->hostbased_accepted_algos;
1591*535af610SEd Maste 		ca_only = 0;
159219261079SEd Maste  parse_pubkey_algos:
159319261079SEd Maste 		arg = argv_next(&ac, &av);
1594bc5531deSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1595bc5531deSDag-Erling Smørgrav 			fatal("%s line %d: Missing argument.",
1596bc5531deSDag-Erling Smørgrav 			    filename, linenum);
1597d93a896eSDag-Erling Smørgrav 		if (*arg != '-' &&
159819261079SEd Maste 		    !sshkey_names_valid2(*arg == '+' || *arg == '^' ?
1599*535af610SEd Maste 		    arg + 1 : arg, 1, ca_only))
1600bc5531deSDag-Erling Smørgrav 			fatal("%s line %d: Bad key types '%s'.",
1601bc5531deSDag-Erling Smørgrav 			    filename, linenum, arg ? arg : "<NONE>");
1602bc5531deSDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
1603bc5531deSDag-Erling Smørgrav 			*charptr = xstrdup(arg);
1604bc5531deSDag-Erling Smørgrav 		break;
1605bc5531deSDag-Erling Smørgrav 
1606eccfee6eSDag-Erling Smørgrav 	case sHostKeyAlgorithms:
1607eccfee6eSDag-Erling Smørgrav 		charptr = &options->hostkeyalgorithms;
1608*535af610SEd Maste 		ca_only = 0;
160919261079SEd Maste 		goto parse_pubkey_algos;
1610eccfee6eSDag-Erling Smørgrav 
16112f513db7SEd Maste 	case sCASignatureAlgorithms:
16122f513db7SEd Maste 		charptr = &options->ca_sign_algorithms;
1613*535af610SEd Maste 		ca_only = 1;
161419261079SEd Maste 		goto parse_pubkey_algos;
16152f513db7SEd Maste 
1616ca3176e7SBrian Feldman 	case sPubkeyAuthentication:
1617ca3176e7SBrian Feldman 		intptr = &options->pubkey_authentication;
1618*535af610SEd Maste 		ca_only = 0;
1619e8aafc91SKris Kennaway 		goto parse_flag;
1620cf2b5f3bSDag-Erling Smørgrav 
162119261079SEd Maste 	case sPubkeyAcceptedAlgorithms:
162219261079SEd Maste 		charptr = &options->pubkey_accepted_algos;
1623*535af610SEd Maste 		ca_only = 0;
162419261079SEd Maste 		goto parse_pubkey_algos;
162519261079SEd Maste 
162619261079SEd Maste 	case sPubkeyAuthOptions:
162719261079SEd Maste 		intptr = &options->pubkey_auth_options;
162819261079SEd Maste 		value = 0;
162919261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
163019261079SEd Maste 			if (strcasecmp(arg, "none") == 0)
163119261079SEd Maste 				continue;
163219261079SEd Maste 			if (strcasecmp(arg, "touch-required") == 0)
163319261079SEd Maste 				value |= PUBKEYAUTH_TOUCH_REQUIRED;
163419261079SEd Maste 			else if (strcasecmp(arg, "verify-required") == 0)
163519261079SEd Maste 				value |= PUBKEYAUTH_VERIFY_REQUIRED;
163619261079SEd Maste 			else {
163719261079SEd Maste 				error("%s line %d: unsupported %s option %s",
163819261079SEd Maste 				    filename, linenum, keyword, arg);
163919261079SEd Maste 				goto out;
164019261079SEd Maste 			}
164119261079SEd Maste 		}
164219261079SEd Maste 		if (*activep && *intptr == -1)
164319261079SEd Maste 			*intptr = value;
164419261079SEd Maste 		break;
1645bc5531deSDag-Erling Smørgrav 
1646cb96ab36SAssar Westerlund 	case sKerberosAuthentication:
1647cb96ab36SAssar Westerlund 		intptr = &options->kerberos_authentication;
1648511b41d2SMark Murray 		goto parse_flag;
1649511b41d2SMark Murray 
1650af12a3e7SDag-Erling Smørgrav 	case sKerberosOrLocalPasswd:
1651af12a3e7SDag-Erling Smørgrav 		intptr = &options->kerberos_or_local_passwd;
1652511b41d2SMark Murray 		goto parse_flag;
1653511b41d2SMark Murray 
1654af12a3e7SDag-Erling Smørgrav 	case sKerberosTicketCleanup:
1655af12a3e7SDag-Erling Smørgrav 		intptr = &options->kerberos_ticket_cleanup;
1656511b41d2SMark Murray 		goto parse_flag;
1657cf2b5f3bSDag-Erling Smørgrav 
16581ec0d754SDag-Erling Smørgrav 	case sKerberosGetAFSToken:
16591ec0d754SDag-Erling Smørgrav 		intptr = &options->kerberos_get_afs_token;
16601ec0d754SDag-Erling Smørgrav 		goto parse_flag;
16611ec0d754SDag-Erling Smørgrav 
1662cf2b5f3bSDag-Erling Smørgrav 	case sGssAuthentication:
1663cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->gss_authentication;
1664fe5fd017SMark Murray 		goto parse_flag;
1665cf2b5f3bSDag-Erling Smørgrav 
1666cf2b5f3bSDag-Erling Smørgrav 	case sGssCleanupCreds:
1667cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->gss_cleanup_creds;
1668511b41d2SMark Murray 		goto parse_flag;
1669511b41d2SMark Murray 
1670557f75e5SDag-Erling Smørgrav 	case sGssStrictAcceptor:
1671557f75e5SDag-Erling Smørgrav 		intptr = &options->gss_strict_acceptor;
1672557f75e5SDag-Erling Smørgrav 		goto parse_flag;
1673557f75e5SDag-Erling Smørgrav 
1674511b41d2SMark Murray 	case sPasswordAuthentication:
1675511b41d2SMark Murray 		intptr = &options->password_authentication;
1676511b41d2SMark Murray 		goto parse_flag;
1677511b41d2SMark Murray 
167809958426SBrian Feldman 	case sKbdInteractiveAuthentication:
167909958426SBrian Feldman 		intptr = &options->kbd_interactive_authentication;
168009958426SBrian Feldman 		goto parse_flag;
168109958426SBrian Feldman 
1682511b41d2SMark Murray 	case sPrintMotd:
1683511b41d2SMark Murray 		intptr = &options->print_motd;
1684511b41d2SMark Murray 		goto parse_flag;
1685511b41d2SMark Murray 
1686ca3176e7SBrian Feldman 	case sPrintLastLog:
1687ca3176e7SBrian Feldman 		intptr = &options->print_lastlog;
1688ca3176e7SBrian Feldman 		goto parse_flag;
1689ca3176e7SBrian Feldman 
1690511b41d2SMark Murray 	case sX11Forwarding:
1691511b41d2SMark Murray 		intptr = &options->x11_forwarding;
1692511b41d2SMark Murray 		goto parse_flag;
1693511b41d2SMark Murray 
1694511b41d2SMark Murray 	case sX11DisplayOffset:
1695511b41d2SMark Murray 		intptr = &options->x11_display_offset;
1696ca86bcf2SDag-Erling Smørgrav  parse_int:
169719261079SEd Maste 		arg = argv_next(&ac, &av);
169847dd1d1bSDag-Erling Smørgrav 		if ((errstr = atoi_err(arg, &value)) != NULL)
169919261079SEd Maste 			fatal("%s line %d: %s integer value %s.",
170019261079SEd Maste 			    filename, linenum, keyword, errstr);
1701ca86bcf2SDag-Erling Smørgrav 		if (*activep && *intptr == -1)
1702ca86bcf2SDag-Erling Smørgrav 			*intptr = value;
1703ca86bcf2SDag-Erling Smørgrav 		break;
1704511b41d2SMark Murray 
1705af12a3e7SDag-Erling Smørgrav 	case sX11UseLocalhost:
1706af12a3e7SDag-Erling Smørgrav 		intptr = &options->x11_use_localhost;
1707af12a3e7SDag-Erling Smørgrav 		goto parse_flag;
1708af12a3e7SDag-Erling Smørgrav 
1709c2d3a559SKris Kennaway 	case sXAuthLocation:
1710c2d3a559SKris Kennaway 		charptr = &options->xauth_location;
1711c2d3a559SKris Kennaway 		goto parse_filename;
1712c2d3a559SKris Kennaway 
1713f7167e0eSDag-Erling Smørgrav 	case sPermitTTY:
1714f7167e0eSDag-Erling Smørgrav 		intptr = &options->permit_tty;
1715f7167e0eSDag-Erling Smørgrav 		goto parse_flag;
1716f7167e0eSDag-Erling Smørgrav 
1717a0ee8cc6SDag-Erling Smørgrav 	case sPermitUserRC:
1718a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->permit_user_rc;
1719a0ee8cc6SDag-Erling Smørgrav 		goto parse_flag;
1720a0ee8cc6SDag-Erling Smørgrav 
1721511b41d2SMark Murray 	case sStrictModes:
1722511b41d2SMark Murray 		intptr = &options->strict_modes;
1723511b41d2SMark Murray 		goto parse_flag;
1724511b41d2SMark Murray 
17251ec0d754SDag-Erling Smørgrav 	case sTCPKeepAlive:
17261ec0d754SDag-Erling Smørgrav 		intptr = &options->tcp_keep_alive;
1727511b41d2SMark Murray 		goto parse_flag;
1728511b41d2SMark Murray 
1729511b41d2SMark Murray 	case sEmptyPasswd:
1730511b41d2SMark Murray 		intptr = &options->permit_empty_passwd;
1731511b41d2SMark Murray 		goto parse_flag;
1732511b41d2SMark Murray 
1733f388f5efSDag-Erling Smørgrav 	case sPermitUserEnvironment:
1734f388f5efSDag-Erling Smørgrav 		intptr = &options->permit_user_env;
173519261079SEd Maste 		charptr = &options->permit_user_env_allowlist;
173619261079SEd Maste 		arg = argv_next(&ac, &av);
1737190cef3dSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
173819261079SEd Maste 			fatal("%s line %d: %s missing argument.",
173919261079SEd Maste 			    filename, linenum, keyword);
1740190cef3dSDag-Erling Smørgrav 		value = 0;
1741190cef3dSDag-Erling Smørgrav 		p = NULL;
1742190cef3dSDag-Erling Smørgrav 		if (strcmp(arg, "yes") == 0)
1743190cef3dSDag-Erling Smørgrav 			value = 1;
1744190cef3dSDag-Erling Smørgrav 		else if (strcmp(arg, "no") == 0)
1745190cef3dSDag-Erling Smørgrav 			value = 0;
1746190cef3dSDag-Erling Smørgrav 		else {
1747190cef3dSDag-Erling Smørgrav 			/* Pattern-list specified */
1748190cef3dSDag-Erling Smørgrav 			value = 1;
1749190cef3dSDag-Erling Smørgrav 			p = xstrdup(arg);
1750190cef3dSDag-Erling Smørgrav 		}
1751190cef3dSDag-Erling Smørgrav 		if (*activep && *intptr == -1) {
1752190cef3dSDag-Erling Smørgrav 			*intptr = value;
1753190cef3dSDag-Erling Smørgrav 			*charptr = p;
1754190cef3dSDag-Erling Smørgrav 			p = NULL;
1755190cef3dSDag-Erling Smørgrav 		}
1756190cef3dSDag-Erling Smørgrav 		free(p);
1757190cef3dSDag-Erling Smørgrav 		break;
1758f388f5efSDag-Erling Smørgrav 
175980628bacSDag-Erling Smørgrav 	case sCompression:
176080628bacSDag-Erling Smørgrav 		intptr = &options->compression;
1761e146993eSDag-Erling Smørgrav 		multistate_ptr = multistate_compression;
1762e146993eSDag-Erling Smørgrav 		goto parse_multistate;
176380628bacSDag-Erling Smørgrav 
1764e4a9863fSDag-Erling Smørgrav 	case sRekeyLimit:
176519261079SEd Maste 		arg = argv_next(&ac, &av);
1766e4a9863fSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
176719261079SEd Maste 			fatal("%s line %d: %s missing argument.",
176819261079SEd Maste 			    filename, linenum, keyword);
1769e4a9863fSDag-Erling Smørgrav 		if (strcmp(arg, "default") == 0) {
1770e4a9863fSDag-Erling Smørgrav 			val64 = 0;
1771e4a9863fSDag-Erling Smørgrav 		} else {
1772e4a9863fSDag-Erling Smørgrav 			if (scan_scaled(arg, &val64) == -1)
177319261079SEd Maste 				fatal("%.200s line %d: Bad %s number '%s': %s",
177419261079SEd Maste 				    filename, linenum, keyword,
177519261079SEd Maste 				    arg, strerror(errno));
1776e4a9863fSDag-Erling Smørgrav 			if (val64 != 0 && val64 < 16)
177719261079SEd Maste 				fatal("%.200s line %d: %s too small",
177819261079SEd Maste 				    filename, linenum, keyword);
1779e4a9863fSDag-Erling Smørgrav 		}
1780e4a9863fSDag-Erling Smørgrav 		if (*activep && options->rekey_limit == -1)
1781acc1a9efSDag-Erling Smørgrav 			options->rekey_limit = val64;
178219261079SEd Maste 		if (ac != 0) { /* optional rekey interval present */
178319261079SEd Maste 			if (strcmp(av[0], "none") == 0) {
178419261079SEd Maste 				(void)argv_next(&ac, &av);	/* discard */
1785e4a9863fSDag-Erling Smørgrav 				break;
1786e4a9863fSDag-Erling Smørgrav 			}
1787e4a9863fSDag-Erling Smørgrav 			intptr = &options->rekey_interval;
1788e4a9863fSDag-Erling Smørgrav 			goto parse_time;
1789e4a9863fSDag-Erling Smørgrav 		}
1790e4a9863fSDag-Erling Smørgrav 		break;
1791e4a9863fSDag-Erling Smørgrav 
1792e8aafc91SKris Kennaway 	case sGatewayPorts:
1793a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->fwd_opts.gateway_ports;
1794e146993eSDag-Erling Smørgrav 		multistate_ptr = multistate_gatewayports;
1795e146993eSDag-Erling Smørgrav 		goto parse_multistate;
1796e8aafc91SKris Kennaway 
1797cf2b5f3bSDag-Erling Smørgrav 	case sUseDNS:
1798cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->use_dns;
1799ca3176e7SBrian Feldman 		goto parse_flag;
1800ca3176e7SBrian Feldman 
1801511b41d2SMark Murray 	case sLogFacility:
1802d4af9e69SDag-Erling Smørgrav 		log_facility_ptr = &options->log_facility;
180319261079SEd Maste 		arg = argv_next(&ac, &av);
1804c2d3a559SKris Kennaway 		value = log_facility_number(arg);
1805af12a3e7SDag-Erling Smørgrav 		if (value == SYSLOG_FACILITY_NOT_SET)
1806ca3176e7SBrian Feldman 			fatal("%.200s line %d: unsupported log facility '%s'",
1807c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
1808d4af9e69SDag-Erling Smørgrav 		if (*log_facility_ptr == -1)
1809d4af9e69SDag-Erling Smørgrav 			*log_facility_ptr = (SyslogFacility) value;
1810511b41d2SMark Murray 		break;
1811511b41d2SMark Murray 
1812511b41d2SMark Murray 	case sLogLevel:
1813d4af9e69SDag-Erling Smørgrav 		log_level_ptr = &options->log_level;
181419261079SEd Maste 		arg = argv_next(&ac, &av);
1815c2d3a559SKris Kennaway 		value = log_level_number(arg);
1816af12a3e7SDag-Erling Smørgrav 		if (value == SYSLOG_LEVEL_NOT_SET)
1817ca3176e7SBrian Feldman 			fatal("%.200s line %d: unsupported log level '%s'",
1818c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
18194f52dfbbSDag-Erling Smørgrav 		if (*activep && *log_level_ptr == -1)
1820d4af9e69SDag-Erling Smørgrav 			*log_level_ptr = (LogLevel) value;
1821511b41d2SMark Murray 		break;
1822511b41d2SMark Murray 
182319261079SEd Maste 	case sLogVerbose:
182419261079SEd Maste 		found = options->num_log_verbose == 0;
182519261079SEd Maste 		i = 0;
182619261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
182719261079SEd Maste 			if (*arg == '\0') {
182819261079SEd Maste 				error("%s line %d: keyword %s empty argument",
182919261079SEd Maste 				    filename, linenum, keyword);
183019261079SEd Maste 				goto out;
183119261079SEd Maste 			}
183219261079SEd Maste 			/* Allow "none" only in first position */
183319261079SEd Maste 			if (strcasecmp(arg, "none") == 0) {
183419261079SEd Maste 				if (i > 0 || ac > 0) {
183519261079SEd Maste 					error("%s line %d: keyword %s \"none\" "
183619261079SEd Maste 					    "argument must appear alone.",
183719261079SEd Maste 					    filename, linenum, keyword);
183819261079SEd Maste 					goto out;
183919261079SEd Maste 				}
184019261079SEd Maste 			}
184119261079SEd Maste 			i++;
184219261079SEd Maste 			if (!found || !*activep)
184319261079SEd Maste 				continue;
184419261079SEd Maste 			opt_array_append(filename, linenum, keyword,
184519261079SEd Maste 			    &options->log_verbose, &options->num_log_verbose,
184619261079SEd Maste 			    arg);
184719261079SEd Maste 		}
184819261079SEd Maste 		break;
184919261079SEd Maste 
185009958426SBrian Feldman 	case sAllowTcpForwarding:
185109958426SBrian Feldman 		intptr = &options->allow_tcp_forwarding;
18526888a9beSDag-Erling Smørgrav 		multistate_ptr = multistate_tcpfwd;
18536888a9beSDag-Erling Smørgrav 		goto parse_multistate;
185409958426SBrian Feldman 
1855a0ee8cc6SDag-Erling Smørgrav 	case sAllowStreamLocalForwarding:
1856a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->allow_streamlocal_forwarding;
1857a0ee8cc6SDag-Erling Smørgrav 		multistate_ptr = multistate_tcpfwd;
1858a0ee8cc6SDag-Erling Smørgrav 		goto parse_multistate;
1859a0ee8cc6SDag-Erling Smørgrav 
1860d4af9e69SDag-Erling Smørgrav 	case sAllowAgentForwarding:
1861d4af9e69SDag-Erling Smørgrav 		intptr = &options->allow_agent_forwarding;
1862d4af9e69SDag-Erling Smørgrav 		goto parse_flag;
1863d4af9e69SDag-Erling Smørgrav 
1864ca86bcf2SDag-Erling Smørgrav 	case sDisableForwarding:
1865ca86bcf2SDag-Erling Smørgrav 		intptr = &options->disable_forwarding;
1866ca86bcf2SDag-Erling Smørgrav 		goto parse_flag;
1867ca86bcf2SDag-Erling Smørgrav 
1868511b41d2SMark Murray 	case sAllowUsers:
186919261079SEd Maste 		chararrayptr = &options->allow_users;
187019261079SEd Maste 		uintptr = &options->num_allow_users;
187119261079SEd Maste  parse_allowdenyusers:
187219261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
187319261079SEd Maste 			if (*arg == '\0' ||
187419261079SEd Maste 			    match_user(NULL, NULL, NULL, arg) == -1)
187519261079SEd Maste 				fatal("%s line %d: invalid %s pattern: \"%s\"",
187619261079SEd Maste 				    filename, linenum, keyword, arg);
1877462c32cbSDag-Erling Smørgrav 			if (!*activep)
1878462c32cbSDag-Erling Smørgrav 				continue;
187919261079SEd Maste 			opt_array_append(filename, linenum, keyword,
188019261079SEd Maste 			    chararrayptr, uintptr, arg);
1881511b41d2SMark Murray 		}
1882511b41d2SMark Murray 		break;
1883511b41d2SMark Murray 
1884511b41d2SMark Murray 	case sDenyUsers:
188519261079SEd Maste 		chararrayptr = &options->deny_users;
188619261079SEd Maste 		uintptr = &options->num_deny_users;
188719261079SEd Maste 		goto parse_allowdenyusers;
1888511b41d2SMark Murray 
1889511b41d2SMark Murray 	case sAllowGroups:
189019261079SEd Maste 		chararrayptr = &options->allow_groups;
189119261079SEd Maste 		uintptr = &options->num_allow_groups;
189219261079SEd Maste  parse_allowdenygroups:
189319261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
189419261079SEd Maste 			if (*arg == '\0')
189519261079SEd Maste 				fatal("%s line %d: empty %s pattern",
189619261079SEd Maste 				    filename, linenum, keyword);
1897462c32cbSDag-Erling Smørgrav 			if (!*activep)
1898462c32cbSDag-Erling Smørgrav 				continue;
189919261079SEd Maste 			opt_array_append(filename, linenum, keyword,
190019261079SEd Maste 			    chararrayptr, uintptr, arg);
1901511b41d2SMark Murray 		}
1902511b41d2SMark Murray 		break;
1903511b41d2SMark Murray 
1904511b41d2SMark Murray 	case sDenyGroups:
190519261079SEd Maste 		chararrayptr = &options->deny_groups;
190619261079SEd Maste 		uintptr = &options->num_deny_groups;
190719261079SEd Maste 		goto parse_allowdenygroups;
1908511b41d2SMark Murray 
1909e8aafc91SKris Kennaway 	case sCiphers:
191019261079SEd Maste 		arg = argv_next(&ac, &av);
1911c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
191219261079SEd Maste 			fatal("%s line %d: %s missing argument.",
191319261079SEd Maste 			    filename, linenum, keyword);
191419261079SEd Maste 		if (*arg != '-' &&
191519261079SEd Maste 		    !ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg))
1916e8aafc91SKris Kennaway 			fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
1917c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
1918e8aafc91SKris Kennaway 		if (options->ciphers == NULL)
1919c2d3a559SKris Kennaway 			options->ciphers = xstrdup(arg);
1920e8aafc91SKris Kennaway 		break;
1921e8aafc91SKris Kennaway 
1922ca3176e7SBrian Feldman 	case sMacs:
192319261079SEd Maste 		arg = argv_next(&ac, &av);
1924ca3176e7SBrian Feldman 		if (!arg || *arg == '\0')
192519261079SEd Maste 			fatal("%s line %d: %s missing argument.",
192619261079SEd Maste 			    filename, linenum, keyword);
192719261079SEd Maste 		if (*arg != '-' &&
192819261079SEd Maste 		    !mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg))
1929ca3176e7SBrian Feldman 			fatal("%s line %d: Bad SSH2 mac spec '%s'.",
1930ca3176e7SBrian Feldman 			    filename, linenum, arg ? arg : "<NONE>");
1931ca3176e7SBrian Feldman 		if (options->macs == NULL)
1932ca3176e7SBrian Feldman 			options->macs = xstrdup(arg);
1933ca3176e7SBrian Feldman 		break;
1934ca3176e7SBrian Feldman 
19354a421b63SDag-Erling Smørgrav 	case sKexAlgorithms:
193619261079SEd Maste 		arg = argv_next(&ac, &av);
19374a421b63SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
193819261079SEd Maste 			fatal("%s line %d: %s missing argument.",
193919261079SEd Maste 			    filename, linenum, keyword);
1940d93a896eSDag-Erling Smørgrav 		if (*arg != '-' &&
194119261079SEd Maste 		    !kex_names_valid(*arg == '+' || *arg == '^' ?
194219261079SEd Maste 		    arg + 1 : arg))
19434a421b63SDag-Erling Smørgrav 			fatal("%s line %d: Bad SSH2 KexAlgorithms '%s'.",
19444a421b63SDag-Erling Smørgrav 			    filename, linenum, arg ? arg : "<NONE>");
19454a421b63SDag-Erling Smørgrav 		if (options->kex_algorithms == NULL)
19464a421b63SDag-Erling Smørgrav 			options->kex_algorithms = xstrdup(arg);
19474a421b63SDag-Erling Smørgrav 		break;
19484a421b63SDag-Erling Smørgrav 
1949c2d3a559SKris Kennaway 	case sSubsystem:
1950c2d3a559SKris Kennaway 		if (options->num_subsystems >= MAX_SUBSYSTEMS) {
1951c2d3a559SKris Kennaway 			fatal("%s line %d: too many subsystems defined.",
1952c2d3a559SKris Kennaway 			    filename, linenum);
1953c2d3a559SKris Kennaway 		}
195419261079SEd Maste 		arg = argv_next(&ac, &av);
1955c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
195619261079SEd Maste 			fatal("%s line %d: %s missing argument.",
195719261079SEd Maste 			    filename, linenum, keyword);
1958333ee039SDag-Erling Smørgrav 		if (!*activep) {
195919261079SEd Maste 			arg = argv_next(&ac, &av);
1960333ee039SDag-Erling Smørgrav 			break;
1961333ee039SDag-Erling Smørgrav 		}
1962c2d3a559SKris Kennaway 		for (i = 0; i < options->num_subsystems; i++)
1963c2d3a559SKris Kennaway 			if (strcmp(arg, options->subsystem_name[i]) == 0)
196419261079SEd Maste 				fatal("%s line %d: Subsystem '%s' "
196519261079SEd Maste 				    "already defined.", filename, linenum, arg);
1966c2d3a559SKris Kennaway 		options->subsystem_name[options->num_subsystems] = xstrdup(arg);
196719261079SEd Maste 		arg = argv_next(&ac, &av);
1968c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1969c2d3a559SKris Kennaway 			fatal("%s line %d: Missing subsystem command.",
1970c2d3a559SKris Kennaway 			    filename, linenum);
1971c2d3a559SKris Kennaway 		options->subsystem_command[options->num_subsystems] = xstrdup(arg);
1972333ee039SDag-Erling Smørgrav 
1973333ee039SDag-Erling Smørgrav 		/* Collect arguments (separate to executable) */
1974333ee039SDag-Erling Smørgrav 		p = xstrdup(arg);
1975333ee039SDag-Erling Smørgrav 		len = strlen(p) + 1;
197619261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
1977333ee039SDag-Erling Smørgrav 			len += 1 + strlen(arg);
1978557f75e5SDag-Erling Smørgrav 			p = xreallocarray(p, 1, len);
1979333ee039SDag-Erling Smørgrav 			strlcat(p, " ", len);
1980333ee039SDag-Erling Smørgrav 			strlcat(p, arg, len);
1981333ee039SDag-Erling Smørgrav 		}
1982333ee039SDag-Erling Smørgrav 		options->subsystem_args[options->num_subsystems] = p;
1983c2d3a559SKris Kennaway 		options->num_subsystems++;
1984c2d3a559SKris Kennaway 		break;
1985c2d3a559SKris Kennaway 
1986c2d3a559SKris Kennaway 	case sMaxStartups:
198719261079SEd Maste 		arg = argv_next(&ac, &av);
1988c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
198919261079SEd Maste 			fatal("%s line %d: %s missing argument.",
199019261079SEd Maste 			    filename, linenum, keyword);
1991af12a3e7SDag-Erling Smørgrav 		if ((n = sscanf(arg, "%d:%d:%d",
1992c2d3a559SKris Kennaway 		    &options->max_startups_begin,
1993c2d3a559SKris Kennaway 		    &options->max_startups_rate,
1994af12a3e7SDag-Erling Smørgrav 		    &options->max_startups)) == 3) {
1995c2d3a559SKris Kennaway 			if (options->max_startups_begin >
1996c2d3a559SKris Kennaway 			    options->max_startups ||
1997c2d3a559SKris Kennaway 			    options->max_startups_rate > 100 ||
1998c2d3a559SKris Kennaway 			    options->max_startups_rate < 1)
199919261079SEd Maste 				fatal("%s line %d: Invalid %s spec.",
200019261079SEd Maste 				    filename, linenum, keyword);
2001af12a3e7SDag-Erling Smørgrav 		} else if (n != 1)
200219261079SEd Maste 			fatal("%s line %d: Invalid %s spec.",
200319261079SEd Maste 			    filename, linenum, keyword);
2004af12a3e7SDag-Erling Smørgrav 		else
2005af12a3e7SDag-Erling Smørgrav 			options->max_startups = options->max_startups_begin;
2006f374ba41SEd Maste 		if (options->max_startups <= 0 ||
2007f374ba41SEd Maste 		    options->max_startups_begin <= 0)
2008f374ba41SEd Maste 			fatal("%s line %d: Invalid %s spec.",
2009f374ba41SEd Maste 			    filename, linenum, keyword);
2010933ca70fSBrian Feldman 		break;
2011933ca70fSBrian Feldman 
201219261079SEd Maste 	case sPerSourceNetBlockSize:
201319261079SEd Maste 		arg = argv_next(&ac, &av);
201419261079SEd Maste 		if (!arg || *arg == '\0')
201519261079SEd Maste 			fatal("%s line %d: %s missing argument.",
201619261079SEd Maste 			    filename, linenum, keyword);
201719261079SEd Maste 		switch (n = sscanf(arg, "%d:%d", &value, &value2)) {
201819261079SEd Maste 		case 2:
201919261079SEd Maste 			if (value2 < 0 || value2 > 128)
202019261079SEd Maste 				n = -1;
202119261079SEd Maste 			/* FALLTHROUGH */
202219261079SEd Maste 		case 1:
202319261079SEd Maste 			if (value < 0 || value > 32)
202419261079SEd Maste 				n = -1;
202519261079SEd Maste 		}
202619261079SEd Maste 		if (n != 1 && n != 2)
202719261079SEd Maste 			fatal("%s line %d: Invalid %s spec.",
202819261079SEd Maste 			    filename, linenum, keyword);
202919261079SEd Maste 		if (*activep) {
203019261079SEd Maste 			options->per_source_masklen_ipv4 = value;
203119261079SEd Maste 			options->per_source_masklen_ipv6 = value2;
203219261079SEd Maste 		}
203319261079SEd Maste 		break;
203419261079SEd Maste 
203519261079SEd Maste 	case sPerSourceMaxStartups:
203619261079SEd Maste 		arg = argv_next(&ac, &av);
203719261079SEd Maste 		if (!arg || *arg == '\0')
203819261079SEd Maste 			fatal("%s line %d: %s missing argument.",
203919261079SEd Maste 			    filename, linenum, keyword);
204019261079SEd Maste 		if (strcmp(arg, "none") == 0) { /* no limit */
204119261079SEd Maste 			value = INT_MAX;
204219261079SEd Maste 		} else {
204319261079SEd Maste 			if ((errstr = atoi_err(arg, &value)) != NULL)
204419261079SEd Maste 				fatal("%s line %d: %s integer value %s.",
204519261079SEd Maste 				    filename, linenum, keyword, errstr);
204619261079SEd Maste 		}
204719261079SEd Maste 		if (*activep)
204819261079SEd Maste 			options->per_source_max_startups = value;
204919261079SEd Maste 		break;
205019261079SEd Maste 
205121e764dfSDag-Erling Smørgrav 	case sMaxAuthTries:
205221e764dfSDag-Erling Smørgrav 		intptr = &options->max_authtries;
205321e764dfSDag-Erling Smørgrav 		goto parse_int;
205421e764dfSDag-Erling Smørgrav 
2055d4af9e69SDag-Erling Smørgrav 	case sMaxSessions:
2056d4af9e69SDag-Erling Smørgrav 		intptr = &options->max_sessions;
2057d4af9e69SDag-Erling Smørgrav 		goto parse_int;
2058d4af9e69SDag-Erling Smørgrav 
2059ca3176e7SBrian Feldman 	case sBanner:
2060ca3176e7SBrian Feldman 		charptr = &options->banner;
2061ca3176e7SBrian Feldman 		goto parse_filename;
2062d4af9e69SDag-Erling Smørgrav 
2063af12a3e7SDag-Erling Smørgrav 	/*
2064af12a3e7SDag-Erling Smørgrav 	 * These options can contain %X options expanded at
2065af12a3e7SDag-Erling Smørgrav 	 * connect time, so that you can specify paths like:
2066af12a3e7SDag-Erling Smørgrav 	 *
2067af12a3e7SDag-Erling Smørgrav 	 * AuthorizedKeysFile	/etc/ssh_keys/%u
2068af12a3e7SDag-Erling Smørgrav 	 */
2069af12a3e7SDag-Erling Smørgrav 	case sAuthorizedKeysFile:
207019261079SEd Maste 		uvalue = options->num_authkeys_files;
207119261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
207219261079SEd Maste 			if (*arg == '\0') {
207319261079SEd Maste 				error("%s line %d: keyword %s empty argument",
207419261079SEd Maste 				    filename, linenum, keyword);
207519261079SEd Maste 				goto out;
207619261079SEd Maste 			}
207719261079SEd Maste 			arg2 = tilde_expand_filename(arg, getuid());
207819261079SEd Maste 			if (*activep && uvalue == 0) {
207919261079SEd Maste 				opt_array_append(filename, linenum, keyword,
208047dd1d1bSDag-Erling Smørgrav 				    &options->authorized_keys_files,
208119261079SEd Maste 				    &options->num_authkeys_files, arg2);
2082e146993eSDag-Erling Smørgrav 			}
208319261079SEd Maste 			free(arg2);
2084e146993eSDag-Erling Smørgrav 		}
208519261079SEd Maste 		break;
2086e146993eSDag-Erling Smørgrav 
2087e2f6069cSDag-Erling Smørgrav 	case sAuthorizedPrincipalsFile:
2088e2f6069cSDag-Erling Smørgrav 		charptr = &options->authorized_principals_file;
208919261079SEd Maste 		arg = argv_next(&ac, &av);
20908ad9b54aSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
209119261079SEd Maste 			fatal("%s line %d: %s missing argument.",
209219261079SEd Maste 			    filename, linenum, keyword);
20938ad9b54aSDag-Erling Smørgrav 		if (*activep && *charptr == NULL) {
20948ad9b54aSDag-Erling Smørgrav 			*charptr = tilde_expand_filename(arg, getuid());
20958ad9b54aSDag-Erling Smørgrav 			/* increase optional counter */
20968ad9b54aSDag-Erling Smørgrav 			if (intptr != NULL)
20978ad9b54aSDag-Erling Smørgrav 				*intptr = *intptr + 1;
20988ad9b54aSDag-Erling Smørgrav 		}
20998ad9b54aSDag-Erling Smørgrav 		break;
2100af12a3e7SDag-Erling Smørgrav 
2101ca3176e7SBrian Feldman 	case sClientAliveInterval:
2102ca3176e7SBrian Feldman 		intptr = &options->client_alive_interval;
2103af12a3e7SDag-Erling Smørgrav 		goto parse_time;
2104af12a3e7SDag-Erling Smørgrav 
2105ca3176e7SBrian Feldman 	case sClientAliveCountMax:
2106ca3176e7SBrian Feldman 		intptr = &options->client_alive_count_max;
2107ca3176e7SBrian Feldman 		goto parse_int;
2108af12a3e7SDag-Erling Smørgrav 
210921e764dfSDag-Erling Smørgrav 	case sAcceptEnv:
211019261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
211119261079SEd Maste 			if (*arg == '\0' || strchr(arg, '=') != NULL)
211221e764dfSDag-Erling Smørgrav 				fatal("%s line %d: Invalid environment name.",
211321e764dfSDag-Erling Smørgrav 				    filename, linenum);
2114333ee039SDag-Erling Smørgrav 			if (!*activep)
2115462c32cbSDag-Erling Smørgrav 				continue;
211619261079SEd Maste 			opt_array_append(filename, linenum, keyword,
211747dd1d1bSDag-Erling Smørgrav 			    &options->accept_env, &options->num_accept_env,
211847dd1d1bSDag-Erling Smørgrav 			    arg);
211921e764dfSDag-Erling Smørgrav 		}
212021e764dfSDag-Erling Smørgrav 		break;
212121e764dfSDag-Erling Smørgrav 
2122190cef3dSDag-Erling Smørgrav 	case sSetEnv:
2123190cef3dSDag-Erling Smørgrav 		uvalue = options->num_setenv;
212419261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
212519261079SEd Maste 			if (*arg == '\0' || strchr(arg, '=') == NULL)
2126190cef3dSDag-Erling Smørgrav 				fatal("%s line %d: Invalid environment.",
2127190cef3dSDag-Erling Smørgrav 				    filename, linenum);
2128190cef3dSDag-Erling Smørgrav 			if (!*activep || uvalue != 0)
2129190cef3dSDag-Erling Smørgrav 				continue;
213038a52bd3SEd Maste 			if (lookup_setenv_in_list(arg, options->setenv,
213138a52bd3SEd Maste 			    options->num_setenv) != NULL) {
213238a52bd3SEd Maste 				debug2("%s line %d: ignoring duplicate env "
213338a52bd3SEd Maste 				    "name \"%.64s\"", filename, linenum, arg);
213438a52bd3SEd Maste 				continue;
213538a52bd3SEd Maste 			}
213619261079SEd Maste 			opt_array_append(filename, linenum, keyword,
2137190cef3dSDag-Erling Smørgrav 			    &options->setenv, &options->num_setenv, arg);
2138190cef3dSDag-Erling Smørgrav 		}
2139190cef3dSDag-Erling Smørgrav 		break;
2140190cef3dSDag-Erling Smørgrav 
2141b74df5b2SDag-Erling Smørgrav 	case sPermitTunnel:
2142b74df5b2SDag-Erling Smørgrav 		intptr = &options->permit_tun;
214319261079SEd Maste 		arg = argv_next(&ac, &av);
2144b74df5b2SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
214519261079SEd Maste 			fatal("%s line %d: %s missing argument.",
214619261079SEd Maste 			    filename, linenum, keyword);
2147d4af9e69SDag-Erling Smørgrav 		value = -1;
2148d4af9e69SDag-Erling Smørgrav 		for (i = 0; tunmode_desc[i].val != -1; i++)
2149d4af9e69SDag-Erling Smørgrav 			if (strcmp(tunmode_desc[i].text, arg) == 0) {
2150d4af9e69SDag-Erling Smørgrav 				value = tunmode_desc[i].val;
2151d4af9e69SDag-Erling Smørgrav 				break;
2152d4af9e69SDag-Erling Smørgrav 			}
2153d4af9e69SDag-Erling Smørgrav 		if (value == -1)
215419261079SEd Maste 			fatal("%s line %d: bad %s argument %s",
215519261079SEd Maste 			    filename, linenum, keyword, arg);
2156557f75e5SDag-Erling Smørgrav 		if (*activep && *intptr == -1)
2157b74df5b2SDag-Erling Smørgrav 			*intptr = value;
2158b74df5b2SDag-Erling Smørgrav 		break;
2159b74df5b2SDag-Erling Smørgrav 
216019261079SEd Maste 	case sInclude:
216119261079SEd Maste 		if (cmdline) {
216219261079SEd Maste 			fatal("Include directive not supported as a "
216319261079SEd Maste 			    "command-line option");
216419261079SEd Maste 		}
216519261079SEd Maste 		value = 0;
216619261079SEd Maste 		while ((arg2 = argv_next(&ac, &av)) != NULL) {
216719261079SEd Maste 			if (*arg2 == '\0') {
216819261079SEd Maste 				error("%s line %d: keyword %s empty argument",
216919261079SEd Maste 				    filename, linenum, keyword);
217019261079SEd Maste 				goto out;
217119261079SEd Maste 			}
217219261079SEd Maste 			value++;
217319261079SEd Maste 			found = 0;
217419261079SEd Maste 			if (*arg2 != '/' && *arg2 != '~') {
217519261079SEd Maste 				xasprintf(&arg, "%s/%s", SSHDIR, arg2);
217619261079SEd Maste 			} else
217719261079SEd Maste 				arg = xstrdup(arg2);
217819261079SEd Maste 
217919261079SEd Maste 			/*
218019261079SEd Maste 			 * Don't let included files clobber the containing
218119261079SEd Maste 			 * file's Match state.
218219261079SEd Maste 			 */
218319261079SEd Maste 			oactive = *activep;
218419261079SEd Maste 
218519261079SEd Maste 			/* consult cache of include files */
218619261079SEd Maste 			TAILQ_FOREACH(item, includes, entry) {
218719261079SEd Maste 				if (strcmp(item->selector, arg) != 0)
218819261079SEd Maste 					continue;
218919261079SEd Maste 				if (item->filename != NULL) {
219019261079SEd Maste 					parse_server_config_depth(options,
219119261079SEd Maste 					    item->filename, item->contents,
219219261079SEd Maste 					    includes, connectinfo,
219319261079SEd Maste 					    (*inc_flags & SSHCFG_MATCH_ONLY
219419261079SEd Maste 					        ? SSHCFG_MATCH_ONLY : (oactive
219519261079SEd Maste 					            ? 0 : SSHCFG_NEVERMATCH)),
219619261079SEd Maste 					    activep, depth + 1);
219719261079SEd Maste 				}
219819261079SEd Maste 				found = 1;
219919261079SEd Maste 				*activep = oactive;
220019261079SEd Maste 			}
220119261079SEd Maste 			if (found != 0) {
220219261079SEd Maste 				free(arg);
220319261079SEd Maste 				continue;
220419261079SEd Maste 			}
220519261079SEd Maste 
220619261079SEd Maste 			/* requested glob was not in cache */
220719261079SEd Maste 			debug2("%s line %d: new include %s",
220819261079SEd Maste 			    filename, linenum, arg);
220919261079SEd Maste 			if ((r = glob(arg, 0, NULL, &gbuf)) != 0) {
221019261079SEd Maste 				if (r != GLOB_NOMATCH) {
221119261079SEd Maste 					fatal("%s line %d: include \"%s\" glob "
221219261079SEd Maste 					    "failed", filename, linenum, arg);
221319261079SEd Maste 				}
221419261079SEd Maste 				/*
221519261079SEd Maste 				 * If no entry matched then record a
221619261079SEd Maste 				 * placeholder to skip later glob calls.
221719261079SEd Maste 				 */
221819261079SEd Maste 				debug2("%s line %d: no match for %s",
221919261079SEd Maste 				    filename, linenum, arg);
222019261079SEd Maste 				item = xcalloc(1, sizeof(*item));
222119261079SEd Maste 				item->selector = strdup(arg);
222219261079SEd Maste 				TAILQ_INSERT_TAIL(includes,
222319261079SEd Maste 				    item, entry);
222419261079SEd Maste 			}
222519261079SEd Maste 			if (gbuf.gl_pathc > INT_MAX)
222619261079SEd Maste 				fatal_f("too many glob results");
222719261079SEd Maste 			for (n = 0; n < (int)gbuf.gl_pathc; n++) {
222819261079SEd Maste 				debug2("%s line %d: including %s",
222919261079SEd Maste 				    filename, linenum, gbuf.gl_pathv[n]);
223019261079SEd Maste 				item = xcalloc(1, sizeof(*item));
223119261079SEd Maste 				item->selector = strdup(arg);
223219261079SEd Maste 				item->filename = strdup(gbuf.gl_pathv[n]);
223319261079SEd Maste 				if ((item->contents = sshbuf_new()) == NULL)
223419261079SEd Maste 					fatal_f("sshbuf_new failed");
223519261079SEd Maste 				load_server_config(item->filename,
223619261079SEd Maste 				    item->contents);
223719261079SEd Maste 				parse_server_config_depth(options,
223819261079SEd Maste 				    item->filename, item->contents,
223919261079SEd Maste 				    includes, connectinfo,
224019261079SEd Maste 				    (*inc_flags & SSHCFG_MATCH_ONLY
224119261079SEd Maste 				        ? SSHCFG_MATCH_ONLY : (oactive
224219261079SEd Maste 				            ? 0 : SSHCFG_NEVERMATCH)),
224319261079SEd Maste 				    activep, depth + 1);
224419261079SEd Maste 				*activep = oactive;
224519261079SEd Maste 				TAILQ_INSERT_TAIL(includes, item, entry);
224619261079SEd Maste 			}
224719261079SEd Maste 			globfree(&gbuf);
224819261079SEd Maste 			free(arg);
224919261079SEd Maste 		}
225019261079SEd Maste 		if (value == 0) {
225119261079SEd Maste 			fatal("%s line %d: %s missing filename argument",
225219261079SEd Maste 			    filename, linenum, keyword);
225319261079SEd Maste 		}
225419261079SEd Maste 		break;
225519261079SEd Maste 
2256333ee039SDag-Erling Smørgrav 	case sMatch:
2257333ee039SDag-Erling Smørgrav 		if (cmdline)
2258333ee039SDag-Erling Smørgrav 			fatal("Match directive not supported as a command-line "
2259333ee039SDag-Erling Smørgrav 			    "option");
226019261079SEd Maste 		value = match_cfg_line(&str, linenum,
226119261079SEd Maste 		    (*inc_flags & SSHCFG_NEVERMATCH ? NULL : connectinfo));
2262333ee039SDag-Erling Smørgrav 		if (value < 0)
2263333ee039SDag-Erling Smørgrav 			fatal("%s line %d: Bad Match condition", filename,
2264333ee039SDag-Erling Smørgrav 			    linenum);
226519261079SEd Maste 		*activep = (*inc_flags & SSHCFG_NEVERMATCH) ? 0 : value;
226619261079SEd Maste 		/*
226719261079SEd Maste 		 * The MATCH_ONLY flag is applicable only until the first
226819261079SEd Maste 		 * match block.
226919261079SEd Maste 		 */
227019261079SEd Maste 		*inc_flags &= ~SSHCFG_MATCH_ONLY;
227119261079SEd Maste 		/*
227219261079SEd Maste 		 * If match_cfg_line() didn't consume all its arguments then
227319261079SEd Maste 		 * arrange for the extra arguments check below to fail.
227419261079SEd Maste 		 */
227519261079SEd Maste 		if (str == NULL || *str == '\0')
227619261079SEd Maste 			argv_consume(&ac);
2277333ee039SDag-Erling Smørgrav 		break;
2278333ee039SDag-Erling Smørgrav 
2279190cef3dSDag-Erling Smørgrav 	case sPermitListen:
2280333ee039SDag-Erling Smørgrav 	case sPermitOpen:
2281190cef3dSDag-Erling Smørgrav 		if (opcode == sPermitListen) {
2282190cef3dSDag-Erling Smørgrav 			uintptr = &options->num_permitted_listens;
2283190cef3dSDag-Erling Smørgrav 			chararrayptr = &options->permitted_listens;
2284190cef3dSDag-Erling Smørgrav 		} else {
2285190cef3dSDag-Erling Smørgrav 			uintptr = &options->num_permitted_opens;
2286190cef3dSDag-Erling Smørgrav 			chararrayptr = &options->permitted_opens;
2287190cef3dSDag-Erling Smørgrav 		}
228819261079SEd Maste 		arg = argv_next(&ac, &av);
2289333ee039SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
229019261079SEd Maste 			fatal("%s line %d: %s missing argument.",
229119261079SEd Maste 			    filename, linenum, keyword);
2292190cef3dSDag-Erling Smørgrav 		uvalue = *uintptr;	/* modified later */
22934f52dfbbSDag-Erling Smørgrav 		if (strcmp(arg, "any") == 0 || strcmp(arg, "none") == 0) {
2294190cef3dSDag-Erling Smørgrav 			if (*activep && uvalue == 0) {
2295190cef3dSDag-Erling Smørgrav 				*uintptr = 1;
2296190cef3dSDag-Erling Smørgrav 				*chararrayptr = xcalloc(1,
2297190cef3dSDag-Erling Smørgrav 				    sizeof(**chararrayptr));
2298190cef3dSDag-Erling Smørgrav 				(*chararrayptr)[0] = xstrdup(arg);
2299462c32cbSDag-Erling Smørgrav 			}
2300462c32cbSDag-Erling Smørgrav 			break;
2301462c32cbSDag-Erling Smørgrav 		}
230219261079SEd Maste 		for (; arg != NULL && *arg != '\0'; arg = argv_next(&ac, &av)) {
2303190cef3dSDag-Erling Smørgrav 			if (opcode == sPermitListen &&
2304190cef3dSDag-Erling Smørgrav 			    strchr(arg, ':') == NULL) {
2305190cef3dSDag-Erling Smørgrav 				/*
2306190cef3dSDag-Erling Smørgrav 				 * Allow bare port number for PermitListen
2307190cef3dSDag-Erling Smørgrav 				 * to indicate a wildcard listen host.
2308190cef3dSDag-Erling Smørgrav 				 */
2309190cef3dSDag-Erling Smørgrav 				xasprintf(&arg2, "*:%s", arg);
2310190cef3dSDag-Erling Smørgrav 			} else {
23114f52dfbbSDag-Erling Smørgrav 				arg2 = xstrdup(arg);
23121323ec57SEd Maste 				p = hpdelim(&arg);
23131323ec57SEd Maste 				if (p == NULL) {
231419261079SEd Maste 					fatal("%s line %d: %s missing host",
231519261079SEd Maste 					    filename, linenum, keyword);
2316190cef3dSDag-Erling Smørgrav 				}
2317333ee039SDag-Erling Smørgrav 				p = cleanhostname(p);
2318190cef3dSDag-Erling Smørgrav 			}
2319190cef3dSDag-Erling Smørgrav 			if (arg == NULL ||
2320190cef3dSDag-Erling Smørgrav 			    ((port = permitopen_port(arg)) < 0)) {
232119261079SEd Maste 				fatal("%s line %d: %s bad port number",
232219261079SEd Maste 				    filename, linenum, keyword);
2323190cef3dSDag-Erling Smørgrav 			}
2324190cef3dSDag-Erling Smørgrav 			if (*activep && uvalue == 0) {
232519261079SEd Maste 				opt_array_append(filename, linenum, keyword,
2326190cef3dSDag-Erling Smørgrav 				    chararrayptr, uintptr, arg2);
232747dd1d1bSDag-Erling Smørgrav 			}
23284f52dfbbSDag-Erling Smørgrav 			free(arg2);
2329333ee039SDag-Erling Smørgrav 		}
2330333ee039SDag-Erling Smørgrav 		break;
2331333ee039SDag-Erling Smørgrav 
2332333ee039SDag-Erling Smørgrav 	case sForceCommand:
233319261079SEd Maste 		if (str == NULL || *str == '\0')
233419261079SEd Maste 			fatal("%s line %d: %s missing argument.",
233519261079SEd Maste 			    filename, linenum, keyword);
233619261079SEd Maste 		len = strspn(str, WHITESPACE);
2337333ee039SDag-Erling Smørgrav 		if (*activep && options->adm_forced_command == NULL)
233819261079SEd Maste 			options->adm_forced_command = xstrdup(str + len);
233919261079SEd Maste 		argv_consume(&ac);
234019261079SEd Maste 		break;
2341333ee039SDag-Erling Smørgrav 
2342d4af9e69SDag-Erling Smørgrav 	case sChrootDirectory:
2343d4af9e69SDag-Erling Smørgrav 		charptr = &options->chroot_directory;
2344d4af9e69SDag-Erling Smørgrav 
234519261079SEd Maste 		arg = argv_next(&ac, &av);
2346d4af9e69SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
234719261079SEd Maste 			fatal("%s line %d: %s missing argument.",
234819261079SEd Maste 			    filename, linenum, keyword);
2349d4af9e69SDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
2350d4af9e69SDag-Erling Smørgrav 			*charptr = xstrdup(arg);
2351d4af9e69SDag-Erling Smørgrav 		break;
2352d4af9e69SDag-Erling Smørgrav 
2353b15c8340SDag-Erling Smørgrav 	case sTrustedUserCAKeys:
2354b15c8340SDag-Erling Smørgrav 		charptr = &options->trusted_user_ca_keys;
2355b15c8340SDag-Erling Smørgrav 		goto parse_filename;
2356b15c8340SDag-Erling Smørgrav 
2357b15c8340SDag-Erling Smørgrav 	case sRevokedKeys:
2358b15c8340SDag-Erling Smørgrav 		charptr = &options->revoked_keys_file;
2359b15c8340SDag-Erling Smørgrav 		goto parse_filename;
2360b15c8340SDag-Erling Smørgrav 
236119261079SEd Maste 	case sSecurityKeyProvider:
236219261079SEd Maste 		charptr = &options->sk_provider;
236319261079SEd Maste 		arg = argv_next(&ac, &av);
236419261079SEd Maste 		if (!arg || *arg == '\0')
236519261079SEd Maste 			fatal("%s line %d: %s missing argument.",
236619261079SEd Maste 			    filename, linenum, keyword);
236719261079SEd Maste 		if (*activep && *charptr == NULL) {
236819261079SEd Maste 			*charptr = strcasecmp(arg, "internal") == 0 ?
236919261079SEd Maste 			    xstrdup(arg) : derelativise_path(arg);
237019261079SEd Maste 			/* increase optional counter */
237119261079SEd Maste 			if (intptr != NULL)
237219261079SEd Maste 				*intptr = *intptr + 1;
237319261079SEd Maste 		}
237419261079SEd Maste 		break;
237519261079SEd Maste 
23764a421b63SDag-Erling Smørgrav 	case sIPQoS:
237719261079SEd Maste 		arg = argv_next(&ac, &av);
237819261079SEd Maste 		if (!arg || *arg == '\0')
237919261079SEd Maste 			fatal("%s line %d: %s missing argument.",
238019261079SEd Maste 			    filename, linenum, keyword);
23814a421b63SDag-Erling Smørgrav 		if ((value = parse_ipqos(arg)) == -1)
238219261079SEd Maste 			fatal("%s line %d: Bad %s value: %s",
238319261079SEd Maste 			    filename, linenum, keyword, arg);
238419261079SEd Maste 		arg = argv_next(&ac, &av);
23854a421b63SDag-Erling Smørgrav 		if (arg == NULL)
23864a421b63SDag-Erling Smørgrav 			value2 = value;
23874a421b63SDag-Erling Smørgrav 		else if ((value2 = parse_ipqos(arg)) == -1)
238819261079SEd Maste 			fatal("%s line %d: Bad %s value: %s",
238919261079SEd Maste 			    filename, linenum, keyword, arg);
23904a421b63SDag-Erling Smørgrav 		if (*activep) {
23914a421b63SDag-Erling Smørgrav 			options->ip_qos_interactive = value;
23924a421b63SDag-Erling Smørgrav 			options->ip_qos_bulk = value2;
23934a421b63SDag-Erling Smørgrav 		}
23944a421b63SDag-Erling Smørgrav 		break;
23954a421b63SDag-Erling Smørgrav 
2396db58a8e4SDag-Erling Smørgrav 	case sVersionAddendum:
239719261079SEd Maste 		if (str == NULL || *str == '\0')
239819261079SEd Maste 			fatal("%s line %d: %s missing argument.",
239919261079SEd Maste 			    filename, linenum, keyword);
240019261079SEd Maste 		len = strspn(str, WHITESPACE);
240119261079SEd Maste 		if (strchr(str + len, '\r') != NULL) {
240219261079SEd Maste 			fatal("%.200s line %d: Invalid %s argument",
240319261079SEd Maste 			    filename, linenum, keyword);
2404462c32cbSDag-Erling Smørgrav 		}
240519261079SEd Maste 		if ((arg = strchr(line, '#')) != NULL) {
240619261079SEd Maste 			*arg = '\0';
240719261079SEd Maste 			rtrim(line);
240819261079SEd Maste 		}
240919261079SEd Maste 		if (*activep && options->version_addendum == NULL) {
241019261079SEd Maste 			if (strcasecmp(str + len, "none") == 0)
241119261079SEd Maste 				options->version_addendum = xstrdup("");
241219261079SEd Maste 			else
241319261079SEd Maste 				options->version_addendum = xstrdup(str + len);
241419261079SEd Maste 		}
241519261079SEd Maste 		argv_consume(&ac);
241619261079SEd Maste 		break;
2417db58a8e4SDag-Erling Smørgrav 
24186888a9beSDag-Erling Smørgrav 	case sAuthorizedKeysCommand:
241919261079SEd Maste 		charptr = &options->authorized_keys_command;
242019261079SEd Maste  parse_command:
242119261079SEd Maste 		len = strspn(str, WHITESPACE);
242219261079SEd Maste 		if (str[len] != '/' && strcasecmp(str + len, "none") != 0) {
242319261079SEd Maste 			fatal("%.200s line %d: %s must be an absolute path",
242419261079SEd Maste 			    filename, linenum, keyword);
24256888a9beSDag-Erling Smørgrav 		}
2426*535af610SEd Maste 		if (*activep && *charptr == NULL)
242719261079SEd Maste 			*charptr = xstrdup(str + len);
242819261079SEd Maste 		argv_consume(&ac);
242919261079SEd Maste 		break;
24306888a9beSDag-Erling Smørgrav 
24316888a9beSDag-Erling Smørgrav 	case sAuthorizedKeysCommandUser:
24326888a9beSDag-Erling Smørgrav 		charptr = &options->authorized_keys_command_user;
243319261079SEd Maste  parse_localuser:
243419261079SEd Maste 		arg = argv_next(&ac, &av);
243519261079SEd Maste 		if (!arg || *arg == '\0') {
243619261079SEd Maste 			fatal("%s line %d: missing %s argument.",
243719261079SEd Maste 			    filename, linenum, keyword);
243819261079SEd Maste 		}
24396888a9beSDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
24406888a9beSDag-Erling Smørgrav 			*charptr = xstrdup(arg);
24416888a9beSDag-Erling Smørgrav 		break;
24426888a9beSDag-Erling Smørgrav 
2443557f75e5SDag-Erling Smørgrav 	case sAuthorizedPrincipalsCommand:
244419261079SEd Maste 		charptr = &options->authorized_principals_command;
244519261079SEd Maste 		goto parse_command;
2446557f75e5SDag-Erling Smørgrav 
2447557f75e5SDag-Erling Smørgrav 	case sAuthorizedPrincipalsCommandUser:
2448557f75e5SDag-Erling Smørgrav 		charptr = &options->authorized_principals_command_user;
244919261079SEd Maste 		goto parse_localuser;
2450557f75e5SDag-Erling Smørgrav 
24516888a9beSDag-Erling Smørgrav 	case sAuthenticationMethods:
245219261079SEd Maste 		found = options->num_auth_methods == 0;
2453076ad2f8SDag-Erling Smørgrav 		value = 0; /* seen "any" pseudo-method */
2454190cef3dSDag-Erling Smørgrav 		value2 = 0; /* successfully parsed any method */
245519261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
2456076ad2f8SDag-Erling Smørgrav 			if (strcmp(arg, "any") == 0) {
2457076ad2f8SDag-Erling Smørgrav 				if (options->num_auth_methods > 0) {
245819261079SEd Maste 					fatal("%s line %d: \"any\" must "
245919261079SEd Maste 					    "appear alone in %s",
246019261079SEd Maste 					    filename, linenum, keyword);
2461076ad2f8SDag-Erling Smørgrav 				}
2462076ad2f8SDag-Erling Smørgrav 				value = 1;
2463076ad2f8SDag-Erling Smørgrav 			} else if (value) {
2464076ad2f8SDag-Erling Smørgrav 				fatal("%s line %d: \"any\" must appear "
246519261079SEd Maste 				    "alone in %s", filename, linenum, keyword);
2466076ad2f8SDag-Erling Smørgrav 			} else if (auth2_methods_valid(arg, 0) != 0) {
246719261079SEd Maste 				fatal("%s line %d: invalid %s method list.",
246819261079SEd Maste 				    filename, linenum, keyword);
2469076ad2f8SDag-Erling Smørgrav 			}
2470076ad2f8SDag-Erling Smørgrav 			value2 = 1;
247119261079SEd Maste 			if (!found || !*activep)
2472557f75e5SDag-Erling Smørgrav 				continue;
247319261079SEd Maste 			opt_array_append(filename, linenum, keyword,
247447dd1d1bSDag-Erling Smørgrav 			    &options->auth_methods,
247547dd1d1bSDag-Erling Smørgrav 			    &options->num_auth_methods, arg);
24766888a9beSDag-Erling Smørgrav 		}
2477076ad2f8SDag-Erling Smørgrav 		if (value2 == 0) {
247819261079SEd Maste 			fatal("%s line %d: no %s specified",
247919261079SEd Maste 			    filename, linenum, keyword);
2480076ad2f8SDag-Erling Smørgrav 		}
248119261079SEd Maste 		break;
24826888a9beSDag-Erling Smørgrav 
2483a0ee8cc6SDag-Erling Smørgrav 	case sStreamLocalBindMask:
248419261079SEd Maste 		arg = argv_next(&ac, &av);
2485a0ee8cc6SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
248619261079SEd Maste 			fatal("%s line %d: %s missing argument.",
248719261079SEd Maste 			    filename, linenum, keyword);
2488a0ee8cc6SDag-Erling Smørgrav 		/* Parse mode in octal format */
2489a0ee8cc6SDag-Erling Smørgrav 		value = strtol(arg, &p, 8);
2490a0ee8cc6SDag-Erling Smørgrav 		if (arg == p || value < 0 || value > 0777)
249119261079SEd Maste 			fatal("%s line %d: Invalid %s.",
249219261079SEd Maste 			    filename, linenum, keyword);
2493557f75e5SDag-Erling Smørgrav 		if (*activep)
2494a0ee8cc6SDag-Erling Smørgrav 			options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
2495a0ee8cc6SDag-Erling Smørgrav 		break;
2496a0ee8cc6SDag-Erling Smørgrav 
2497a0ee8cc6SDag-Erling Smørgrav 	case sStreamLocalBindUnlink:
2498a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->fwd_opts.streamlocal_bind_unlink;
2499a0ee8cc6SDag-Erling Smørgrav 		goto parse_flag;
2500a0ee8cc6SDag-Erling Smørgrav 
2501bc5531deSDag-Erling Smørgrav 	case sFingerprintHash:
250219261079SEd Maste 		arg = argv_next(&ac, &av);
2503bc5531deSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
250419261079SEd Maste 			fatal("%s line %d: %s missing argument.",
250519261079SEd Maste 			    filename, linenum, keyword);
2506bc5531deSDag-Erling Smørgrav 		if ((value = ssh_digest_alg_by_name(arg)) == -1)
250719261079SEd Maste 			fatal("%.200s line %d: Invalid %s algorithm \"%s\".",
250819261079SEd Maste 			    filename, linenum, keyword, arg);
2509bc5531deSDag-Erling Smørgrav 		if (*activep)
2510bc5531deSDag-Erling Smørgrav 			options->fingerprint_hash = value;
2511bc5531deSDag-Erling Smørgrav 		break;
2512bc5531deSDag-Erling Smørgrav 
25134f52dfbbSDag-Erling Smørgrav 	case sExposeAuthInfo:
25144f52dfbbSDag-Erling Smørgrav 		intptr = &options->expose_userauth_info;
25154f52dfbbSDag-Erling Smørgrav 		goto parse_flag;
25164f52dfbbSDag-Erling Smørgrav 
251747dd1d1bSDag-Erling Smørgrav 	case sRDomain:
251819261079SEd Maste #if !defined(__OpenBSD__) && !defined(HAVE_SYS_SET_PROCESS_RDOMAIN)
251919261079SEd Maste 		fatal("%s line %d: setting RDomain not supported on this "
252019261079SEd Maste 		    "platform.", filename, linenum);
252119261079SEd Maste #endif
252247dd1d1bSDag-Erling Smørgrav 		charptr = &options->routing_domain;
252319261079SEd Maste 		arg = argv_next(&ac, &av);
252447dd1d1bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
252519261079SEd Maste 			fatal("%s line %d: %s missing argument.",
252619261079SEd Maste 			    filename, linenum, keyword);
252747dd1d1bSDag-Erling Smørgrav 		if (strcasecmp(arg, "none") != 0 && strcmp(arg, "%D") != 0 &&
252847dd1d1bSDag-Erling Smørgrav 		    !valid_rdomain(arg))
252919261079SEd Maste 			fatal("%s line %d: invalid routing domain",
253047dd1d1bSDag-Erling Smørgrav 			    filename, linenum);
253147dd1d1bSDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
253247dd1d1bSDag-Erling Smørgrav 			*charptr = xstrdup(arg);
253347dd1d1bSDag-Erling Smørgrav 		break;
253447dd1d1bSDag-Erling Smørgrav 
253538a52bd3SEd Maste 	case sRequiredRSASize:
253638a52bd3SEd Maste 		intptr = &options->required_rsa_size;
253738a52bd3SEd Maste 		goto parse_int;
253838a52bd3SEd Maste 
2539f374ba41SEd Maste 	case sChannelTimeout:
2540f374ba41SEd Maste 		uvalue = options->num_channel_timeouts;
2541f374ba41SEd Maste 		i = 0;
2542f374ba41SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
2543f374ba41SEd Maste 			/* Allow "none" only in first position */
2544f374ba41SEd Maste 			if (strcasecmp(arg, "none") == 0) {
2545f374ba41SEd Maste 				if (i > 0 || ac > 0) {
2546f374ba41SEd Maste 					error("%s line %d: keyword %s \"none\" "
2547f374ba41SEd Maste 					    "argument must appear alone.",
2548f374ba41SEd Maste 					    filename, linenum, keyword);
2549f374ba41SEd Maste 					goto out;
2550f374ba41SEd Maste 				}
2551f374ba41SEd Maste 			} else if (parse_timeout(arg, NULL, NULL) != 0) {
2552f374ba41SEd Maste 				fatal("%s line %d: invalid channel timeout %s",
2553f374ba41SEd Maste 				    filename, linenum, arg);
2554f374ba41SEd Maste 			}
2555f374ba41SEd Maste 			if (!*activep || uvalue != 0)
2556f374ba41SEd Maste 				continue;
2557f374ba41SEd Maste 			opt_array_append(filename, linenum, keyword,
2558f374ba41SEd Maste 			    &options->channel_timeouts,
2559f374ba41SEd Maste 			    &options->num_channel_timeouts, arg);
2560f374ba41SEd Maste 		}
2561f374ba41SEd Maste 		break;
2562f374ba41SEd Maste 
2563f374ba41SEd Maste 	case sUnusedConnectionTimeout:
2564f374ba41SEd Maste 		intptr = &options->unused_connection_timeout;
2565f374ba41SEd Maste 		/* peek at first arg for "none" so we can reuse parse_time */
2566f374ba41SEd Maste 		if (av[0] != NULL && strcasecmp(av[0], "none") == 0) {
2567f374ba41SEd Maste 			(void)argv_next(&ac, &av); /* consume arg */
2568f374ba41SEd Maste 			if (*activep)
2569f374ba41SEd Maste 				*intptr = 0;
2570f374ba41SEd Maste 			break;
2571f374ba41SEd Maste 		}
2572f374ba41SEd Maste 		goto parse_time;
2573f374ba41SEd Maste 
2574b2af61ecSKurt Lidl 	case sUseBlacklist:
2575b2af61ecSKurt Lidl 		intptr = &options->use_blacklist;
2576b2af61ecSKurt Lidl 		goto parse_flag;
2577b2af61ecSKurt Lidl 
2578af12a3e7SDag-Erling Smørgrav 	case sDeprecated:
2579ca86bcf2SDag-Erling Smørgrav 	case sIgnore:
2580cf2b5f3bSDag-Erling Smørgrav 	case sUnsupported:
2581ca86bcf2SDag-Erling Smørgrav 		do_log2(opcode == sIgnore ?
2582ca86bcf2SDag-Erling Smørgrav 		    SYSLOG_LEVEL_DEBUG2 : SYSLOG_LEVEL_INFO,
2583ca86bcf2SDag-Erling Smørgrav 		    "%s line %d: %s option %s", filename, linenum,
258419261079SEd Maste 		    opcode == sUnsupported ? "Unsupported" : "Deprecated",
258519261079SEd Maste 		    keyword);
258619261079SEd Maste 		argv_consume(&ac);
2587af12a3e7SDag-Erling Smørgrav 		break;
2588af12a3e7SDag-Erling Smørgrav 
258942f71286SMark Murray 	default:
2590af12a3e7SDag-Erling Smørgrav 		fatal("%s line %d: Missing handler for opcode %s (%d)",
259119261079SEd Maste 		    filename, linenum, keyword, opcode);
2592511b41d2SMark Murray 	}
259319261079SEd Maste 	/* Check that there is no garbage at end of line. */
259419261079SEd Maste 	if (ac > 0) {
259519261079SEd Maste 		error("%.200s line %d: keyword %s extra arguments "
259619261079SEd Maste 		    "at end of line", filename, linenum, keyword);
259719261079SEd Maste 		goto out;
2598af12a3e7SDag-Erling Smørgrav 	}
2599af12a3e7SDag-Erling Smørgrav 
260019261079SEd Maste 	/* success */
260119261079SEd Maste 	ret = 0;
260219261079SEd Maste  out:
260319261079SEd Maste 	argv_free(oav, oac);
260419261079SEd Maste 	return ret;
260519261079SEd Maste }
260619261079SEd Maste 
260719261079SEd Maste int
260819261079SEd Maste process_server_config_line(ServerOptions *options, char *line,
260919261079SEd Maste     const char *filename, int linenum, int *activep,
261019261079SEd Maste     struct connection_info *connectinfo, struct include_list *includes)
261119261079SEd Maste {
261219261079SEd Maste 	int inc_flags = 0;
261319261079SEd Maste 
261419261079SEd Maste 	return process_server_config_line_depth(options, line, filename,
261519261079SEd Maste 	    linenum, activep, connectinfo, &inc_flags, 0, includes);
261619261079SEd Maste }
261719261079SEd Maste 
261819261079SEd Maste 
2619af12a3e7SDag-Erling Smørgrav /* Reads the server configuration file. */
2620af12a3e7SDag-Erling Smørgrav 
2621af12a3e7SDag-Erling Smørgrav void
2622190cef3dSDag-Erling Smørgrav load_server_config(const char *filename, struct sshbuf *conf)
2623af12a3e7SDag-Erling Smørgrav {
262419261079SEd Maste 	struct stat st;
2625190cef3dSDag-Erling Smørgrav 	char *line = NULL, *cp;
2626190cef3dSDag-Erling Smørgrav 	size_t linesize = 0;
2627a82e551fSDag-Erling Smørgrav 	FILE *f;
2628f374ba41SEd Maste 	int r;
2629af12a3e7SDag-Erling Smørgrav 
263019261079SEd Maste 	debug2_f("filename %s", filename);
263121e764dfSDag-Erling Smørgrav 	if ((f = fopen(filename, "r")) == NULL) {
2632af12a3e7SDag-Erling Smørgrav 		perror(filename);
2633af12a3e7SDag-Erling Smørgrav 		exit(1);
2634af12a3e7SDag-Erling Smørgrav 	}
2635190cef3dSDag-Erling Smørgrav 	sshbuf_reset(conf);
263619261079SEd Maste 	/* grow buffer, so realloc is avoided for large config files */
263719261079SEd Maste 	if (fstat(fileno(f), &st) == 0 && st.st_size > 0 &&
263819261079SEd Maste 	    (r = sshbuf_allocate(conf, st.st_size)) != 0)
263919261079SEd Maste 		fatal_fr(r, "allocate");
2640190cef3dSDag-Erling Smørgrav 	while (getline(&line, &linesize, f) != -1) {
264121e764dfSDag-Erling Smørgrav 		/*
264219261079SEd Maste 		 * Strip whitespace
264321e764dfSDag-Erling Smørgrav 		 * NB - preserve newlines, they are needed to reproduce
264421e764dfSDag-Erling Smørgrav 		 * line numbers later for error messages
264521e764dfSDag-Erling Smørgrav 		 */
264621e764dfSDag-Erling Smørgrav 		cp = line + strspn(line, " \t\r");
2647190cef3dSDag-Erling Smørgrav 		if ((r = sshbuf_put(conf, cp, strlen(cp))) != 0)
264819261079SEd Maste 			fatal_fr(r, "sshbuf_put");
264921e764dfSDag-Erling Smørgrav 	}
2650190cef3dSDag-Erling Smørgrav 	free(line);
2651190cef3dSDag-Erling Smørgrav 	if ((r = sshbuf_put_u8(conf, 0)) != 0)
265219261079SEd Maste 		fatal_fr(r, "sshbuf_put_u8");
265321e764dfSDag-Erling Smørgrav 	fclose(f);
265419261079SEd Maste 	debug2_f("done config len = %zu", sshbuf_len(conf));
265521e764dfSDag-Erling Smørgrav }
265621e764dfSDag-Erling Smørgrav 
265721e764dfSDag-Erling Smørgrav void
2658462c32cbSDag-Erling Smørgrav parse_server_match_config(ServerOptions *options,
265919261079SEd Maste    struct include_list *includes, struct connection_info *connectinfo)
266021e764dfSDag-Erling Smørgrav {
2661333ee039SDag-Erling Smørgrav 	ServerOptions mo;
2662333ee039SDag-Erling Smørgrav 
2663333ee039SDag-Erling Smørgrav 	initialize_server_options(&mo);
266419261079SEd Maste 	parse_server_config(&mo, "reprocess config", cfg, includes,
266587c1498dSEd Maste 	    connectinfo, 0);
2666d4af9e69SDag-Erling Smørgrav 	copy_set_server_options(options, &mo, 0);
2667333ee039SDag-Erling Smørgrav }
2668333ee039SDag-Erling Smørgrav 
2669462c32cbSDag-Erling Smørgrav int parse_server_match_testspec(struct connection_info *ci, char *spec)
2670462c32cbSDag-Erling Smørgrav {
2671462c32cbSDag-Erling Smørgrav 	char *p;
2672462c32cbSDag-Erling Smørgrav 
2673462c32cbSDag-Erling Smørgrav 	while ((p = strsep(&spec, ",")) && *p != '\0') {
2674462c32cbSDag-Erling Smørgrav 		if (strncmp(p, "addr=", 5) == 0) {
2675462c32cbSDag-Erling Smørgrav 			ci->address = xstrdup(p + 5);
2676462c32cbSDag-Erling Smørgrav 		} else if (strncmp(p, "host=", 5) == 0) {
2677462c32cbSDag-Erling Smørgrav 			ci->host = xstrdup(p + 5);
2678462c32cbSDag-Erling Smørgrav 		} else if (strncmp(p, "user=", 5) == 0) {
2679462c32cbSDag-Erling Smørgrav 			ci->user = xstrdup(p + 5);
2680462c32cbSDag-Erling Smørgrav 		} else if (strncmp(p, "laddr=", 6) == 0) {
2681462c32cbSDag-Erling Smørgrav 			ci->laddress = xstrdup(p + 6);
268247dd1d1bSDag-Erling Smørgrav 		} else if (strncmp(p, "rdomain=", 8) == 0) {
268347dd1d1bSDag-Erling Smørgrav 			ci->rdomain = xstrdup(p + 8);
2684462c32cbSDag-Erling Smørgrav 		} else if (strncmp(p, "lport=", 6) == 0) {
2685462c32cbSDag-Erling Smørgrav 			ci->lport = a2port(p + 6);
2686462c32cbSDag-Erling Smørgrav 			if (ci->lport == -1) {
2687462c32cbSDag-Erling Smørgrav 				fprintf(stderr, "Invalid port '%s' in test mode"
2688462c32cbSDag-Erling Smørgrav 				    " specification %s\n", p+6, p);
2689462c32cbSDag-Erling Smørgrav 				return -1;
2690462c32cbSDag-Erling Smørgrav 			}
2691462c32cbSDag-Erling Smørgrav 		} else {
2692462c32cbSDag-Erling Smørgrav 			fprintf(stderr, "Invalid test mode specification %s\n",
2693462c32cbSDag-Erling Smørgrav 			    p);
2694462c32cbSDag-Erling Smørgrav 			return -1;
2695462c32cbSDag-Erling Smørgrav 		}
2696462c32cbSDag-Erling Smørgrav 	}
2697462c32cbSDag-Erling Smørgrav 	return 0;
2698462c32cbSDag-Erling Smørgrav }
2699462c32cbSDag-Erling Smørgrav 
2700462c32cbSDag-Erling Smørgrav /*
2701d4af9e69SDag-Erling Smørgrav  * Copy any supported values that are set.
2702d4af9e69SDag-Erling Smørgrav  *
27037aee6ffeSDag-Erling Smørgrav  * If the preauth flag is set, we do not bother copying the string or
2704d4af9e69SDag-Erling Smørgrav  * array values that are not used pre-authentication, because any that we
2705190cef3dSDag-Erling Smørgrav  * do use must be explicitly sent in mm_getpwnamallow().
2706d4af9e69SDag-Erling Smørgrav  */
2707333ee039SDag-Erling Smørgrav void
2708d4af9e69SDag-Erling Smørgrav copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
2709333ee039SDag-Erling Smørgrav {
2710f7167e0eSDag-Erling Smørgrav #define M_CP_INTOPT(n) do {\
2711f7167e0eSDag-Erling Smørgrav 	if (src->n != -1) \
2712f7167e0eSDag-Erling Smørgrav 		dst->n = src->n; \
2713f7167e0eSDag-Erling Smørgrav } while (0)
2714f7167e0eSDag-Erling Smørgrav 
2715d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(password_authentication);
2716d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(gss_authentication);
2717d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(pubkey_authentication);
271819261079SEd Maste 	M_CP_INTOPT(pubkey_auth_options);
2719d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(kerberos_authentication);
2720d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(hostbased_authentication);
2721e2f6069cSDag-Erling Smørgrav 	M_CP_INTOPT(hostbased_uses_name_from_packet_only);
2722d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(kbd_interactive_authentication);
2723d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(permit_root_login);
2724cce7d346SDag-Erling Smørgrav 	M_CP_INTOPT(permit_empty_passwd);
272519261079SEd Maste 	M_CP_INTOPT(ignore_rhosts);
2726d4af9e69SDag-Erling Smørgrav 
2727d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(allow_tcp_forwarding);
2728a0ee8cc6SDag-Erling Smørgrav 	M_CP_INTOPT(allow_streamlocal_forwarding);
2729d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(allow_agent_forwarding);
2730ca86bcf2SDag-Erling Smørgrav 	M_CP_INTOPT(disable_forwarding);
27314f52dfbbSDag-Erling Smørgrav 	M_CP_INTOPT(expose_userauth_info);
2732e2f6069cSDag-Erling Smørgrav 	M_CP_INTOPT(permit_tun);
2733a0ee8cc6SDag-Erling Smørgrav 	M_CP_INTOPT(fwd_opts.gateway_ports);
2734076ad2f8SDag-Erling Smørgrav 	M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink);
2735d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(x11_display_offset);
2736d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(x11_forwarding);
2737d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(x11_use_localhost);
2738f7167e0eSDag-Erling Smørgrav 	M_CP_INTOPT(permit_tty);
2739a0ee8cc6SDag-Erling Smørgrav 	M_CP_INTOPT(permit_user_rc);
2740d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(max_sessions);
2741d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(max_authtries);
2742ca86bcf2SDag-Erling Smørgrav 	M_CP_INTOPT(client_alive_count_max);
2743ca86bcf2SDag-Erling Smørgrav 	M_CP_INTOPT(client_alive_interval);
27444a421b63SDag-Erling Smørgrav 	M_CP_INTOPT(ip_qos_interactive);
27454a421b63SDag-Erling Smørgrav 	M_CP_INTOPT(ip_qos_bulk);
2746e4a9863fSDag-Erling Smørgrav 	M_CP_INTOPT(rekey_limit);
2747e4a9863fSDag-Erling Smørgrav 	M_CP_INTOPT(rekey_interval);
27484f52dfbbSDag-Erling Smørgrav 	M_CP_INTOPT(log_level);
274938a52bd3SEd Maste 	M_CP_INTOPT(required_rsa_size);
2750f374ba41SEd Maste 	M_CP_INTOPT(unused_connection_timeout);
2751d4af9e69SDag-Erling Smørgrav 
2752076ad2f8SDag-Erling Smørgrav 	/*
2753076ad2f8SDag-Erling Smørgrav 	 * The bind_mask is a mode_t that may be unsigned, so we can't use
2754076ad2f8SDag-Erling Smørgrav 	 * M_CP_INTOPT - it does a signed comparison that causes compiler
2755076ad2f8SDag-Erling Smørgrav 	 * warnings.
2756076ad2f8SDag-Erling Smørgrav 	 */
2757076ad2f8SDag-Erling Smørgrav 	if (src->fwd_opts.streamlocal_bind_mask != (mode_t)-1) {
2758076ad2f8SDag-Erling Smørgrav 		dst->fwd_opts.streamlocal_bind_mask =
2759076ad2f8SDag-Erling Smørgrav 		    src->fwd_opts.streamlocal_bind_mask;
2760076ad2f8SDag-Erling Smørgrav 	}
2761076ad2f8SDag-Erling Smørgrav 
2762f7167e0eSDag-Erling Smørgrav 	/* M_CP_STROPT and M_CP_STRARRAYOPT should not appear before here */
2763f7167e0eSDag-Erling Smørgrav #define M_CP_STROPT(n) do {\
2764f7167e0eSDag-Erling Smørgrav 	if (src->n != NULL && dst->n != src->n) { \
2765f7167e0eSDag-Erling Smørgrav 		free(dst->n); \
2766f7167e0eSDag-Erling Smørgrav 		dst->n = src->n; \
2767f7167e0eSDag-Erling Smørgrav 	} \
2768f7167e0eSDag-Erling Smørgrav } while(0)
276947dd1d1bSDag-Erling Smørgrav #define M_CP_STRARRAYOPT(s, num_s) do {\
277047dd1d1bSDag-Erling Smørgrav 	u_int i; \
277147dd1d1bSDag-Erling Smørgrav 	if (src->num_s != 0) { \
277247dd1d1bSDag-Erling Smørgrav 		for (i = 0; i < dst->num_s; i++) \
277347dd1d1bSDag-Erling Smørgrav 			free(dst->s[i]); \
277447dd1d1bSDag-Erling Smørgrav 		free(dst->s); \
277547dd1d1bSDag-Erling Smørgrav 		dst->s = xcalloc(src->num_s, sizeof(*dst->s)); \
277647dd1d1bSDag-Erling Smørgrav 		for (i = 0; i < src->num_s; i++) \
277747dd1d1bSDag-Erling Smørgrav 			dst->s[i] = xstrdup(src->s[i]); \
277847dd1d1bSDag-Erling Smørgrav 		dst->num_s = src->num_s; \
27794f52dfbbSDag-Erling Smørgrav 	} \
27804f52dfbbSDag-Erling Smørgrav } while(0)
2781f7167e0eSDag-Erling Smørgrav 
2782e146993eSDag-Erling Smørgrav 	/* See comment in servconf.h */
2783e146993eSDag-Erling Smørgrav 	COPY_MATCH_STRING_OPTS();
2784e146993eSDag-Erling Smørgrav 
2785acc1a9efSDag-Erling Smørgrav 	/* Arguments that accept '+...' need to be expanded */
2786acc1a9efSDag-Erling Smørgrav 	assemble_algorithms(dst);
2787acc1a9efSDag-Erling Smørgrav 
2788e146993eSDag-Erling Smørgrav 	/*
2789e146993eSDag-Erling Smørgrav 	 * The only things that should be below this point are string options
2790e146993eSDag-Erling Smørgrav 	 * which are only used after authentication.
2791e146993eSDag-Erling Smørgrav 	 */
2792d4af9e69SDag-Erling Smørgrav 	if (preauth)
2793d4af9e69SDag-Erling Smørgrav 		return;
2794e146993eSDag-Erling Smørgrav 
2795acc1a9efSDag-Erling Smørgrav 	/* These options may be "none" to clear a global setting */
2796d4af9e69SDag-Erling Smørgrav 	M_CP_STROPT(adm_forced_command);
2797acc1a9efSDag-Erling Smørgrav 	if (option_clear_or_none(dst->adm_forced_command)) {
2798acc1a9efSDag-Erling Smørgrav 		free(dst->adm_forced_command);
2799acc1a9efSDag-Erling Smørgrav 		dst->adm_forced_command = NULL;
2800acc1a9efSDag-Erling Smørgrav 	}
2801d4af9e69SDag-Erling Smørgrav 	M_CP_STROPT(chroot_directory);
2802acc1a9efSDag-Erling Smørgrav 	if (option_clear_or_none(dst->chroot_directory)) {
2803acc1a9efSDag-Erling Smørgrav 		free(dst->chroot_directory);
2804acc1a9efSDag-Erling Smørgrav 		dst->chroot_directory = NULL;
2805acc1a9efSDag-Erling Smørgrav 	}
2806333ee039SDag-Erling Smørgrav }
2807d4af9e69SDag-Erling Smørgrav 
2808d4af9e69SDag-Erling Smørgrav #undef M_CP_INTOPT
2809d4af9e69SDag-Erling Smørgrav #undef M_CP_STROPT
2810e146993eSDag-Erling Smørgrav #undef M_CP_STRARRAYOPT
2811333ee039SDag-Erling Smørgrav 
281219261079SEd Maste #define SERVCONF_MAX_DEPTH	16
281319261079SEd Maste static void
281419261079SEd Maste parse_server_config_depth(ServerOptions *options, const char *filename,
281519261079SEd Maste     struct sshbuf *conf, struct include_list *includes,
281619261079SEd Maste     struct connection_info *connectinfo, int flags, int *activep, int depth)
2817333ee039SDag-Erling Smørgrav {
281819261079SEd Maste 	int linenum, bad_options = 0;
281921e764dfSDag-Erling Smørgrav 	char *cp, *obuf, *cbuf;
282021e764dfSDag-Erling Smørgrav 
282119261079SEd Maste 	if (depth < 0 || depth > SERVCONF_MAX_DEPTH)
282219261079SEd Maste 		fatal("Too many recursive configuration includes");
282319261079SEd Maste 
282419261079SEd Maste 	debug2_f("config %s len %zu%s", filename, sshbuf_len(conf),
282519261079SEd Maste 	    (flags & SSHCFG_NEVERMATCH ? " [checking syntax only]" : ""));
282621e764dfSDag-Erling Smørgrav 
2827076ad2f8SDag-Erling Smørgrav 	if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL)
282819261079SEd Maste 		fatal_f("sshbuf_dup_string failed");
282921e764dfSDag-Erling Smørgrav 	linenum = 1;
283021e764dfSDag-Erling Smørgrav 	while ((cp = strsep(&cbuf, "\n")) != NULL) {
283119261079SEd Maste 		if (process_server_config_line_depth(options, cp,
283219261079SEd Maste 		    filename, linenum++, activep, connectinfo, &flags,
283319261079SEd Maste 		    depth, includes) != 0)
2834af12a3e7SDag-Erling Smørgrav 			bad_options++;
2835511b41d2SMark Murray 	}
2836e4a9863fSDag-Erling Smørgrav 	free(obuf);
2837ca3176e7SBrian Feldman 	if (bad_options > 0)
2838af12a3e7SDag-Erling Smørgrav 		fatal("%s: terminating, %d bad configuration options",
2839511b41d2SMark Murray 		    filename, bad_options);
284019261079SEd Maste }
284119261079SEd Maste 
284219261079SEd Maste void
284319261079SEd Maste parse_server_config(ServerOptions *options, const char *filename,
284419261079SEd Maste     struct sshbuf *conf, struct include_list *includes,
284587c1498dSEd Maste     struct connection_info *connectinfo, int reexec)
284619261079SEd Maste {
284719261079SEd Maste 	int active = connectinfo ? 0 : 1;
284819261079SEd Maste 	parse_server_config_depth(options, filename, conf, includes,
284919261079SEd Maste 	    connectinfo, (connectinfo ? SSHCFG_MATCH_ONLY : 0), &active, 0);
285087c1498dSEd Maste 	if (!reexec)
2851557f75e5SDag-Erling Smørgrav 		process_queued_listen_addrs(options);
2852511b41d2SMark Murray }
2853d4af9e69SDag-Erling Smørgrav 
2854d4af9e69SDag-Erling Smørgrav static const char *
2855e146993eSDag-Erling Smørgrav fmt_multistate_int(int val, const struct multistate *m)
2856d4af9e69SDag-Erling Smørgrav {
2857e146993eSDag-Erling Smørgrav 	u_int i;
2858e146993eSDag-Erling Smørgrav 
2859e146993eSDag-Erling Smørgrav 	for (i = 0; m[i].key != NULL; i++) {
2860e146993eSDag-Erling Smørgrav 		if (m[i].value == val)
2861e146993eSDag-Erling Smørgrav 			return m[i].key;
2862e146993eSDag-Erling Smørgrav 	}
2863d4af9e69SDag-Erling Smørgrav 	return "UNKNOWN";
2864d4af9e69SDag-Erling Smørgrav }
2865e146993eSDag-Erling Smørgrav 
2866e146993eSDag-Erling Smørgrav static const char *
2867e146993eSDag-Erling Smørgrav fmt_intarg(ServerOpCodes code, int val)
2868e146993eSDag-Erling Smørgrav {
2869e146993eSDag-Erling Smørgrav 	if (val == -1)
2870e146993eSDag-Erling Smørgrav 		return "unset";
2871e146993eSDag-Erling Smørgrav 	switch (code) {
2872e146993eSDag-Erling Smørgrav 	case sAddressFamily:
2873e146993eSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_addressfamily);
2874e146993eSDag-Erling Smørgrav 	case sPermitRootLogin:
2875e146993eSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_permitrootlogin);
2876e146993eSDag-Erling Smørgrav 	case sGatewayPorts:
2877e146993eSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_gatewayports);
2878e146993eSDag-Erling Smørgrav 	case sCompression:
2879e146993eSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_compression);
28806888a9beSDag-Erling Smørgrav 	case sAllowTcpForwarding:
28816888a9beSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_tcpfwd);
2882a0ee8cc6SDag-Erling Smørgrav 	case sAllowStreamLocalForwarding:
2883a0ee8cc6SDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_tcpfwd);
288419261079SEd Maste 	case sIgnoreRhosts:
288519261079SEd Maste 		return fmt_multistate_int(val, multistate_ignore_rhosts);
2886bc5531deSDag-Erling Smørgrav 	case sFingerprintHash:
2887bc5531deSDag-Erling Smørgrav 		return ssh_digest_alg_name(val);
2888e146993eSDag-Erling Smørgrav 	default:
2889d4af9e69SDag-Erling Smørgrav 		switch (val) {
2890d4af9e69SDag-Erling Smørgrav 		case 0:
2891d4af9e69SDag-Erling Smørgrav 			return "no";
2892d4af9e69SDag-Erling Smørgrav 		case 1:
2893d4af9e69SDag-Erling Smørgrav 			return "yes";
2894e146993eSDag-Erling Smørgrav 		default:
2895d4af9e69SDag-Erling Smørgrav 			return "UNKNOWN";
2896d4af9e69SDag-Erling Smørgrav 		}
2897e146993eSDag-Erling Smørgrav 	}
2898e146993eSDag-Erling Smørgrav }
2899d4af9e69SDag-Erling Smørgrav 
2900d4af9e69SDag-Erling Smørgrav static void
2901d4af9e69SDag-Erling Smørgrav dump_cfg_int(ServerOpCodes code, int val)
2902d4af9e69SDag-Erling Smørgrav {
2903f374ba41SEd Maste 	if (code == sUnusedConnectionTimeout && val == 0) {
2904f374ba41SEd Maste 		printf("%s none\n", lookup_opcode_name(code));
2905f374ba41SEd Maste 		return;
2906f374ba41SEd Maste 	}
2907d4af9e69SDag-Erling Smørgrav 	printf("%s %d\n", lookup_opcode_name(code), val);
2908d4af9e69SDag-Erling Smørgrav }
2909d4af9e69SDag-Erling Smørgrav 
2910d4af9e69SDag-Erling Smørgrav static void
2911557f75e5SDag-Erling Smørgrav dump_cfg_oct(ServerOpCodes code, int val)
2912557f75e5SDag-Erling Smørgrav {
2913557f75e5SDag-Erling Smørgrav 	printf("%s 0%o\n", lookup_opcode_name(code), val);
2914557f75e5SDag-Erling Smørgrav }
2915557f75e5SDag-Erling Smørgrav 
2916557f75e5SDag-Erling Smørgrav static void
2917d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(ServerOpCodes code, int val)
2918d4af9e69SDag-Erling Smørgrav {
2919d4af9e69SDag-Erling Smørgrav 	printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
2920d4af9e69SDag-Erling Smørgrav }
2921d4af9e69SDag-Erling Smørgrav 
2922d4af9e69SDag-Erling Smørgrav static void
2923d4af9e69SDag-Erling Smørgrav dump_cfg_string(ServerOpCodes code, const char *val)
2924d4af9e69SDag-Erling Smørgrav {
2925bc5531deSDag-Erling Smørgrav 	printf("%s %s\n", lookup_opcode_name(code),
2926bc5531deSDag-Erling Smørgrav 	    val == NULL ? "none" : val);
2927d4af9e69SDag-Erling Smørgrav }
2928d4af9e69SDag-Erling Smørgrav 
2929d4af9e69SDag-Erling Smørgrav static void
2930d4af9e69SDag-Erling Smørgrav dump_cfg_strarray(ServerOpCodes code, u_int count, char **vals)
2931d4af9e69SDag-Erling Smørgrav {
2932d4af9e69SDag-Erling Smørgrav 	u_int i;
2933d4af9e69SDag-Erling Smørgrav 
2934d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < count; i++)
2935d4af9e69SDag-Erling Smørgrav 		printf("%s %s\n", lookup_opcode_name(code), vals[i]);
2936d4af9e69SDag-Erling Smørgrav }
2937d4af9e69SDag-Erling Smørgrav 
2938e146993eSDag-Erling Smørgrav static void
2939e146993eSDag-Erling Smørgrav dump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals)
2940e146993eSDag-Erling Smørgrav {
2941e146993eSDag-Erling Smørgrav 	u_int i;
2942e146993eSDag-Erling Smørgrav 
29434d3fc8b0SEd Maste 	switch (code) {
29444d3fc8b0SEd Maste 	case sAuthenticationMethods:
29454d3fc8b0SEd Maste 	case sChannelTimeout:
29464d3fc8b0SEd Maste 		break;
29474d3fc8b0SEd Maste 	default:
29484d3fc8b0SEd Maste 		if (count <= 0)
2949557f75e5SDag-Erling Smørgrav 			return;
29504d3fc8b0SEd Maste 		break;
29514d3fc8b0SEd Maste 	}
29524d3fc8b0SEd Maste 
2953e146993eSDag-Erling Smørgrav 	printf("%s", lookup_opcode_name(code));
2954e146993eSDag-Erling Smørgrav 	for (i = 0; i < count; i++)
2955e146993eSDag-Erling Smørgrav 		printf(" %s",  vals[i]);
2956076ad2f8SDag-Erling Smørgrav 	if (code == sAuthenticationMethods && count == 0)
2957076ad2f8SDag-Erling Smørgrav 		printf(" any");
2958f374ba41SEd Maste 	else if (code == sChannelTimeout && count == 0)
2959f374ba41SEd Maste 		printf(" none");
2960e146993eSDag-Erling Smørgrav 	printf("\n");
2961e146993eSDag-Erling Smørgrav }
2962e146993eSDag-Erling Smørgrav 
296347dd1d1bSDag-Erling Smørgrav static char *
296447dd1d1bSDag-Erling Smørgrav format_listen_addrs(struct listenaddr *la)
2965d4af9e69SDag-Erling Smørgrav {
296647dd1d1bSDag-Erling Smørgrav 	int r;
2967d4af9e69SDag-Erling Smørgrav 	struct addrinfo *ai;
296847dd1d1bSDag-Erling Smørgrav 	char addr[NI_MAXHOST], port[NI_MAXSERV];
2969557f75e5SDag-Erling Smørgrav 	char *laddr1 = xstrdup(""), *laddr2 = NULL;
2970d4af9e69SDag-Erling Smørgrav 
2971557f75e5SDag-Erling Smørgrav 	/*
2972557f75e5SDag-Erling Smørgrav 	 * ListenAddress must be after Port.  add_one_listen_addr pushes
2973557f75e5SDag-Erling Smørgrav 	 * addresses onto a stack, so to maintain ordering we need to
2974557f75e5SDag-Erling Smørgrav 	 * print these in reverse order.
2975557f75e5SDag-Erling Smørgrav 	 */
297647dd1d1bSDag-Erling Smørgrav 	for (ai = la->addrs; ai; ai = ai->ai_next) {
297747dd1d1bSDag-Erling Smørgrav 		if ((r = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
2978d4af9e69SDag-Erling Smørgrav 		    sizeof(addr), port, sizeof(port),
2979d4af9e69SDag-Erling Smørgrav 		    NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
298047dd1d1bSDag-Erling Smørgrav 			error("getnameinfo: %.100s", ssh_gai_strerror(r));
298147dd1d1bSDag-Erling Smørgrav 			continue;
298247dd1d1bSDag-Erling Smørgrav 		}
2983557f75e5SDag-Erling Smørgrav 		laddr2 = laddr1;
298447dd1d1bSDag-Erling Smørgrav 		if (ai->ai_family == AF_INET6) {
298547dd1d1bSDag-Erling Smørgrav 			xasprintf(&laddr1, "listenaddress [%s]:%s%s%s\n%s",
298647dd1d1bSDag-Erling Smørgrav 			    addr, port,
298747dd1d1bSDag-Erling Smørgrav 			    la->rdomain == NULL ? "" : " rdomain ",
298847dd1d1bSDag-Erling Smørgrav 			    la->rdomain == NULL ? "" : la->rdomain,
298947dd1d1bSDag-Erling Smørgrav 			    laddr2);
299047dd1d1bSDag-Erling Smørgrav 		} else {
299147dd1d1bSDag-Erling Smørgrav 			xasprintf(&laddr1, "listenaddress %s:%s%s%s\n%s",
299247dd1d1bSDag-Erling Smørgrav 			    addr, port,
299347dd1d1bSDag-Erling Smørgrav 			    la->rdomain == NULL ? "" : " rdomain ",
299447dd1d1bSDag-Erling Smørgrav 			    la->rdomain == NULL ? "" : la->rdomain,
299547dd1d1bSDag-Erling Smørgrav 			    laddr2);
299647dd1d1bSDag-Erling Smørgrav 		}
2997557f75e5SDag-Erling Smørgrav 		free(laddr2);
2998d4af9e69SDag-Erling Smørgrav 	}
299947dd1d1bSDag-Erling Smørgrav 	return laddr1;
3000d4af9e69SDag-Erling Smørgrav }
300147dd1d1bSDag-Erling Smørgrav 
300247dd1d1bSDag-Erling Smørgrav void
300347dd1d1bSDag-Erling Smørgrav dump_config(ServerOptions *o)
300447dd1d1bSDag-Erling Smørgrav {
300547dd1d1bSDag-Erling Smørgrav 	char *s;
300647dd1d1bSDag-Erling Smørgrav 	u_int i;
300747dd1d1bSDag-Erling Smørgrav 
300847dd1d1bSDag-Erling Smørgrav 	/* these are usually at the top of the config */
300947dd1d1bSDag-Erling Smørgrav 	for (i = 0; i < o->num_ports; i++)
301047dd1d1bSDag-Erling Smørgrav 		printf("port %d\n", o->ports[i]);
301147dd1d1bSDag-Erling Smørgrav 	dump_cfg_fmtint(sAddressFamily, o->address_family);
301247dd1d1bSDag-Erling Smørgrav 
301347dd1d1bSDag-Erling Smørgrav 	for (i = 0; i < o->num_listen_addrs; i++) {
301447dd1d1bSDag-Erling Smørgrav 		s = format_listen_addrs(&o->listen_addrs[i]);
301547dd1d1bSDag-Erling Smørgrav 		printf("%s", s);
301647dd1d1bSDag-Erling Smørgrav 		free(s);
301747dd1d1bSDag-Erling Smørgrav 	}
3018d4af9e69SDag-Erling Smørgrav 
3019d4af9e69SDag-Erling Smørgrav 	/* integer arguments */
3020cce7d346SDag-Erling Smørgrav #ifdef USE_PAM
3021557f75e5SDag-Erling Smørgrav 	dump_cfg_fmtint(sUsePAM, o->use_pam);
3022cce7d346SDag-Erling Smørgrav #endif
3023d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sLoginGraceTime, o->login_grace_time);
3024d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sX11DisplayOffset, o->x11_display_offset);
3025d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sMaxAuthTries, o->max_authtries);
3026cce7d346SDag-Erling Smørgrav 	dump_cfg_int(sMaxSessions, o->max_sessions);
3027d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
3028d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
302938a52bd3SEd Maste 	dump_cfg_int(sRequiredRSASize, o->required_rsa_size);
3030557f75e5SDag-Erling Smørgrav 	dump_cfg_oct(sStreamLocalBindMask, o->fwd_opts.streamlocal_bind_mask);
3031f374ba41SEd Maste 	dump_cfg_int(sUnusedConnectionTimeout, o->unused_connection_timeout);
3032d4af9e69SDag-Erling Smørgrav 
3033d4af9e69SDag-Erling Smørgrav 	/* formatted integer arguments */
3034d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login);
3035d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sIgnoreRhosts, o->ignore_rhosts);
3036d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sIgnoreUserKnownHosts, o->ignore_user_known_hosts);
3037d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sHostbasedAuthentication, o->hostbased_authentication);
3038d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sHostbasedUsesNameFromPacketOnly,
3039d4af9e69SDag-Erling Smørgrav 	    o->hostbased_uses_name_from_packet_only);
3040d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPubkeyAuthentication, o->pubkey_authentication);
3041cce7d346SDag-Erling Smørgrav #ifdef KRB5
3042d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKerberosAuthentication, o->kerberos_authentication);
3043d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKerberosOrLocalPasswd, o->kerberos_or_local_passwd);
3044d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKerberosTicketCleanup, o->kerberos_ticket_cleanup);
3045cce7d346SDag-Erling Smørgrav # ifdef USE_AFS
3046d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
3047cce7d346SDag-Erling Smørgrav # endif
3048cce7d346SDag-Erling Smørgrav #endif
3049cce7d346SDag-Erling Smørgrav #ifdef GSSAPI
3050d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
3051d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
3052cce7d346SDag-Erling Smørgrav #endif
3053d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
3054d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKbdInteractiveAuthentication,
3055d4af9e69SDag-Erling Smørgrav 	    o->kbd_interactive_authentication);
3056d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPrintMotd, o->print_motd);
3057acc1a9efSDag-Erling Smørgrav #ifndef DISABLE_LASTLOG
3058d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPrintLastLog, o->print_lastlog);
3059acc1a9efSDag-Erling Smørgrav #endif
3060d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding);
3061d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost);
3062f7167e0eSDag-Erling Smørgrav 	dump_cfg_fmtint(sPermitTTY, o->permit_tty);
3063a0ee8cc6SDag-Erling Smørgrav 	dump_cfg_fmtint(sPermitUserRC, o->permit_user_rc);
3064d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sStrictModes, o->strict_modes);
3065d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive);
3066d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd);
3067d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sCompression, o->compression);
3068a0ee8cc6SDag-Erling Smørgrav 	dump_cfg_fmtint(sGatewayPorts, o->fwd_opts.gateway_ports);
3069d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sUseDNS, o->use_dns);
3070d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
3071557f75e5SDag-Erling Smørgrav 	dump_cfg_fmtint(sAllowAgentForwarding, o->allow_agent_forwarding);
3072ca86bcf2SDag-Erling Smørgrav 	dump_cfg_fmtint(sDisableForwarding, o->disable_forwarding);
3073a0ee8cc6SDag-Erling Smørgrav 	dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding);
3074076ad2f8SDag-Erling Smørgrav 	dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
3075bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash);
30764f52dfbbSDag-Erling Smørgrav 	dump_cfg_fmtint(sExposeAuthInfo, o->expose_userauth_info);
3077b2af61ecSKurt Lidl 	dump_cfg_fmtint(sUseBlacklist, o->use_blacklist);
3078d4af9e69SDag-Erling Smørgrav 
3079d4af9e69SDag-Erling Smørgrav 	/* string arguments */
3080d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sPidFile, o->pid_file);
308119261079SEd Maste 	dump_cfg_string(sModuliFile, o->moduli_file);
3082d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sXAuthLocation, o->xauth_location);
308319261079SEd Maste 	dump_cfg_string(sCiphers, o->ciphers);
308419261079SEd Maste 	dump_cfg_string(sMacs, o->macs);
3085d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sBanner, o->banner);
3086d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sForceCommand, o->adm_forced_command);
3087b15c8340SDag-Erling Smørgrav 	dump_cfg_string(sChrootDirectory, o->chroot_directory);
3088b15c8340SDag-Erling Smørgrav 	dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys);
3089b15c8340SDag-Erling Smørgrav 	dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
309019261079SEd Maste 	dump_cfg_string(sSecurityKeyProvider, o->sk_provider);
3091e2f6069cSDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedPrincipalsFile,
3092e2f6069cSDag-Erling Smørgrav 	    o->authorized_principals_file);
3093557f75e5SDag-Erling Smørgrav 	dump_cfg_string(sVersionAddendum, *o->version_addendum == '\0'
3094557f75e5SDag-Erling Smørgrav 	    ? "none" : o->version_addendum);
30956888a9beSDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command);
30966888a9beSDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedKeysCommandUser, o->authorized_keys_command_user);
3097557f75e5SDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedPrincipalsCommand, o->authorized_principals_command);
3098557f75e5SDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedPrincipalsCommandUser, o->authorized_principals_command_user);
3099e4a9863fSDag-Erling Smørgrav 	dump_cfg_string(sHostKeyAgent, o->host_key_agent);
310019261079SEd Maste 	dump_cfg_string(sKexAlgorithms, o->kex_algorithms);
310119261079SEd Maste 	dump_cfg_string(sCASignatureAlgorithms, o->ca_sign_algorithms);
310219261079SEd Maste 	dump_cfg_string(sHostbasedAcceptedAlgorithms, o->hostbased_accepted_algos);
310319261079SEd Maste 	dump_cfg_string(sHostKeyAlgorithms, o->hostkeyalgorithms);
310419261079SEd Maste 	dump_cfg_string(sPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos);
310519261079SEd Maste #if defined(__OpenBSD__) || defined(HAVE_SYS_SET_PROCESS_RDOMAIN)
310647dd1d1bSDag-Erling Smørgrav 	dump_cfg_string(sRDomain, o->routing_domain);
310719261079SEd Maste #endif
3108d4af9e69SDag-Erling Smørgrav 
3109d4af9e69SDag-Erling Smørgrav 	/* string arguments requiring a lookup */
3110d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sLogLevel, log_level_name(o->log_level));
3111d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sLogFacility, log_facility_name(o->log_facility));
3112d4af9e69SDag-Erling Smørgrav 
3113d4af9e69SDag-Erling Smørgrav 	/* string array arguments */
3114e146993eSDag-Erling Smørgrav 	dump_cfg_strarray_oneline(sAuthorizedKeysFile, o->num_authkeys_files,
3115e146993eSDag-Erling Smørgrav 	    o->authorized_keys_files);
3116d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sHostKeyFile, o->num_host_key_files,
3117d4af9e69SDag-Erling Smørgrav 	    o->host_key_files);
3118557f75e5SDag-Erling Smørgrav 	dump_cfg_strarray(sHostCertificate, o->num_host_cert_files,
3119b15c8340SDag-Erling Smørgrav 	    o->host_cert_files);
3120d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users);
3121d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users);
3122d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups);
3123d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sDenyGroups, o->num_deny_groups, o->deny_groups);
3124d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env);
3125190cef3dSDag-Erling Smørgrav 	dump_cfg_strarray(sSetEnv, o->num_setenv, o->setenv);
31266888a9beSDag-Erling Smørgrav 	dump_cfg_strarray_oneline(sAuthenticationMethods,
31276888a9beSDag-Erling Smørgrav 	    o->num_auth_methods, o->auth_methods);
312819261079SEd Maste 	dump_cfg_strarray_oneline(sLogVerbose,
312919261079SEd Maste 	    o->num_log_verbose, o->log_verbose);
3130f374ba41SEd Maste 	dump_cfg_strarray_oneline(sChannelTimeout,
3131f374ba41SEd Maste 	    o->num_channel_timeouts, o->channel_timeouts);
3132d4af9e69SDag-Erling Smørgrav 
3133d4af9e69SDag-Erling Smørgrav 	/* other arguments */
3134d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < o->num_subsystems; i++)
3135d4af9e69SDag-Erling Smørgrav 		printf("subsystem %s %s\n", o->subsystem_name[i],
3136d4af9e69SDag-Erling Smørgrav 		    o->subsystem_args[i]);
3137d4af9e69SDag-Erling Smørgrav 
3138d4af9e69SDag-Erling Smørgrav 	printf("maxstartups %d:%d:%d\n", o->max_startups_begin,
3139d4af9e69SDag-Erling Smørgrav 	    o->max_startups_rate, o->max_startups);
314019261079SEd Maste 	printf("persourcemaxstartups ");
314119261079SEd Maste 	if (o->per_source_max_startups == INT_MAX)
314219261079SEd Maste 		printf("none\n");
314319261079SEd Maste 	else
314419261079SEd Maste 		printf("%d\n", o->per_source_max_startups);
314519261079SEd Maste 	printf("persourcenetblocksize %d:%d\n", o->per_source_masklen_ipv4,
314619261079SEd Maste 	    o->per_source_masklen_ipv6);
3147d4af9e69SDag-Erling Smørgrav 
314847dd1d1bSDag-Erling Smørgrav 	s = NULL;
314947dd1d1bSDag-Erling Smørgrav 	for (i = 0; tunmode_desc[i].val != -1; i++) {
3150d4af9e69SDag-Erling Smørgrav 		if (tunmode_desc[i].val == o->permit_tun) {
3151d4af9e69SDag-Erling Smørgrav 			s = tunmode_desc[i].text;
3152d4af9e69SDag-Erling Smørgrav 			break;
3153d4af9e69SDag-Erling Smørgrav 		}
315447dd1d1bSDag-Erling Smørgrav 	}
3155d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sPermitTunnel, s);
3156d4af9e69SDag-Erling Smørgrav 
3157e146993eSDag-Erling Smørgrav 	printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
3158e146993eSDag-Erling Smørgrav 	printf("%s\n", iptos2str(o->ip_qos_bulk));
31594a421b63SDag-Erling Smørgrav 
3160acc1a9efSDag-Erling Smørgrav 	printf("rekeylimit %llu %d\n", (unsigned long long)o->rekey_limit,
3161e4a9863fSDag-Erling Smørgrav 	    o->rekey_interval);
3162e4a9863fSDag-Erling Smørgrav 
31634f52dfbbSDag-Erling Smørgrav 	printf("permitopen");
31644f52dfbbSDag-Erling Smørgrav 	if (o->num_permitted_opens == 0)
31654f52dfbbSDag-Erling Smørgrav 		printf(" any");
31664f52dfbbSDag-Erling Smørgrav 	else {
31674f52dfbbSDag-Erling Smørgrav 		for (i = 0; i < o->num_permitted_opens; i++)
31684f52dfbbSDag-Erling Smørgrav 			printf(" %s", o->permitted_opens[i]);
31694f52dfbbSDag-Erling Smørgrav 	}
31704f52dfbbSDag-Erling Smørgrav 	printf("\n");
3171190cef3dSDag-Erling Smørgrav 	printf("permitlisten");
3172190cef3dSDag-Erling Smørgrav 	if (o->num_permitted_listens == 0)
3173190cef3dSDag-Erling Smørgrav 		printf(" any");
3174190cef3dSDag-Erling Smørgrav 	else {
3175190cef3dSDag-Erling Smørgrav 		for (i = 0; i < o->num_permitted_listens; i++)
3176190cef3dSDag-Erling Smørgrav 			printf(" %s", o->permitted_listens[i]);
3177190cef3dSDag-Erling Smørgrav 	}
3178190cef3dSDag-Erling Smørgrav 	printf("\n");
3179190cef3dSDag-Erling Smørgrav 
318019261079SEd Maste 	if (o->permit_user_env_allowlist == NULL) {
3181190cef3dSDag-Erling Smørgrav 		dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
3182190cef3dSDag-Erling Smørgrav 	} else {
3183190cef3dSDag-Erling Smørgrav 		printf("permituserenvironment %s\n",
318419261079SEd Maste 		    o->permit_user_env_allowlist);
3185190cef3dSDag-Erling Smørgrav 	}
3186190cef3dSDag-Erling Smørgrav 
318719261079SEd Maste 	printf("pubkeyauthoptions");
318819261079SEd Maste 	if (o->pubkey_auth_options == 0)
318919261079SEd Maste 		printf(" none");
319019261079SEd Maste 	if (o->pubkey_auth_options & PUBKEYAUTH_TOUCH_REQUIRED)
319119261079SEd Maste 		printf(" touch-required");
319219261079SEd Maste 	if (o->pubkey_auth_options & PUBKEYAUTH_VERIFY_REQUIRED)
319319261079SEd Maste 		printf(" verify-required");
319419261079SEd Maste 	printf("\n");
3195d4af9e69SDag-Erling Smørgrav }
3196