xref: /freebsd/crypto/openssh/servconf.c (revision a91a246563dffa876a52f53a98de4af9fa364c52)
1*a91a2465SEd Maste /* $OpenBSD: servconf.c,v 1.405 2024/03/04 02:16:11 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 },
657edf85781SEd Maste 	{ "subsystem", sSubsystem, SSHCFG_ALL },
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 void
974f374ba41SEd Maste process_channel_timeouts(struct ssh *ssh, ServerOptions *options)
975f374ba41SEd Maste {
976535af610SEd Maste 	int secs;
977535af610SEd Maste 	u_int i;
978f374ba41SEd Maste 	char *type;
979f374ba41SEd Maste 
980f374ba41SEd Maste 	debug3_f("setting %u timeouts", options->num_channel_timeouts);
981f374ba41SEd Maste 	channel_clear_timeouts(ssh);
982f374ba41SEd Maste 	for (i = 0; i < options->num_channel_timeouts; i++) {
983069ac184SEd Maste 		if (parse_pattern_interval(options->channel_timeouts[i],
984f374ba41SEd Maste 		    &type, &secs) != 0) {
985f374ba41SEd Maste 			fatal_f("internal error: bad timeout %s",
986f374ba41SEd Maste 			    options->channel_timeouts[i]);
987f374ba41SEd Maste 		}
988f374ba41SEd Maste 		channel_add_timeout(ssh, type, secs);
989f374ba41SEd Maste 		free(type);
990f374ba41SEd Maste 	}
991f374ba41SEd Maste }
992f374ba41SEd Maste 
993462c32cbSDag-Erling Smørgrav struct connection_info *
99419261079SEd Maste get_connection_info(struct ssh *ssh, int populate, int use_dns)
995462c32cbSDag-Erling Smørgrav {
996462c32cbSDag-Erling Smørgrav 	static struct connection_info ci;
997462c32cbSDag-Erling Smørgrav 
99819261079SEd Maste 	if (ssh == NULL || !populate)
999462c32cbSDag-Erling Smørgrav 		return &ci;
1000076ad2f8SDag-Erling Smørgrav 	ci.host = auth_get_canonical_hostname(ssh, use_dns);
1001076ad2f8SDag-Erling Smørgrav 	ci.address = ssh_remote_ipaddr(ssh);
1002076ad2f8SDag-Erling Smørgrav 	ci.laddress = ssh_local_ipaddr(ssh);
1003076ad2f8SDag-Erling Smørgrav 	ci.lport = ssh_local_port(ssh);
100447dd1d1bSDag-Erling Smørgrav 	ci.rdomain = ssh_packet_rdomain_in(ssh);
1005462c32cbSDag-Erling Smørgrav 	return &ci;
1006462c32cbSDag-Erling Smørgrav }
1007462c32cbSDag-Erling Smørgrav 
1008333ee039SDag-Erling Smørgrav /*
1009333ee039SDag-Erling Smørgrav  * The strategy for the Match blocks is that the config file is parsed twice.
1010333ee039SDag-Erling Smørgrav  *
1011333ee039SDag-Erling Smørgrav  * The first time is at startup.  activep is initialized to 1 and the
1012333ee039SDag-Erling Smørgrav  * directives in the global context are processed and acted on.  Hitting a
1013333ee039SDag-Erling Smørgrav  * Match directive unsets activep and the directives inside the block are
1014333ee039SDag-Erling Smørgrav  * checked for syntax only.
1015333ee039SDag-Erling Smørgrav  *
1016333ee039SDag-Erling Smørgrav  * The second time is after a connection has been established but before
1017333ee039SDag-Erling Smørgrav  * authentication.  activep is initialized to 2 and global config directives
1018333ee039SDag-Erling Smørgrav  * are ignored since they have already been processed.  If the criteria in a
1019333ee039SDag-Erling Smørgrav  * Match block is met, activep is set and the subsequent directives
1020333ee039SDag-Erling Smørgrav  * processed and actioned until EOF or another Match block unsets it.  Any
1021333ee039SDag-Erling Smørgrav  * options set are copied into the main server config.
1022333ee039SDag-Erling Smørgrav  *
1023333ee039SDag-Erling Smørgrav  * Potential additions/improvements:
1024ca86bcf2SDag-Erling Smørgrav  *  - Add Match support for pre-kex directives, eg. Ciphers.
1025333ee039SDag-Erling Smørgrav  *
1026333ee039SDag-Erling Smørgrav  *  - Add a Tag directive (idea from David Leonard) ala pf, eg:
1027333ee039SDag-Erling Smørgrav  *	Match Address 192.168.0.*
1028333ee039SDag-Erling Smørgrav  *		Tag trusted
1029333ee039SDag-Erling Smørgrav  *	Match Group wheel
1030333ee039SDag-Erling Smørgrav  *		Tag trusted
1031333ee039SDag-Erling Smørgrav  *	Match Tag trusted
1032333ee039SDag-Erling Smørgrav  *		AllowTcpForwarding yes
1033333ee039SDag-Erling Smørgrav  *		GatewayPorts clientspecified
1034333ee039SDag-Erling Smørgrav  *		[...]
1035333ee039SDag-Erling Smørgrav  *
1036333ee039SDag-Erling Smørgrav  *  - Add a PermittedChannelRequests directive
1037333ee039SDag-Erling Smørgrav  *	Match Group shell
1038333ee039SDag-Erling Smørgrav  *		PermittedChannelRequests session,forwarded-tcpip
1039333ee039SDag-Erling Smørgrav  */
1040333ee039SDag-Erling Smørgrav 
1041333ee039SDag-Erling Smørgrav static int
1042333ee039SDag-Erling Smørgrav match_cfg_line_group(const char *grps, int line, const char *user)
1043333ee039SDag-Erling Smørgrav {
1044333ee039SDag-Erling Smørgrav 	int result = 0;
1045333ee039SDag-Erling Smørgrav 	struct passwd *pw;
1046333ee039SDag-Erling Smørgrav 
1047333ee039SDag-Erling Smørgrav 	if (user == NULL)
1048333ee039SDag-Erling Smørgrav 		goto out;
1049333ee039SDag-Erling Smørgrav 
1050333ee039SDag-Erling Smørgrav 	if ((pw = getpwnam(user)) == NULL) {
1051333ee039SDag-Erling Smørgrav 		debug("Can't match group at line %d because user %.100s does "
1052333ee039SDag-Erling Smørgrav 		    "not exist", line, user);
1053333ee039SDag-Erling Smørgrav 	} else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
1054333ee039SDag-Erling Smørgrav 		debug("Can't Match group because user %.100s not in any group "
1055333ee039SDag-Erling Smørgrav 		    "at line %d", user, line);
1056d4af9e69SDag-Erling Smørgrav 	} else if (ga_match_pattern_list(grps) != 1) {
1057d4af9e69SDag-Erling Smørgrav 		debug("user %.100s does not match group list %.100s at line %d",
1058d4af9e69SDag-Erling Smørgrav 		    user, grps, line);
1059333ee039SDag-Erling Smørgrav 	} else {
1060d4af9e69SDag-Erling Smørgrav 		debug("user %.100s matched group list %.100s at line %d", user,
1061d4af9e69SDag-Erling Smørgrav 		    grps, line);
1062333ee039SDag-Erling Smørgrav 		result = 1;
1063333ee039SDag-Erling Smørgrav 	}
1064333ee039SDag-Erling Smørgrav out:
1065333ee039SDag-Erling Smørgrav 	ga_free();
1066333ee039SDag-Erling Smørgrav 	return result;
1067333ee039SDag-Erling Smørgrav }
1068333ee039SDag-Erling Smørgrav 
106947dd1d1bSDag-Erling Smørgrav static void
107047dd1d1bSDag-Erling Smørgrav match_test_missing_fatal(const char *criteria, const char *attrib)
107147dd1d1bSDag-Erling Smørgrav {
107247dd1d1bSDag-Erling Smørgrav 	fatal("'Match %s' in configuration but '%s' not in connection "
107347dd1d1bSDag-Erling Smørgrav 	    "test specification.", criteria, attrib);
107447dd1d1bSDag-Erling Smørgrav }
107547dd1d1bSDag-Erling Smørgrav 
1076462c32cbSDag-Erling Smørgrav /*
10776888a9beSDag-Erling Smørgrav  * All of the attributes on a single Match line are ANDed together, so we need
1078f7167e0eSDag-Erling Smørgrav  * to check every attribute and set the result to zero if any attribute does
10796888a9beSDag-Erling Smørgrav  * not match.
1080462c32cbSDag-Erling Smørgrav  */
1081333ee039SDag-Erling Smørgrav static int
1082462c32cbSDag-Erling Smørgrav match_cfg_line(char **condition, int line, struct connection_info *ci)
1083333ee039SDag-Erling Smørgrav {
1084f7167e0eSDag-Erling Smørgrav 	int result = 1, attributes = 0, port;
1085333ee039SDag-Erling Smørgrav 	char *arg, *attrib, *cp = *condition;
1086333ee039SDag-Erling Smørgrav 
1087462c32cbSDag-Erling Smørgrav 	if (ci == NULL)
1088333ee039SDag-Erling Smørgrav 		debug3("checking syntax for 'Match %s'", cp);
1089333ee039SDag-Erling Smørgrav 	else
1090462c32cbSDag-Erling Smørgrav 		debug3("checking match for '%s' user %s host %s addr %s "
1091462c32cbSDag-Erling Smørgrav 		    "laddr %s lport %d", cp, ci->user ? ci->user : "(null)",
1092462c32cbSDag-Erling Smørgrav 		    ci->host ? ci->host : "(null)",
1093462c32cbSDag-Erling Smørgrav 		    ci->address ? ci->address : "(null)",
1094462c32cbSDag-Erling Smørgrav 		    ci->laddress ? ci->laddress : "(null)", ci->lport);
1095333ee039SDag-Erling Smørgrav 
1096333ee039SDag-Erling Smørgrav 	while ((attrib = strdelim(&cp)) && *attrib != '\0') {
109719261079SEd Maste 		/* Terminate on comment */
109819261079SEd Maste 		if (*attrib == '#') {
109919261079SEd Maste 			cp = NULL; /* mark all arguments consumed */
110019261079SEd Maste 			break;
110119261079SEd Maste 		}
110219261079SEd Maste 		arg = NULL;
1103f7167e0eSDag-Erling Smørgrav 		attributes++;
110419261079SEd Maste 		/* Criterion "all" has no argument and must appear alone */
1105f7167e0eSDag-Erling Smørgrav 		if (strcasecmp(attrib, "all") == 0) {
110619261079SEd Maste 			if (attributes > 1 || ((arg = strdelim(&cp)) != NULL &&
110719261079SEd Maste 			    *arg != '\0' && *arg != '#')) {
1108f7167e0eSDag-Erling Smørgrav 				error("'all' cannot be combined with other "
1109f7167e0eSDag-Erling Smørgrav 				    "Match attributes");
1110f7167e0eSDag-Erling Smørgrav 				return -1;
1111f7167e0eSDag-Erling Smørgrav 			}
111219261079SEd Maste 			if (arg != NULL && *arg == '#')
111319261079SEd Maste 				cp = NULL; /* mark all arguments consumed */
1114f7167e0eSDag-Erling Smørgrav 			*condition = cp;
1115f7167e0eSDag-Erling Smørgrav 			return 1;
1116f7167e0eSDag-Erling Smørgrav 		}
111719261079SEd Maste 		/* All other criteria require an argument */
111819261079SEd Maste 		if ((arg = strdelim(&cp)) == NULL ||
111919261079SEd Maste 		    *arg == '\0' || *arg == '#') {
1120333ee039SDag-Erling Smørgrav 			error("Missing Match criteria for %s", attrib);
1121333ee039SDag-Erling Smørgrav 			return -1;
1122333ee039SDag-Erling Smørgrav 		}
1123333ee039SDag-Erling Smørgrav 		if (strcasecmp(attrib, "user") == 0) {
112419261079SEd Maste 			if (ci == NULL || (ci->test && ci->user == NULL)) {
1125333ee039SDag-Erling Smørgrav 				result = 0;
1126333ee039SDag-Erling Smørgrav 				continue;
1127333ee039SDag-Erling Smørgrav 			}
112847dd1d1bSDag-Erling Smørgrav 			if (ci->user == NULL)
112947dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("User", "user");
113019261079SEd Maste 			if (match_usergroup_pattern_list(ci->user, arg) != 1)
1131333ee039SDag-Erling Smørgrav 				result = 0;
1132333ee039SDag-Erling Smørgrav 			else
1133333ee039SDag-Erling Smørgrav 				debug("user %.100s matched 'User %.100s' at "
1134462c32cbSDag-Erling Smørgrav 				    "line %d", ci->user, arg, line);
1135333ee039SDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "group") == 0) {
113619261079SEd Maste 			if (ci == NULL || (ci->test && ci->user == NULL)) {
1137462c32cbSDag-Erling Smørgrav 				result = 0;
1138462c32cbSDag-Erling Smørgrav 				continue;
1139462c32cbSDag-Erling Smørgrav 			}
114047dd1d1bSDag-Erling Smørgrav 			if (ci->user == NULL)
114147dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("Group", "user");
1142462c32cbSDag-Erling Smørgrav 			switch (match_cfg_line_group(arg, line, ci->user)) {
1143333ee039SDag-Erling Smørgrav 			case -1:
1144333ee039SDag-Erling Smørgrav 				return -1;
1145333ee039SDag-Erling Smørgrav 			case 0:
1146333ee039SDag-Erling Smørgrav 				result = 0;
1147333ee039SDag-Erling Smørgrav 			}
1148333ee039SDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "host") == 0) {
114919261079SEd Maste 			if (ci == NULL || (ci->test && ci->host == NULL)) {
1150333ee039SDag-Erling Smørgrav 				result = 0;
1151333ee039SDag-Erling Smørgrav 				continue;
1152333ee039SDag-Erling Smørgrav 			}
115347dd1d1bSDag-Erling Smørgrav 			if (ci->host == NULL)
115447dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("Host", "host");
1155557f75e5SDag-Erling Smørgrav 			if (match_hostname(ci->host, arg) != 1)
1156333ee039SDag-Erling Smørgrav 				result = 0;
1157333ee039SDag-Erling Smørgrav 			else
1158333ee039SDag-Erling Smørgrav 				debug("connection from %.100s matched 'Host "
1159462c32cbSDag-Erling Smørgrav 				    "%.100s' at line %d", ci->host, arg, line);
1160333ee039SDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "address") == 0) {
116119261079SEd Maste 			if (ci == NULL || (ci->test && ci->address == NULL)) {
116219261079SEd Maste 				if (addr_match_list(NULL, arg) != 0)
116319261079SEd Maste 					fatal("Invalid Match address argument "
116419261079SEd Maste 					    "'%s' at line %d", arg, line);
1165462c32cbSDag-Erling Smørgrav 				result = 0;
1166462c32cbSDag-Erling Smørgrav 				continue;
1167462c32cbSDag-Erling Smørgrav 			}
116847dd1d1bSDag-Erling Smørgrav 			if (ci->address == NULL)
116947dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("Address", "addr");
1170462c32cbSDag-Erling Smørgrav 			switch (addr_match_list(ci->address, arg)) {
1171d4af9e69SDag-Erling Smørgrav 			case 1:
1172333ee039SDag-Erling Smørgrav 				debug("connection from %.100s matched 'Address "
1173462c32cbSDag-Erling Smørgrav 				    "%.100s' at line %d", ci->address, arg, line);
1174d4af9e69SDag-Erling Smørgrav 				break;
1175d4af9e69SDag-Erling Smørgrav 			case 0:
1176d4af9e69SDag-Erling Smørgrav 			case -1:
1177d4af9e69SDag-Erling Smørgrav 				result = 0;
1178d4af9e69SDag-Erling Smørgrav 				break;
1179d4af9e69SDag-Erling Smørgrav 			case -2:
1180d4af9e69SDag-Erling Smørgrav 				return -1;
1181d4af9e69SDag-Erling Smørgrav 			}
1182462c32cbSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "localaddress") == 0){
118319261079SEd Maste 			if (ci == NULL || (ci->test && ci->laddress == NULL)) {
118419261079SEd Maste 				if (addr_match_list(NULL, arg) != 0)
118519261079SEd Maste 					fatal("Invalid Match localaddress "
118619261079SEd Maste 					    "argument '%s' at line %d", arg,
118719261079SEd Maste 					    line);
1188462c32cbSDag-Erling Smørgrav 				result = 0;
1189462c32cbSDag-Erling Smørgrav 				continue;
1190462c32cbSDag-Erling Smørgrav 			}
119147dd1d1bSDag-Erling Smørgrav 			if (ci->laddress == NULL)
119247dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("LocalAddress",
119347dd1d1bSDag-Erling Smørgrav 				    "laddr");
1194462c32cbSDag-Erling Smørgrav 			switch (addr_match_list(ci->laddress, arg)) {
1195462c32cbSDag-Erling Smørgrav 			case 1:
1196462c32cbSDag-Erling Smørgrav 				debug("connection from %.100s matched "
1197462c32cbSDag-Erling Smørgrav 				    "'LocalAddress %.100s' at line %d",
1198462c32cbSDag-Erling Smørgrav 				    ci->laddress, arg, line);
1199462c32cbSDag-Erling Smørgrav 				break;
1200462c32cbSDag-Erling Smørgrav 			case 0:
1201462c32cbSDag-Erling Smørgrav 			case -1:
1202462c32cbSDag-Erling Smørgrav 				result = 0;
1203462c32cbSDag-Erling Smørgrav 				break;
1204462c32cbSDag-Erling Smørgrav 			case -2:
1205462c32cbSDag-Erling Smørgrav 				return -1;
1206462c32cbSDag-Erling Smørgrav 			}
1207462c32cbSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "localport") == 0) {
1208462c32cbSDag-Erling Smørgrav 			if ((port = a2port(arg)) == -1) {
1209462c32cbSDag-Erling Smørgrav 				error("Invalid LocalPort '%s' on Match line",
1210462c32cbSDag-Erling Smørgrav 				    arg);
1211462c32cbSDag-Erling Smørgrav 				return -1;
1212462c32cbSDag-Erling Smørgrav 			}
121319261079SEd Maste 			if (ci == NULL || (ci->test && ci->lport == -1)) {
1214462c32cbSDag-Erling Smørgrav 				result = 0;
1215462c32cbSDag-Erling Smørgrav 				continue;
1216462c32cbSDag-Erling Smørgrav 			}
121747dd1d1bSDag-Erling Smørgrav 			if (ci->lport == 0)
121847dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("LocalPort", "lport");
1219462c32cbSDag-Erling Smørgrav 			/* TODO support port lists */
1220462c32cbSDag-Erling Smørgrav 			if (port == ci->lport)
1221462c32cbSDag-Erling Smørgrav 				debug("connection from %.100s matched "
1222462c32cbSDag-Erling Smørgrav 				    "'LocalPort %d' at line %d",
1223462c32cbSDag-Erling Smørgrav 				    ci->laddress, port, line);
1224462c32cbSDag-Erling Smørgrav 			else
1225462c32cbSDag-Erling Smørgrav 				result = 0;
122647dd1d1bSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "rdomain") == 0) {
122719261079SEd Maste 			if (ci == NULL || (ci->test && ci->rdomain == NULL)) {
122847dd1d1bSDag-Erling Smørgrav 				result = 0;
122947dd1d1bSDag-Erling Smørgrav 				continue;
123047dd1d1bSDag-Erling Smørgrav 			}
123119261079SEd Maste 			if (ci->rdomain == NULL)
123219261079SEd Maste 				match_test_missing_fatal("RDomain", "rdomain");
123347dd1d1bSDag-Erling Smørgrav 			if (match_pattern_list(ci->rdomain, arg, 0) != 1)
123447dd1d1bSDag-Erling Smørgrav 				result = 0;
123547dd1d1bSDag-Erling Smørgrav 			else
123647dd1d1bSDag-Erling Smørgrav 				debug("user %.100s matched 'RDomain %.100s' at "
123747dd1d1bSDag-Erling Smørgrav 				    "line %d", ci->rdomain, arg, line);
1238333ee039SDag-Erling Smørgrav 		} else {
1239333ee039SDag-Erling Smørgrav 			error("Unsupported Match attribute %s", attrib);
1240333ee039SDag-Erling Smørgrav 			return -1;
1241333ee039SDag-Erling Smørgrav 		}
1242333ee039SDag-Erling Smørgrav 	}
1243f7167e0eSDag-Erling Smørgrav 	if (attributes == 0) {
1244f7167e0eSDag-Erling Smørgrav 		error("One or more attributes required for Match");
1245f7167e0eSDag-Erling Smørgrav 		return -1;
1246f7167e0eSDag-Erling Smørgrav 	}
1247462c32cbSDag-Erling Smørgrav 	if (ci != NULL)
1248333ee039SDag-Erling Smørgrav 		debug3("match %sfound", result ? "" : "not ");
1249333ee039SDag-Erling Smørgrav 	*condition = cp;
1250333ee039SDag-Erling Smørgrav 	return result;
1251333ee039SDag-Erling Smørgrav }
1252333ee039SDag-Erling Smørgrav 
1253333ee039SDag-Erling Smørgrav #define WHITESPACE " \t\r\n"
1254333ee039SDag-Erling Smørgrav 
1255e146993eSDag-Erling Smørgrav /* Multistate option parsing */
1256e146993eSDag-Erling Smørgrav struct multistate {
1257e146993eSDag-Erling Smørgrav 	char *key;
1258e146993eSDag-Erling Smørgrav 	int value;
1259e146993eSDag-Erling Smørgrav };
126047dd1d1bSDag-Erling Smørgrav static const struct multistate multistate_flag[] = {
126147dd1d1bSDag-Erling Smørgrav 	{ "yes",			1 },
126247dd1d1bSDag-Erling Smørgrav 	{ "no",				0 },
126347dd1d1bSDag-Erling Smørgrav 	{ NULL, -1 }
126447dd1d1bSDag-Erling Smørgrav };
126519261079SEd Maste static const struct multistate multistate_ignore_rhosts[] = {
126619261079SEd Maste 	{ "yes",			IGNORE_RHOSTS_YES },
126719261079SEd Maste 	{ "no",				IGNORE_RHOSTS_NO },
126819261079SEd Maste 	{ "shosts-only",		IGNORE_RHOSTS_SHOSTS },
126919261079SEd Maste 	{ NULL, -1 }
127019261079SEd Maste };
1271e146993eSDag-Erling Smørgrav static const struct multistate multistate_addressfamily[] = {
1272e146993eSDag-Erling Smørgrav 	{ "inet",			AF_INET },
1273e146993eSDag-Erling Smørgrav 	{ "inet6",			AF_INET6 },
1274e146993eSDag-Erling Smørgrav 	{ "any",			AF_UNSPEC },
1275e146993eSDag-Erling Smørgrav 	{ NULL, -1 }
1276e146993eSDag-Erling Smørgrav };
1277e146993eSDag-Erling Smørgrav static const struct multistate multistate_permitrootlogin[] = {
1278e146993eSDag-Erling Smørgrav 	{ "without-password",		PERMIT_NO_PASSWD },
1279eccfee6eSDag-Erling Smørgrav 	{ "prohibit-password",		PERMIT_NO_PASSWD },
1280e146993eSDag-Erling Smørgrav 	{ "forced-commands-only",	PERMIT_FORCED_ONLY },
1281e146993eSDag-Erling Smørgrav 	{ "yes",			PERMIT_YES },
1282e146993eSDag-Erling Smørgrav 	{ "no",				PERMIT_NO },
1283e146993eSDag-Erling Smørgrav 	{ NULL, -1 }
1284e146993eSDag-Erling Smørgrav };
1285e146993eSDag-Erling Smørgrav static const struct multistate multistate_compression[] = {
128619261079SEd Maste #ifdef WITH_ZLIB
1287ca86bcf2SDag-Erling Smørgrav 	{ "yes",			COMP_DELAYED },
1288e146993eSDag-Erling Smørgrav 	{ "delayed",			COMP_DELAYED },
128919261079SEd Maste #endif
1290e146993eSDag-Erling Smørgrav 	{ "no",				COMP_NONE },
1291e146993eSDag-Erling Smørgrav 	{ NULL, -1 }
1292e146993eSDag-Erling Smørgrav };
1293e146993eSDag-Erling Smørgrav static const struct multistate multistate_gatewayports[] = {
1294e146993eSDag-Erling Smørgrav 	{ "clientspecified",		2 },
1295e146993eSDag-Erling Smørgrav 	{ "yes",			1 },
1296e146993eSDag-Erling Smørgrav 	{ "no",				0 },
1297e146993eSDag-Erling Smørgrav 	{ NULL, -1 }
1298e146993eSDag-Erling Smørgrav };
12996888a9beSDag-Erling Smørgrav static const struct multistate multistate_tcpfwd[] = {
13006888a9beSDag-Erling Smørgrav 	{ "yes",			FORWARD_ALLOW },
13016888a9beSDag-Erling Smørgrav 	{ "all",			FORWARD_ALLOW },
13026888a9beSDag-Erling Smørgrav 	{ "no",				FORWARD_DENY },
13036888a9beSDag-Erling Smørgrav 	{ "remote",			FORWARD_REMOTE },
13046888a9beSDag-Erling Smørgrav 	{ "local",			FORWARD_LOCAL },
13056888a9beSDag-Erling Smørgrav 	{ NULL, -1 }
13066888a9beSDag-Erling Smørgrav };
1307e146993eSDag-Erling Smørgrav 
130819261079SEd Maste static int
130919261079SEd Maste process_server_config_line_depth(ServerOptions *options, char *line,
1310462c32cbSDag-Erling Smørgrav     const char *filename, int linenum, int *activep,
131119261079SEd Maste     struct connection_info *connectinfo, int *inc_flags, int depth,
131219261079SEd Maste     struct include_list *includes)
1313511b41d2SMark Murray {
13141323ec57SEd Maste 	char *str, ***chararrayptr, **charptr, *arg, *arg2, *p, *keyword;
1315*a91a2465SEd Maste 	int cmdline = 0, *intptr, value, value2, n, port, oactive, r;
1316*a91a2465SEd Maste 	int ca_only = 0, found = 0;
1317d4af9e69SDag-Erling Smørgrav 	SyslogFacility *log_facility_ptr;
1318d4af9e69SDag-Erling Smørgrav 	LogLevel *log_level_ptr;
1319511b41d2SMark Murray 	ServerOpCodes opcode;
1320*a91a2465SEd Maste 	u_int i, *uintptr, flags = 0;
1321333ee039SDag-Erling Smørgrav 	size_t len;
1322e4a9863fSDag-Erling Smørgrav 	long long val64;
1323e146993eSDag-Erling Smørgrav 	const struct multistate *multistate_ptr;
132447dd1d1bSDag-Erling Smørgrav 	const char *errstr;
132519261079SEd Maste 	struct include_item *item;
132619261079SEd Maste 	glob_t gbuf;
132719261079SEd Maste 	char **oav = NULL, **av;
132819261079SEd Maste 	int oac = 0, ac;
132919261079SEd Maste 	int ret = -1;
1330*a91a2465SEd Maste 	char **strs = NULL; /* string array arguments; freed implicitly */
1331*a91a2465SEd Maste 	u_int nstrs = 0;
1332511b41d2SMark Murray 
1333d93a896eSDag-Erling Smørgrav 	/* Strip trailing whitespace. Allow \f (form feed) at EOL only */
1334d93a896eSDag-Erling Smørgrav 	if ((len = strlen(line)) == 0)
1335d93a896eSDag-Erling Smørgrav 		return 0;
1336d93a896eSDag-Erling Smørgrav 	for (len--; len > 0; len--) {
1337d93a896eSDag-Erling Smørgrav 		if (strchr(WHITESPACE "\f", line[len]) == NULL)
1338d93a896eSDag-Erling Smørgrav 			break;
1339d93a896eSDag-Erling Smørgrav 		line[len] = '\0';
1340d93a896eSDag-Erling Smørgrav 	}
1341d93a896eSDag-Erling Smørgrav 
134219261079SEd Maste 	str = line;
134319261079SEd Maste 	if ((keyword = strdelim(&str)) == NULL)
1344333ee039SDag-Erling Smørgrav 		return 0;
1345c2d3a559SKris Kennaway 	/* Ignore leading whitespace */
134619261079SEd Maste 	if (*keyword == '\0')
134719261079SEd Maste 		keyword = strdelim(&str);
134819261079SEd Maste 	if (!keyword || !*keyword || *keyword == '#')
1349af12a3e7SDag-Erling Smørgrav 		return 0;
135019261079SEd Maste 	if (str == NULL || *str == '\0') {
135119261079SEd Maste 		error("%s line %d: no argument after keyword \"%s\"",
135219261079SEd Maste 		    filename, linenum, keyword);
135319261079SEd Maste 		return -1;
135419261079SEd Maste 	}
1355ca3176e7SBrian Feldman 	intptr = NULL;
1356ca3176e7SBrian Feldman 	charptr = NULL;
135719261079SEd Maste 	opcode = parse_token(keyword, filename, linenum, &flags);
135819261079SEd Maste 
135919261079SEd Maste 	if (argv_split(str, &oac, &oav, 1) != 0) {
136019261079SEd Maste 		error("%s line %d: invalid quotes", filename, linenum);
136119261079SEd Maste 		return -1;
136219261079SEd Maste 	}
136319261079SEd Maste 	ac = oac;
136419261079SEd Maste 	av = oav;
1365333ee039SDag-Erling Smørgrav 
1366333ee039SDag-Erling Smørgrav 	if (activep == NULL) { /* We are processing a command line directive */
1367333ee039SDag-Erling Smørgrav 		cmdline = 1;
1368333ee039SDag-Erling Smørgrav 		activep = &cmdline;
1369333ee039SDag-Erling Smørgrav 	}
137019261079SEd Maste 	if (*activep && opcode != sMatch && opcode != sInclude)
137119261079SEd Maste 		debug3("%s:%d setting %s %s", filename, linenum, keyword, str);
1372333ee039SDag-Erling Smørgrav 	if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
1373462c32cbSDag-Erling Smørgrav 		if (connectinfo == NULL) {
1374333ee039SDag-Erling Smørgrav 			fatal("%s line %d: Directive '%s' is not allowed "
137519261079SEd Maste 			    "within a Match block", filename, linenum, keyword);
1376333ee039SDag-Erling Smørgrav 		} else { /* this is a directive we have already processed */
137719261079SEd Maste 			ret = 0;
137819261079SEd Maste 			goto out;
1379333ee039SDag-Erling Smørgrav 		}
1380333ee039SDag-Erling Smørgrav 	}
1381333ee039SDag-Erling Smørgrav 
1382511b41d2SMark Murray 	switch (opcode) {
1383989dd127SDag-Erling Smørgrav 	/* Portable-specific options */
1384cf2b5f3bSDag-Erling Smørgrav 	case sUsePAM:
1385cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->use_pam;
1386989dd127SDag-Erling Smørgrav 		goto parse_flag;
1387989dd127SDag-Erling Smørgrav 
1388989dd127SDag-Erling Smørgrav 	/* Standard Options */
1389511b41d2SMark Murray 	case sBadOption:
139019261079SEd Maste 		goto out;
1391511b41d2SMark Murray 	case sPort:
1392511b41d2SMark Murray 		/* ignore ports from configfile if cmdline specifies ports */
139319261079SEd Maste 		if (options->ports_from_cmdline) {
139419261079SEd Maste 			argv_consume(&ac);
139519261079SEd Maste 			break;
139619261079SEd Maste 		}
1397511b41d2SMark Murray 		if (options->num_ports >= MAX_PORTS)
1398ca3176e7SBrian Feldman 			fatal("%s line %d: too many ports.",
1399511b41d2SMark Murray 			    filename, linenum);
140019261079SEd Maste 		arg = argv_next(&ac, &av);
1401c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1402ca3176e7SBrian Feldman 			fatal("%s line %d: missing port number.",
1403511b41d2SMark Murray 			    filename, linenum);
1404ca3176e7SBrian Feldman 		options->ports[options->num_ports++] = a2port(arg);
1405cce7d346SDag-Erling Smørgrav 		if (options->ports[options->num_ports-1] <= 0)
1406ca3176e7SBrian Feldman 			fatal("%s line %d: Badly formatted port number.",
1407ca3176e7SBrian Feldman 			    filename, linenum);
1408511b41d2SMark Murray 		break;
1409511b41d2SMark Murray 
1410511b41d2SMark Murray 	case sLoginGraceTime:
1411511b41d2SMark Murray 		intptr = &options->login_grace_time;
1412af12a3e7SDag-Erling Smørgrav  parse_time:
141319261079SEd Maste 		arg = argv_next(&ac, &av);
1414af12a3e7SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1415af12a3e7SDag-Erling Smørgrav 			fatal("%s line %d: missing time value.",
1416af12a3e7SDag-Erling Smørgrav 			    filename, linenum);
1417af12a3e7SDag-Erling Smørgrav 		if ((value = convtime(arg)) == -1)
1418af12a3e7SDag-Erling Smørgrav 			fatal("%s line %d: invalid time value.",
1419af12a3e7SDag-Erling Smørgrav 			    filename, linenum);
1420557f75e5SDag-Erling Smørgrav 		if (*activep && *intptr == -1)
1421af12a3e7SDag-Erling Smørgrav 			*intptr = value;
1422af12a3e7SDag-Erling Smørgrav 		break;
1423511b41d2SMark Murray 
1424511b41d2SMark Murray 	case sListenAddress:
142519261079SEd Maste 		arg = argv_next(&ac, &av);
1426aa49c926SDag-Erling Smørgrav 		if (arg == NULL || *arg == '\0')
1427aa49c926SDag-Erling Smørgrav 			fatal("%s line %d: missing address",
1428511b41d2SMark Murray 			    filename, linenum);
1429d4ecd108SDag-Erling Smørgrav 		/* check for bare IPv6 address: no "[]" and 2 or more ":" */
1430d4ecd108SDag-Erling Smørgrav 		if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL
1431d4ecd108SDag-Erling Smørgrav 		    && strchr(p+1, ':') != NULL) {
143247dd1d1bSDag-Erling Smørgrav 			port = 0;
143347dd1d1bSDag-Erling Smørgrav 			p = arg;
143447dd1d1bSDag-Erling Smørgrav 		} else {
143519261079SEd Maste 			arg2 = NULL;
14361323ec57SEd Maste 			p = hpdelim(&arg);
14371323ec57SEd Maste 			if (p == NULL)
1438aa49c926SDag-Erling Smørgrav 				fatal("%s line %d: bad address:port usage",
1439ca3176e7SBrian Feldman 				    filename, linenum);
1440aa49c926SDag-Erling Smørgrav 			p = cleanhostname(p);
1441aa49c926SDag-Erling Smørgrav 			if (arg == NULL)
1442aa49c926SDag-Erling Smørgrav 				port = 0;
1443cce7d346SDag-Erling Smørgrav 			else if ((port = a2port(arg)) <= 0)
144447dd1d1bSDag-Erling Smørgrav 				fatal("%s line %d: bad port number",
144547dd1d1bSDag-Erling Smørgrav 				    filename, linenum);
144647dd1d1bSDag-Erling Smørgrav 		}
144747dd1d1bSDag-Erling Smørgrav 		/* Optional routing table */
144847dd1d1bSDag-Erling Smørgrav 		arg2 = NULL;
144919261079SEd Maste 		if ((arg = argv_next(&ac, &av)) != NULL) {
145047dd1d1bSDag-Erling Smørgrav 			if (strcmp(arg, "rdomain") != 0 ||
145119261079SEd Maste 			    (arg2 = argv_next(&ac, &av)) == NULL)
145247dd1d1bSDag-Erling Smørgrav 				fatal("%s line %d: bad ListenAddress syntax",
145347dd1d1bSDag-Erling Smørgrav 				    filename, linenum);
145447dd1d1bSDag-Erling Smørgrav 			if (!valid_rdomain(arg2))
145547dd1d1bSDag-Erling Smørgrav 				fatal("%s line %d: bad routing domain",
145647dd1d1bSDag-Erling Smørgrav 				    filename, linenum);
145747dd1d1bSDag-Erling Smørgrav 		}
145847dd1d1bSDag-Erling Smørgrav 		queue_listen_addr(options, p, arg2, port);
1459aa49c926SDag-Erling Smørgrav 
1460aa49c926SDag-Erling Smørgrav 		break;
1461aa49c926SDag-Erling Smørgrav 
1462aa49c926SDag-Erling Smørgrav 	case sAddressFamily:
1463e146993eSDag-Erling Smørgrav 		intptr = &options->address_family;
1464e146993eSDag-Erling Smørgrav 		multistate_ptr = multistate_addressfamily;
1465e146993eSDag-Erling Smørgrav  parse_multistate:
146619261079SEd Maste 		arg = argv_next(&ac, &av);
1467d4ecd108SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1468e146993eSDag-Erling Smørgrav 			fatal("%s line %d: missing argument.",
1469d4ecd108SDag-Erling Smørgrav 			    filename, linenum);
1470e146993eSDag-Erling Smørgrav 		value = -1;
1471e146993eSDag-Erling Smørgrav 		for (i = 0; multistate_ptr[i].key != NULL; i++) {
1472e146993eSDag-Erling Smørgrav 			if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
1473e146993eSDag-Erling Smørgrav 				value = multistate_ptr[i].value;
1474e146993eSDag-Erling Smørgrav 				break;
1475e146993eSDag-Erling Smørgrav 			}
1476e146993eSDag-Erling Smørgrav 		}
1477e146993eSDag-Erling Smørgrav 		if (value == -1)
1478e146993eSDag-Erling Smørgrav 			fatal("%s line %d: unsupported option \"%s\".",
1479aa49c926SDag-Erling Smørgrav 			    filename, linenum, arg);
1480e146993eSDag-Erling Smørgrav 		if (*activep && *intptr == -1)
1481aa49c926SDag-Erling Smørgrav 			*intptr = value;
1482511b41d2SMark Murray 		break;
1483511b41d2SMark Murray 
1484511b41d2SMark Murray 	case sHostKeyFile:
148519261079SEd Maste 		arg = argv_next(&ac, &av);
1486ca3176e7SBrian Feldman 		if (!arg || *arg == '\0')
1487ca3176e7SBrian Feldman 			fatal("%s line %d: missing file name.",
1488e8aafc91SKris Kennaway 			    filename, linenum);
148919261079SEd Maste 		if (*activep) {
149019261079SEd Maste 			servconf_add_hostkey(filename, linenum,
149119261079SEd Maste 			    options, arg, 1);
149219261079SEd Maste 		}
1493e8aafc91SKris Kennaway 		break;
1494e8aafc91SKris Kennaway 
1495e4a9863fSDag-Erling Smørgrav 	case sHostKeyAgent:
1496e4a9863fSDag-Erling Smørgrav 		charptr = &options->host_key_agent;
149719261079SEd Maste 		arg = argv_next(&ac, &av);
1498e4a9863fSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1499e4a9863fSDag-Erling Smørgrav 			fatal("%s line %d: missing socket name.",
1500e4a9863fSDag-Erling Smørgrav 			    filename, linenum);
1501e4a9863fSDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
1502e4a9863fSDag-Erling Smørgrav 			*charptr = !strcmp(arg, SSH_AUTHSOCKET_ENV_NAME) ?
1503e4a9863fSDag-Erling Smørgrav 			    xstrdup(arg) : derelativise_path(arg);
1504e4a9863fSDag-Erling Smørgrav 		break;
1505e4a9863fSDag-Erling Smørgrav 
1506b15c8340SDag-Erling Smørgrav 	case sHostCertificate:
150719261079SEd Maste 		arg = argv_next(&ac, &av);
150847dd1d1bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
150947dd1d1bSDag-Erling Smørgrav 			fatal("%s line %d: missing file name.",
151047dd1d1bSDag-Erling Smørgrav 			    filename, linenum);
151147dd1d1bSDag-Erling Smørgrav 		if (*activep)
151247dd1d1bSDag-Erling Smørgrav 			servconf_add_hostcert(filename, linenum, options, arg);
151347dd1d1bSDag-Erling Smørgrav 		break;
1514b15c8340SDag-Erling Smørgrav 
1515e8aafc91SKris Kennaway 	case sPidFile:
1516e8aafc91SKris Kennaway 		charptr = &options->pid_file;
151747dd1d1bSDag-Erling Smørgrav  parse_filename:
151819261079SEd Maste 		arg = argv_next(&ac, &av);
151947dd1d1bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
152047dd1d1bSDag-Erling Smørgrav 			fatal("%s line %d: missing file name.",
152147dd1d1bSDag-Erling Smørgrav 			    filename, linenum);
152247dd1d1bSDag-Erling Smørgrav 		if (*activep && *charptr == NULL) {
152347dd1d1bSDag-Erling Smørgrav 			*charptr = derelativise_path(arg);
152447dd1d1bSDag-Erling Smørgrav 			/* increase optional counter */
152547dd1d1bSDag-Erling Smørgrav 			if (intptr != NULL)
152647dd1d1bSDag-Erling Smørgrav 				*intptr = *intptr + 1;
152747dd1d1bSDag-Erling Smørgrav 		}
152847dd1d1bSDag-Erling Smørgrav 		break;
1529511b41d2SMark Murray 
153019261079SEd Maste 	case sModuliFile:
153119261079SEd Maste 		charptr = &options->moduli_file;
153219261079SEd Maste 		goto parse_filename;
153319261079SEd Maste 
1534511b41d2SMark Murray 	case sPermitRootLogin:
1535511b41d2SMark Murray 		intptr = &options->permit_root_login;
1536e146993eSDag-Erling Smørgrav 		multistate_ptr = multistate_permitrootlogin;
1537e146993eSDag-Erling Smørgrav 		goto parse_multistate;
1538511b41d2SMark Murray 
1539511b41d2SMark Murray 	case sIgnoreRhosts:
1540511b41d2SMark Murray 		intptr = &options->ignore_rhosts;
154119261079SEd Maste 		multistate_ptr = multistate_ignore_rhosts;
154247dd1d1bSDag-Erling Smørgrav 		goto parse_multistate;
1543511b41d2SMark Murray 
1544511b41d2SMark Murray 	case sIgnoreUserKnownHosts:
1545511b41d2SMark Murray 		intptr = &options->ignore_user_known_hosts;
154619261079SEd Maste  parse_flag:
154719261079SEd Maste 		multistate_ptr = multistate_flag;
154819261079SEd Maste 		goto parse_multistate;
1549511b41d2SMark Murray 
1550ca3176e7SBrian Feldman 	case sHostbasedAuthentication:
1551ca3176e7SBrian Feldman 		intptr = &options->hostbased_authentication;
1552ca3176e7SBrian Feldman 		goto parse_flag;
1553ca3176e7SBrian Feldman 
1554ca3176e7SBrian Feldman 	case sHostbasedUsesNameFromPacketOnly:
1555ca3176e7SBrian Feldman 		intptr = &options->hostbased_uses_name_from_packet_only;
1556ca3176e7SBrian Feldman 		goto parse_flag;
1557ca3176e7SBrian Feldman 
155819261079SEd Maste 	case sHostbasedAcceptedAlgorithms:
155919261079SEd Maste 		charptr = &options->hostbased_accepted_algos;
1560535af610SEd Maste 		ca_only = 0;
156119261079SEd Maste  parse_pubkey_algos:
156219261079SEd Maste 		arg = argv_next(&ac, &av);
1563bc5531deSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1564bc5531deSDag-Erling Smørgrav 			fatal("%s line %d: Missing argument.",
1565bc5531deSDag-Erling Smørgrav 			    filename, linenum);
1566d93a896eSDag-Erling Smørgrav 		if (*arg != '-' &&
156719261079SEd Maste 		    !sshkey_names_valid2(*arg == '+' || *arg == '^' ?
1568535af610SEd Maste 		    arg + 1 : arg, 1, ca_only))
1569bc5531deSDag-Erling Smørgrav 			fatal("%s line %d: Bad key types '%s'.",
1570bc5531deSDag-Erling Smørgrav 			    filename, linenum, arg ? arg : "<NONE>");
1571bc5531deSDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
1572bc5531deSDag-Erling Smørgrav 			*charptr = xstrdup(arg);
1573bc5531deSDag-Erling Smørgrav 		break;
1574bc5531deSDag-Erling Smørgrav 
1575eccfee6eSDag-Erling Smørgrav 	case sHostKeyAlgorithms:
1576eccfee6eSDag-Erling Smørgrav 		charptr = &options->hostkeyalgorithms;
1577535af610SEd Maste 		ca_only = 0;
157819261079SEd Maste 		goto parse_pubkey_algos;
1579eccfee6eSDag-Erling Smørgrav 
15802f513db7SEd Maste 	case sCASignatureAlgorithms:
15812f513db7SEd Maste 		charptr = &options->ca_sign_algorithms;
1582535af610SEd Maste 		ca_only = 1;
158319261079SEd Maste 		goto parse_pubkey_algos;
15842f513db7SEd Maste 
1585ca3176e7SBrian Feldman 	case sPubkeyAuthentication:
1586ca3176e7SBrian Feldman 		intptr = &options->pubkey_authentication;
1587535af610SEd Maste 		ca_only = 0;
1588e8aafc91SKris Kennaway 		goto parse_flag;
1589cf2b5f3bSDag-Erling Smørgrav 
159019261079SEd Maste 	case sPubkeyAcceptedAlgorithms:
159119261079SEd Maste 		charptr = &options->pubkey_accepted_algos;
1592535af610SEd Maste 		ca_only = 0;
159319261079SEd Maste 		goto parse_pubkey_algos;
159419261079SEd Maste 
159519261079SEd Maste 	case sPubkeyAuthOptions:
159619261079SEd Maste 		intptr = &options->pubkey_auth_options;
159719261079SEd Maste 		value = 0;
159819261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
159919261079SEd Maste 			if (strcasecmp(arg, "none") == 0)
160019261079SEd Maste 				continue;
160119261079SEd Maste 			if (strcasecmp(arg, "touch-required") == 0)
160219261079SEd Maste 				value |= PUBKEYAUTH_TOUCH_REQUIRED;
160319261079SEd Maste 			else if (strcasecmp(arg, "verify-required") == 0)
160419261079SEd Maste 				value |= PUBKEYAUTH_VERIFY_REQUIRED;
160519261079SEd Maste 			else {
160619261079SEd Maste 				error("%s line %d: unsupported %s option %s",
160719261079SEd Maste 				    filename, linenum, keyword, arg);
160819261079SEd Maste 				goto out;
160919261079SEd Maste 			}
161019261079SEd Maste 		}
161119261079SEd Maste 		if (*activep && *intptr == -1)
161219261079SEd Maste 			*intptr = value;
161319261079SEd Maste 		break;
1614bc5531deSDag-Erling Smørgrav 
1615cb96ab36SAssar Westerlund 	case sKerberosAuthentication:
1616cb96ab36SAssar Westerlund 		intptr = &options->kerberos_authentication;
1617511b41d2SMark Murray 		goto parse_flag;
1618511b41d2SMark Murray 
1619af12a3e7SDag-Erling Smørgrav 	case sKerberosOrLocalPasswd:
1620af12a3e7SDag-Erling Smørgrav 		intptr = &options->kerberos_or_local_passwd;
1621511b41d2SMark Murray 		goto parse_flag;
1622511b41d2SMark Murray 
1623af12a3e7SDag-Erling Smørgrav 	case sKerberosTicketCleanup:
1624af12a3e7SDag-Erling Smørgrav 		intptr = &options->kerberos_ticket_cleanup;
1625511b41d2SMark Murray 		goto parse_flag;
1626cf2b5f3bSDag-Erling Smørgrav 
16271ec0d754SDag-Erling Smørgrav 	case sKerberosGetAFSToken:
16281ec0d754SDag-Erling Smørgrav 		intptr = &options->kerberos_get_afs_token;
16291ec0d754SDag-Erling Smørgrav 		goto parse_flag;
16301ec0d754SDag-Erling Smørgrav 
1631cf2b5f3bSDag-Erling Smørgrav 	case sGssAuthentication:
1632cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->gss_authentication;
1633fe5fd017SMark Murray 		goto parse_flag;
1634cf2b5f3bSDag-Erling Smørgrav 
1635cf2b5f3bSDag-Erling Smørgrav 	case sGssCleanupCreds:
1636cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->gss_cleanup_creds;
1637511b41d2SMark Murray 		goto parse_flag;
1638511b41d2SMark Murray 
1639557f75e5SDag-Erling Smørgrav 	case sGssStrictAcceptor:
1640557f75e5SDag-Erling Smørgrav 		intptr = &options->gss_strict_acceptor;
1641557f75e5SDag-Erling Smørgrav 		goto parse_flag;
1642557f75e5SDag-Erling Smørgrav 
1643511b41d2SMark Murray 	case sPasswordAuthentication:
1644511b41d2SMark Murray 		intptr = &options->password_authentication;
1645511b41d2SMark Murray 		goto parse_flag;
1646511b41d2SMark Murray 
164709958426SBrian Feldman 	case sKbdInteractiveAuthentication:
164809958426SBrian Feldman 		intptr = &options->kbd_interactive_authentication;
164909958426SBrian Feldman 		goto parse_flag;
165009958426SBrian Feldman 
1651511b41d2SMark Murray 	case sPrintMotd:
1652511b41d2SMark Murray 		intptr = &options->print_motd;
1653511b41d2SMark Murray 		goto parse_flag;
1654511b41d2SMark Murray 
1655ca3176e7SBrian Feldman 	case sPrintLastLog:
1656ca3176e7SBrian Feldman 		intptr = &options->print_lastlog;
1657ca3176e7SBrian Feldman 		goto parse_flag;
1658ca3176e7SBrian Feldman 
1659511b41d2SMark Murray 	case sX11Forwarding:
1660511b41d2SMark Murray 		intptr = &options->x11_forwarding;
1661511b41d2SMark Murray 		goto parse_flag;
1662511b41d2SMark Murray 
1663511b41d2SMark Murray 	case sX11DisplayOffset:
1664511b41d2SMark Murray 		intptr = &options->x11_display_offset;
1665ca86bcf2SDag-Erling Smørgrav  parse_int:
166619261079SEd Maste 		arg = argv_next(&ac, &av);
166747dd1d1bSDag-Erling Smørgrav 		if ((errstr = atoi_err(arg, &value)) != NULL)
166819261079SEd Maste 			fatal("%s line %d: %s integer value %s.",
166919261079SEd Maste 			    filename, linenum, keyword, errstr);
1670ca86bcf2SDag-Erling Smørgrav 		if (*activep && *intptr == -1)
1671ca86bcf2SDag-Erling Smørgrav 			*intptr = value;
1672ca86bcf2SDag-Erling Smørgrav 		break;
1673511b41d2SMark Murray 
1674af12a3e7SDag-Erling Smørgrav 	case sX11UseLocalhost:
1675af12a3e7SDag-Erling Smørgrav 		intptr = &options->x11_use_localhost;
1676af12a3e7SDag-Erling Smørgrav 		goto parse_flag;
1677af12a3e7SDag-Erling Smørgrav 
1678c2d3a559SKris Kennaway 	case sXAuthLocation:
1679c2d3a559SKris Kennaway 		charptr = &options->xauth_location;
1680c2d3a559SKris Kennaway 		goto parse_filename;
1681c2d3a559SKris Kennaway 
1682f7167e0eSDag-Erling Smørgrav 	case sPermitTTY:
1683f7167e0eSDag-Erling Smørgrav 		intptr = &options->permit_tty;
1684f7167e0eSDag-Erling Smørgrav 		goto parse_flag;
1685f7167e0eSDag-Erling Smørgrav 
1686a0ee8cc6SDag-Erling Smørgrav 	case sPermitUserRC:
1687a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->permit_user_rc;
1688a0ee8cc6SDag-Erling Smørgrav 		goto parse_flag;
1689a0ee8cc6SDag-Erling Smørgrav 
1690511b41d2SMark Murray 	case sStrictModes:
1691511b41d2SMark Murray 		intptr = &options->strict_modes;
1692511b41d2SMark Murray 		goto parse_flag;
1693511b41d2SMark Murray 
16941ec0d754SDag-Erling Smørgrav 	case sTCPKeepAlive:
16951ec0d754SDag-Erling Smørgrav 		intptr = &options->tcp_keep_alive;
1696511b41d2SMark Murray 		goto parse_flag;
1697511b41d2SMark Murray 
1698511b41d2SMark Murray 	case sEmptyPasswd:
1699511b41d2SMark Murray 		intptr = &options->permit_empty_passwd;
1700511b41d2SMark Murray 		goto parse_flag;
1701511b41d2SMark Murray 
1702f388f5efSDag-Erling Smørgrav 	case sPermitUserEnvironment:
1703f388f5efSDag-Erling Smørgrav 		intptr = &options->permit_user_env;
170419261079SEd Maste 		charptr = &options->permit_user_env_allowlist;
170519261079SEd Maste 		arg = argv_next(&ac, &av);
1706190cef3dSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
170719261079SEd Maste 			fatal("%s line %d: %s missing argument.",
170819261079SEd Maste 			    filename, linenum, keyword);
1709190cef3dSDag-Erling Smørgrav 		value = 0;
1710190cef3dSDag-Erling Smørgrav 		p = NULL;
1711190cef3dSDag-Erling Smørgrav 		if (strcmp(arg, "yes") == 0)
1712190cef3dSDag-Erling Smørgrav 			value = 1;
1713190cef3dSDag-Erling Smørgrav 		else if (strcmp(arg, "no") == 0)
1714190cef3dSDag-Erling Smørgrav 			value = 0;
1715190cef3dSDag-Erling Smørgrav 		else {
1716190cef3dSDag-Erling Smørgrav 			/* Pattern-list specified */
1717190cef3dSDag-Erling Smørgrav 			value = 1;
1718190cef3dSDag-Erling Smørgrav 			p = xstrdup(arg);
1719190cef3dSDag-Erling Smørgrav 		}
1720190cef3dSDag-Erling Smørgrav 		if (*activep && *intptr == -1) {
1721190cef3dSDag-Erling Smørgrav 			*intptr = value;
1722190cef3dSDag-Erling Smørgrav 			*charptr = p;
1723190cef3dSDag-Erling Smørgrav 			p = NULL;
1724190cef3dSDag-Erling Smørgrav 		}
1725190cef3dSDag-Erling Smørgrav 		free(p);
1726190cef3dSDag-Erling Smørgrav 		break;
1727f388f5efSDag-Erling Smørgrav 
172880628bacSDag-Erling Smørgrav 	case sCompression:
172980628bacSDag-Erling Smørgrav 		intptr = &options->compression;
1730e146993eSDag-Erling Smørgrav 		multistate_ptr = multistate_compression;
1731e146993eSDag-Erling Smørgrav 		goto parse_multistate;
173280628bacSDag-Erling Smørgrav 
1733e4a9863fSDag-Erling Smørgrav 	case sRekeyLimit:
173419261079SEd Maste 		arg = argv_next(&ac, &av);
1735e4a9863fSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
173619261079SEd Maste 			fatal("%s line %d: %s missing argument.",
173719261079SEd Maste 			    filename, linenum, keyword);
1738e4a9863fSDag-Erling Smørgrav 		if (strcmp(arg, "default") == 0) {
1739e4a9863fSDag-Erling Smørgrav 			val64 = 0;
1740e4a9863fSDag-Erling Smørgrav 		} else {
1741e4a9863fSDag-Erling Smørgrav 			if (scan_scaled(arg, &val64) == -1)
174219261079SEd Maste 				fatal("%.200s line %d: Bad %s number '%s': %s",
174319261079SEd Maste 				    filename, linenum, keyword,
174419261079SEd Maste 				    arg, strerror(errno));
1745e4a9863fSDag-Erling Smørgrav 			if (val64 != 0 && val64 < 16)
174619261079SEd Maste 				fatal("%.200s line %d: %s too small",
174719261079SEd Maste 				    filename, linenum, keyword);
1748e4a9863fSDag-Erling Smørgrav 		}
1749e4a9863fSDag-Erling Smørgrav 		if (*activep && options->rekey_limit == -1)
1750acc1a9efSDag-Erling Smørgrav 			options->rekey_limit = val64;
175119261079SEd Maste 		if (ac != 0) { /* optional rekey interval present */
175219261079SEd Maste 			if (strcmp(av[0], "none") == 0) {
175319261079SEd Maste 				(void)argv_next(&ac, &av);	/* discard */
1754e4a9863fSDag-Erling Smørgrav 				break;
1755e4a9863fSDag-Erling Smørgrav 			}
1756e4a9863fSDag-Erling Smørgrav 			intptr = &options->rekey_interval;
1757e4a9863fSDag-Erling Smørgrav 			goto parse_time;
1758e4a9863fSDag-Erling Smørgrav 		}
1759e4a9863fSDag-Erling Smørgrav 		break;
1760e4a9863fSDag-Erling Smørgrav 
1761e8aafc91SKris Kennaway 	case sGatewayPorts:
1762a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->fwd_opts.gateway_ports;
1763e146993eSDag-Erling Smørgrav 		multistate_ptr = multistate_gatewayports;
1764e146993eSDag-Erling Smørgrav 		goto parse_multistate;
1765e8aafc91SKris Kennaway 
1766cf2b5f3bSDag-Erling Smørgrav 	case sUseDNS:
1767cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->use_dns;
1768ca3176e7SBrian Feldman 		goto parse_flag;
1769ca3176e7SBrian Feldman 
1770511b41d2SMark Murray 	case sLogFacility:
1771d4af9e69SDag-Erling Smørgrav 		log_facility_ptr = &options->log_facility;
177219261079SEd Maste 		arg = argv_next(&ac, &av);
1773c2d3a559SKris Kennaway 		value = log_facility_number(arg);
1774af12a3e7SDag-Erling Smørgrav 		if (value == SYSLOG_FACILITY_NOT_SET)
1775ca3176e7SBrian Feldman 			fatal("%.200s line %d: unsupported log facility '%s'",
1776c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
1777d4af9e69SDag-Erling Smørgrav 		if (*log_facility_ptr == -1)
1778d4af9e69SDag-Erling Smørgrav 			*log_facility_ptr = (SyslogFacility) value;
1779511b41d2SMark Murray 		break;
1780511b41d2SMark Murray 
1781511b41d2SMark Murray 	case sLogLevel:
1782d4af9e69SDag-Erling Smørgrav 		log_level_ptr = &options->log_level;
178319261079SEd Maste 		arg = argv_next(&ac, &av);
1784c2d3a559SKris Kennaway 		value = log_level_number(arg);
1785af12a3e7SDag-Erling Smørgrav 		if (value == SYSLOG_LEVEL_NOT_SET)
1786ca3176e7SBrian Feldman 			fatal("%.200s line %d: unsupported log level '%s'",
1787c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
17884f52dfbbSDag-Erling Smørgrav 		if (*activep && *log_level_ptr == -1)
1789d4af9e69SDag-Erling Smørgrav 			*log_level_ptr = (LogLevel) value;
1790511b41d2SMark Murray 		break;
1791511b41d2SMark Murray 
179219261079SEd Maste 	case sLogVerbose:
179319261079SEd Maste 		found = options->num_log_verbose == 0;
179419261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
179519261079SEd Maste 			if (*arg == '\0') {
179619261079SEd Maste 				error("%s line %d: keyword %s empty argument",
179719261079SEd Maste 				    filename, linenum, keyword);
179819261079SEd Maste 				goto out;
179919261079SEd Maste 			}
180019261079SEd Maste 			/* Allow "none" only in first position */
180119261079SEd Maste 			if (strcasecmp(arg, "none") == 0) {
1802*a91a2465SEd Maste 				if (nstrs > 0 || ac > 0) {
180319261079SEd Maste 					error("%s line %d: keyword %s \"none\" "
180419261079SEd Maste 					    "argument must appear alone.",
180519261079SEd Maste 					    filename, linenum, keyword);
180619261079SEd Maste 					goto out;
180719261079SEd Maste 				}
180819261079SEd Maste 			}
180919261079SEd Maste 			opt_array_append(filename, linenum, keyword,
1810*a91a2465SEd Maste 			    &strs, &nstrs, arg);
1811*a91a2465SEd Maste 		}
1812*a91a2465SEd Maste 		if (nstrs == 0) {
1813*a91a2465SEd Maste 			fatal("%s line %d: no %s specified",
1814*a91a2465SEd Maste 			    filename, linenum, keyword);
1815*a91a2465SEd Maste 		}
1816*a91a2465SEd Maste 		if (found && *activep) {
1817*a91a2465SEd Maste 			options->log_verbose = strs;
1818*a91a2465SEd Maste 			options->num_log_verbose = nstrs;
1819*a91a2465SEd Maste 			strs = NULL; /* transferred */
1820*a91a2465SEd Maste 			nstrs = 0;
182119261079SEd Maste 		}
182219261079SEd Maste 		break;
182319261079SEd Maste 
182409958426SBrian Feldman 	case sAllowTcpForwarding:
182509958426SBrian Feldman 		intptr = &options->allow_tcp_forwarding;
18266888a9beSDag-Erling Smørgrav 		multistate_ptr = multistate_tcpfwd;
18276888a9beSDag-Erling Smørgrav 		goto parse_multistate;
182809958426SBrian Feldman 
1829a0ee8cc6SDag-Erling Smørgrav 	case sAllowStreamLocalForwarding:
1830a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->allow_streamlocal_forwarding;
1831a0ee8cc6SDag-Erling Smørgrav 		multistate_ptr = multistate_tcpfwd;
1832a0ee8cc6SDag-Erling Smørgrav 		goto parse_multistate;
1833a0ee8cc6SDag-Erling Smørgrav 
1834d4af9e69SDag-Erling Smørgrav 	case sAllowAgentForwarding:
1835d4af9e69SDag-Erling Smørgrav 		intptr = &options->allow_agent_forwarding;
1836d4af9e69SDag-Erling Smørgrav 		goto parse_flag;
1837d4af9e69SDag-Erling Smørgrav 
1838ca86bcf2SDag-Erling Smørgrav 	case sDisableForwarding:
1839ca86bcf2SDag-Erling Smørgrav 		intptr = &options->disable_forwarding;
1840ca86bcf2SDag-Erling Smørgrav 		goto parse_flag;
1841ca86bcf2SDag-Erling Smørgrav 
1842511b41d2SMark Murray 	case sAllowUsers:
184319261079SEd Maste 		chararrayptr = &options->allow_users;
184419261079SEd Maste 		uintptr = &options->num_allow_users;
184519261079SEd Maste  parse_allowdenyusers:
1846*a91a2465SEd Maste 		/* XXX appends to list; doesn't respect first-match-wins */
184719261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
184819261079SEd Maste 			if (*arg == '\0' ||
184919261079SEd Maste 			    match_user(NULL, NULL, NULL, arg) == -1)
185019261079SEd Maste 				fatal("%s line %d: invalid %s pattern: \"%s\"",
185119261079SEd Maste 				    filename, linenum, keyword, arg);
1852*a91a2465SEd Maste 			found = 1;
1853462c32cbSDag-Erling Smørgrav 			if (!*activep)
1854462c32cbSDag-Erling Smørgrav 				continue;
185519261079SEd Maste 			opt_array_append(filename, linenum, keyword,
185619261079SEd Maste 			    chararrayptr, uintptr, arg);
1857511b41d2SMark Murray 		}
1858*a91a2465SEd Maste 		if (!found) {
1859*a91a2465SEd Maste 			fatal("%s line %d: no %s specified",
1860*a91a2465SEd Maste 			    filename, linenum, keyword);
1861*a91a2465SEd Maste 		}
1862511b41d2SMark Murray 		break;
1863511b41d2SMark Murray 
1864511b41d2SMark Murray 	case sDenyUsers:
186519261079SEd Maste 		chararrayptr = &options->deny_users;
186619261079SEd Maste 		uintptr = &options->num_deny_users;
186719261079SEd Maste 		goto parse_allowdenyusers;
1868511b41d2SMark Murray 
1869511b41d2SMark Murray 	case sAllowGroups:
187019261079SEd Maste 		chararrayptr = &options->allow_groups;
187119261079SEd Maste 		uintptr = &options->num_allow_groups;
1872*a91a2465SEd Maste 		/* XXX appends to list; doesn't respect first-match-wins */
187319261079SEd Maste  parse_allowdenygroups:
187419261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
187519261079SEd Maste 			if (*arg == '\0')
187619261079SEd Maste 				fatal("%s line %d: empty %s pattern",
187719261079SEd Maste 				    filename, linenum, keyword);
1878*a91a2465SEd Maste 			found = 1;
1879462c32cbSDag-Erling Smørgrav 			if (!*activep)
1880462c32cbSDag-Erling Smørgrav 				continue;
188119261079SEd Maste 			opt_array_append(filename, linenum, keyword,
188219261079SEd Maste 			    chararrayptr, uintptr, arg);
1883511b41d2SMark Murray 		}
1884*a91a2465SEd Maste 		if (!found) {
1885*a91a2465SEd Maste 			fatal("%s line %d: no %s specified",
1886*a91a2465SEd Maste 			    filename, linenum, keyword);
1887*a91a2465SEd Maste 		}
1888511b41d2SMark Murray 		break;
1889511b41d2SMark Murray 
1890511b41d2SMark Murray 	case sDenyGroups:
189119261079SEd Maste 		chararrayptr = &options->deny_groups;
189219261079SEd Maste 		uintptr = &options->num_deny_groups;
189319261079SEd Maste 		goto parse_allowdenygroups;
1894511b41d2SMark Murray 
1895e8aafc91SKris Kennaway 	case sCiphers:
189619261079SEd Maste 		arg = argv_next(&ac, &av);
1897c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
189819261079SEd Maste 			fatal("%s line %d: %s missing argument.",
189919261079SEd Maste 			    filename, linenum, keyword);
190019261079SEd Maste 		if (*arg != '-' &&
190119261079SEd Maste 		    !ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg))
1902e8aafc91SKris Kennaway 			fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
1903c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
1904e8aafc91SKris Kennaway 		if (options->ciphers == NULL)
1905c2d3a559SKris Kennaway 			options->ciphers = xstrdup(arg);
1906e8aafc91SKris Kennaway 		break;
1907e8aafc91SKris Kennaway 
1908ca3176e7SBrian Feldman 	case sMacs:
190919261079SEd Maste 		arg = argv_next(&ac, &av);
1910ca3176e7SBrian Feldman 		if (!arg || *arg == '\0')
191119261079SEd Maste 			fatal("%s line %d: %s missing argument.",
191219261079SEd Maste 			    filename, linenum, keyword);
191319261079SEd Maste 		if (*arg != '-' &&
191419261079SEd Maste 		    !mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg))
1915ca3176e7SBrian Feldman 			fatal("%s line %d: Bad SSH2 mac spec '%s'.",
1916ca3176e7SBrian Feldman 			    filename, linenum, arg ? arg : "<NONE>");
1917ca3176e7SBrian Feldman 		if (options->macs == NULL)
1918ca3176e7SBrian Feldman 			options->macs = xstrdup(arg);
1919ca3176e7SBrian Feldman 		break;
1920ca3176e7SBrian Feldman 
19214a421b63SDag-Erling Smørgrav 	case sKexAlgorithms:
192219261079SEd Maste 		arg = argv_next(&ac, &av);
19234a421b63SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
192419261079SEd Maste 			fatal("%s line %d: %s missing argument.",
192519261079SEd Maste 			    filename, linenum, keyword);
1926d93a896eSDag-Erling Smørgrav 		if (*arg != '-' &&
192719261079SEd Maste 		    !kex_names_valid(*arg == '+' || *arg == '^' ?
192819261079SEd Maste 		    arg + 1 : arg))
19294a421b63SDag-Erling Smørgrav 			fatal("%s line %d: Bad SSH2 KexAlgorithms '%s'.",
19304a421b63SDag-Erling Smørgrav 			    filename, linenum, arg ? arg : "<NONE>");
19314a421b63SDag-Erling Smørgrav 		if (options->kex_algorithms == NULL)
19324a421b63SDag-Erling Smørgrav 			options->kex_algorithms = xstrdup(arg);
19334a421b63SDag-Erling Smørgrav 		break;
19344a421b63SDag-Erling Smørgrav 
1935c2d3a559SKris Kennaway 	case sSubsystem:
193619261079SEd Maste 		arg = argv_next(&ac, &av);
1937c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
193819261079SEd Maste 			fatal("%s line %d: %s missing argument.",
193919261079SEd Maste 			    filename, linenum, keyword);
1940333ee039SDag-Erling Smørgrav 		if (!*activep) {
1941edf85781SEd Maste 			argv_consume(&ac);
1942333ee039SDag-Erling Smørgrav 			break;
1943333ee039SDag-Erling Smørgrav 		}
1944edf85781SEd Maste 		found = 0;
1945edf85781SEd Maste 		for (i = 0; i < options->num_subsystems; i++) {
1946edf85781SEd Maste 			if (strcmp(arg, options->subsystem_name[i]) == 0) {
1947edf85781SEd Maste 				found = 1;
1948edf85781SEd Maste 				break;
1949edf85781SEd Maste 			}
1950edf85781SEd Maste 		}
1951edf85781SEd Maste 		if (found) {
1952edf85781SEd Maste 			debug("%s line %d: Subsystem '%s' already defined.",
1953edf85781SEd Maste 			    filename, linenum, arg);
1954edf85781SEd Maste 			argv_consume(&ac);
1955edf85781SEd Maste 			break;
1956edf85781SEd Maste 		}
1957edf85781SEd Maste 		options->subsystem_name = xrecallocarray(
1958edf85781SEd Maste 		    options->subsystem_name, options->num_subsystems,
1959edf85781SEd Maste 		    options->num_subsystems + 1,
1960edf85781SEd Maste 		    sizeof(*options->subsystem_name));
1961edf85781SEd Maste 		options->subsystem_command = xrecallocarray(
1962edf85781SEd Maste 		    options->subsystem_command, options->num_subsystems,
1963edf85781SEd Maste 		    options->num_subsystems + 1,
1964edf85781SEd Maste 		    sizeof(*options->subsystem_command));
1965edf85781SEd Maste 		options->subsystem_args = xrecallocarray(
1966edf85781SEd Maste 		    options->subsystem_args, options->num_subsystems,
1967edf85781SEd Maste 		    options->num_subsystems + 1,
1968edf85781SEd Maste 		    sizeof(*options->subsystem_args));
1969c2d3a559SKris Kennaway 		options->subsystem_name[options->num_subsystems] = xstrdup(arg);
197019261079SEd Maste 		arg = argv_next(&ac, &av);
1971edf85781SEd Maste 		if (!arg || *arg == '\0') {
1972c2d3a559SKris Kennaway 			fatal("%s line %d: Missing subsystem command.",
1973c2d3a559SKris Kennaway 			    filename, linenum);
1974333ee039SDag-Erling Smørgrav 		}
1975edf85781SEd Maste 		options->subsystem_command[options->num_subsystems] =
1976edf85781SEd Maste 		    xstrdup(arg);
1977edf85781SEd Maste 		/* Collect arguments (separate to executable) */
1978edf85781SEd Maste 		arg = argv_assemble(1, &arg); /* quote command correctly */
1979edf85781SEd Maste 		arg2 = argv_assemble(ac, av); /* rest of command */
1980edf85781SEd Maste 		xasprintf(&options->subsystem_args[options->num_subsystems],
1981*a91a2465SEd Maste 		    "%s%s%s", arg, *arg2 == '\0' ? "" : " ", arg2);
1982edf85781SEd Maste 		free(arg2);
1983edf85781SEd Maste 		argv_consume(&ac);
1984c2d3a559SKris Kennaway 		options->num_subsystems++;
1985c2d3a559SKris Kennaway 		break;
1986c2d3a559SKris Kennaway 
1987c2d3a559SKris Kennaway 	case sMaxStartups:
198819261079SEd Maste 		arg = argv_next(&ac, &av);
1989c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
199019261079SEd Maste 			fatal("%s line %d: %s missing argument.",
199119261079SEd Maste 			    filename, linenum, keyword);
1992af12a3e7SDag-Erling Smørgrav 		if ((n = sscanf(arg, "%d:%d:%d",
1993c2d3a559SKris Kennaway 		    &options->max_startups_begin,
1994c2d3a559SKris Kennaway 		    &options->max_startups_rate,
1995af12a3e7SDag-Erling Smørgrav 		    &options->max_startups)) == 3) {
1996c2d3a559SKris Kennaway 			if (options->max_startups_begin >
1997c2d3a559SKris Kennaway 			    options->max_startups ||
1998c2d3a559SKris Kennaway 			    options->max_startups_rate > 100 ||
1999c2d3a559SKris Kennaway 			    options->max_startups_rate < 1)
200019261079SEd Maste 				fatal("%s line %d: Invalid %s spec.",
200119261079SEd Maste 				    filename, linenum, keyword);
2002af12a3e7SDag-Erling Smørgrav 		} else if (n != 1)
200319261079SEd Maste 			fatal("%s line %d: Invalid %s spec.",
200419261079SEd Maste 			    filename, linenum, keyword);
2005af12a3e7SDag-Erling Smørgrav 		else
2006af12a3e7SDag-Erling Smørgrav 			options->max_startups = options->max_startups_begin;
2007f374ba41SEd Maste 		if (options->max_startups <= 0 ||
2008f374ba41SEd Maste 		    options->max_startups_begin <= 0)
2009f374ba41SEd Maste 			fatal("%s line %d: Invalid %s spec.",
2010f374ba41SEd Maste 			    filename, linenum, keyword);
2011933ca70fSBrian Feldman 		break;
2012933ca70fSBrian Feldman 
201319261079SEd Maste 	case sPerSourceNetBlockSize:
201419261079SEd Maste 		arg = argv_next(&ac, &av);
201519261079SEd Maste 		if (!arg || *arg == '\0')
201619261079SEd Maste 			fatal("%s line %d: %s missing argument.",
201719261079SEd Maste 			    filename, linenum, keyword);
201819261079SEd Maste 		switch (n = sscanf(arg, "%d:%d", &value, &value2)) {
201919261079SEd Maste 		case 2:
202019261079SEd Maste 			if (value2 < 0 || value2 > 128)
202119261079SEd Maste 				n = -1;
202219261079SEd Maste 			/* FALLTHROUGH */
202319261079SEd Maste 		case 1:
202419261079SEd Maste 			if (value < 0 || value > 32)
202519261079SEd Maste 				n = -1;
202619261079SEd Maste 		}
202719261079SEd Maste 		if (n != 1 && n != 2)
202819261079SEd Maste 			fatal("%s line %d: Invalid %s spec.",
202919261079SEd Maste 			    filename, linenum, keyword);
203019261079SEd Maste 		if (*activep) {
203119261079SEd Maste 			options->per_source_masklen_ipv4 = value;
203219261079SEd Maste 			options->per_source_masklen_ipv6 = value2;
203319261079SEd Maste 		}
203419261079SEd Maste 		break;
203519261079SEd Maste 
203619261079SEd Maste 	case sPerSourceMaxStartups:
203719261079SEd Maste 		arg = argv_next(&ac, &av);
203819261079SEd Maste 		if (!arg || *arg == '\0')
203919261079SEd Maste 			fatal("%s line %d: %s missing argument.",
204019261079SEd Maste 			    filename, linenum, keyword);
204119261079SEd Maste 		if (strcmp(arg, "none") == 0) { /* no limit */
204219261079SEd Maste 			value = INT_MAX;
204319261079SEd Maste 		} else {
204419261079SEd Maste 			if ((errstr = atoi_err(arg, &value)) != NULL)
204519261079SEd Maste 				fatal("%s line %d: %s integer value %s.",
204619261079SEd Maste 				    filename, linenum, keyword, errstr);
204719261079SEd Maste 		}
2048edf85781SEd Maste 		if (*activep && options->per_source_max_startups == -1)
204919261079SEd Maste 			options->per_source_max_startups = value;
205019261079SEd Maste 		break;
205119261079SEd Maste 
205221e764dfSDag-Erling Smørgrav 	case sMaxAuthTries:
205321e764dfSDag-Erling Smørgrav 		intptr = &options->max_authtries;
205421e764dfSDag-Erling Smørgrav 		goto parse_int;
205521e764dfSDag-Erling Smørgrav 
2056d4af9e69SDag-Erling Smørgrav 	case sMaxSessions:
2057d4af9e69SDag-Erling Smørgrav 		intptr = &options->max_sessions;
2058d4af9e69SDag-Erling Smørgrav 		goto parse_int;
2059d4af9e69SDag-Erling Smørgrav 
2060ca3176e7SBrian Feldman 	case sBanner:
2061ca3176e7SBrian Feldman 		charptr = &options->banner;
2062ca3176e7SBrian Feldman 		goto parse_filename;
2063d4af9e69SDag-Erling Smørgrav 
2064af12a3e7SDag-Erling Smørgrav 	/*
2065af12a3e7SDag-Erling Smørgrav 	 * These options can contain %X options expanded at
2066af12a3e7SDag-Erling Smørgrav 	 * connect time, so that you can specify paths like:
2067af12a3e7SDag-Erling Smørgrav 	 *
2068af12a3e7SDag-Erling Smørgrav 	 * AuthorizedKeysFile	/etc/ssh_keys/%u
2069af12a3e7SDag-Erling Smørgrav 	 */
2070af12a3e7SDag-Erling Smørgrav 	case sAuthorizedKeysFile:
2071*a91a2465SEd Maste 		found = options->num_authkeys_files == 0;
207219261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
207319261079SEd Maste 			if (*arg == '\0') {
207419261079SEd Maste 				error("%s line %d: keyword %s empty argument",
207519261079SEd Maste 				    filename, linenum, keyword);
207619261079SEd Maste 				goto out;
207719261079SEd Maste 			}
207819261079SEd Maste 			arg2 = tilde_expand_filename(arg, getuid());
207919261079SEd Maste 			opt_array_append(filename, linenum, keyword,
2080*a91a2465SEd Maste 			    &strs, &nstrs, arg2);
208119261079SEd Maste 			free(arg2);
2082e146993eSDag-Erling Smørgrav 		}
2083*a91a2465SEd Maste 		if (nstrs == 0) {
2084*a91a2465SEd Maste 			fatal("%s line %d: no %s specified",
2085*a91a2465SEd Maste 			    filename, linenum, keyword);
2086*a91a2465SEd Maste 		}
2087*a91a2465SEd Maste 		if (found && *activep) {
2088*a91a2465SEd Maste 			options->authorized_keys_files = strs;
2089*a91a2465SEd Maste 			options->num_authkeys_files = nstrs;
2090*a91a2465SEd Maste 			strs = NULL; /* transferred */
2091*a91a2465SEd Maste 			nstrs = 0;
2092*a91a2465SEd Maste 		}
209319261079SEd Maste 		break;
2094e146993eSDag-Erling Smørgrav 
2095e2f6069cSDag-Erling Smørgrav 	case sAuthorizedPrincipalsFile:
2096e2f6069cSDag-Erling Smørgrav 		charptr = &options->authorized_principals_file;
209719261079SEd Maste 		arg = argv_next(&ac, &av);
20988ad9b54aSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
209919261079SEd Maste 			fatal("%s line %d: %s missing argument.",
210019261079SEd Maste 			    filename, linenum, keyword);
21018ad9b54aSDag-Erling Smørgrav 		if (*activep && *charptr == NULL) {
21028ad9b54aSDag-Erling Smørgrav 			*charptr = tilde_expand_filename(arg, getuid());
21038ad9b54aSDag-Erling Smørgrav 			/* increase optional counter */
21048ad9b54aSDag-Erling Smørgrav 			if (intptr != NULL)
21058ad9b54aSDag-Erling Smørgrav 				*intptr = *intptr + 1;
21068ad9b54aSDag-Erling Smørgrav 		}
21078ad9b54aSDag-Erling Smørgrav 		break;
2108af12a3e7SDag-Erling Smørgrav 
2109ca3176e7SBrian Feldman 	case sClientAliveInterval:
2110ca3176e7SBrian Feldman 		intptr = &options->client_alive_interval;
2111af12a3e7SDag-Erling Smørgrav 		goto parse_time;
2112af12a3e7SDag-Erling Smørgrav 
2113ca3176e7SBrian Feldman 	case sClientAliveCountMax:
2114ca3176e7SBrian Feldman 		intptr = &options->client_alive_count_max;
2115ca3176e7SBrian Feldman 		goto parse_int;
2116af12a3e7SDag-Erling Smørgrav 
211721e764dfSDag-Erling Smørgrav 	case sAcceptEnv:
2118*a91a2465SEd Maste 		/* XXX appends to list; doesn't respect first-match-wins */
211919261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
212019261079SEd Maste 			if (*arg == '\0' || strchr(arg, '=') != NULL)
212121e764dfSDag-Erling Smørgrav 				fatal("%s line %d: Invalid environment name.",
212221e764dfSDag-Erling Smørgrav 				    filename, linenum);
2123*a91a2465SEd Maste 			found = 1;
2124333ee039SDag-Erling Smørgrav 			if (!*activep)
2125462c32cbSDag-Erling Smørgrav 				continue;
212619261079SEd Maste 			opt_array_append(filename, linenum, keyword,
212747dd1d1bSDag-Erling Smørgrav 			    &options->accept_env, &options->num_accept_env,
212847dd1d1bSDag-Erling Smørgrav 			    arg);
212921e764dfSDag-Erling Smørgrav 		}
2130*a91a2465SEd Maste 		if (!found) {
2131*a91a2465SEd Maste 			fatal("%s line %d: no %s specified",
2132*a91a2465SEd Maste 			    filename, linenum, keyword);
2133*a91a2465SEd Maste 		}
213421e764dfSDag-Erling Smørgrav 		break;
213521e764dfSDag-Erling Smørgrav 
2136190cef3dSDag-Erling Smørgrav 	case sSetEnv:
2137*a91a2465SEd Maste 		found = options->num_setenv == 0;
213819261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
213919261079SEd Maste 			if (*arg == '\0' || strchr(arg, '=') == NULL)
2140190cef3dSDag-Erling Smørgrav 				fatal("%s line %d: Invalid environment.",
2141190cef3dSDag-Erling Smørgrav 				    filename, linenum);
2142*a91a2465SEd Maste 			if (lookup_setenv_in_list(arg, strs, nstrs) != NULL) {
214338a52bd3SEd Maste 				debug2("%s line %d: ignoring duplicate env "
214438a52bd3SEd Maste 				    "name \"%.64s\"", filename, linenum, arg);
214538a52bd3SEd Maste 				continue;
214638a52bd3SEd Maste 			}
214719261079SEd Maste 			opt_array_append(filename, linenum, keyword,
2148*a91a2465SEd Maste 			    &strs, &nstrs, arg);
2149*a91a2465SEd Maste 		}
2150*a91a2465SEd Maste 		if (nstrs == 0) {
2151*a91a2465SEd Maste 			fatal("%s line %d: no %s specified",
2152*a91a2465SEd Maste 			    filename, linenum, keyword);
2153*a91a2465SEd Maste 		}
2154*a91a2465SEd Maste 		if (found && *activep) {
2155*a91a2465SEd Maste 			options->setenv = strs;
2156*a91a2465SEd Maste 			options->num_setenv = nstrs;
2157*a91a2465SEd Maste 			strs = NULL; /* transferred */
2158*a91a2465SEd Maste 			nstrs = 0;
2159190cef3dSDag-Erling Smørgrav 		}
2160190cef3dSDag-Erling Smørgrav 		break;
2161190cef3dSDag-Erling Smørgrav 
2162b74df5b2SDag-Erling Smørgrav 	case sPermitTunnel:
2163b74df5b2SDag-Erling Smørgrav 		intptr = &options->permit_tun;
216419261079SEd Maste 		arg = argv_next(&ac, &av);
2165b74df5b2SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
216619261079SEd Maste 			fatal("%s line %d: %s missing argument.",
216719261079SEd Maste 			    filename, linenum, keyword);
2168d4af9e69SDag-Erling Smørgrav 		value = -1;
2169d4af9e69SDag-Erling Smørgrav 		for (i = 0; tunmode_desc[i].val != -1; i++)
2170d4af9e69SDag-Erling Smørgrav 			if (strcmp(tunmode_desc[i].text, arg) == 0) {
2171d4af9e69SDag-Erling Smørgrav 				value = tunmode_desc[i].val;
2172d4af9e69SDag-Erling Smørgrav 				break;
2173d4af9e69SDag-Erling Smørgrav 			}
2174d4af9e69SDag-Erling Smørgrav 		if (value == -1)
217519261079SEd Maste 			fatal("%s line %d: bad %s argument %s",
217619261079SEd Maste 			    filename, linenum, keyword, arg);
2177557f75e5SDag-Erling Smørgrav 		if (*activep && *intptr == -1)
2178b74df5b2SDag-Erling Smørgrav 			*intptr = value;
2179b74df5b2SDag-Erling Smørgrav 		break;
2180b74df5b2SDag-Erling Smørgrav 
218119261079SEd Maste 	case sInclude:
218219261079SEd Maste 		if (cmdline) {
218319261079SEd Maste 			fatal("Include directive not supported as a "
218419261079SEd Maste 			    "command-line option");
218519261079SEd Maste 		}
218619261079SEd Maste 		value = 0;
218719261079SEd Maste 		while ((arg2 = argv_next(&ac, &av)) != NULL) {
218819261079SEd Maste 			if (*arg2 == '\0') {
218919261079SEd Maste 				error("%s line %d: keyword %s empty argument",
219019261079SEd Maste 				    filename, linenum, keyword);
219119261079SEd Maste 				goto out;
219219261079SEd Maste 			}
219319261079SEd Maste 			value++;
219419261079SEd Maste 			found = 0;
219519261079SEd Maste 			if (*arg2 != '/' && *arg2 != '~') {
219619261079SEd Maste 				xasprintf(&arg, "%s/%s", SSHDIR, arg2);
219719261079SEd Maste 			} else
219819261079SEd Maste 				arg = xstrdup(arg2);
219919261079SEd Maste 
220019261079SEd Maste 			/*
220119261079SEd Maste 			 * Don't let included files clobber the containing
220219261079SEd Maste 			 * file's Match state.
220319261079SEd Maste 			 */
220419261079SEd Maste 			oactive = *activep;
220519261079SEd Maste 
220619261079SEd Maste 			/* consult cache of include files */
220719261079SEd Maste 			TAILQ_FOREACH(item, includes, entry) {
220819261079SEd Maste 				if (strcmp(item->selector, arg) != 0)
220919261079SEd Maste 					continue;
221019261079SEd Maste 				if (item->filename != NULL) {
221119261079SEd Maste 					parse_server_config_depth(options,
221219261079SEd Maste 					    item->filename, item->contents,
221319261079SEd Maste 					    includes, connectinfo,
221419261079SEd Maste 					    (*inc_flags & SSHCFG_MATCH_ONLY
221519261079SEd Maste 					        ? SSHCFG_MATCH_ONLY : (oactive
221619261079SEd Maste 					            ? 0 : SSHCFG_NEVERMATCH)),
221719261079SEd Maste 					    activep, depth + 1);
221819261079SEd Maste 				}
221919261079SEd Maste 				found = 1;
222019261079SEd Maste 				*activep = oactive;
222119261079SEd Maste 			}
222219261079SEd Maste 			if (found != 0) {
222319261079SEd Maste 				free(arg);
222419261079SEd Maste 				continue;
222519261079SEd Maste 			}
222619261079SEd Maste 
222719261079SEd Maste 			/* requested glob was not in cache */
222819261079SEd Maste 			debug2("%s line %d: new include %s",
222919261079SEd Maste 			    filename, linenum, arg);
223019261079SEd Maste 			if ((r = glob(arg, 0, NULL, &gbuf)) != 0) {
223119261079SEd Maste 				if (r != GLOB_NOMATCH) {
223219261079SEd Maste 					fatal("%s line %d: include \"%s\" glob "
223319261079SEd Maste 					    "failed", filename, linenum, arg);
223419261079SEd Maste 				}
223519261079SEd Maste 				/*
223619261079SEd Maste 				 * If no entry matched then record a
223719261079SEd Maste 				 * placeholder to skip later glob calls.
223819261079SEd Maste 				 */
223919261079SEd Maste 				debug2("%s line %d: no match for %s",
224019261079SEd Maste 				    filename, linenum, arg);
224119261079SEd Maste 				item = xcalloc(1, sizeof(*item));
224219261079SEd Maste 				item->selector = strdup(arg);
224319261079SEd Maste 				TAILQ_INSERT_TAIL(includes,
224419261079SEd Maste 				    item, entry);
224519261079SEd Maste 			}
224619261079SEd Maste 			if (gbuf.gl_pathc > INT_MAX)
224719261079SEd Maste 				fatal_f("too many glob results");
224819261079SEd Maste 			for (n = 0; n < (int)gbuf.gl_pathc; n++) {
224919261079SEd Maste 				debug2("%s line %d: including %s",
225019261079SEd Maste 				    filename, linenum, gbuf.gl_pathv[n]);
225119261079SEd Maste 				item = xcalloc(1, sizeof(*item));
225219261079SEd Maste 				item->selector = strdup(arg);
225319261079SEd Maste 				item->filename = strdup(gbuf.gl_pathv[n]);
225419261079SEd Maste 				if ((item->contents = sshbuf_new()) == NULL)
225519261079SEd Maste 					fatal_f("sshbuf_new failed");
225619261079SEd Maste 				load_server_config(item->filename,
225719261079SEd Maste 				    item->contents);
225819261079SEd Maste 				parse_server_config_depth(options,
225919261079SEd Maste 				    item->filename, item->contents,
226019261079SEd Maste 				    includes, connectinfo,
226119261079SEd Maste 				    (*inc_flags & SSHCFG_MATCH_ONLY
226219261079SEd Maste 				        ? SSHCFG_MATCH_ONLY : (oactive
226319261079SEd Maste 				            ? 0 : SSHCFG_NEVERMATCH)),
226419261079SEd Maste 				    activep, depth + 1);
226519261079SEd Maste 				*activep = oactive;
226619261079SEd Maste 				TAILQ_INSERT_TAIL(includes, item, entry);
226719261079SEd Maste 			}
226819261079SEd Maste 			globfree(&gbuf);
226919261079SEd Maste 			free(arg);
227019261079SEd Maste 		}
227119261079SEd Maste 		if (value == 0) {
227219261079SEd Maste 			fatal("%s line %d: %s missing filename argument",
227319261079SEd Maste 			    filename, linenum, keyword);
227419261079SEd Maste 		}
227519261079SEd Maste 		break;
227619261079SEd Maste 
2277333ee039SDag-Erling Smørgrav 	case sMatch:
2278333ee039SDag-Erling Smørgrav 		if (cmdline)
2279333ee039SDag-Erling Smørgrav 			fatal("Match directive not supported as a command-line "
2280333ee039SDag-Erling Smørgrav 			    "option");
228119261079SEd Maste 		value = match_cfg_line(&str, linenum,
228219261079SEd Maste 		    (*inc_flags & SSHCFG_NEVERMATCH ? NULL : connectinfo));
2283333ee039SDag-Erling Smørgrav 		if (value < 0)
2284333ee039SDag-Erling Smørgrav 			fatal("%s line %d: Bad Match condition", filename,
2285333ee039SDag-Erling Smørgrav 			    linenum);
228619261079SEd Maste 		*activep = (*inc_flags & SSHCFG_NEVERMATCH) ? 0 : value;
228719261079SEd Maste 		/*
228819261079SEd Maste 		 * The MATCH_ONLY flag is applicable only until the first
228919261079SEd Maste 		 * match block.
229019261079SEd Maste 		 */
229119261079SEd Maste 		*inc_flags &= ~SSHCFG_MATCH_ONLY;
229219261079SEd Maste 		/*
229319261079SEd Maste 		 * If match_cfg_line() didn't consume all its arguments then
229419261079SEd Maste 		 * arrange for the extra arguments check below to fail.
229519261079SEd Maste 		 */
229619261079SEd Maste 		if (str == NULL || *str == '\0')
229719261079SEd Maste 			argv_consume(&ac);
2298333ee039SDag-Erling Smørgrav 		break;
2299333ee039SDag-Erling Smørgrav 
2300190cef3dSDag-Erling Smørgrav 	case sPermitListen:
2301333ee039SDag-Erling Smørgrav 	case sPermitOpen:
2302190cef3dSDag-Erling Smørgrav 		if (opcode == sPermitListen) {
2303190cef3dSDag-Erling Smørgrav 			uintptr = &options->num_permitted_listens;
2304190cef3dSDag-Erling Smørgrav 			chararrayptr = &options->permitted_listens;
2305190cef3dSDag-Erling Smørgrav 		} else {
2306190cef3dSDag-Erling Smørgrav 			uintptr = &options->num_permitted_opens;
2307190cef3dSDag-Erling Smørgrav 			chararrayptr = &options->permitted_opens;
2308190cef3dSDag-Erling Smørgrav 		}
2309*a91a2465SEd Maste 		found = *uintptr == 0;
2310*a91a2465SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
2311*a91a2465SEd Maste 			if (strcmp(arg, "any") == 0 ||
2312*a91a2465SEd Maste 			    strcmp(arg, "none") == 0) {
2313*a91a2465SEd Maste 				if (nstrs != 0) {
2314*a91a2465SEd Maste 					fatal("%s line %d: %s must appear "
2315*a91a2465SEd Maste 					    "alone on a %s line.",
2316*a91a2465SEd Maste 					    filename, linenum, arg, keyword);
2317462c32cbSDag-Erling Smørgrav 				}
2318*a91a2465SEd Maste 				opt_array_append(filename, linenum, keyword,
2319*a91a2465SEd Maste 				    &strs, &nstrs, arg);
2320*a91a2465SEd Maste 				continue;
2321462c32cbSDag-Erling Smørgrav 			}
2322*a91a2465SEd Maste 
2323190cef3dSDag-Erling Smørgrav 			if (opcode == sPermitListen &&
2324190cef3dSDag-Erling Smørgrav 			    strchr(arg, ':') == NULL) {
2325190cef3dSDag-Erling Smørgrav 				/*
2326190cef3dSDag-Erling Smørgrav 				 * Allow bare port number for PermitListen
2327190cef3dSDag-Erling Smørgrav 				 * to indicate a wildcard listen host.
2328190cef3dSDag-Erling Smørgrav 				 */
2329190cef3dSDag-Erling Smørgrav 				xasprintf(&arg2, "*:%s", arg);
2330190cef3dSDag-Erling Smørgrav 			} else {
23314f52dfbbSDag-Erling Smørgrav 				arg2 = xstrdup(arg);
23321323ec57SEd Maste 				p = hpdelim(&arg);
23331323ec57SEd Maste 				if (p == NULL) {
233419261079SEd Maste 					fatal("%s line %d: %s missing host",
233519261079SEd Maste 					    filename, linenum, keyword);
2336190cef3dSDag-Erling Smørgrav 				}
2337333ee039SDag-Erling Smørgrav 				p = cleanhostname(p);
2338190cef3dSDag-Erling Smørgrav 			}
2339190cef3dSDag-Erling Smørgrav 			if (arg == NULL ||
2340190cef3dSDag-Erling Smørgrav 			    ((port = permitopen_port(arg)) < 0)) {
234119261079SEd Maste 				fatal("%s line %d: %s bad port number",
234219261079SEd Maste 				    filename, linenum, keyword);
2343190cef3dSDag-Erling Smørgrav 			}
234419261079SEd Maste 			opt_array_append(filename, linenum, keyword,
2345*a91a2465SEd Maste 			    &strs, &nstrs, arg2);
23464f52dfbbSDag-Erling Smørgrav 			free(arg2);
2347333ee039SDag-Erling Smørgrav 		}
2348*a91a2465SEd Maste 		if (nstrs == 0) {
2349*a91a2465SEd Maste 			fatal("%s line %d: %s missing argument.",
2350*a91a2465SEd Maste 			    filename, linenum, keyword);
2351*a91a2465SEd Maste 		}
2352*a91a2465SEd Maste 		if (found && *activep) {
2353*a91a2465SEd Maste 			*chararrayptr = strs;
2354*a91a2465SEd Maste 			*uintptr = nstrs;
2355*a91a2465SEd Maste 			strs = NULL; /* transferred */
2356*a91a2465SEd Maste 			nstrs = 0;
2357*a91a2465SEd Maste 		}
2358333ee039SDag-Erling Smørgrav 		break;
2359333ee039SDag-Erling Smørgrav 
2360333ee039SDag-Erling Smørgrav 	case sForceCommand:
236119261079SEd Maste 		if (str == NULL || *str == '\0')
236219261079SEd Maste 			fatal("%s line %d: %s missing argument.",
236319261079SEd Maste 			    filename, linenum, keyword);
236419261079SEd Maste 		len = strspn(str, WHITESPACE);
2365333ee039SDag-Erling Smørgrav 		if (*activep && options->adm_forced_command == NULL)
236619261079SEd Maste 			options->adm_forced_command = xstrdup(str + len);
236719261079SEd Maste 		argv_consume(&ac);
236819261079SEd Maste 		break;
2369333ee039SDag-Erling Smørgrav 
2370d4af9e69SDag-Erling Smørgrav 	case sChrootDirectory:
2371d4af9e69SDag-Erling Smørgrav 		charptr = &options->chroot_directory;
2372d4af9e69SDag-Erling Smørgrav 
237319261079SEd Maste 		arg = argv_next(&ac, &av);
2374d4af9e69SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
237519261079SEd Maste 			fatal("%s line %d: %s missing argument.",
237619261079SEd Maste 			    filename, linenum, keyword);
2377d4af9e69SDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
2378d4af9e69SDag-Erling Smørgrav 			*charptr = xstrdup(arg);
2379d4af9e69SDag-Erling Smørgrav 		break;
2380d4af9e69SDag-Erling Smørgrav 
2381b15c8340SDag-Erling Smørgrav 	case sTrustedUserCAKeys:
2382b15c8340SDag-Erling Smørgrav 		charptr = &options->trusted_user_ca_keys;
2383b15c8340SDag-Erling Smørgrav 		goto parse_filename;
2384b15c8340SDag-Erling Smørgrav 
2385b15c8340SDag-Erling Smørgrav 	case sRevokedKeys:
2386b15c8340SDag-Erling Smørgrav 		charptr = &options->revoked_keys_file;
2387b15c8340SDag-Erling Smørgrav 		goto parse_filename;
2388b15c8340SDag-Erling Smørgrav 
238919261079SEd Maste 	case sSecurityKeyProvider:
239019261079SEd Maste 		charptr = &options->sk_provider;
239119261079SEd Maste 		arg = argv_next(&ac, &av);
239219261079SEd Maste 		if (!arg || *arg == '\0')
239319261079SEd Maste 			fatal("%s line %d: %s missing argument.",
239419261079SEd Maste 			    filename, linenum, keyword);
239519261079SEd Maste 		if (*activep && *charptr == NULL) {
239619261079SEd Maste 			*charptr = strcasecmp(arg, "internal") == 0 ?
239719261079SEd Maste 			    xstrdup(arg) : derelativise_path(arg);
239819261079SEd Maste 			/* increase optional counter */
239919261079SEd Maste 			if (intptr != NULL)
240019261079SEd Maste 				*intptr = *intptr + 1;
240119261079SEd Maste 		}
240219261079SEd Maste 		break;
240319261079SEd Maste 
24044a421b63SDag-Erling Smørgrav 	case sIPQoS:
240519261079SEd Maste 		arg = argv_next(&ac, &av);
240619261079SEd Maste 		if (!arg || *arg == '\0')
240719261079SEd Maste 			fatal("%s line %d: %s missing argument.",
240819261079SEd Maste 			    filename, linenum, keyword);
24094a421b63SDag-Erling Smørgrav 		if ((value = parse_ipqos(arg)) == -1)
241019261079SEd Maste 			fatal("%s line %d: Bad %s value: %s",
241119261079SEd Maste 			    filename, linenum, keyword, arg);
241219261079SEd Maste 		arg = argv_next(&ac, &av);
24134a421b63SDag-Erling Smørgrav 		if (arg == NULL)
24144a421b63SDag-Erling Smørgrav 			value2 = value;
24154a421b63SDag-Erling Smørgrav 		else if ((value2 = parse_ipqos(arg)) == -1)
241619261079SEd Maste 			fatal("%s line %d: Bad %s value: %s",
241719261079SEd Maste 			    filename, linenum, keyword, arg);
24184a421b63SDag-Erling Smørgrav 		if (*activep) {
24194a421b63SDag-Erling Smørgrav 			options->ip_qos_interactive = value;
24204a421b63SDag-Erling Smørgrav 			options->ip_qos_bulk = value2;
24214a421b63SDag-Erling Smørgrav 		}
24224a421b63SDag-Erling Smørgrav 		break;
24234a421b63SDag-Erling Smørgrav 
2424db58a8e4SDag-Erling Smørgrav 	case sVersionAddendum:
242519261079SEd Maste 		if (str == NULL || *str == '\0')
242619261079SEd Maste 			fatal("%s line %d: %s missing argument.",
242719261079SEd Maste 			    filename, linenum, keyword);
242819261079SEd Maste 		len = strspn(str, WHITESPACE);
242919261079SEd Maste 		if (strchr(str + len, '\r') != NULL) {
243019261079SEd Maste 			fatal("%.200s line %d: Invalid %s argument",
243119261079SEd Maste 			    filename, linenum, keyword);
2432462c32cbSDag-Erling Smørgrav 		}
243319261079SEd Maste 		if ((arg = strchr(line, '#')) != NULL) {
243419261079SEd Maste 			*arg = '\0';
243519261079SEd Maste 			rtrim(line);
243619261079SEd Maste 		}
243719261079SEd Maste 		if (*activep && options->version_addendum == NULL) {
243819261079SEd Maste 			if (strcasecmp(str + len, "none") == 0)
243919261079SEd Maste 				options->version_addendum = xstrdup("");
244019261079SEd Maste 			else
244119261079SEd Maste 				options->version_addendum = xstrdup(str + len);
244219261079SEd Maste 		}
244319261079SEd Maste 		argv_consume(&ac);
244419261079SEd Maste 		break;
2445db58a8e4SDag-Erling Smørgrav 
24466888a9beSDag-Erling Smørgrav 	case sAuthorizedKeysCommand:
244719261079SEd Maste 		charptr = &options->authorized_keys_command;
244819261079SEd Maste  parse_command:
244919261079SEd Maste 		len = strspn(str, WHITESPACE);
245019261079SEd Maste 		if (str[len] != '/' && strcasecmp(str + len, "none") != 0) {
245119261079SEd Maste 			fatal("%.200s line %d: %s must be an absolute path",
245219261079SEd Maste 			    filename, linenum, keyword);
24536888a9beSDag-Erling Smørgrav 		}
2454535af610SEd Maste 		if (*activep && *charptr == NULL)
245519261079SEd Maste 			*charptr = xstrdup(str + len);
245619261079SEd Maste 		argv_consume(&ac);
245719261079SEd Maste 		break;
24586888a9beSDag-Erling Smørgrav 
24596888a9beSDag-Erling Smørgrav 	case sAuthorizedKeysCommandUser:
24606888a9beSDag-Erling Smørgrav 		charptr = &options->authorized_keys_command_user;
246119261079SEd Maste  parse_localuser:
246219261079SEd Maste 		arg = argv_next(&ac, &av);
246319261079SEd Maste 		if (!arg || *arg == '\0') {
246419261079SEd Maste 			fatal("%s line %d: missing %s argument.",
246519261079SEd Maste 			    filename, linenum, keyword);
246619261079SEd Maste 		}
24676888a9beSDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
24686888a9beSDag-Erling Smørgrav 			*charptr = xstrdup(arg);
24696888a9beSDag-Erling Smørgrav 		break;
24706888a9beSDag-Erling Smørgrav 
2471557f75e5SDag-Erling Smørgrav 	case sAuthorizedPrincipalsCommand:
247219261079SEd Maste 		charptr = &options->authorized_principals_command;
247319261079SEd Maste 		goto parse_command;
2474557f75e5SDag-Erling Smørgrav 
2475557f75e5SDag-Erling Smørgrav 	case sAuthorizedPrincipalsCommandUser:
2476557f75e5SDag-Erling Smørgrav 		charptr = &options->authorized_principals_command_user;
247719261079SEd Maste 		goto parse_localuser;
2478557f75e5SDag-Erling Smørgrav 
24796888a9beSDag-Erling Smørgrav 	case sAuthenticationMethods:
248019261079SEd Maste 		found = options->num_auth_methods == 0;
2481076ad2f8SDag-Erling Smørgrav 		value = 0; /* seen "any" pseudo-method */
248219261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
2483076ad2f8SDag-Erling Smørgrav 			if (strcmp(arg, "any") == 0) {
2484*a91a2465SEd Maste 				if (nstrs > 0) {
248519261079SEd Maste 					fatal("%s line %d: \"any\" must "
248619261079SEd Maste 					    "appear alone in %s",
248719261079SEd Maste 					    filename, linenum, keyword);
2488076ad2f8SDag-Erling Smørgrav 				}
2489076ad2f8SDag-Erling Smørgrav 				value = 1;
2490076ad2f8SDag-Erling Smørgrav 			} else if (value) {
2491076ad2f8SDag-Erling Smørgrav 				fatal("%s line %d: \"any\" must appear "
249219261079SEd Maste 				    "alone in %s", filename, linenum, keyword);
2493076ad2f8SDag-Erling Smørgrav 			} else if (auth2_methods_valid(arg, 0) != 0) {
249419261079SEd Maste 				fatal("%s line %d: invalid %s method list.",
249519261079SEd Maste 				    filename, linenum, keyword);
2496076ad2f8SDag-Erling Smørgrav 			}
249719261079SEd Maste 			opt_array_append(filename, linenum, keyword,
2498*a91a2465SEd Maste 			    &strs, &nstrs, arg);
24996888a9beSDag-Erling Smørgrav 		}
2500*a91a2465SEd Maste 		if (nstrs == 0) {
250119261079SEd Maste 			fatal("%s line %d: no %s specified",
250219261079SEd Maste 			    filename, linenum, keyword);
2503076ad2f8SDag-Erling Smørgrav 		}
2504*a91a2465SEd Maste 		if (found && *activep) {
2505*a91a2465SEd Maste 			options->auth_methods = strs;
2506*a91a2465SEd Maste 			options->num_auth_methods = nstrs;
2507*a91a2465SEd Maste 			strs = NULL; /* transferred */
2508*a91a2465SEd Maste 			nstrs = 0;
2509*a91a2465SEd Maste 		}
251019261079SEd Maste 		break;
25116888a9beSDag-Erling Smørgrav 
2512a0ee8cc6SDag-Erling Smørgrav 	case sStreamLocalBindMask:
251319261079SEd Maste 		arg = argv_next(&ac, &av);
2514a0ee8cc6SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
251519261079SEd Maste 			fatal("%s line %d: %s missing argument.",
251619261079SEd Maste 			    filename, linenum, keyword);
2517a0ee8cc6SDag-Erling Smørgrav 		/* Parse mode in octal format */
2518a0ee8cc6SDag-Erling Smørgrav 		value = strtol(arg, &p, 8);
2519a0ee8cc6SDag-Erling Smørgrav 		if (arg == p || value < 0 || value > 0777)
252019261079SEd Maste 			fatal("%s line %d: Invalid %s.",
252119261079SEd Maste 			    filename, linenum, keyword);
2522557f75e5SDag-Erling Smørgrav 		if (*activep)
2523a0ee8cc6SDag-Erling Smørgrav 			options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
2524a0ee8cc6SDag-Erling Smørgrav 		break;
2525a0ee8cc6SDag-Erling Smørgrav 
2526a0ee8cc6SDag-Erling Smørgrav 	case sStreamLocalBindUnlink:
2527a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->fwd_opts.streamlocal_bind_unlink;
2528a0ee8cc6SDag-Erling Smørgrav 		goto parse_flag;
2529a0ee8cc6SDag-Erling Smørgrav 
2530bc5531deSDag-Erling Smørgrav 	case sFingerprintHash:
253119261079SEd Maste 		arg = argv_next(&ac, &av);
2532bc5531deSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
253319261079SEd Maste 			fatal("%s line %d: %s missing argument.",
253419261079SEd Maste 			    filename, linenum, keyword);
2535bc5531deSDag-Erling Smørgrav 		if ((value = ssh_digest_alg_by_name(arg)) == -1)
253619261079SEd Maste 			fatal("%.200s line %d: Invalid %s algorithm \"%s\".",
253719261079SEd Maste 			    filename, linenum, keyword, arg);
2538bc5531deSDag-Erling Smørgrav 		if (*activep)
2539bc5531deSDag-Erling Smørgrav 			options->fingerprint_hash = value;
2540bc5531deSDag-Erling Smørgrav 		break;
2541bc5531deSDag-Erling Smørgrav 
25424f52dfbbSDag-Erling Smørgrav 	case sExposeAuthInfo:
25434f52dfbbSDag-Erling Smørgrav 		intptr = &options->expose_userauth_info;
25444f52dfbbSDag-Erling Smørgrav 		goto parse_flag;
25454f52dfbbSDag-Erling Smørgrav 
254647dd1d1bSDag-Erling Smørgrav 	case sRDomain:
254719261079SEd Maste #if !defined(__OpenBSD__) && !defined(HAVE_SYS_SET_PROCESS_RDOMAIN)
254819261079SEd Maste 		fatal("%s line %d: setting RDomain not supported on this "
254919261079SEd Maste 		    "platform.", filename, linenum);
255019261079SEd Maste #endif
255147dd1d1bSDag-Erling Smørgrav 		charptr = &options->routing_domain;
255219261079SEd Maste 		arg = argv_next(&ac, &av);
255347dd1d1bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
255419261079SEd Maste 			fatal("%s line %d: %s missing argument.",
255519261079SEd Maste 			    filename, linenum, keyword);
255647dd1d1bSDag-Erling Smørgrav 		if (strcasecmp(arg, "none") != 0 && strcmp(arg, "%D") != 0 &&
255747dd1d1bSDag-Erling Smørgrav 		    !valid_rdomain(arg))
255819261079SEd Maste 			fatal("%s line %d: invalid routing domain",
255947dd1d1bSDag-Erling Smørgrav 			    filename, linenum);
256047dd1d1bSDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
256147dd1d1bSDag-Erling Smørgrav 			*charptr = xstrdup(arg);
256247dd1d1bSDag-Erling Smørgrav 		break;
256347dd1d1bSDag-Erling Smørgrav 
256438a52bd3SEd Maste 	case sRequiredRSASize:
256538a52bd3SEd Maste 		intptr = &options->required_rsa_size;
256638a52bd3SEd Maste 		goto parse_int;
256738a52bd3SEd Maste 
2568f374ba41SEd Maste 	case sChannelTimeout:
2569*a91a2465SEd Maste 		found = options->num_channel_timeouts == 0;
2570f374ba41SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
2571f374ba41SEd Maste 			/* Allow "none" only in first position */
2572f374ba41SEd Maste 			if (strcasecmp(arg, "none") == 0) {
2573*a91a2465SEd Maste 				if (nstrs > 0 || ac > 0) {
2574f374ba41SEd Maste 					error("%s line %d: keyword %s \"none\" "
2575f374ba41SEd Maste 					    "argument must appear alone.",
2576f374ba41SEd Maste 					    filename, linenum, keyword);
2577f374ba41SEd Maste 					goto out;
2578f374ba41SEd Maste 				}
2579069ac184SEd Maste 			} else if (parse_pattern_interval(arg,
2580069ac184SEd Maste 			    NULL, NULL) != 0) {
2581f374ba41SEd Maste 				fatal("%s line %d: invalid channel timeout %s",
2582f374ba41SEd Maste 				    filename, linenum, arg);
2583f374ba41SEd Maste 			}
2584f374ba41SEd Maste 			opt_array_append(filename, linenum, keyword,
2585*a91a2465SEd Maste 			    &strs, &nstrs, arg);
2586*a91a2465SEd Maste 		}
2587*a91a2465SEd Maste 		if (nstrs == 0) {
2588*a91a2465SEd Maste 			fatal("%s line %d: no %s specified",
2589*a91a2465SEd Maste 			    filename, linenum, keyword);
2590*a91a2465SEd Maste 		}
2591*a91a2465SEd Maste 		if (found && *activep) {
2592*a91a2465SEd Maste 			options->channel_timeouts = strs;
2593*a91a2465SEd Maste 			options->num_channel_timeouts = nstrs;
2594*a91a2465SEd Maste 			strs = NULL; /* transferred */
2595*a91a2465SEd Maste 			nstrs = 0;
2596f374ba41SEd Maste 		}
2597f374ba41SEd Maste 		break;
2598f374ba41SEd Maste 
2599f374ba41SEd Maste 	case sUnusedConnectionTimeout:
2600f374ba41SEd Maste 		intptr = &options->unused_connection_timeout;
2601f374ba41SEd Maste 		/* peek at first arg for "none" so we can reuse parse_time */
2602f374ba41SEd Maste 		if (av[0] != NULL && strcasecmp(av[0], "none") == 0) {
2603f374ba41SEd Maste 			(void)argv_next(&ac, &av); /* consume arg */
2604f374ba41SEd Maste 			if (*activep)
2605f374ba41SEd Maste 				*intptr = 0;
2606f374ba41SEd Maste 			break;
2607f374ba41SEd Maste 		}
2608f374ba41SEd Maste 		goto parse_time;
2609f374ba41SEd Maste 
2610b2af61ecSKurt Lidl 	case sUseBlacklist:
2611b2af61ecSKurt Lidl 		intptr = &options->use_blacklist;
2612b2af61ecSKurt Lidl 		goto parse_flag;
2613b2af61ecSKurt Lidl 
2614af12a3e7SDag-Erling Smørgrav 	case sDeprecated:
2615ca86bcf2SDag-Erling Smørgrav 	case sIgnore:
2616cf2b5f3bSDag-Erling Smørgrav 	case sUnsupported:
2617ca86bcf2SDag-Erling Smørgrav 		do_log2(opcode == sIgnore ?
2618ca86bcf2SDag-Erling Smørgrav 		    SYSLOG_LEVEL_DEBUG2 : SYSLOG_LEVEL_INFO,
2619ca86bcf2SDag-Erling Smørgrav 		    "%s line %d: %s option %s", filename, linenum,
262019261079SEd Maste 		    opcode == sUnsupported ? "Unsupported" : "Deprecated",
262119261079SEd Maste 		    keyword);
262219261079SEd Maste 		argv_consume(&ac);
2623af12a3e7SDag-Erling Smørgrav 		break;
2624af12a3e7SDag-Erling Smørgrav 
262542f71286SMark Murray 	default:
2626af12a3e7SDag-Erling Smørgrav 		fatal("%s line %d: Missing handler for opcode %s (%d)",
262719261079SEd Maste 		    filename, linenum, keyword, opcode);
2628511b41d2SMark Murray 	}
262919261079SEd Maste 	/* Check that there is no garbage at end of line. */
263019261079SEd Maste 	if (ac > 0) {
263119261079SEd Maste 		error("%.200s line %d: keyword %s extra arguments "
263219261079SEd Maste 		    "at end of line", filename, linenum, keyword);
263319261079SEd Maste 		goto out;
2634af12a3e7SDag-Erling Smørgrav 	}
2635af12a3e7SDag-Erling Smørgrav 
263619261079SEd Maste 	/* success */
263719261079SEd Maste 	ret = 0;
263819261079SEd Maste  out:
2639*a91a2465SEd Maste 	opt_array_free2(strs, NULL, nstrs);
264019261079SEd Maste 	argv_free(oav, oac);
264119261079SEd Maste 	return ret;
264219261079SEd Maste }
264319261079SEd Maste 
264419261079SEd Maste int
264519261079SEd Maste process_server_config_line(ServerOptions *options, char *line,
264619261079SEd Maste     const char *filename, int linenum, int *activep,
264719261079SEd Maste     struct connection_info *connectinfo, struct include_list *includes)
264819261079SEd Maste {
264919261079SEd Maste 	int inc_flags = 0;
265019261079SEd Maste 
265119261079SEd Maste 	return process_server_config_line_depth(options, line, filename,
265219261079SEd Maste 	    linenum, activep, connectinfo, &inc_flags, 0, includes);
265319261079SEd Maste }
265419261079SEd Maste 
265519261079SEd Maste 
2656af12a3e7SDag-Erling Smørgrav /* Reads the server configuration file. */
2657af12a3e7SDag-Erling Smørgrav 
2658af12a3e7SDag-Erling Smørgrav void
2659190cef3dSDag-Erling Smørgrav load_server_config(const char *filename, struct sshbuf *conf)
2660af12a3e7SDag-Erling Smørgrav {
266119261079SEd Maste 	struct stat st;
2662190cef3dSDag-Erling Smørgrav 	char *line = NULL, *cp;
2663190cef3dSDag-Erling Smørgrav 	size_t linesize = 0;
2664a82e551fSDag-Erling Smørgrav 	FILE *f;
2665f374ba41SEd Maste 	int r;
2666af12a3e7SDag-Erling Smørgrav 
266719261079SEd Maste 	debug2_f("filename %s", filename);
266821e764dfSDag-Erling Smørgrav 	if ((f = fopen(filename, "r")) == NULL) {
2669af12a3e7SDag-Erling Smørgrav 		perror(filename);
2670af12a3e7SDag-Erling Smørgrav 		exit(1);
2671af12a3e7SDag-Erling Smørgrav 	}
2672190cef3dSDag-Erling Smørgrav 	sshbuf_reset(conf);
267319261079SEd Maste 	/* grow buffer, so realloc is avoided for large config files */
267419261079SEd Maste 	if (fstat(fileno(f), &st) == 0 && st.st_size > 0 &&
267519261079SEd Maste 	    (r = sshbuf_allocate(conf, st.st_size)) != 0)
267619261079SEd Maste 		fatal_fr(r, "allocate");
2677190cef3dSDag-Erling Smørgrav 	while (getline(&line, &linesize, f) != -1) {
267821e764dfSDag-Erling Smørgrav 		/*
267919261079SEd Maste 		 * Strip whitespace
268021e764dfSDag-Erling Smørgrav 		 * NB - preserve newlines, they are needed to reproduce
268121e764dfSDag-Erling Smørgrav 		 * line numbers later for error messages
268221e764dfSDag-Erling Smørgrav 		 */
268321e764dfSDag-Erling Smørgrav 		cp = line + strspn(line, " \t\r");
2684190cef3dSDag-Erling Smørgrav 		if ((r = sshbuf_put(conf, cp, strlen(cp))) != 0)
268519261079SEd Maste 			fatal_fr(r, "sshbuf_put");
268621e764dfSDag-Erling Smørgrav 	}
2687190cef3dSDag-Erling Smørgrav 	free(line);
2688190cef3dSDag-Erling Smørgrav 	if ((r = sshbuf_put_u8(conf, 0)) != 0)
268919261079SEd Maste 		fatal_fr(r, "sshbuf_put_u8");
269021e764dfSDag-Erling Smørgrav 	fclose(f);
269119261079SEd Maste 	debug2_f("done config len = %zu", sshbuf_len(conf));
269221e764dfSDag-Erling Smørgrav }
269321e764dfSDag-Erling Smørgrav 
269421e764dfSDag-Erling Smørgrav void
2695462c32cbSDag-Erling Smørgrav parse_server_match_config(ServerOptions *options,
269619261079SEd Maste    struct include_list *includes, struct connection_info *connectinfo)
269721e764dfSDag-Erling Smørgrav {
2698333ee039SDag-Erling Smørgrav 	ServerOptions mo;
2699333ee039SDag-Erling Smørgrav 
2700333ee039SDag-Erling Smørgrav 	initialize_server_options(&mo);
270119261079SEd Maste 	parse_server_config(&mo, "reprocess config", cfg, includes,
270287c1498dSEd Maste 	    connectinfo, 0);
2703d4af9e69SDag-Erling Smørgrav 	copy_set_server_options(options, &mo, 0);
2704333ee039SDag-Erling Smørgrav }
2705333ee039SDag-Erling Smørgrav 
2706462c32cbSDag-Erling Smørgrav int parse_server_match_testspec(struct connection_info *ci, char *spec)
2707462c32cbSDag-Erling Smørgrav {
2708462c32cbSDag-Erling Smørgrav 	char *p;
2709462c32cbSDag-Erling Smørgrav 
2710462c32cbSDag-Erling Smørgrav 	while ((p = strsep(&spec, ",")) && *p != '\0') {
2711462c32cbSDag-Erling Smørgrav 		if (strncmp(p, "addr=", 5) == 0) {
2712462c32cbSDag-Erling Smørgrav 			ci->address = xstrdup(p + 5);
2713462c32cbSDag-Erling Smørgrav 		} else if (strncmp(p, "host=", 5) == 0) {
2714462c32cbSDag-Erling Smørgrav 			ci->host = xstrdup(p + 5);
2715462c32cbSDag-Erling Smørgrav 		} else if (strncmp(p, "user=", 5) == 0) {
2716462c32cbSDag-Erling Smørgrav 			ci->user = xstrdup(p + 5);
2717462c32cbSDag-Erling Smørgrav 		} else if (strncmp(p, "laddr=", 6) == 0) {
2718462c32cbSDag-Erling Smørgrav 			ci->laddress = xstrdup(p + 6);
271947dd1d1bSDag-Erling Smørgrav 		} else if (strncmp(p, "rdomain=", 8) == 0) {
272047dd1d1bSDag-Erling Smørgrav 			ci->rdomain = xstrdup(p + 8);
2721462c32cbSDag-Erling Smørgrav 		} else if (strncmp(p, "lport=", 6) == 0) {
2722462c32cbSDag-Erling Smørgrav 			ci->lport = a2port(p + 6);
2723462c32cbSDag-Erling Smørgrav 			if (ci->lport == -1) {
2724462c32cbSDag-Erling Smørgrav 				fprintf(stderr, "Invalid port '%s' in test mode"
2725462c32cbSDag-Erling Smørgrav 				    " specification %s\n", p+6, p);
2726462c32cbSDag-Erling Smørgrav 				return -1;
2727462c32cbSDag-Erling Smørgrav 			}
2728462c32cbSDag-Erling Smørgrav 		} else {
2729462c32cbSDag-Erling Smørgrav 			fprintf(stderr, "Invalid test mode specification %s\n",
2730462c32cbSDag-Erling Smørgrav 			    p);
2731462c32cbSDag-Erling Smørgrav 			return -1;
2732462c32cbSDag-Erling Smørgrav 		}
2733462c32cbSDag-Erling Smørgrav 	}
2734462c32cbSDag-Erling Smørgrav 	return 0;
2735462c32cbSDag-Erling Smørgrav }
2736462c32cbSDag-Erling Smørgrav 
2737edf85781SEd Maste void
2738edf85781SEd Maste servconf_merge_subsystems(ServerOptions *dst, ServerOptions *src)
2739edf85781SEd Maste {
2740edf85781SEd Maste 	u_int i, j, found;
2741edf85781SEd Maste 
2742edf85781SEd Maste 	for (i = 0; i < src->num_subsystems; i++) {
2743edf85781SEd Maste 		found = 0;
2744edf85781SEd Maste 		for (j = 0; j < dst->num_subsystems; j++) {
2745edf85781SEd Maste 			if (strcmp(src->subsystem_name[i],
2746edf85781SEd Maste 			    dst->subsystem_name[j]) == 0) {
2747edf85781SEd Maste 				found = 1;
2748edf85781SEd Maste 				break;
2749edf85781SEd Maste 			}
2750edf85781SEd Maste 		}
2751edf85781SEd Maste 		if (found) {
2752edf85781SEd Maste 			debug_f("override \"%s\"", dst->subsystem_name[j]);
2753edf85781SEd Maste 			free(dst->subsystem_command[j]);
2754edf85781SEd Maste 			free(dst->subsystem_args[j]);
2755edf85781SEd Maste 			dst->subsystem_command[j] =
2756edf85781SEd Maste 			    xstrdup(src->subsystem_command[i]);
2757edf85781SEd Maste 			dst->subsystem_args[j] =
2758edf85781SEd Maste 			    xstrdup(src->subsystem_args[i]);
2759edf85781SEd Maste 			continue;
2760edf85781SEd Maste 		}
2761edf85781SEd Maste 		debug_f("add \"%s\"", src->subsystem_name[i]);
2762edf85781SEd Maste 		dst->subsystem_name = xrecallocarray(
2763edf85781SEd Maste 		    dst->subsystem_name, dst->num_subsystems,
2764edf85781SEd Maste 		    dst->num_subsystems + 1, sizeof(*dst->subsystem_name));
2765edf85781SEd Maste 		dst->subsystem_command = xrecallocarray(
2766edf85781SEd Maste 		    dst->subsystem_command, dst->num_subsystems,
2767edf85781SEd Maste 		    dst->num_subsystems + 1, sizeof(*dst->subsystem_command));
2768edf85781SEd Maste 		dst->subsystem_args = xrecallocarray(
2769edf85781SEd Maste 		    dst->subsystem_args, dst->num_subsystems,
2770edf85781SEd Maste 		    dst->num_subsystems + 1, sizeof(*dst->subsystem_args));
2771edf85781SEd Maste 		j = dst->num_subsystems++;
2772edf85781SEd Maste 		dst->subsystem_name[j] = xstrdup(src->subsystem_name[i]);
2773edf85781SEd Maste 		dst->subsystem_command[j] = xstrdup(src->subsystem_command[i]);
2774edf85781SEd Maste 		dst->subsystem_args[j] = xstrdup(src->subsystem_args[i]);
2775edf85781SEd Maste 	}
2776edf85781SEd Maste }
2777edf85781SEd Maste 
2778462c32cbSDag-Erling Smørgrav /*
2779d4af9e69SDag-Erling Smørgrav  * Copy any supported values that are set.
2780d4af9e69SDag-Erling Smørgrav  *
27817aee6ffeSDag-Erling Smørgrav  * If the preauth flag is set, we do not bother copying the string or
2782d4af9e69SDag-Erling Smørgrav  * array values that are not used pre-authentication, because any that we
2783190cef3dSDag-Erling Smørgrav  * do use must be explicitly sent in mm_getpwnamallow().
2784d4af9e69SDag-Erling Smørgrav  */
2785333ee039SDag-Erling Smørgrav void
2786d4af9e69SDag-Erling Smørgrav copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
2787333ee039SDag-Erling Smørgrav {
2788f7167e0eSDag-Erling Smørgrav #define M_CP_INTOPT(n) do {\
2789f7167e0eSDag-Erling Smørgrav 	if (src->n != -1) \
2790f7167e0eSDag-Erling Smørgrav 		dst->n = src->n; \
2791f7167e0eSDag-Erling Smørgrav } while (0)
2792f7167e0eSDag-Erling Smørgrav 
2793d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(password_authentication);
2794d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(gss_authentication);
2795d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(pubkey_authentication);
279619261079SEd Maste 	M_CP_INTOPT(pubkey_auth_options);
2797d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(kerberos_authentication);
2798d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(hostbased_authentication);
2799e2f6069cSDag-Erling Smørgrav 	M_CP_INTOPT(hostbased_uses_name_from_packet_only);
2800d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(kbd_interactive_authentication);
2801d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(permit_root_login);
2802cce7d346SDag-Erling Smørgrav 	M_CP_INTOPT(permit_empty_passwd);
280319261079SEd Maste 	M_CP_INTOPT(ignore_rhosts);
2804d4af9e69SDag-Erling Smørgrav 
2805d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(allow_tcp_forwarding);
2806a0ee8cc6SDag-Erling Smørgrav 	M_CP_INTOPT(allow_streamlocal_forwarding);
2807d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(allow_agent_forwarding);
2808ca86bcf2SDag-Erling Smørgrav 	M_CP_INTOPT(disable_forwarding);
28094f52dfbbSDag-Erling Smørgrav 	M_CP_INTOPT(expose_userauth_info);
2810e2f6069cSDag-Erling Smørgrav 	M_CP_INTOPT(permit_tun);
2811a0ee8cc6SDag-Erling Smørgrav 	M_CP_INTOPT(fwd_opts.gateway_ports);
2812076ad2f8SDag-Erling Smørgrav 	M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink);
2813d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(x11_display_offset);
2814d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(x11_forwarding);
2815d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(x11_use_localhost);
2816f7167e0eSDag-Erling Smørgrav 	M_CP_INTOPT(permit_tty);
2817a0ee8cc6SDag-Erling Smørgrav 	M_CP_INTOPT(permit_user_rc);
2818d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(max_sessions);
2819d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(max_authtries);
2820ca86bcf2SDag-Erling Smørgrav 	M_CP_INTOPT(client_alive_count_max);
2821ca86bcf2SDag-Erling Smørgrav 	M_CP_INTOPT(client_alive_interval);
28224a421b63SDag-Erling Smørgrav 	M_CP_INTOPT(ip_qos_interactive);
28234a421b63SDag-Erling Smørgrav 	M_CP_INTOPT(ip_qos_bulk);
2824e4a9863fSDag-Erling Smørgrav 	M_CP_INTOPT(rekey_limit);
2825e4a9863fSDag-Erling Smørgrav 	M_CP_INTOPT(rekey_interval);
28264f52dfbbSDag-Erling Smørgrav 	M_CP_INTOPT(log_level);
282738a52bd3SEd Maste 	M_CP_INTOPT(required_rsa_size);
2828f374ba41SEd Maste 	M_CP_INTOPT(unused_connection_timeout);
2829d4af9e69SDag-Erling Smørgrav 
2830076ad2f8SDag-Erling Smørgrav 	/*
2831076ad2f8SDag-Erling Smørgrav 	 * The bind_mask is a mode_t that may be unsigned, so we can't use
2832076ad2f8SDag-Erling Smørgrav 	 * M_CP_INTOPT - it does a signed comparison that causes compiler
2833076ad2f8SDag-Erling Smørgrav 	 * warnings.
2834076ad2f8SDag-Erling Smørgrav 	 */
2835076ad2f8SDag-Erling Smørgrav 	if (src->fwd_opts.streamlocal_bind_mask != (mode_t)-1) {
2836076ad2f8SDag-Erling Smørgrav 		dst->fwd_opts.streamlocal_bind_mask =
2837076ad2f8SDag-Erling Smørgrav 		    src->fwd_opts.streamlocal_bind_mask;
2838076ad2f8SDag-Erling Smørgrav 	}
2839076ad2f8SDag-Erling Smørgrav 
2840f7167e0eSDag-Erling Smørgrav 	/* M_CP_STROPT and M_CP_STRARRAYOPT should not appear before here */
2841f7167e0eSDag-Erling Smørgrav #define M_CP_STROPT(n) do {\
2842f7167e0eSDag-Erling Smørgrav 	if (src->n != NULL && dst->n != src->n) { \
2843f7167e0eSDag-Erling Smørgrav 		free(dst->n); \
2844f7167e0eSDag-Erling Smørgrav 		dst->n = src->n; \
2845f7167e0eSDag-Erling Smørgrav 	} \
2846f7167e0eSDag-Erling Smørgrav } while(0)
284747dd1d1bSDag-Erling Smørgrav #define M_CP_STRARRAYOPT(s, num_s) do {\
284847dd1d1bSDag-Erling Smørgrav 	u_int i; \
284947dd1d1bSDag-Erling Smørgrav 	if (src->num_s != 0) { \
285047dd1d1bSDag-Erling Smørgrav 		for (i = 0; i < dst->num_s; i++) \
285147dd1d1bSDag-Erling Smørgrav 			free(dst->s[i]); \
285247dd1d1bSDag-Erling Smørgrav 		free(dst->s); \
285347dd1d1bSDag-Erling Smørgrav 		dst->s = xcalloc(src->num_s, sizeof(*dst->s)); \
285447dd1d1bSDag-Erling Smørgrav 		for (i = 0; i < src->num_s; i++) \
285547dd1d1bSDag-Erling Smørgrav 			dst->s[i] = xstrdup(src->s[i]); \
285647dd1d1bSDag-Erling Smørgrav 		dst->num_s = src->num_s; \
28574f52dfbbSDag-Erling Smørgrav 	} \
28584f52dfbbSDag-Erling Smørgrav } while(0)
2859f7167e0eSDag-Erling Smørgrav 
2860e146993eSDag-Erling Smørgrav 	/* See comment in servconf.h */
2861e146993eSDag-Erling Smørgrav 	COPY_MATCH_STRING_OPTS();
2862e146993eSDag-Erling Smørgrav 
2863acc1a9efSDag-Erling Smørgrav 	/* Arguments that accept '+...' need to be expanded */
2864acc1a9efSDag-Erling Smørgrav 	assemble_algorithms(dst);
2865acc1a9efSDag-Erling Smørgrav 
2866e146993eSDag-Erling Smørgrav 	/*
2867e146993eSDag-Erling Smørgrav 	 * The only things that should be below this point are string options
2868e146993eSDag-Erling Smørgrav 	 * which are only used after authentication.
2869e146993eSDag-Erling Smørgrav 	 */
2870d4af9e69SDag-Erling Smørgrav 	if (preauth)
2871d4af9e69SDag-Erling Smørgrav 		return;
2872e146993eSDag-Erling Smørgrav 
2873acc1a9efSDag-Erling Smørgrav 	/* These options may be "none" to clear a global setting */
2874d4af9e69SDag-Erling Smørgrav 	M_CP_STROPT(adm_forced_command);
2875acc1a9efSDag-Erling Smørgrav 	if (option_clear_or_none(dst->adm_forced_command)) {
2876acc1a9efSDag-Erling Smørgrav 		free(dst->adm_forced_command);
2877acc1a9efSDag-Erling Smørgrav 		dst->adm_forced_command = NULL;
2878acc1a9efSDag-Erling Smørgrav 	}
2879d4af9e69SDag-Erling Smørgrav 	M_CP_STROPT(chroot_directory);
2880acc1a9efSDag-Erling Smørgrav 	if (option_clear_or_none(dst->chroot_directory)) {
2881acc1a9efSDag-Erling Smørgrav 		free(dst->chroot_directory);
2882acc1a9efSDag-Erling Smørgrav 		dst->chroot_directory = NULL;
2883acc1a9efSDag-Erling Smørgrav 	}
2884edf85781SEd Maste 
2885edf85781SEd Maste 	/* Subsystems require merging. */
2886edf85781SEd Maste 	servconf_merge_subsystems(dst, src);
2887333ee039SDag-Erling Smørgrav }
2888d4af9e69SDag-Erling Smørgrav 
2889d4af9e69SDag-Erling Smørgrav #undef M_CP_INTOPT
2890d4af9e69SDag-Erling Smørgrav #undef M_CP_STROPT
2891e146993eSDag-Erling Smørgrav #undef M_CP_STRARRAYOPT
2892333ee039SDag-Erling Smørgrav 
289319261079SEd Maste #define SERVCONF_MAX_DEPTH	16
289419261079SEd Maste static void
289519261079SEd Maste parse_server_config_depth(ServerOptions *options, const char *filename,
289619261079SEd Maste     struct sshbuf *conf, struct include_list *includes,
289719261079SEd Maste     struct connection_info *connectinfo, int flags, int *activep, int depth)
2898333ee039SDag-Erling Smørgrav {
289919261079SEd Maste 	int linenum, bad_options = 0;
290021e764dfSDag-Erling Smørgrav 	char *cp, *obuf, *cbuf;
290121e764dfSDag-Erling Smørgrav 
290219261079SEd Maste 	if (depth < 0 || depth > SERVCONF_MAX_DEPTH)
290319261079SEd Maste 		fatal("Too many recursive configuration includes");
290419261079SEd Maste 
290519261079SEd Maste 	debug2_f("config %s len %zu%s", filename, sshbuf_len(conf),
290619261079SEd Maste 	    (flags & SSHCFG_NEVERMATCH ? " [checking syntax only]" : ""));
290721e764dfSDag-Erling Smørgrav 
2908076ad2f8SDag-Erling Smørgrav 	if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL)
290919261079SEd Maste 		fatal_f("sshbuf_dup_string failed");
291021e764dfSDag-Erling Smørgrav 	linenum = 1;
291121e764dfSDag-Erling Smørgrav 	while ((cp = strsep(&cbuf, "\n")) != NULL) {
291219261079SEd Maste 		if (process_server_config_line_depth(options, cp,
291319261079SEd Maste 		    filename, linenum++, activep, connectinfo, &flags,
291419261079SEd Maste 		    depth, includes) != 0)
2915af12a3e7SDag-Erling Smørgrav 			bad_options++;
2916511b41d2SMark Murray 	}
2917e4a9863fSDag-Erling Smørgrav 	free(obuf);
2918ca3176e7SBrian Feldman 	if (bad_options > 0)
2919af12a3e7SDag-Erling Smørgrav 		fatal("%s: terminating, %d bad configuration options",
2920511b41d2SMark Murray 		    filename, bad_options);
292119261079SEd Maste }
292219261079SEd Maste 
292319261079SEd Maste void
292419261079SEd Maste parse_server_config(ServerOptions *options, const char *filename,
292519261079SEd Maste     struct sshbuf *conf, struct include_list *includes,
292687c1498dSEd Maste     struct connection_info *connectinfo, int reexec)
292719261079SEd Maste {
292819261079SEd Maste 	int active = connectinfo ? 0 : 1;
292919261079SEd Maste 	parse_server_config_depth(options, filename, conf, includes,
293019261079SEd Maste 	    connectinfo, (connectinfo ? SSHCFG_MATCH_ONLY : 0), &active, 0);
293187c1498dSEd Maste 	if (!reexec)
2932557f75e5SDag-Erling Smørgrav 		process_queued_listen_addrs(options);
2933511b41d2SMark Murray }
2934d4af9e69SDag-Erling Smørgrav 
2935d4af9e69SDag-Erling Smørgrav static const char *
2936e146993eSDag-Erling Smørgrav fmt_multistate_int(int val, const struct multistate *m)
2937d4af9e69SDag-Erling Smørgrav {
2938e146993eSDag-Erling Smørgrav 	u_int i;
2939e146993eSDag-Erling Smørgrav 
2940e146993eSDag-Erling Smørgrav 	for (i = 0; m[i].key != NULL; i++) {
2941e146993eSDag-Erling Smørgrav 		if (m[i].value == val)
2942e146993eSDag-Erling Smørgrav 			return m[i].key;
2943e146993eSDag-Erling Smørgrav 	}
2944d4af9e69SDag-Erling Smørgrav 	return "UNKNOWN";
2945d4af9e69SDag-Erling Smørgrav }
2946e146993eSDag-Erling Smørgrav 
2947e146993eSDag-Erling Smørgrav static const char *
2948e146993eSDag-Erling Smørgrav fmt_intarg(ServerOpCodes code, int val)
2949e146993eSDag-Erling Smørgrav {
2950e146993eSDag-Erling Smørgrav 	if (val == -1)
2951e146993eSDag-Erling Smørgrav 		return "unset";
2952e146993eSDag-Erling Smørgrav 	switch (code) {
2953e146993eSDag-Erling Smørgrav 	case sAddressFamily:
2954e146993eSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_addressfamily);
2955e146993eSDag-Erling Smørgrav 	case sPermitRootLogin:
2956e146993eSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_permitrootlogin);
2957e146993eSDag-Erling Smørgrav 	case sGatewayPorts:
2958e146993eSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_gatewayports);
2959e146993eSDag-Erling Smørgrav 	case sCompression:
2960e146993eSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_compression);
29616888a9beSDag-Erling Smørgrav 	case sAllowTcpForwarding:
29626888a9beSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_tcpfwd);
2963a0ee8cc6SDag-Erling Smørgrav 	case sAllowStreamLocalForwarding:
2964a0ee8cc6SDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_tcpfwd);
296519261079SEd Maste 	case sIgnoreRhosts:
296619261079SEd Maste 		return fmt_multistate_int(val, multistate_ignore_rhosts);
2967bc5531deSDag-Erling Smørgrav 	case sFingerprintHash:
2968bc5531deSDag-Erling Smørgrav 		return ssh_digest_alg_name(val);
2969e146993eSDag-Erling Smørgrav 	default:
2970d4af9e69SDag-Erling Smørgrav 		switch (val) {
2971d4af9e69SDag-Erling Smørgrav 		case 0:
2972d4af9e69SDag-Erling Smørgrav 			return "no";
2973d4af9e69SDag-Erling Smørgrav 		case 1:
2974d4af9e69SDag-Erling Smørgrav 			return "yes";
2975e146993eSDag-Erling Smørgrav 		default:
2976d4af9e69SDag-Erling Smørgrav 			return "UNKNOWN";
2977d4af9e69SDag-Erling Smørgrav 		}
2978e146993eSDag-Erling Smørgrav 	}
2979e146993eSDag-Erling Smørgrav }
2980d4af9e69SDag-Erling Smørgrav 
2981d4af9e69SDag-Erling Smørgrav static void
2982d4af9e69SDag-Erling Smørgrav dump_cfg_int(ServerOpCodes code, int val)
2983d4af9e69SDag-Erling Smørgrav {
2984f374ba41SEd Maste 	if (code == sUnusedConnectionTimeout && val == 0) {
2985f374ba41SEd Maste 		printf("%s none\n", lookup_opcode_name(code));
2986f374ba41SEd Maste 		return;
2987f374ba41SEd Maste 	}
2988d4af9e69SDag-Erling Smørgrav 	printf("%s %d\n", lookup_opcode_name(code), val);
2989d4af9e69SDag-Erling Smørgrav }
2990d4af9e69SDag-Erling Smørgrav 
2991d4af9e69SDag-Erling Smørgrav static void
2992557f75e5SDag-Erling Smørgrav dump_cfg_oct(ServerOpCodes code, int val)
2993557f75e5SDag-Erling Smørgrav {
2994557f75e5SDag-Erling Smørgrav 	printf("%s 0%o\n", lookup_opcode_name(code), val);
2995557f75e5SDag-Erling Smørgrav }
2996557f75e5SDag-Erling Smørgrav 
2997557f75e5SDag-Erling Smørgrav static void
2998d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(ServerOpCodes code, int val)
2999d4af9e69SDag-Erling Smørgrav {
3000d4af9e69SDag-Erling Smørgrav 	printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
3001d4af9e69SDag-Erling Smørgrav }
3002d4af9e69SDag-Erling Smørgrav 
3003d4af9e69SDag-Erling Smørgrav static void
3004d4af9e69SDag-Erling Smørgrav dump_cfg_string(ServerOpCodes code, const char *val)
3005d4af9e69SDag-Erling Smørgrav {
3006bc5531deSDag-Erling Smørgrav 	printf("%s %s\n", lookup_opcode_name(code),
3007bc5531deSDag-Erling Smørgrav 	    val == NULL ? "none" : val);
3008d4af9e69SDag-Erling Smørgrav }
3009d4af9e69SDag-Erling Smørgrav 
3010d4af9e69SDag-Erling Smørgrav static void
3011d4af9e69SDag-Erling Smørgrav dump_cfg_strarray(ServerOpCodes code, u_int count, char **vals)
3012d4af9e69SDag-Erling Smørgrav {
3013d4af9e69SDag-Erling Smørgrav 	u_int i;
3014d4af9e69SDag-Erling Smørgrav 
3015d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < count; i++)
3016d4af9e69SDag-Erling Smørgrav 		printf("%s %s\n", lookup_opcode_name(code), vals[i]);
3017d4af9e69SDag-Erling Smørgrav }
3018d4af9e69SDag-Erling Smørgrav 
3019e146993eSDag-Erling Smørgrav static void
3020e146993eSDag-Erling Smørgrav dump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals)
3021e146993eSDag-Erling Smørgrav {
3022e146993eSDag-Erling Smørgrav 	u_int i;
3023e146993eSDag-Erling Smørgrav 
30244d3fc8b0SEd Maste 	switch (code) {
30254d3fc8b0SEd Maste 	case sAuthenticationMethods:
30264d3fc8b0SEd Maste 	case sChannelTimeout:
30274d3fc8b0SEd Maste 		break;
30284d3fc8b0SEd Maste 	default:
30294d3fc8b0SEd Maste 		if (count <= 0)
3030557f75e5SDag-Erling Smørgrav 			return;
30314d3fc8b0SEd Maste 		break;
30324d3fc8b0SEd Maste 	}
30334d3fc8b0SEd Maste 
3034e146993eSDag-Erling Smørgrav 	printf("%s", lookup_opcode_name(code));
3035e146993eSDag-Erling Smørgrav 	for (i = 0; i < count; i++)
3036e146993eSDag-Erling Smørgrav 		printf(" %s",  vals[i]);
3037076ad2f8SDag-Erling Smørgrav 	if (code == sAuthenticationMethods && count == 0)
3038076ad2f8SDag-Erling Smørgrav 		printf(" any");
3039f374ba41SEd Maste 	else if (code == sChannelTimeout && count == 0)
3040f374ba41SEd Maste 		printf(" none");
3041e146993eSDag-Erling Smørgrav 	printf("\n");
3042e146993eSDag-Erling Smørgrav }
3043e146993eSDag-Erling Smørgrav 
304447dd1d1bSDag-Erling Smørgrav static char *
304547dd1d1bSDag-Erling Smørgrav format_listen_addrs(struct listenaddr *la)
3046d4af9e69SDag-Erling Smørgrav {
304747dd1d1bSDag-Erling Smørgrav 	int r;
3048d4af9e69SDag-Erling Smørgrav 	struct addrinfo *ai;
304947dd1d1bSDag-Erling Smørgrav 	char addr[NI_MAXHOST], port[NI_MAXSERV];
3050557f75e5SDag-Erling Smørgrav 	char *laddr1 = xstrdup(""), *laddr2 = NULL;
3051d4af9e69SDag-Erling Smørgrav 
3052557f75e5SDag-Erling Smørgrav 	/*
3053557f75e5SDag-Erling Smørgrav 	 * ListenAddress must be after Port.  add_one_listen_addr pushes
3054557f75e5SDag-Erling Smørgrav 	 * addresses onto a stack, so to maintain ordering we need to
3055557f75e5SDag-Erling Smørgrav 	 * print these in reverse order.
3056557f75e5SDag-Erling Smørgrav 	 */
305747dd1d1bSDag-Erling Smørgrav 	for (ai = la->addrs; ai; ai = ai->ai_next) {
305847dd1d1bSDag-Erling Smørgrav 		if ((r = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
3059d4af9e69SDag-Erling Smørgrav 		    sizeof(addr), port, sizeof(port),
3060d4af9e69SDag-Erling Smørgrav 		    NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
306147dd1d1bSDag-Erling Smørgrav 			error("getnameinfo: %.100s", ssh_gai_strerror(r));
306247dd1d1bSDag-Erling Smørgrav 			continue;
306347dd1d1bSDag-Erling Smørgrav 		}
3064557f75e5SDag-Erling Smørgrav 		laddr2 = laddr1;
306547dd1d1bSDag-Erling Smørgrav 		if (ai->ai_family == AF_INET6) {
306647dd1d1bSDag-Erling Smørgrav 			xasprintf(&laddr1, "listenaddress [%s]:%s%s%s\n%s",
306747dd1d1bSDag-Erling Smørgrav 			    addr, port,
306847dd1d1bSDag-Erling Smørgrav 			    la->rdomain == NULL ? "" : " rdomain ",
306947dd1d1bSDag-Erling Smørgrav 			    la->rdomain == NULL ? "" : la->rdomain,
307047dd1d1bSDag-Erling Smørgrav 			    laddr2);
307147dd1d1bSDag-Erling Smørgrav 		} else {
307247dd1d1bSDag-Erling Smørgrav 			xasprintf(&laddr1, "listenaddress %s:%s%s%s\n%s",
307347dd1d1bSDag-Erling Smørgrav 			    addr, port,
307447dd1d1bSDag-Erling Smørgrav 			    la->rdomain == NULL ? "" : " rdomain ",
307547dd1d1bSDag-Erling Smørgrav 			    la->rdomain == NULL ? "" : la->rdomain,
307647dd1d1bSDag-Erling Smørgrav 			    laddr2);
307747dd1d1bSDag-Erling Smørgrav 		}
3078557f75e5SDag-Erling Smørgrav 		free(laddr2);
3079d4af9e69SDag-Erling Smørgrav 	}
308047dd1d1bSDag-Erling Smørgrav 	return laddr1;
3081d4af9e69SDag-Erling Smørgrav }
308247dd1d1bSDag-Erling Smørgrav 
308347dd1d1bSDag-Erling Smørgrav void
308447dd1d1bSDag-Erling Smørgrav dump_config(ServerOptions *o)
308547dd1d1bSDag-Erling Smørgrav {
308647dd1d1bSDag-Erling Smørgrav 	char *s;
308747dd1d1bSDag-Erling Smørgrav 	u_int i;
308847dd1d1bSDag-Erling Smørgrav 
308947dd1d1bSDag-Erling Smørgrav 	/* these are usually at the top of the config */
309047dd1d1bSDag-Erling Smørgrav 	for (i = 0; i < o->num_ports; i++)
309147dd1d1bSDag-Erling Smørgrav 		printf("port %d\n", o->ports[i]);
309247dd1d1bSDag-Erling Smørgrav 	dump_cfg_fmtint(sAddressFamily, o->address_family);
309347dd1d1bSDag-Erling Smørgrav 
309447dd1d1bSDag-Erling Smørgrav 	for (i = 0; i < o->num_listen_addrs; i++) {
309547dd1d1bSDag-Erling Smørgrav 		s = format_listen_addrs(&o->listen_addrs[i]);
309647dd1d1bSDag-Erling Smørgrav 		printf("%s", s);
309747dd1d1bSDag-Erling Smørgrav 		free(s);
309847dd1d1bSDag-Erling Smørgrav 	}
3099d4af9e69SDag-Erling Smørgrav 
3100d4af9e69SDag-Erling Smørgrav 	/* integer arguments */
3101cce7d346SDag-Erling Smørgrav #ifdef USE_PAM
3102557f75e5SDag-Erling Smørgrav 	dump_cfg_fmtint(sUsePAM, o->use_pam);
3103cce7d346SDag-Erling Smørgrav #endif
3104d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sLoginGraceTime, o->login_grace_time);
3105d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sX11DisplayOffset, o->x11_display_offset);
3106d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sMaxAuthTries, o->max_authtries);
3107cce7d346SDag-Erling Smørgrav 	dump_cfg_int(sMaxSessions, o->max_sessions);
3108d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
3109d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
311038a52bd3SEd Maste 	dump_cfg_int(sRequiredRSASize, o->required_rsa_size);
3111557f75e5SDag-Erling Smørgrav 	dump_cfg_oct(sStreamLocalBindMask, o->fwd_opts.streamlocal_bind_mask);
3112f374ba41SEd Maste 	dump_cfg_int(sUnusedConnectionTimeout, o->unused_connection_timeout);
3113d4af9e69SDag-Erling Smørgrav 
3114d4af9e69SDag-Erling Smørgrav 	/* formatted integer arguments */
3115d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login);
3116d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sIgnoreRhosts, o->ignore_rhosts);
3117d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sIgnoreUserKnownHosts, o->ignore_user_known_hosts);
3118d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sHostbasedAuthentication, o->hostbased_authentication);
3119d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sHostbasedUsesNameFromPacketOnly,
3120d4af9e69SDag-Erling Smørgrav 	    o->hostbased_uses_name_from_packet_only);
3121d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPubkeyAuthentication, o->pubkey_authentication);
3122cce7d346SDag-Erling Smørgrav #ifdef KRB5
3123d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKerberosAuthentication, o->kerberos_authentication);
3124d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKerberosOrLocalPasswd, o->kerberos_or_local_passwd);
3125d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKerberosTicketCleanup, o->kerberos_ticket_cleanup);
3126cce7d346SDag-Erling Smørgrav # ifdef USE_AFS
3127d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
3128cce7d346SDag-Erling Smørgrav # endif
3129cce7d346SDag-Erling Smørgrav #endif
3130cce7d346SDag-Erling Smørgrav #ifdef GSSAPI
3131d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
3132d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
3133cce7d346SDag-Erling Smørgrav #endif
3134d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
3135d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKbdInteractiveAuthentication,
3136d4af9e69SDag-Erling Smørgrav 	    o->kbd_interactive_authentication);
3137d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPrintMotd, o->print_motd);
3138acc1a9efSDag-Erling Smørgrav #ifndef DISABLE_LASTLOG
3139d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPrintLastLog, o->print_lastlog);
3140acc1a9efSDag-Erling Smørgrav #endif
3141d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding);
3142d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost);
3143f7167e0eSDag-Erling Smørgrav 	dump_cfg_fmtint(sPermitTTY, o->permit_tty);
3144a0ee8cc6SDag-Erling Smørgrav 	dump_cfg_fmtint(sPermitUserRC, o->permit_user_rc);
3145d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sStrictModes, o->strict_modes);
3146d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive);
3147d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd);
3148d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sCompression, o->compression);
3149a0ee8cc6SDag-Erling Smørgrav 	dump_cfg_fmtint(sGatewayPorts, o->fwd_opts.gateway_ports);
3150d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sUseDNS, o->use_dns);
3151d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
3152557f75e5SDag-Erling Smørgrav 	dump_cfg_fmtint(sAllowAgentForwarding, o->allow_agent_forwarding);
3153ca86bcf2SDag-Erling Smørgrav 	dump_cfg_fmtint(sDisableForwarding, o->disable_forwarding);
3154a0ee8cc6SDag-Erling Smørgrav 	dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding);
3155076ad2f8SDag-Erling Smørgrav 	dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
3156bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash);
31574f52dfbbSDag-Erling Smørgrav 	dump_cfg_fmtint(sExposeAuthInfo, o->expose_userauth_info);
3158b2af61ecSKurt Lidl 	dump_cfg_fmtint(sUseBlacklist, o->use_blacklist);
3159d4af9e69SDag-Erling Smørgrav 
3160d4af9e69SDag-Erling Smørgrav 	/* string arguments */
3161d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sPidFile, o->pid_file);
316219261079SEd Maste 	dump_cfg_string(sModuliFile, o->moduli_file);
3163d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sXAuthLocation, o->xauth_location);
316419261079SEd Maste 	dump_cfg_string(sCiphers, o->ciphers);
316519261079SEd Maste 	dump_cfg_string(sMacs, o->macs);
3166d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sBanner, o->banner);
3167d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sForceCommand, o->adm_forced_command);
3168b15c8340SDag-Erling Smørgrav 	dump_cfg_string(sChrootDirectory, o->chroot_directory);
3169b15c8340SDag-Erling Smørgrav 	dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys);
3170b15c8340SDag-Erling Smørgrav 	dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
317119261079SEd Maste 	dump_cfg_string(sSecurityKeyProvider, o->sk_provider);
3172e2f6069cSDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedPrincipalsFile,
3173e2f6069cSDag-Erling Smørgrav 	    o->authorized_principals_file);
3174557f75e5SDag-Erling Smørgrav 	dump_cfg_string(sVersionAddendum, *o->version_addendum == '\0'
3175557f75e5SDag-Erling Smørgrav 	    ? "none" : o->version_addendum);
31766888a9beSDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command);
31776888a9beSDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedKeysCommandUser, o->authorized_keys_command_user);
3178557f75e5SDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedPrincipalsCommand, o->authorized_principals_command);
3179557f75e5SDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedPrincipalsCommandUser, o->authorized_principals_command_user);
3180e4a9863fSDag-Erling Smørgrav 	dump_cfg_string(sHostKeyAgent, o->host_key_agent);
318119261079SEd Maste 	dump_cfg_string(sKexAlgorithms, o->kex_algorithms);
318219261079SEd Maste 	dump_cfg_string(sCASignatureAlgorithms, o->ca_sign_algorithms);
318319261079SEd Maste 	dump_cfg_string(sHostbasedAcceptedAlgorithms, o->hostbased_accepted_algos);
318419261079SEd Maste 	dump_cfg_string(sHostKeyAlgorithms, o->hostkeyalgorithms);
318519261079SEd Maste 	dump_cfg_string(sPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos);
318619261079SEd Maste #if defined(__OpenBSD__) || defined(HAVE_SYS_SET_PROCESS_RDOMAIN)
318747dd1d1bSDag-Erling Smørgrav 	dump_cfg_string(sRDomain, o->routing_domain);
318819261079SEd Maste #endif
3189d4af9e69SDag-Erling Smørgrav 
3190d4af9e69SDag-Erling Smørgrav 	/* string arguments requiring a lookup */
3191d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sLogLevel, log_level_name(o->log_level));
3192d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sLogFacility, log_facility_name(o->log_facility));
3193d4af9e69SDag-Erling Smørgrav 
3194d4af9e69SDag-Erling Smørgrav 	/* string array arguments */
3195e146993eSDag-Erling Smørgrav 	dump_cfg_strarray_oneline(sAuthorizedKeysFile, o->num_authkeys_files,
3196e146993eSDag-Erling Smørgrav 	    o->authorized_keys_files);
3197d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sHostKeyFile, o->num_host_key_files,
3198d4af9e69SDag-Erling Smørgrav 	    o->host_key_files);
3199557f75e5SDag-Erling Smørgrav 	dump_cfg_strarray(sHostCertificate, o->num_host_cert_files,
3200b15c8340SDag-Erling Smørgrav 	    o->host_cert_files);
3201d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users);
3202d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users);
3203d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups);
3204d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sDenyGroups, o->num_deny_groups, o->deny_groups);
3205d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env);
3206190cef3dSDag-Erling Smørgrav 	dump_cfg_strarray(sSetEnv, o->num_setenv, o->setenv);
32076888a9beSDag-Erling Smørgrav 	dump_cfg_strarray_oneline(sAuthenticationMethods,
32086888a9beSDag-Erling Smørgrav 	    o->num_auth_methods, o->auth_methods);
320919261079SEd Maste 	dump_cfg_strarray_oneline(sLogVerbose,
321019261079SEd Maste 	    o->num_log_verbose, o->log_verbose);
3211f374ba41SEd Maste 	dump_cfg_strarray_oneline(sChannelTimeout,
3212f374ba41SEd Maste 	    o->num_channel_timeouts, o->channel_timeouts);
3213d4af9e69SDag-Erling Smørgrav 
3214d4af9e69SDag-Erling Smørgrav 	/* other arguments */
3215d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < o->num_subsystems; i++)
3216d4af9e69SDag-Erling Smørgrav 		printf("subsystem %s %s\n", o->subsystem_name[i],
3217d4af9e69SDag-Erling Smørgrav 		    o->subsystem_args[i]);
3218d4af9e69SDag-Erling Smørgrav 
3219d4af9e69SDag-Erling Smørgrav 	printf("maxstartups %d:%d:%d\n", o->max_startups_begin,
3220d4af9e69SDag-Erling Smørgrav 	    o->max_startups_rate, o->max_startups);
322119261079SEd Maste 	printf("persourcemaxstartups ");
322219261079SEd Maste 	if (o->per_source_max_startups == INT_MAX)
322319261079SEd Maste 		printf("none\n");
322419261079SEd Maste 	else
322519261079SEd Maste 		printf("%d\n", o->per_source_max_startups);
322619261079SEd Maste 	printf("persourcenetblocksize %d:%d\n", o->per_source_masklen_ipv4,
322719261079SEd Maste 	    o->per_source_masklen_ipv6);
3228d4af9e69SDag-Erling Smørgrav 
322947dd1d1bSDag-Erling Smørgrav 	s = NULL;
323047dd1d1bSDag-Erling Smørgrav 	for (i = 0; tunmode_desc[i].val != -1; i++) {
3231d4af9e69SDag-Erling Smørgrav 		if (tunmode_desc[i].val == o->permit_tun) {
3232d4af9e69SDag-Erling Smørgrav 			s = tunmode_desc[i].text;
3233d4af9e69SDag-Erling Smørgrav 			break;
3234d4af9e69SDag-Erling Smørgrav 		}
323547dd1d1bSDag-Erling Smørgrav 	}
3236d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sPermitTunnel, s);
3237d4af9e69SDag-Erling Smørgrav 
3238e146993eSDag-Erling Smørgrav 	printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
3239e146993eSDag-Erling Smørgrav 	printf("%s\n", iptos2str(o->ip_qos_bulk));
32404a421b63SDag-Erling Smørgrav 
3241acc1a9efSDag-Erling Smørgrav 	printf("rekeylimit %llu %d\n", (unsigned long long)o->rekey_limit,
3242e4a9863fSDag-Erling Smørgrav 	    o->rekey_interval);
3243e4a9863fSDag-Erling Smørgrav 
32444f52dfbbSDag-Erling Smørgrav 	printf("permitopen");
32454f52dfbbSDag-Erling Smørgrav 	if (o->num_permitted_opens == 0)
32464f52dfbbSDag-Erling Smørgrav 		printf(" any");
32474f52dfbbSDag-Erling Smørgrav 	else {
32484f52dfbbSDag-Erling Smørgrav 		for (i = 0; i < o->num_permitted_opens; i++)
32494f52dfbbSDag-Erling Smørgrav 			printf(" %s", o->permitted_opens[i]);
32504f52dfbbSDag-Erling Smørgrav 	}
32514f52dfbbSDag-Erling Smørgrav 	printf("\n");
3252190cef3dSDag-Erling Smørgrav 	printf("permitlisten");
3253190cef3dSDag-Erling Smørgrav 	if (o->num_permitted_listens == 0)
3254190cef3dSDag-Erling Smørgrav 		printf(" any");
3255190cef3dSDag-Erling Smørgrav 	else {
3256190cef3dSDag-Erling Smørgrav 		for (i = 0; i < o->num_permitted_listens; i++)
3257190cef3dSDag-Erling Smørgrav 			printf(" %s", o->permitted_listens[i]);
3258190cef3dSDag-Erling Smørgrav 	}
3259190cef3dSDag-Erling Smørgrav 	printf("\n");
3260190cef3dSDag-Erling Smørgrav 
326119261079SEd Maste 	if (o->permit_user_env_allowlist == NULL) {
3262190cef3dSDag-Erling Smørgrav 		dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
3263190cef3dSDag-Erling Smørgrav 	} else {
3264190cef3dSDag-Erling Smørgrav 		printf("permituserenvironment %s\n",
326519261079SEd Maste 		    o->permit_user_env_allowlist);
3266190cef3dSDag-Erling Smørgrav 	}
3267190cef3dSDag-Erling Smørgrav 
326819261079SEd Maste 	printf("pubkeyauthoptions");
326919261079SEd Maste 	if (o->pubkey_auth_options == 0)
327019261079SEd Maste 		printf(" none");
327119261079SEd Maste 	if (o->pubkey_auth_options & PUBKEYAUTH_TOUCH_REQUIRED)
327219261079SEd Maste 		printf(" touch-required");
327319261079SEd Maste 	if (o->pubkey_auth_options & PUBKEYAUTH_VERIFY_REQUIRED)
327419261079SEd Maste 		printf(" verify-required");
327519261079SEd Maste 	printf("\n");
3276d4af9e69SDag-Erling Smørgrav }
3277