xref: /freebsd/crypto/openssh/servconf.c (revision f374ba41f55c1a127303d92d830dd58eef2f5243)
1eccfee6eSDag-Erling Smørgrav 
2*f374ba41SEd Maste /* $OpenBSD: servconf.c,v 1.390 2023/01/17 09:44:48 djm Exp $ */
3511b41d2SMark Murray /*
4511b41d2SMark Murray  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5511b41d2SMark Murray  *                    All rights reserved
6511b41d2SMark Murray  *
7c2d3a559SKris Kennaway  * As far as I am concerned, the code I have written for this software
8c2d3a559SKris Kennaway  * can be used freely for any purpose.  Any derived versions of this
9c2d3a559SKris Kennaway  * software must be clearly marked as such, and if the derived work is
10c2d3a559SKris Kennaway  * incompatible with the protocol description in the RFC file, it must be
11c2d3a559SKris Kennaway  * called by a name other than "ssh" or "Secure Shell".
12511b41d2SMark Murray  */
13511b41d2SMark Murray 
14511b41d2SMark Murray #include "includes.h"
15511b41d2SMark Murray 
16333ee039SDag-Erling Smørgrav #include <sys/types.h>
17333ee039SDag-Erling Smørgrav #include <sys/socket.h>
1819261079SEd Maste #include <sys/stat.h>
1919261079SEd Maste #ifdef __OpenBSD__
2047dd1d1bSDag-Erling Smørgrav #include <sys/sysctl.h>
2147dd1d1bSDag-Erling Smørgrav #endif
22333ee039SDag-Erling Smørgrav 
234a421b63SDag-Erling Smørgrav #include <netinet/in.h>
244a421b63SDag-Erling Smørgrav #include <netinet/in_systm.h>
254a421b63SDag-Erling Smørgrav #include <netinet/ip.h>
2647dd1d1bSDag-Erling Smørgrav #ifdef HAVE_NET_ROUTE_H
2747dd1d1bSDag-Erling Smørgrav #include <net/route.h>
2847dd1d1bSDag-Erling Smørgrav #endif
294a421b63SDag-Erling Smørgrav 
30e4a9863fSDag-Erling Smørgrav #include <ctype.h>
31333ee039SDag-Erling Smørgrav #include <netdb.h>
32333ee039SDag-Erling Smørgrav #include <pwd.h>
33333ee039SDag-Erling Smørgrav #include <stdio.h>
34333ee039SDag-Erling Smørgrav #include <stdlib.h>
35333ee039SDag-Erling Smørgrav #include <string.h>
36333ee039SDag-Erling Smørgrav #include <signal.h>
37333ee039SDag-Erling Smørgrav #include <unistd.h>
38bc5531deSDag-Erling Smørgrav #include <limits.h>
39333ee039SDag-Erling Smørgrav #include <stdarg.h>
40d4af9e69SDag-Erling Smørgrav #include <errno.h>
41e4a9863fSDag-Erling Smørgrav #ifdef HAVE_UTIL_H
42e4a9863fSDag-Erling Smørgrav #include <util.h>
43e4a9863fSDag-Erling Smørgrav #endif
4419261079SEd Maste #ifdef USE_SYSTEM_GLOB
4519261079SEd Maste # include <glob.h>
4619261079SEd Maste #else
4719261079SEd Maste # include "openbsd-compat/glob.h"
4819261079SEd Maste #endif
49333ee039SDag-Erling Smørgrav 
50d4af9e69SDag-Erling Smørgrav #include "openbsd-compat/sys-queue.h"
51333ee039SDag-Erling Smørgrav #include "xmalloc.h"
52511b41d2SMark Murray #include "ssh.h"
53ca3176e7SBrian Feldman #include "log.h"
54190cef3dSDag-Erling Smørgrav #include "sshbuf.h"
55a0ee8cc6SDag-Erling Smørgrav #include "misc.h"
56511b41d2SMark Murray #include "servconf.h"
57e8aafc91SKris Kennaway #include "compat.h"
58ca3176e7SBrian Feldman #include "pathnames.h"
59ca3176e7SBrian Feldman #include "cipher.h"
60190cef3dSDag-Erling Smørgrav #include "sshkey.h"
61ca3176e7SBrian Feldman #include "kex.h"
62ca3176e7SBrian Feldman #include "mac.h"
63333ee039SDag-Erling Smørgrav #include "match.h"
64333ee039SDag-Erling Smørgrav #include "channels.h"
65333ee039SDag-Erling Smørgrav #include "groupaccess.h"
66462c32cbSDag-Erling Smørgrav #include "canohost.h"
67462c32cbSDag-Erling Smørgrav #include "packet.h"
68190cef3dSDag-Erling Smørgrav #include "ssherr.h"
696888a9beSDag-Erling Smørgrav #include "hostfile.h"
706888a9beSDag-Erling Smørgrav #include "auth.h"
71bc5531deSDag-Erling Smørgrav #include "myproposal.h"
72bc5531deSDag-Erling Smørgrav #include "digest.h"
73b15c8340SDag-Erling Smørgrav #include "version.h"
74511b41d2SMark Murray 
7547dd1d1bSDag-Erling Smørgrav static void add_listen_addr(ServerOptions *, const char *,
7647dd1d1bSDag-Erling Smørgrav     const char *, int);
7747dd1d1bSDag-Erling Smørgrav static void add_one_listen_addr(ServerOptions *, const char *,
7847dd1d1bSDag-Erling Smørgrav     const char *, int);
7919261079SEd Maste static void parse_server_config_depth(ServerOptions *options,
8019261079SEd Maste     const char *filename, struct sshbuf *conf, struct include_list *includes,
8119261079SEd Maste     struct connection_info *connectinfo, int flags, int *activep, int depth);
82ca3176e7SBrian Feldman 
8380628bacSDag-Erling Smørgrav /* Use of privilege separation or not */
8480628bacSDag-Erling Smørgrav extern int use_privsep;
85190cef3dSDag-Erling Smørgrav extern struct sshbuf *cfg;
86511b41d2SMark Murray 
87511b41d2SMark Murray /* Initializes the server options to their default values. */
88511b41d2SMark Murray 
89511b41d2SMark Murray void
90511b41d2SMark Murray initialize_server_options(ServerOptions *options)
91511b41d2SMark Murray {
92511b41d2SMark Murray 	memset(options, 0, sizeof(*options));
93989dd127SDag-Erling Smørgrav 
94989dd127SDag-Erling Smørgrav 	/* Portable-specific options */
95cf2b5f3bSDag-Erling Smørgrav 	options->use_pam = -1;
96989dd127SDag-Erling Smørgrav 
97989dd127SDag-Erling Smørgrav 	/* Standard Options */
98511b41d2SMark Murray 	options->num_ports = 0;
99511b41d2SMark Murray 	options->ports_from_cmdline = 0;
100557f75e5SDag-Erling Smørgrav 	options->queued_listen_addrs = NULL;
101557f75e5SDag-Erling Smørgrav 	options->num_queued_listens = 0;
102511b41d2SMark Murray 	options->listen_addrs = NULL;
10347dd1d1bSDag-Erling Smørgrav 	options->num_listen_addrs = 0;
104aa49c926SDag-Erling Smørgrav 	options->address_family = -1;
10547dd1d1bSDag-Erling Smørgrav 	options->routing_domain = NULL;
106ca3176e7SBrian Feldman 	options->num_host_key_files = 0;
107b15c8340SDag-Erling Smørgrav 	options->num_host_cert_files = 0;
108e4a9863fSDag-Erling Smørgrav 	options->host_key_agent = NULL;
109e8aafc91SKris Kennaway 	options->pid_file = NULL;
110511b41d2SMark Murray 	options->login_grace_time = -1;
111ca3176e7SBrian Feldman 	options->permit_root_login = PERMIT_NOT_SET;
112511b41d2SMark Murray 	options->ignore_rhosts = -1;
113511b41d2SMark Murray 	options->ignore_user_known_hosts = -1;
114511b41d2SMark Murray 	options->print_motd = -1;
115ca3176e7SBrian Feldman 	options->print_lastlog = -1;
116511b41d2SMark Murray 	options->x11_forwarding = -1;
117511b41d2SMark Murray 	options->x11_display_offset = -1;
118af12a3e7SDag-Erling Smørgrav 	options->x11_use_localhost = -1;
119f7167e0eSDag-Erling Smørgrav 	options->permit_tty = -1;
120a0ee8cc6SDag-Erling Smørgrav 	options->permit_user_rc = -1;
121c2d3a559SKris Kennaway 	options->xauth_location = NULL;
122511b41d2SMark Murray 	options->strict_modes = -1;
1231ec0d754SDag-Erling Smørgrav 	options->tcp_keep_alive = -1;
124af12a3e7SDag-Erling Smørgrav 	options->log_facility = SYSLOG_FACILITY_NOT_SET;
125af12a3e7SDag-Erling Smørgrav 	options->log_level = SYSLOG_LEVEL_NOT_SET;
12619261079SEd Maste 	options->num_log_verbose = 0;
12719261079SEd Maste 	options->log_verbose = NULL;
128ca3176e7SBrian Feldman 	options->hostbased_authentication = -1;
129ca3176e7SBrian Feldman 	options->hostbased_uses_name_from_packet_only = -1;
13019261079SEd Maste 	options->hostbased_accepted_algos = NULL;
131eccfee6eSDag-Erling Smørgrav 	options->hostkeyalgorithms = NULL;
132ca3176e7SBrian Feldman 	options->pubkey_authentication = -1;
13319261079SEd Maste 	options->pubkey_auth_options = -1;
13419261079SEd Maste 	options->pubkey_accepted_algos = NULL;
135cb96ab36SAssar Westerlund 	options->kerberos_authentication = -1;
136af12a3e7SDag-Erling Smørgrav 	options->kerberos_or_local_passwd = -1;
137af12a3e7SDag-Erling Smørgrav 	options->kerberos_ticket_cleanup = -1;
1381ec0d754SDag-Erling Smørgrav 	options->kerberos_get_afs_token = -1;
139cf2b5f3bSDag-Erling Smørgrav 	options->gss_authentication=-1;
140cf2b5f3bSDag-Erling Smørgrav 	options->gss_cleanup_creds = -1;
141557f75e5SDag-Erling Smørgrav 	options->gss_strict_acceptor = -1;
142511b41d2SMark Murray 	options->password_authentication = -1;
14309958426SBrian Feldman 	options->kbd_interactive_authentication = -1;
144511b41d2SMark Murray 	options->permit_empty_passwd = -1;
145f388f5efSDag-Erling Smørgrav 	options->permit_user_env = -1;
14619261079SEd Maste 	options->permit_user_env_allowlist = NULL;
14780628bacSDag-Erling Smørgrav 	options->compression = -1;
148e4a9863fSDag-Erling Smørgrav 	options->rekey_limit = -1;
149e4a9863fSDag-Erling Smørgrav 	options->rekey_interval = -1;
15009958426SBrian Feldman 	options->allow_tcp_forwarding = -1;
151a0ee8cc6SDag-Erling Smørgrav 	options->allow_streamlocal_forwarding = -1;
152d4af9e69SDag-Erling Smørgrav 	options->allow_agent_forwarding = -1;
153511b41d2SMark Murray 	options->num_allow_users = 0;
154511b41d2SMark Murray 	options->num_deny_users = 0;
155511b41d2SMark Murray 	options->num_allow_groups = 0;
156511b41d2SMark Murray 	options->num_deny_groups = 0;
157e8aafc91SKris Kennaway 	options->ciphers = NULL;
158ca3176e7SBrian Feldman 	options->macs = NULL;
1594a421b63SDag-Erling Smørgrav 	options->kex_algorithms = NULL;
1602f513db7SEd Maste 	options->ca_sign_algorithms = NULL;
161a0ee8cc6SDag-Erling Smørgrav 	options->fwd_opts.gateway_ports = -1;
162a0ee8cc6SDag-Erling Smørgrav 	options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
163a0ee8cc6SDag-Erling Smørgrav 	options->fwd_opts.streamlocal_bind_unlink = -1;
164c2d3a559SKris Kennaway 	options->num_subsystems = 0;
165c2d3a559SKris Kennaway 	options->max_startups_begin = -1;
166c2d3a559SKris Kennaway 	options->max_startups_rate = -1;
167c2d3a559SKris Kennaway 	options->max_startups = -1;
16819261079SEd Maste 	options->per_source_max_startups = -1;
16919261079SEd Maste 	options->per_source_masklen_ipv4 = -1;
17019261079SEd Maste 	options->per_source_masklen_ipv6 = -1;
17121e764dfSDag-Erling Smørgrav 	options->max_authtries = -1;
172d4af9e69SDag-Erling Smørgrav 	options->max_sessions = -1;
173ca3176e7SBrian Feldman 	options->banner = NULL;
174cf2b5f3bSDag-Erling Smørgrav 	options->use_dns = -1;
175ca3176e7SBrian Feldman 	options->client_alive_interval = -1;
176ca3176e7SBrian Feldman 	options->client_alive_count_max = -1;
177e146993eSDag-Erling Smørgrav 	options->num_authkeys_files = 0;
17821e764dfSDag-Erling Smørgrav 	options->num_accept_env = 0;
179190cef3dSDag-Erling Smørgrav 	options->num_setenv = 0;
180b74df5b2SDag-Erling Smørgrav 	options->permit_tun = -1;
1814f52dfbbSDag-Erling Smørgrav 	options->permitted_opens = NULL;
182190cef3dSDag-Erling Smørgrav 	options->permitted_listens = NULL;
183333ee039SDag-Erling Smørgrav 	options->adm_forced_command = NULL;
184d4af9e69SDag-Erling Smørgrav 	options->chroot_directory = NULL;
1856888a9beSDag-Erling Smørgrav 	options->authorized_keys_command = NULL;
1866888a9beSDag-Erling Smørgrav 	options->authorized_keys_command_user = NULL;
187b15c8340SDag-Erling Smørgrav 	options->revoked_keys_file = NULL;
18819261079SEd Maste 	options->sk_provider = NULL;
189b15c8340SDag-Erling Smørgrav 	options->trusted_user_ca_keys = NULL;
190e2f6069cSDag-Erling Smørgrav 	options->authorized_principals_file = NULL;
191557f75e5SDag-Erling Smørgrav 	options->authorized_principals_command = NULL;
192557f75e5SDag-Erling Smørgrav 	options->authorized_principals_command_user = NULL;
1934a421b63SDag-Erling Smørgrav 	options->ip_qos_interactive = -1;
1944a421b63SDag-Erling Smørgrav 	options->ip_qos_bulk = -1;
195462c32cbSDag-Erling Smørgrav 	options->version_addendum = NULL;
196bc5531deSDag-Erling Smørgrav 	options->fingerprint_hash = -1;
197ca86bcf2SDag-Erling Smørgrav 	options->disable_forwarding = -1;
1984f52dfbbSDag-Erling Smørgrav 	options->expose_userauth_info = -1;
19938a52bd3SEd Maste 	options->required_rsa_size = -1;
200*f374ba41SEd Maste 	options->channel_timeouts = NULL;
201*f374ba41SEd Maste 	options->num_channel_timeouts = 0;
202*f374ba41SEd Maste 	options->unused_connection_timeout = -1;
203b2af61ecSKurt Lidl 	options->use_blacklist = -1;
204bc5531deSDag-Erling Smørgrav }
205bc5531deSDag-Erling Smørgrav 
206bc5531deSDag-Erling Smørgrav /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
207bc5531deSDag-Erling Smørgrav static int
208bc5531deSDag-Erling Smørgrav option_clear_or_none(const char *o)
209bc5531deSDag-Erling Smørgrav {
210bc5531deSDag-Erling Smørgrav 	return o == NULL || strcasecmp(o, "none") == 0;
211511b41d2SMark Murray }
212511b41d2SMark Murray 
213acc1a9efSDag-Erling Smørgrav static void
214acc1a9efSDag-Erling Smørgrav assemble_algorithms(ServerOptions *o)
215acc1a9efSDag-Erling Smørgrav {
2162f513db7SEd Maste 	char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
21719261079SEd Maste 	char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig;
218190cef3dSDag-Erling Smørgrav 	int r;
219190cef3dSDag-Erling Smørgrav 
220190cef3dSDag-Erling Smørgrav 	all_cipher = cipher_alg_list(',', 0);
221190cef3dSDag-Erling Smørgrav 	all_mac = mac_alg_list(',');
222190cef3dSDag-Erling Smørgrav 	all_kex = kex_alg_list(',');
223190cef3dSDag-Erling Smørgrav 	all_key = sshkey_alg_list(0, 0, 1, ',');
2242f513db7SEd Maste 	all_sig = sshkey_alg_list(0, 1, 1, ',');
22519261079SEd Maste 	/* remove unsupported algos from default lists */
22619261079SEd Maste 	def_cipher = match_filter_allowlist(KEX_SERVER_ENCRYPT, all_cipher);
22719261079SEd Maste 	def_mac = match_filter_allowlist(KEX_SERVER_MAC, all_mac);
22819261079SEd Maste 	def_kex = match_filter_allowlist(KEX_SERVER_KEX, all_kex);
22919261079SEd Maste 	def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
23019261079SEd Maste 	def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig);
231190cef3dSDag-Erling Smørgrav #define ASSEMBLE(what, defaults, all) \
232190cef3dSDag-Erling Smørgrav 	do { \
233190cef3dSDag-Erling Smørgrav 		if ((r = kex_assemble_names(&o->what, defaults, all)) != 0) \
23419261079SEd Maste 			fatal_fr(r, "%s", #what); \
235190cef3dSDag-Erling Smørgrav 	} while (0)
23619261079SEd Maste 	ASSEMBLE(ciphers, def_cipher, all_cipher);
23719261079SEd Maste 	ASSEMBLE(macs, def_mac, all_mac);
23819261079SEd Maste 	ASSEMBLE(kex_algorithms, def_kex, all_kex);
23919261079SEd Maste 	ASSEMBLE(hostkeyalgorithms, def_key, all_key);
24019261079SEd Maste 	ASSEMBLE(hostbased_accepted_algos, def_key, all_key);
24119261079SEd Maste 	ASSEMBLE(pubkey_accepted_algos, def_key, all_key);
24219261079SEd Maste 	ASSEMBLE(ca_sign_algorithms, def_sig, all_sig);
243190cef3dSDag-Erling Smørgrav #undef ASSEMBLE
244190cef3dSDag-Erling Smørgrav 	free(all_cipher);
245190cef3dSDag-Erling Smørgrav 	free(all_mac);
246190cef3dSDag-Erling Smørgrav 	free(all_kex);
247190cef3dSDag-Erling Smørgrav 	free(all_key);
2482f513db7SEd Maste 	free(all_sig);
24919261079SEd Maste 	free(def_cipher);
25019261079SEd Maste 	free(def_mac);
25119261079SEd Maste 	free(def_kex);
25219261079SEd Maste 	free(def_key);
25319261079SEd Maste 	free(def_sig);
25447dd1d1bSDag-Erling Smørgrav }
25547dd1d1bSDag-Erling Smørgrav 
25647dd1d1bSDag-Erling Smørgrav static const char *defaultkey = "[default]";
25747dd1d1bSDag-Erling Smørgrav 
25847dd1d1bSDag-Erling Smørgrav void
25947dd1d1bSDag-Erling Smørgrav servconf_add_hostkey(const char *file, const int line,
26019261079SEd Maste     ServerOptions *options, const char *path, int userprovided)
26147dd1d1bSDag-Erling Smørgrav {
26247dd1d1bSDag-Erling Smørgrav 	char *apath = derelativise_path(path);
26347dd1d1bSDag-Erling Smørgrav 
26447dd1d1bSDag-Erling Smørgrav 	if (file == defaultkey && access(path, R_OK) != 0)
26547dd1d1bSDag-Erling Smørgrav 		return;
26619261079SEd Maste 	opt_array_append2(file, line, "HostKey",
26719261079SEd Maste 	    &options->host_key_files, &options->host_key_file_userprovided,
26819261079SEd Maste 	    &options->num_host_key_files, apath, userprovided);
26947dd1d1bSDag-Erling Smørgrav 	free(apath);
27047dd1d1bSDag-Erling Smørgrav }
27147dd1d1bSDag-Erling Smørgrav 
27247dd1d1bSDag-Erling Smørgrav void
27347dd1d1bSDag-Erling Smørgrav servconf_add_hostcert(const char *file, const int line,
27447dd1d1bSDag-Erling Smørgrav     ServerOptions *options, const char *path)
27547dd1d1bSDag-Erling Smørgrav {
27647dd1d1bSDag-Erling Smørgrav 	char *apath = derelativise_path(path);
27747dd1d1bSDag-Erling Smørgrav 
27819261079SEd Maste 	opt_array_append(file, line, "HostCertificate",
27947dd1d1bSDag-Erling Smørgrav 	    &options->host_cert_files, &options->num_host_cert_files, apath);
28047dd1d1bSDag-Erling Smørgrav 	free(apath);
28147dd1d1bSDag-Erling Smørgrav }
28247dd1d1bSDag-Erling Smørgrav 
283511b41d2SMark Murray void
284511b41d2SMark Murray fill_default_server_options(ServerOptions *options)
285511b41d2SMark Murray {
28647dd1d1bSDag-Erling Smørgrav 	u_int i;
287bc5531deSDag-Erling Smørgrav 
288989dd127SDag-Erling Smørgrav 	/* Portable-specific options */
289cf2b5f3bSDag-Erling Smørgrav 	if (options->use_pam == -1)
290f0477b26SDag-Erling Smørgrav 		options->use_pam = 1;
291989dd127SDag-Erling Smørgrav 
292989dd127SDag-Erling Smørgrav 	/* Standard Options */
293ca3176e7SBrian Feldman 	if (options->num_host_key_files == 0) {
294ca3176e7SBrian Feldman 		/* fill default hostkeys for protocols */
29547dd1d1bSDag-Erling Smørgrav 		servconf_add_hostkey(defaultkey, 0, options,
29619261079SEd Maste 		    _PATH_HOST_RSA_KEY_FILE, 0);
2974a421b63SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC
29847dd1d1bSDag-Erling Smørgrav 		servconf_add_hostkey(defaultkey, 0, options,
29919261079SEd Maste 		    _PATH_HOST_ECDSA_KEY_FILE, 0);
3004a421b63SDag-Erling Smørgrav #endif
30147dd1d1bSDag-Erling Smørgrav 		servconf_add_hostkey(defaultkey, 0, options,
30219261079SEd Maste 		    _PATH_HOST_ED25519_KEY_FILE, 0);
30347dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
30447dd1d1bSDag-Erling Smørgrav 		servconf_add_hostkey(defaultkey, 0, options,
30519261079SEd Maste 		    _PATH_HOST_XMSS_KEY_FILE, 0);
30647dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
307af12a3e7SDag-Erling Smørgrav 	}
308144a80bdSDag-Erling Smørgrav 	if (options->num_host_key_files == 0)
309144a80bdSDag-Erling Smørgrav 		fatal("No host key files found");
310b15c8340SDag-Erling Smørgrav 	/* No certificates by default */
311511b41d2SMark Murray 	if (options->num_ports == 0)
312511b41d2SMark Murray 		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
313557f75e5SDag-Erling Smørgrav 	if (options->address_family == -1)
314557f75e5SDag-Erling Smørgrav 		options->address_family = AF_UNSPEC;
315511b41d2SMark Murray 	if (options->listen_addrs == NULL)
31647dd1d1bSDag-Erling Smørgrav 		add_listen_addr(options, NULL, NULL, 0);
317e8aafc91SKris Kennaway 	if (options->pid_file == NULL)
318bc5531deSDag-Erling Smørgrav 		options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE);
31919261079SEd Maste 	if (options->moduli_file == NULL)
32019261079SEd Maste 		options->moduli_file = xstrdup(_PATH_DH_MODULI);
321511b41d2SMark Murray 	if (options->login_grace_time == -1)
322975616f0SDag-Erling Smørgrav 		options->login_grace_time = 120;
323ca3176e7SBrian Feldman 	if (options->permit_root_login == PERMIT_NOT_SET)
324975616f0SDag-Erling Smørgrav 		options->permit_root_login = PERMIT_NO;
325511b41d2SMark Murray 	if (options->ignore_rhosts == -1)
326fe5fd017SMark Murray 		options->ignore_rhosts = 1;
327511b41d2SMark Murray 	if (options->ignore_user_known_hosts == -1)
328511b41d2SMark Murray 		options->ignore_user_known_hosts = 0;
329511b41d2SMark Murray 	if (options->print_motd == -1)
330511b41d2SMark Murray 		options->print_motd = 1;
331ca3176e7SBrian Feldman 	if (options->print_lastlog == -1)
332ca3176e7SBrian Feldman 		options->print_lastlog = 1;
333511b41d2SMark Murray 	if (options->x11_forwarding == -1)
334975616f0SDag-Erling Smørgrav 		options->x11_forwarding = 1;
335511b41d2SMark Murray 	if (options->x11_display_offset == -1)
336fe5fd017SMark Murray 		options->x11_display_offset = 10;
337af12a3e7SDag-Erling Smørgrav 	if (options->x11_use_localhost == -1)
338af12a3e7SDag-Erling Smørgrav 		options->x11_use_localhost = 1;
339c2d3a559SKris Kennaway 	if (options->xauth_location == NULL)
340bc5531deSDag-Erling Smørgrav 		options->xauth_location = xstrdup(_PATH_XAUTH);
341f7167e0eSDag-Erling Smørgrav 	if (options->permit_tty == -1)
342f7167e0eSDag-Erling Smørgrav 		options->permit_tty = 1;
343a0ee8cc6SDag-Erling Smørgrav 	if (options->permit_user_rc == -1)
344a0ee8cc6SDag-Erling Smørgrav 		options->permit_user_rc = 1;
345511b41d2SMark Murray 	if (options->strict_modes == -1)
346511b41d2SMark Murray 		options->strict_modes = 1;
3471ec0d754SDag-Erling Smørgrav 	if (options->tcp_keep_alive == -1)
3481ec0d754SDag-Erling Smørgrav 		options->tcp_keep_alive = 1;
349af12a3e7SDag-Erling Smørgrav 	if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
350511b41d2SMark Murray 		options->log_facility = SYSLOG_FACILITY_AUTH;
351af12a3e7SDag-Erling Smørgrav 	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
352511b41d2SMark Murray 		options->log_level = SYSLOG_LEVEL_INFO;
353ca3176e7SBrian Feldman 	if (options->hostbased_authentication == -1)
354ca3176e7SBrian Feldman 		options->hostbased_authentication = 0;
355ca3176e7SBrian Feldman 	if (options->hostbased_uses_name_from_packet_only == -1)
356ca3176e7SBrian Feldman 		options->hostbased_uses_name_from_packet_only = 0;
357ca3176e7SBrian Feldman 	if (options->pubkey_authentication == -1)
358ca3176e7SBrian Feldman 		options->pubkey_authentication = 1;
35919261079SEd Maste 	if (options->pubkey_auth_options == -1)
36019261079SEd Maste 		options->pubkey_auth_options = 0;
361989dd127SDag-Erling Smørgrav 	if (options->kerberos_authentication == -1)
362cf2b5f3bSDag-Erling Smørgrav 		options->kerberos_authentication = 0;
363af12a3e7SDag-Erling Smørgrav 	if (options->kerberos_or_local_passwd == -1)
364af12a3e7SDag-Erling Smørgrav 		options->kerberos_or_local_passwd = 1;
365af12a3e7SDag-Erling Smørgrav 	if (options->kerberos_ticket_cleanup == -1)
366af12a3e7SDag-Erling Smørgrav 		options->kerberos_ticket_cleanup = 1;
3671ec0d754SDag-Erling Smørgrav 	if (options->kerberos_get_afs_token == -1)
3681ec0d754SDag-Erling Smørgrav 		options->kerberos_get_afs_token = 0;
369cf2b5f3bSDag-Erling Smørgrav 	if (options->gss_authentication == -1)
370cf2b5f3bSDag-Erling Smørgrav 		options->gss_authentication = 0;
371cf2b5f3bSDag-Erling Smørgrav 	if (options->gss_cleanup_creds == -1)
372cf2b5f3bSDag-Erling Smørgrav 		options->gss_cleanup_creds = 1;
373557f75e5SDag-Erling Smørgrav 	if (options->gss_strict_acceptor == -1)
374d93a896eSDag-Erling Smørgrav 		options->gss_strict_acceptor = 1;
375511b41d2SMark Murray 	if (options->password_authentication == -1)
376b909c84bSDag-Erling Smørgrav 		options->password_authentication = 0;
37709958426SBrian Feldman 	if (options->kbd_interactive_authentication == -1)
37819261079SEd Maste 		options->kbd_interactive_authentication = 1;
379511b41d2SMark Murray 	if (options->permit_empty_passwd == -1)
380fe5fd017SMark Murray 		options->permit_empty_passwd = 0;
381190cef3dSDag-Erling Smørgrav 	if (options->permit_user_env == -1) {
382f388f5efSDag-Erling Smørgrav 		options->permit_user_env = 0;
38319261079SEd Maste 		options->permit_user_env_allowlist = NULL;
384190cef3dSDag-Erling Smørgrav 	}
38580628bacSDag-Erling Smørgrav 	if (options->compression == -1)
38619261079SEd Maste #ifdef WITH_ZLIB
387d4ecd108SDag-Erling Smørgrav 		options->compression = COMP_DELAYED;
38819261079SEd Maste #else
38919261079SEd Maste 		options->compression = COMP_NONE;
39019261079SEd Maste #endif
39119261079SEd Maste 
392e4a9863fSDag-Erling Smørgrav 	if (options->rekey_limit == -1)
393e4a9863fSDag-Erling Smørgrav 		options->rekey_limit = 0;
394e4a9863fSDag-Erling Smørgrav 	if (options->rekey_interval == -1)
395e4a9863fSDag-Erling Smørgrav 		options->rekey_interval = 0;
39609958426SBrian Feldman 	if (options->allow_tcp_forwarding == -1)
3976888a9beSDag-Erling Smørgrav 		options->allow_tcp_forwarding = FORWARD_ALLOW;
398a0ee8cc6SDag-Erling Smørgrav 	if (options->allow_streamlocal_forwarding == -1)
399a0ee8cc6SDag-Erling Smørgrav 		options->allow_streamlocal_forwarding = FORWARD_ALLOW;
400d4af9e69SDag-Erling Smørgrav 	if (options->allow_agent_forwarding == -1)
401d4af9e69SDag-Erling Smørgrav 		options->allow_agent_forwarding = 1;
402a0ee8cc6SDag-Erling Smørgrav 	if (options->fwd_opts.gateway_ports == -1)
403a0ee8cc6SDag-Erling Smørgrav 		options->fwd_opts.gateway_ports = 0;
404c2d3a559SKris Kennaway 	if (options->max_startups == -1)
4056888a9beSDag-Erling Smørgrav 		options->max_startups = 100;
406c2d3a559SKris Kennaway 	if (options->max_startups_rate == -1)
4076888a9beSDag-Erling Smørgrav 		options->max_startups_rate = 30;		/* 30% */
408c2d3a559SKris Kennaway 	if (options->max_startups_begin == -1)
4096888a9beSDag-Erling Smørgrav 		options->max_startups_begin = 10;
41019261079SEd Maste 	if (options->per_source_max_startups == -1)
41119261079SEd Maste 		options->per_source_max_startups = INT_MAX;
41219261079SEd Maste 	if (options->per_source_masklen_ipv4 == -1)
41319261079SEd Maste 		options->per_source_masklen_ipv4 = 32;
41419261079SEd Maste 	if (options->per_source_masklen_ipv6 == -1)
41519261079SEd Maste 		options->per_source_masklen_ipv6 = 128;
41621e764dfSDag-Erling Smørgrav 	if (options->max_authtries == -1)
41721e764dfSDag-Erling Smørgrav 		options->max_authtries = DEFAULT_AUTH_FAIL_MAX;
418d4af9e69SDag-Erling Smørgrav 	if (options->max_sessions == -1)
419d4af9e69SDag-Erling Smørgrav 		options->max_sessions = DEFAULT_SESSIONS_MAX;
420cf2b5f3bSDag-Erling Smørgrav 	if (options->use_dns == -1)
421c4cd1fa4SDag-Erling Smørgrav 		options->use_dns = 1;
422ca3176e7SBrian Feldman 	if (options->client_alive_interval == -1)
423ca3176e7SBrian Feldman 		options->client_alive_interval = 0;
424ca3176e7SBrian Feldman 	if (options->client_alive_count_max == -1)
425ca3176e7SBrian Feldman 		options->client_alive_count_max = 3;
426e146993eSDag-Erling Smørgrav 	if (options->num_authkeys_files == 0) {
42719261079SEd Maste 		opt_array_append(defaultkey, 0, "AuthorizedKeysFiles",
42847dd1d1bSDag-Erling Smørgrav 		    &options->authorized_keys_files,
42947dd1d1bSDag-Erling Smørgrav 		    &options->num_authkeys_files,
43047dd1d1bSDag-Erling Smørgrav 		    _PATH_SSH_USER_PERMITTED_KEYS);
43119261079SEd Maste 		opt_array_append(defaultkey, 0, "AuthorizedKeysFiles",
43247dd1d1bSDag-Erling Smørgrav 		    &options->authorized_keys_files,
43347dd1d1bSDag-Erling Smørgrav 		    &options->num_authkeys_files,
43447dd1d1bSDag-Erling Smørgrav 		    _PATH_SSH_USER_PERMITTED_KEYS2);
435af12a3e7SDag-Erling Smørgrav 	}
436b74df5b2SDag-Erling Smørgrav 	if (options->permit_tun == -1)
437b74df5b2SDag-Erling Smørgrav 		options->permit_tun = SSH_TUNMODE_NO;
4384a421b63SDag-Erling Smørgrav 	if (options->ip_qos_interactive == -1)
439190cef3dSDag-Erling Smørgrav 		options->ip_qos_interactive = IPTOS_DSCP_AF21;
4404a421b63SDag-Erling Smørgrav 	if (options->ip_qos_bulk == -1)
441190cef3dSDag-Erling Smørgrav 		options->ip_qos_bulk = IPTOS_DSCP_CS1;
442462c32cbSDag-Erling Smørgrav 	if (options->version_addendum == NULL)
443462c32cbSDag-Erling Smørgrav 		options->version_addendum = xstrdup(SSH_VERSION_FREEBSD);
444a0ee8cc6SDag-Erling Smørgrav 	if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
445a0ee8cc6SDag-Erling Smørgrav 		options->fwd_opts.streamlocal_bind_mask = 0177;
446a0ee8cc6SDag-Erling Smørgrav 	if (options->fwd_opts.streamlocal_bind_unlink == -1)
447a0ee8cc6SDag-Erling Smørgrav 		options->fwd_opts.streamlocal_bind_unlink = 0;
448bc5531deSDag-Erling Smørgrav 	if (options->fingerprint_hash == -1)
449bc5531deSDag-Erling Smørgrav 		options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
450ca86bcf2SDag-Erling Smørgrav 	if (options->disable_forwarding == -1)
451ca86bcf2SDag-Erling Smørgrav 		options->disable_forwarding = 0;
4524f52dfbbSDag-Erling Smørgrav 	if (options->expose_userauth_info == -1)
4534f52dfbbSDag-Erling Smørgrav 		options->expose_userauth_info = 0;
45419261079SEd Maste 	if (options->sk_provider == NULL)
45519261079SEd Maste 		options->sk_provider = xstrdup("internal");
45638a52bd3SEd Maste 	if (options->required_rsa_size == -1)
45738a52bd3SEd Maste 		options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
458*f374ba41SEd Maste 	if (options->unused_connection_timeout == -1)
459*f374ba41SEd Maste 		options->unused_connection_timeout = 0;
460b2af61ecSKurt Lidl 	if (options->use_blacklist == -1)
461b2af61ecSKurt Lidl 		options->use_blacklist = 0;
462eccfee6eSDag-Erling Smørgrav 
463acc1a9efSDag-Erling Smørgrav 	assemble_algorithms(options);
464eccfee6eSDag-Erling Smørgrav 
465acc1a9efSDag-Erling Smørgrav 	/* Turn privilege separation and sandboxing on by default */
466462c32cbSDag-Erling Smørgrav 	if (use_privsep == -1)
4672b1970f3SDag-Erling Smørgrav 		use_privsep = PRIVSEP_ON;
468462c32cbSDag-Erling Smørgrav 
469bc5531deSDag-Erling Smørgrav #define CLEAR_ON_NONE(v) \
470bc5531deSDag-Erling Smørgrav 	do { \
471bc5531deSDag-Erling Smørgrav 		if (option_clear_or_none(v)) { \
472bc5531deSDag-Erling Smørgrav 			free(v); \
473bc5531deSDag-Erling Smørgrav 			v = NULL; \
474bc5531deSDag-Erling Smørgrav 		} \
475bc5531deSDag-Erling Smørgrav 	} while(0)
476*f374ba41SEd Maste #define CLEAR_ON_NONE_ARRAY(v, nv, none) \
477*f374ba41SEd Maste 	do { \
478*f374ba41SEd Maste 		if (options->nv == 1 && \
479*f374ba41SEd Maste 		    strcasecmp(options->v[0], none) == 0) { \
480*f374ba41SEd Maste 			free(options->v[0]); \
481*f374ba41SEd Maste 			free(options->v); \
482*f374ba41SEd Maste 			options->v = NULL; \
483*f374ba41SEd Maste 			options->nv = 0; \
484*f374ba41SEd Maste 		} \
485*f374ba41SEd Maste 	} while (0)
486bc5531deSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->pid_file);
487bc5531deSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->xauth_location);
488bc5531deSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->banner);
489bc5531deSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->trusted_user_ca_keys);
490bc5531deSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->revoked_keys_file);
49119261079SEd Maste 	CLEAR_ON_NONE(options->sk_provider);
492557f75e5SDag-Erling Smørgrav 	CLEAR_ON_NONE(options->authorized_principals_file);
493acc1a9efSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->adm_forced_command);
494acc1a9efSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->chroot_directory);
49547dd1d1bSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->routing_domain);
49619261079SEd Maste 	CLEAR_ON_NONE(options->host_key_agent);
497*f374ba41SEd Maste 
498bc5531deSDag-Erling Smørgrav 	for (i = 0; i < options->num_host_key_files; i++)
499bc5531deSDag-Erling Smørgrav 		CLEAR_ON_NONE(options->host_key_files[i]);
500bc5531deSDag-Erling Smørgrav 	for (i = 0; i < options->num_host_cert_files; i++)
501bc5531deSDag-Erling Smørgrav 		CLEAR_ON_NONE(options->host_cert_files[i]);
502bc5531deSDag-Erling Smørgrav 
503*f374ba41SEd Maste 	CLEAR_ON_NONE_ARRAY(channel_timeouts, num_channel_timeouts, "none");
504*f374ba41SEd Maste 	CLEAR_ON_NONE_ARRAY(auth_methods, num_auth_methods, "any");
505*f374ba41SEd Maste #undef CLEAR_ON_NONE
506*f374ba41SEd Maste #undef CLEAR_ON_NONE_ARRAY
507511b41d2SMark Murray }
508511b41d2SMark Murray 
509511b41d2SMark Murray /* Keyword tokens. */
510511b41d2SMark Murray typedef enum {
511511b41d2SMark Murray 	sBadOption,		/* == unknown option */
512989dd127SDag-Erling Smørgrav 	/* Portable-specific options */
513cf2b5f3bSDag-Erling Smørgrav 	sUsePAM,
514989dd127SDag-Erling Smørgrav 	/* Standard Options */
515ca86bcf2SDag-Erling Smørgrav 	sPort, sHostKeyFile, sLoginGraceTime,
51619261079SEd Maste 	sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose,
517af12a3e7SDag-Erling Smørgrav 	sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
518e9e8876aSEd Maste 	sKerberosGetAFSToken, sPasswordAuthentication,
519e9e8876aSEd Maste 	sKbdInteractiveAuthentication, sListenAddress, sAddressFamily,
520ca3176e7SBrian Feldman 	sPrintMotd, sPrintLastLog, sIgnoreRhosts,
521af12a3e7SDag-Erling Smørgrav 	sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
522f7167e0eSDag-Erling Smørgrav 	sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive,
523ca86bcf2SDag-Erling Smørgrav 	sPermitUserEnvironment, sAllowTcpForwarding, sCompression,
524e4a9863fSDag-Erling Smørgrav 	sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
52519261079SEd Maste 	sIgnoreUserKnownHosts, sCiphers, sMacs, sPidFile, sModuliFile,
52619261079SEd Maste 	sGatewayPorts, sPubkeyAuthentication, sPubkeyAcceptedAlgorithms,
527bc5531deSDag-Erling Smørgrav 	sXAuthLocation, sSubsystem, sMaxStartups, sMaxAuthTries, sMaxSessions,
528cf2b5f3bSDag-Erling Smørgrav 	sBanner, sUseDNS, sHostbasedAuthentication,
52919261079SEd Maste 	sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedAlgorithms,
53019261079SEd Maste 	sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize,
531bc5531deSDag-Erling Smørgrav 	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
532557f75e5SDag-Erling Smørgrav 	sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
533190cef3dSDag-Erling Smørgrav 	sAcceptEnv, sSetEnv, sPermitTunnel,
534190cef3dSDag-Erling Smørgrav 	sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory,
535d4af9e69SDag-Erling Smørgrav 	sUsePrivilegeSeparation, sAllowAgentForwarding,
53619261079SEd Maste 	sHostCertificate, sInclude,
537e2f6069cSDag-Erling Smørgrav 	sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
538557f75e5SDag-Erling Smørgrav 	sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser,
5392f513db7SEd Maste 	sKexAlgorithms, sCASignatureAlgorithms, sIPQoS, sVersionAddendum,
5406888a9beSDag-Erling Smørgrav 	sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
541a0ee8cc6SDag-Erling Smørgrav 	sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
542a0ee8cc6SDag-Erling Smørgrav 	sStreamLocalBindMask, sStreamLocalBindUnlink,
543ca86bcf2SDag-Erling Smørgrav 	sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
54419261079SEd Maste 	sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider,
545*f374ba41SEd Maste 	sRequiredRSASize, sChannelTimeout, sUnusedConnectionTimeout,
546b2af61ecSKurt Lidl 	sUseBlacklist,
547ca86bcf2SDag-Erling Smørgrav 	sDeprecated, sIgnore, sUnsupported
548511b41d2SMark Murray } ServerOpCodes;
549511b41d2SMark Murray 
55019261079SEd Maste #define SSHCFG_GLOBAL		0x01	/* allowed in main section of config */
551333ee039SDag-Erling Smørgrav #define SSHCFG_MATCH		0x02	/* allowed inside a Match section */
552333ee039SDag-Erling Smørgrav #define SSHCFG_ALL		(SSHCFG_GLOBAL|SSHCFG_MATCH)
55319261079SEd Maste #define SSHCFG_NEVERMATCH	0x04  /* Match never matches; internal only */
55419261079SEd Maste #define SSHCFG_MATCH_ONLY	0x08  /* Match only in conditional blocks; internal only */
555333ee039SDag-Erling Smørgrav 
556511b41d2SMark Murray /* Textual representation of the tokens. */
557511b41d2SMark Murray static struct {
558511b41d2SMark Murray 	const char *name;
559511b41d2SMark Murray 	ServerOpCodes opcode;
560333ee039SDag-Erling Smørgrav 	u_int flags;
561511b41d2SMark Murray } keywords[] = {
562989dd127SDag-Erling Smørgrav 	/* Portable-specific options */
563cf2b5f3bSDag-Erling Smørgrav #ifdef USE_PAM
564333ee039SDag-Erling Smørgrav 	{ "usepam", sUsePAM, SSHCFG_GLOBAL },
565cf2b5f3bSDag-Erling Smørgrav #else
566333ee039SDag-Erling Smørgrav 	{ "usepam", sUnsupported, SSHCFG_GLOBAL },
567975616f0SDag-Erling Smørgrav #endif
568333ee039SDag-Erling Smørgrav 	{ "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
569989dd127SDag-Erling Smørgrav 	/* Standard Options */
570333ee039SDag-Erling Smørgrav 	{ "port", sPort, SSHCFG_GLOBAL },
571333ee039SDag-Erling Smørgrav 	{ "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
572333ee039SDag-Erling Smørgrav 	{ "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL },		/* alias */
573e4a9863fSDag-Erling Smørgrav 	{ "hostkeyagent", sHostKeyAgent, SSHCFG_GLOBAL },
574333ee039SDag-Erling Smørgrav 	{ "pidfile", sPidFile, SSHCFG_GLOBAL },
57519261079SEd Maste 	{ "modulifile", sModuliFile, SSHCFG_GLOBAL },
576ca86bcf2SDag-Erling Smørgrav 	{ "serverkeybits", sDeprecated, SSHCFG_GLOBAL },
577333ee039SDag-Erling Smørgrav 	{ "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL },
578ca86bcf2SDag-Erling Smørgrav 	{ "keyregenerationinterval", sDeprecated, SSHCFG_GLOBAL },
579d4af9e69SDag-Erling Smørgrav 	{ "permitrootlogin", sPermitRootLogin, SSHCFG_ALL },
580333ee039SDag-Erling Smørgrav 	{ "syslogfacility", sLogFacility, SSHCFG_GLOBAL },
5814f52dfbbSDag-Erling Smørgrav 	{ "loglevel", sLogLevel, SSHCFG_ALL },
58219261079SEd Maste 	{ "logverbose", sLogVerbose, SSHCFG_ALL },
583333ee039SDag-Erling Smørgrav 	{ "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL },
584ca86bcf2SDag-Erling Smørgrav 	{ "rhostsrsaauthentication", sDeprecated, SSHCFG_ALL },
585d4af9e69SDag-Erling Smørgrav 	{ "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL },
586e2f6069cSDag-Erling Smørgrav 	{ "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_ALL },
58719261079SEd Maste 	{ "hostbasedacceptedalgorithms", sHostbasedAcceptedAlgorithms, SSHCFG_ALL },
58819261079SEd Maste 	{ "hostbasedacceptedkeytypes", sHostbasedAcceptedAlgorithms, SSHCFG_ALL }, /* obsolete */
589eccfee6eSDag-Erling Smørgrav 	{ "hostkeyalgorithms", sHostKeyAlgorithms, SSHCFG_GLOBAL },
590ca86bcf2SDag-Erling Smørgrav 	{ "rsaauthentication", sDeprecated, SSHCFG_ALL },
591d4af9e69SDag-Erling Smørgrav 	{ "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL },
59219261079SEd Maste 	{ "pubkeyacceptedalgorithms", sPubkeyAcceptedAlgorithms, SSHCFG_ALL },
59319261079SEd Maste 	{ "pubkeyacceptedkeytypes", sPubkeyAcceptedAlgorithms, SSHCFG_ALL }, /* obsolete */
59419261079SEd Maste 	{ "pubkeyauthoptions", sPubkeyAuthOptions, SSHCFG_ALL },
595333ee039SDag-Erling Smørgrav 	{ "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */
596cf2b5f3bSDag-Erling Smørgrav #ifdef KRB5
597d4af9e69SDag-Erling Smørgrav 	{ "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL },
598333ee039SDag-Erling Smørgrav 	{ "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL },
599333ee039SDag-Erling Smørgrav 	{ "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL },
6001ec0d754SDag-Erling Smørgrav #ifdef USE_AFS
601333ee039SDag-Erling Smørgrav 	{ "kerberosgetafstoken", sKerberosGetAFSToken, SSHCFG_GLOBAL },
6021ec0d754SDag-Erling Smørgrav #else
603333ee039SDag-Erling Smørgrav 	{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
6041ec0d754SDag-Erling Smørgrav #endif
605cf2b5f3bSDag-Erling Smørgrav #else
606d4af9e69SDag-Erling Smørgrav 	{ "kerberosauthentication", sUnsupported, SSHCFG_ALL },
607333ee039SDag-Erling Smørgrav 	{ "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
608333ee039SDag-Erling Smørgrav 	{ "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
609333ee039SDag-Erling Smørgrav 	{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
610cb96ab36SAssar Westerlund #endif
611333ee039SDag-Erling Smørgrav 	{ "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
612333ee039SDag-Erling Smørgrav 	{ "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
613cf2b5f3bSDag-Erling Smørgrav #ifdef GSSAPI
614d4af9e69SDag-Erling Smørgrav 	{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
615333ee039SDag-Erling Smørgrav 	{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
616557f75e5SDag-Erling Smørgrav 	{ "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
617cf2b5f3bSDag-Erling Smørgrav #else
618d4af9e69SDag-Erling Smørgrav 	{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
619333ee039SDag-Erling Smørgrav 	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
620557f75e5SDag-Erling Smørgrav 	{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
621511b41d2SMark Murray #endif
622d4af9e69SDag-Erling Smørgrav 	{ "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
623d4af9e69SDag-Erling Smørgrav 	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
62419261079SEd Maste 	{ "challengeresponseauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */
62519261079SEd Maste 	{ "skeyauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */
626333ee039SDag-Erling Smørgrav 	{ "checkmail", sDeprecated, SSHCFG_GLOBAL },
627333ee039SDag-Erling Smørgrav 	{ "listenaddress", sListenAddress, SSHCFG_GLOBAL },
628333ee039SDag-Erling Smørgrav 	{ "addressfamily", sAddressFamily, SSHCFG_GLOBAL },
629333ee039SDag-Erling Smørgrav 	{ "printmotd", sPrintMotd, SSHCFG_GLOBAL },
630acc1a9efSDag-Erling Smørgrav #ifdef DISABLE_LASTLOG
631acc1a9efSDag-Erling Smørgrav 	{ "printlastlog", sUnsupported, SSHCFG_GLOBAL },
632acc1a9efSDag-Erling Smørgrav #else
633333ee039SDag-Erling Smørgrav 	{ "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
634acc1a9efSDag-Erling Smørgrav #endif
63519261079SEd Maste 	{ "ignorerhosts", sIgnoreRhosts, SSHCFG_ALL },
636333ee039SDag-Erling Smørgrav 	{ "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
637333ee039SDag-Erling Smørgrav 	{ "x11forwarding", sX11Forwarding, SSHCFG_ALL },
638333ee039SDag-Erling Smørgrav 	{ "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
639333ee039SDag-Erling Smørgrav 	{ "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
640333ee039SDag-Erling Smørgrav 	{ "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
641333ee039SDag-Erling Smørgrav 	{ "strictmodes", sStrictModes, SSHCFG_GLOBAL },
642cce7d346SDag-Erling Smørgrav 	{ "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL },
643333ee039SDag-Erling Smørgrav 	{ "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
644ca86bcf2SDag-Erling Smørgrav 	{ "uselogin", sDeprecated, SSHCFG_GLOBAL },
645333ee039SDag-Erling Smørgrav 	{ "compression", sCompression, SSHCFG_GLOBAL },
646e4a9863fSDag-Erling Smørgrav 	{ "rekeylimit", sRekeyLimit, SSHCFG_ALL },
647333ee039SDag-Erling Smørgrav 	{ "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
648333ee039SDag-Erling Smørgrav 	{ "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL },	/* obsolete alias */
649333ee039SDag-Erling Smørgrav 	{ "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
650d4af9e69SDag-Erling Smørgrav 	{ "allowagentforwarding", sAllowAgentForwarding, SSHCFG_ALL },
651462c32cbSDag-Erling Smørgrav 	{ "allowusers", sAllowUsers, SSHCFG_ALL },
652462c32cbSDag-Erling Smørgrav 	{ "denyusers", sDenyUsers, SSHCFG_ALL },
653462c32cbSDag-Erling Smørgrav 	{ "allowgroups", sAllowGroups, SSHCFG_ALL },
654462c32cbSDag-Erling Smørgrav 	{ "denygroups", sDenyGroups, SSHCFG_ALL },
655333ee039SDag-Erling Smørgrav 	{ "ciphers", sCiphers, SSHCFG_GLOBAL },
656333ee039SDag-Erling Smørgrav 	{ "macs", sMacs, SSHCFG_GLOBAL },
657ca86bcf2SDag-Erling Smørgrav 	{ "protocol", sIgnore, SSHCFG_GLOBAL },
658333ee039SDag-Erling Smørgrav 	{ "gatewayports", sGatewayPorts, SSHCFG_ALL },
659333ee039SDag-Erling Smørgrav 	{ "subsystem", sSubsystem, SSHCFG_GLOBAL },
660333ee039SDag-Erling Smørgrav 	{ "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
66119261079SEd Maste 	{ "persourcemaxstartups", sPerSourceMaxStartups, SSHCFG_GLOBAL },
66219261079SEd Maste 	{ "persourcenetblocksize", sPerSourceNetBlockSize, SSHCFG_GLOBAL },
663d4af9e69SDag-Erling Smørgrav 	{ "maxauthtries", sMaxAuthTries, SSHCFG_ALL },
664d4af9e69SDag-Erling Smørgrav 	{ "maxsessions", sMaxSessions, SSHCFG_ALL },
665d4af9e69SDag-Erling Smørgrav 	{ "banner", sBanner, SSHCFG_ALL },
666333ee039SDag-Erling Smørgrav 	{ "usedns", sUseDNS, SSHCFG_GLOBAL },
667333ee039SDag-Erling Smørgrav 	{ "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
668333ee039SDag-Erling Smørgrav 	{ "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL },
669ca86bcf2SDag-Erling Smørgrav 	{ "clientaliveinterval", sClientAliveInterval, SSHCFG_ALL },
670ca86bcf2SDag-Erling Smørgrav 	{ "clientalivecountmax", sClientAliveCountMax, SSHCFG_ALL },
671e2f6069cSDag-Erling Smørgrav 	{ "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_ALL },
672e146993eSDag-Erling Smørgrav 	{ "authorizedkeysfile2", sDeprecated, SSHCFG_ALL },
673d93a896eSDag-Erling Smørgrav 	{ "useprivilegeseparation", sDeprecated, SSHCFG_GLOBAL},
674462c32cbSDag-Erling Smørgrav 	{ "acceptenv", sAcceptEnv, SSHCFG_ALL },
675190cef3dSDag-Erling Smørgrav 	{ "setenv", sSetEnv, SSHCFG_ALL },
676e2f6069cSDag-Erling Smørgrav 	{ "permittunnel", sPermitTunnel, SSHCFG_ALL },
677f7167e0eSDag-Erling Smørgrav 	{ "permittty", sPermitTTY, SSHCFG_ALL },
678a0ee8cc6SDag-Erling Smørgrav 	{ "permituserrc", sPermitUserRC, SSHCFG_ALL },
679333ee039SDag-Erling Smørgrav 	{ "match", sMatch, SSHCFG_ALL },
680333ee039SDag-Erling Smørgrav 	{ "permitopen", sPermitOpen, SSHCFG_ALL },
681190cef3dSDag-Erling Smørgrav 	{ "permitlisten", sPermitListen, SSHCFG_ALL },
682333ee039SDag-Erling Smørgrav 	{ "forcecommand", sForceCommand, SSHCFG_ALL },
683d4af9e69SDag-Erling Smørgrav 	{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
684b15c8340SDag-Erling Smørgrav 	{ "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
685b15c8340SDag-Erling Smørgrav 	{ "revokedkeys", sRevokedKeys, SSHCFG_ALL },
686b15c8340SDag-Erling Smørgrav 	{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
687e2f6069cSDag-Erling Smørgrav 	{ "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
6884a421b63SDag-Erling Smørgrav 	{ "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
68919261079SEd Maste 	{ "include", sInclude, SSHCFG_ALL },
6904a421b63SDag-Erling Smørgrav 	{ "ipqos", sIPQoS, SSHCFG_ALL },
6916888a9beSDag-Erling Smørgrav 	{ "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
6926888a9beSDag-Erling Smørgrav 	{ "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
693557f75e5SDag-Erling Smørgrav 	{ "authorizedprincipalscommand", sAuthorizedPrincipalsCommand, SSHCFG_ALL },
694557f75e5SDag-Erling Smørgrav 	{ "authorizedprincipalscommanduser", sAuthorizedPrincipalsCommandUser, SSHCFG_ALL },
695462c32cbSDag-Erling Smørgrav 	{ "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL },
6966888a9beSDag-Erling Smørgrav 	{ "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL },
697a0ee8cc6SDag-Erling Smørgrav 	{ "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_ALL },
698a0ee8cc6SDag-Erling Smørgrav 	{ "streamlocalbindunlink", sStreamLocalBindUnlink, SSHCFG_ALL },
699a0ee8cc6SDag-Erling Smørgrav 	{ "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL },
700bc5531deSDag-Erling Smørgrav 	{ "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL },
701ca86bcf2SDag-Erling Smørgrav 	{ "disableforwarding", sDisableForwarding, SSHCFG_ALL },
7024f52dfbbSDag-Erling Smørgrav 	{ "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL },
70347dd1d1bSDag-Erling Smørgrav 	{ "rdomain", sRDomain, SSHCFG_ALL },
7042f513db7SEd Maste 	{ "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL },
70519261079SEd Maste 	{ "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL },
70638a52bd3SEd Maste 	{ "requiredrsasize", sRequiredRSASize, SSHCFG_ALL },
707*f374ba41SEd Maste 	{ "channeltimeout", sChannelTimeout, SSHCFG_ALL },
708*f374ba41SEd Maste 	{ "unusedconnectiontimeout", sUnusedConnectionTimeout, SSHCFG_ALL },
709b2af61ecSKurt Lidl 	{ "useblacklist", sUseBlacklist, SSHCFG_GLOBAL },
710e426c743SEd Maste 	{ "useblocklist", sUseBlacklist, SSHCFG_GLOBAL }, /* alias */
7116f351346SDag-Erling Smørgrav 	{ "noneenabled", sUnsupported, SSHCFG_ALL },
7129860d96eSDag-Erling Smørgrav 	{ "hpndisabled", sDeprecated, SSHCFG_ALL },
7139860d96eSDag-Erling Smørgrav 	{ "hpnbuffersize", sDeprecated, SSHCFG_ALL },
7149860d96eSDag-Erling Smørgrav 	{ "tcprcvbufpoll", sDeprecated, SSHCFG_ALL },
715333ee039SDag-Erling Smørgrav 	{ NULL, sBadOption, 0 }
716511b41d2SMark Murray };
717511b41d2SMark Murray 
718d4af9e69SDag-Erling Smørgrav static struct {
719d4af9e69SDag-Erling Smørgrav 	int val;
720d4af9e69SDag-Erling Smørgrav 	char *text;
721d4af9e69SDag-Erling Smørgrav } tunmode_desc[] = {
722d4af9e69SDag-Erling Smørgrav 	{ SSH_TUNMODE_NO, "no" },
723d4af9e69SDag-Erling Smørgrav 	{ SSH_TUNMODE_POINTOPOINT, "point-to-point" },
724d4af9e69SDag-Erling Smørgrav 	{ SSH_TUNMODE_ETHERNET, "ethernet" },
725d4af9e69SDag-Erling Smørgrav 	{ SSH_TUNMODE_YES, "yes" },
726d4af9e69SDag-Erling Smørgrav 	{ -1, NULL }
727d4af9e69SDag-Erling Smørgrav };
728d4af9e69SDag-Erling Smørgrav 
729190cef3dSDag-Erling Smørgrav /* Returns an opcode name from its number */
730190cef3dSDag-Erling Smørgrav 
731190cef3dSDag-Erling Smørgrav static const char *
732190cef3dSDag-Erling Smørgrav lookup_opcode_name(ServerOpCodes code)
733190cef3dSDag-Erling Smørgrav {
734190cef3dSDag-Erling Smørgrav 	u_int i;
735190cef3dSDag-Erling Smørgrav 
736190cef3dSDag-Erling Smørgrav 	for (i = 0; keywords[i].name != NULL; i++)
737190cef3dSDag-Erling Smørgrav 		if (keywords[i].opcode == code)
738190cef3dSDag-Erling Smørgrav 			return(keywords[i].name);
739190cef3dSDag-Erling Smørgrav 	return "UNKNOWN";
740190cef3dSDag-Erling Smørgrav }
741190cef3dSDag-Erling Smørgrav 
742190cef3dSDag-Erling Smørgrav 
743511b41d2SMark Murray /*
744ca3176e7SBrian Feldman  * Returns the number of the token pointed to by cp or sBadOption.
745511b41d2SMark Murray  */
746511b41d2SMark Murray 
747511b41d2SMark Murray static ServerOpCodes
748511b41d2SMark Murray parse_token(const char *cp, const char *filename,
749333ee039SDag-Erling Smørgrav 	    int linenum, u_int *flags)
750511b41d2SMark Murray {
751ca3176e7SBrian Feldman 	u_int i;
752511b41d2SMark Murray 
753511b41d2SMark Murray 	for (i = 0; keywords[i].name; i++)
754333ee039SDag-Erling Smørgrav 		if (strcasecmp(cp, keywords[i].name) == 0) {
755333ee039SDag-Erling Smørgrav 			*flags = keywords[i].flags;
756511b41d2SMark Murray 			return keywords[i].opcode;
757333ee039SDag-Erling Smørgrav 		}
758511b41d2SMark Murray 
759ca3176e7SBrian Feldman 	error("%s: line %d: Bad configuration option: %s",
760511b41d2SMark Murray 	    filename, linenum, cp);
761511b41d2SMark Murray 	return sBadOption;
762511b41d2SMark Murray }
763511b41d2SMark Murray 
764b15c8340SDag-Erling Smørgrav char *
765b15c8340SDag-Erling Smørgrav derelativise_path(const char *path)
766b15c8340SDag-Erling Smørgrav {
767bc5531deSDag-Erling Smørgrav 	char *expanded, *ret, cwd[PATH_MAX];
768b15c8340SDag-Erling Smørgrav 
769bc5531deSDag-Erling Smørgrav 	if (strcasecmp(path, "none") == 0)
770bc5531deSDag-Erling Smørgrav 		return xstrdup("none");
771b15c8340SDag-Erling Smørgrav 	expanded = tilde_expand_filename(path, getuid());
77219261079SEd Maste 	if (path_absolute(expanded))
773b15c8340SDag-Erling Smørgrav 		return expanded;
7748ad9b54aSDag-Erling Smørgrav 	if (getcwd(cwd, sizeof(cwd)) == NULL)
77519261079SEd Maste 		fatal_f("getcwd: %s", strerror(errno));
776b15c8340SDag-Erling Smørgrav 	xasprintf(&ret, "%s/%s", cwd, expanded);
777e4a9863fSDag-Erling Smørgrav 	free(expanded);
778b15c8340SDag-Erling Smørgrav 	return ret;
779b15c8340SDag-Erling Smørgrav }
780b15c8340SDag-Erling Smørgrav 
781af12a3e7SDag-Erling Smørgrav static void
78247dd1d1bSDag-Erling Smørgrav add_listen_addr(ServerOptions *options, const char *addr,
78347dd1d1bSDag-Erling Smørgrav     const char *rdomain, int port)
784511b41d2SMark Murray {
785d4ecd108SDag-Erling Smørgrav 	u_int i;
786511b41d2SMark Murray 
78747dd1d1bSDag-Erling Smørgrav 	if (port > 0)
78847dd1d1bSDag-Erling Smørgrav 		add_one_listen_addr(options, addr, rdomain, port);
78947dd1d1bSDag-Erling Smørgrav 	else {
79047dd1d1bSDag-Erling Smørgrav 		for (i = 0; i < options->num_ports; i++) {
79147dd1d1bSDag-Erling Smørgrav 			add_one_listen_addr(options, addr, rdomain,
79247dd1d1bSDag-Erling Smørgrav 			    options->ports[i]);
79347dd1d1bSDag-Erling Smørgrav 		}
79447dd1d1bSDag-Erling Smørgrav 	}
795ca3176e7SBrian Feldman }
796ca3176e7SBrian Feldman 
797af12a3e7SDag-Erling Smørgrav static void
79847dd1d1bSDag-Erling Smørgrav add_one_listen_addr(ServerOptions *options, const char *addr,
79947dd1d1bSDag-Erling Smørgrav     const char *rdomain, int port)
800ca3176e7SBrian Feldman {
801ca3176e7SBrian Feldman 	struct addrinfo hints, *ai, *aitop;
802ca3176e7SBrian Feldman 	char strport[NI_MAXSERV];
803ca3176e7SBrian Feldman 	int gaierr;
80447dd1d1bSDag-Erling Smørgrav 	u_int i;
80547dd1d1bSDag-Erling Smørgrav 
80647dd1d1bSDag-Erling Smørgrav 	/* Find listen_addrs entry for this rdomain */
80747dd1d1bSDag-Erling Smørgrav 	for (i = 0; i < options->num_listen_addrs; i++) {
80847dd1d1bSDag-Erling Smørgrav 		if (rdomain == NULL && options->listen_addrs[i].rdomain == NULL)
80947dd1d1bSDag-Erling Smørgrav 			break;
81047dd1d1bSDag-Erling Smørgrav 		if (rdomain == NULL || options->listen_addrs[i].rdomain == NULL)
81147dd1d1bSDag-Erling Smørgrav 			continue;
81247dd1d1bSDag-Erling Smørgrav 		if (strcmp(rdomain, options->listen_addrs[i].rdomain) == 0)
81347dd1d1bSDag-Erling Smørgrav 			break;
81447dd1d1bSDag-Erling Smørgrav 	}
81547dd1d1bSDag-Erling Smørgrav 	if (i >= options->num_listen_addrs) {
81647dd1d1bSDag-Erling Smørgrav 		/* No entry for this rdomain; allocate one */
81747dd1d1bSDag-Erling Smørgrav 		if (i >= INT_MAX)
81819261079SEd Maste 			fatal_f("too many listen addresses");
81947dd1d1bSDag-Erling Smørgrav 		options->listen_addrs = xrecallocarray(options->listen_addrs,
82047dd1d1bSDag-Erling Smørgrav 		    options->num_listen_addrs, options->num_listen_addrs + 1,
82147dd1d1bSDag-Erling Smørgrav 		    sizeof(*options->listen_addrs));
82247dd1d1bSDag-Erling Smørgrav 		i = options->num_listen_addrs++;
82347dd1d1bSDag-Erling Smørgrav 		if (rdomain != NULL)
82447dd1d1bSDag-Erling Smørgrav 			options->listen_addrs[i].rdomain = xstrdup(rdomain);
82547dd1d1bSDag-Erling Smørgrav 	}
82647dd1d1bSDag-Erling Smørgrav 	/* options->listen_addrs[i] points to the addresses for this rdomain */
827ca3176e7SBrian Feldman 
828511b41d2SMark Murray 	memset(&hints, 0, sizeof(hints));
829aa49c926SDag-Erling Smørgrav 	hints.ai_family = options->address_family;
830511b41d2SMark Murray 	hints.ai_socktype = SOCK_STREAM;
831511b41d2SMark Murray 	hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
832cce7d346SDag-Erling Smørgrav 	snprintf(strport, sizeof strport, "%d", port);
833511b41d2SMark Murray 	if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
834ca3176e7SBrian Feldman 		fatal("bad addr or host: %s (%s)",
835511b41d2SMark Murray 		    addr ? addr : "<NULL>",
836d4af9e69SDag-Erling Smørgrav 		    ssh_gai_strerror(gaierr));
837511b41d2SMark Murray 	for (ai = aitop; ai->ai_next; ai = ai->ai_next)
838511b41d2SMark Murray 		;
83947dd1d1bSDag-Erling Smørgrav 	ai->ai_next = options->listen_addrs[i].addrs;
84047dd1d1bSDag-Erling Smørgrav 	options->listen_addrs[i].addrs = aitop;
84147dd1d1bSDag-Erling Smørgrav }
84247dd1d1bSDag-Erling Smørgrav 
84347dd1d1bSDag-Erling Smørgrav /* Returns nonzero if the routing domain name is valid */
84447dd1d1bSDag-Erling Smørgrav static int
84547dd1d1bSDag-Erling Smørgrav valid_rdomain(const char *name)
84647dd1d1bSDag-Erling Smørgrav {
84747dd1d1bSDag-Erling Smørgrav #if defined(HAVE_SYS_VALID_RDOMAIN)
84847dd1d1bSDag-Erling Smørgrav 	return sys_valid_rdomain(name);
84947dd1d1bSDag-Erling Smørgrav #elif defined(__OpenBSD__)
85047dd1d1bSDag-Erling Smørgrav 	const char *errstr;
85147dd1d1bSDag-Erling Smørgrav 	long long num;
85247dd1d1bSDag-Erling Smørgrav 	struct rt_tableinfo info;
85347dd1d1bSDag-Erling Smørgrav 	int mib[6];
85447dd1d1bSDag-Erling Smørgrav 	size_t miblen = sizeof(mib);
85547dd1d1bSDag-Erling Smørgrav 
85647dd1d1bSDag-Erling Smørgrav 	if (name == NULL)
85747dd1d1bSDag-Erling Smørgrav 		return 1;
85847dd1d1bSDag-Erling Smørgrav 
85947dd1d1bSDag-Erling Smørgrav 	num = strtonum(name, 0, 255, &errstr);
86047dd1d1bSDag-Erling Smørgrav 	if (errstr != NULL)
86147dd1d1bSDag-Erling Smørgrav 		return 0;
86247dd1d1bSDag-Erling Smørgrav 
86347dd1d1bSDag-Erling Smørgrav 	/* Check whether the table actually exists */
86447dd1d1bSDag-Erling Smørgrav 	memset(mib, 0, sizeof(mib));
86547dd1d1bSDag-Erling Smørgrav 	mib[0] = CTL_NET;
86647dd1d1bSDag-Erling Smørgrav 	mib[1] = PF_ROUTE;
86747dd1d1bSDag-Erling Smørgrav 	mib[4] = NET_RT_TABLE;
86847dd1d1bSDag-Erling Smørgrav 	mib[5] = (int)num;
86947dd1d1bSDag-Erling Smørgrav 	if (sysctl(mib, 6, &info, &miblen, NULL, 0) == -1)
87047dd1d1bSDag-Erling Smørgrav 		return 0;
87147dd1d1bSDag-Erling Smørgrav 
87247dd1d1bSDag-Erling Smørgrav 	return 1;
87347dd1d1bSDag-Erling Smørgrav #else /* defined(__OpenBSD__) */
87447dd1d1bSDag-Erling Smørgrav 	error("Routing domains are not supported on this platform");
87547dd1d1bSDag-Erling Smørgrav 	return 0;
87647dd1d1bSDag-Erling Smørgrav #endif
877511b41d2SMark Murray }
878511b41d2SMark Murray 
879557f75e5SDag-Erling Smørgrav /*
880557f75e5SDag-Erling Smørgrav  * Queue a ListenAddress to be processed once we have all of the Ports
881557f75e5SDag-Erling Smørgrav  * and AddressFamily options.
882557f75e5SDag-Erling Smørgrav  */
883557f75e5SDag-Erling Smørgrav static void
88447dd1d1bSDag-Erling Smørgrav queue_listen_addr(ServerOptions *options, const char *addr,
88547dd1d1bSDag-Erling Smørgrav     const char *rdomain, int port)
886557f75e5SDag-Erling Smørgrav {
88747dd1d1bSDag-Erling Smørgrav 	struct queued_listenaddr *qla;
88847dd1d1bSDag-Erling Smørgrav 
88947dd1d1bSDag-Erling Smørgrav 	options->queued_listen_addrs = xrecallocarray(
89047dd1d1bSDag-Erling Smørgrav 	    options->queued_listen_addrs,
89147dd1d1bSDag-Erling Smørgrav 	    options->num_queued_listens, options->num_queued_listens + 1,
89247dd1d1bSDag-Erling Smørgrav 	    sizeof(*options->queued_listen_addrs));
89347dd1d1bSDag-Erling Smørgrav 	qla = &options->queued_listen_addrs[options->num_queued_listens++];
89447dd1d1bSDag-Erling Smørgrav 	qla->addr = xstrdup(addr);
89547dd1d1bSDag-Erling Smørgrav 	qla->port = port;
89647dd1d1bSDag-Erling Smørgrav 	qla->rdomain = rdomain == NULL ? NULL : xstrdup(rdomain);
897557f75e5SDag-Erling Smørgrav }
898557f75e5SDag-Erling Smørgrav 
899557f75e5SDag-Erling Smørgrav /*
900557f75e5SDag-Erling Smørgrav  * Process queued (text) ListenAddress entries.
901557f75e5SDag-Erling Smørgrav  */
902557f75e5SDag-Erling Smørgrav static void
903557f75e5SDag-Erling Smørgrav process_queued_listen_addrs(ServerOptions *options)
904557f75e5SDag-Erling Smørgrav {
905557f75e5SDag-Erling Smørgrav 	u_int i;
90647dd1d1bSDag-Erling Smørgrav 	struct queued_listenaddr *qla;
907557f75e5SDag-Erling Smørgrav 
908557f75e5SDag-Erling Smørgrav 	if (options->num_ports == 0)
909557f75e5SDag-Erling Smørgrav 		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
910557f75e5SDag-Erling Smørgrav 	if (options->address_family == -1)
911557f75e5SDag-Erling Smørgrav 		options->address_family = AF_UNSPEC;
912557f75e5SDag-Erling Smørgrav 
913557f75e5SDag-Erling Smørgrav 	for (i = 0; i < options->num_queued_listens; i++) {
91447dd1d1bSDag-Erling Smørgrav 		qla = &options->queued_listen_addrs[i];
91547dd1d1bSDag-Erling Smørgrav 		add_listen_addr(options, qla->addr, qla->rdomain, qla->port);
91647dd1d1bSDag-Erling Smørgrav 		free(qla->addr);
91747dd1d1bSDag-Erling Smørgrav 		free(qla->rdomain);
918557f75e5SDag-Erling Smørgrav 	}
919557f75e5SDag-Erling Smørgrav 	free(options->queued_listen_addrs);
920557f75e5SDag-Erling Smørgrav 	options->queued_listen_addrs = NULL;
921557f75e5SDag-Erling Smørgrav 	options->num_queued_listens = 0;
922557f75e5SDag-Erling Smørgrav }
923557f75e5SDag-Erling Smørgrav 
9244f52dfbbSDag-Erling Smørgrav /*
925190cef3dSDag-Erling Smørgrav  * Inform channels layer of permitopen options for a single forwarding
926190cef3dSDag-Erling Smørgrav  * direction (local/remote).
927190cef3dSDag-Erling Smørgrav  */
928190cef3dSDag-Erling Smørgrav static void
929190cef3dSDag-Erling Smørgrav process_permitopen_list(struct ssh *ssh, ServerOpCodes opcode,
930190cef3dSDag-Erling Smørgrav     char **opens, u_int num_opens)
931190cef3dSDag-Erling Smørgrav {
932190cef3dSDag-Erling Smørgrav 	u_int i;
933190cef3dSDag-Erling Smørgrav 	int port;
9341323ec57SEd Maste 	char *host, *arg, *oarg;
935190cef3dSDag-Erling Smørgrav 	int where = opcode == sPermitOpen ? FORWARD_LOCAL : FORWARD_REMOTE;
936190cef3dSDag-Erling Smørgrav 	const char *what = lookup_opcode_name(opcode);
937190cef3dSDag-Erling Smørgrav 
938190cef3dSDag-Erling Smørgrav 	channel_clear_permission(ssh, FORWARD_ADM, where);
939190cef3dSDag-Erling Smørgrav 	if (num_opens == 0)
940190cef3dSDag-Erling Smørgrav 		return; /* permit any */
941190cef3dSDag-Erling Smørgrav 
942190cef3dSDag-Erling Smørgrav 	/* handle keywords: "any" / "none" */
943190cef3dSDag-Erling Smørgrav 	if (num_opens == 1 && strcmp(opens[0], "any") == 0)
944190cef3dSDag-Erling Smørgrav 		return;
945190cef3dSDag-Erling Smørgrav 	if (num_opens == 1 && strcmp(opens[0], "none") == 0) {
946190cef3dSDag-Erling Smørgrav 		channel_disable_admin(ssh, where);
947190cef3dSDag-Erling Smørgrav 		return;
948190cef3dSDag-Erling Smørgrav 	}
949190cef3dSDag-Erling Smørgrav 	/* Otherwise treat it as a list of permitted host:port */
950190cef3dSDag-Erling Smørgrav 	for (i = 0; i < num_opens; i++) {
951190cef3dSDag-Erling Smørgrav 		oarg = arg = xstrdup(opens[i]);
9521323ec57SEd Maste 		host = hpdelim(&arg);
9531323ec57SEd Maste 		if (host == NULL)
95419261079SEd Maste 			fatal_f("missing host in %s", what);
955190cef3dSDag-Erling Smørgrav 		host = cleanhostname(host);
956190cef3dSDag-Erling Smørgrav 		if (arg == NULL || ((port = permitopen_port(arg)) < 0))
95719261079SEd Maste 			fatal_f("bad port number in %s", what);
958190cef3dSDag-Erling Smørgrav 		/* Send it to channels layer */
959190cef3dSDag-Erling Smørgrav 		channel_add_permission(ssh, FORWARD_ADM,
960190cef3dSDag-Erling Smørgrav 		    where, host, port);
961190cef3dSDag-Erling Smørgrav 		free(oarg);
962190cef3dSDag-Erling Smørgrav 	}
963190cef3dSDag-Erling Smørgrav }
964190cef3dSDag-Erling Smørgrav 
965190cef3dSDag-Erling Smørgrav /*
9664f52dfbbSDag-Erling Smørgrav  * Inform channels layer of permitopen options from configuration.
9674f52dfbbSDag-Erling Smørgrav  */
9684f52dfbbSDag-Erling Smørgrav void
9694f52dfbbSDag-Erling Smørgrav process_permitopen(struct ssh *ssh, ServerOptions *options)
9704f52dfbbSDag-Erling Smørgrav {
971190cef3dSDag-Erling Smørgrav 	process_permitopen_list(ssh, sPermitOpen,
972190cef3dSDag-Erling Smørgrav 	    options->permitted_opens, options->num_permitted_opens);
973190cef3dSDag-Erling Smørgrav 	process_permitopen_list(ssh, sPermitListen,
974190cef3dSDag-Erling Smørgrav 	    options->permitted_listens,
975190cef3dSDag-Erling Smørgrav 	    options->num_permitted_listens);
9764f52dfbbSDag-Erling Smørgrav }
9774f52dfbbSDag-Erling Smørgrav 
978*f374ba41SEd Maste /* Parse a ChannelTimeout clause "pattern=interval" */
979*f374ba41SEd Maste static int
980*f374ba41SEd Maste parse_timeout(const char *s, char **typep, u_int *secsp)
981*f374ba41SEd Maste {
982*f374ba41SEd Maste 	char *cp, *sdup;
983*f374ba41SEd Maste 	int secs;
984*f374ba41SEd Maste 
985*f374ba41SEd Maste 	if (typep != NULL)
986*f374ba41SEd Maste 		*typep = NULL;
987*f374ba41SEd Maste 	if (secsp != NULL)
988*f374ba41SEd Maste 		*secsp = 0;
989*f374ba41SEd Maste 	if (s == NULL)
990*f374ba41SEd Maste 		return -1;
991*f374ba41SEd Maste 	sdup = xstrdup(s);
992*f374ba41SEd Maste 
993*f374ba41SEd Maste 	if ((cp = strchr(sdup, '=')) == NULL || cp == sdup) {
994*f374ba41SEd Maste 		free(sdup);
995*f374ba41SEd Maste 		return -1;
996*f374ba41SEd Maste 	}
997*f374ba41SEd Maste 	*cp++ = '\0';
998*f374ba41SEd Maste 	if ((secs = convtime(cp)) < 0) {
999*f374ba41SEd Maste 		free(sdup);
1000*f374ba41SEd Maste 		return -1;
1001*f374ba41SEd Maste 	}
1002*f374ba41SEd Maste 	/* success */
1003*f374ba41SEd Maste 	if (typep != NULL)
1004*f374ba41SEd Maste 		*typep = xstrdup(sdup);
1005*f374ba41SEd Maste 	if (secsp != NULL)
1006*f374ba41SEd Maste 		*secsp = (u_int)secs;
1007*f374ba41SEd Maste 	free(sdup);
1008*f374ba41SEd Maste 	return 0;
1009*f374ba41SEd Maste }
1010*f374ba41SEd Maste 
1011*f374ba41SEd Maste void
1012*f374ba41SEd Maste process_channel_timeouts(struct ssh *ssh, ServerOptions *options)
1013*f374ba41SEd Maste {
1014*f374ba41SEd Maste 	u_int i, secs;
1015*f374ba41SEd Maste 	char *type;
1016*f374ba41SEd Maste 
1017*f374ba41SEd Maste 	debug3_f("setting %u timeouts", options->num_channel_timeouts);
1018*f374ba41SEd Maste 	channel_clear_timeouts(ssh);
1019*f374ba41SEd Maste 	for (i = 0; i < options->num_channel_timeouts; i++) {
1020*f374ba41SEd Maste 		if (parse_timeout(options->channel_timeouts[i],
1021*f374ba41SEd Maste 		    &type, &secs) != 0) {
1022*f374ba41SEd Maste 			fatal_f("internal error: bad timeout %s",
1023*f374ba41SEd Maste 			    options->channel_timeouts[i]);
1024*f374ba41SEd Maste 		}
1025*f374ba41SEd Maste 		channel_add_timeout(ssh, type, secs);
1026*f374ba41SEd Maste 		free(type);
1027*f374ba41SEd Maste 	}
1028*f374ba41SEd Maste }
1029*f374ba41SEd Maste 
1030462c32cbSDag-Erling Smørgrav struct connection_info *
103119261079SEd Maste get_connection_info(struct ssh *ssh, int populate, int use_dns)
1032462c32cbSDag-Erling Smørgrav {
1033462c32cbSDag-Erling Smørgrav 	static struct connection_info ci;
1034462c32cbSDag-Erling Smørgrav 
103519261079SEd Maste 	if (ssh == NULL || !populate)
1036462c32cbSDag-Erling Smørgrav 		return &ci;
1037076ad2f8SDag-Erling Smørgrav 	ci.host = auth_get_canonical_hostname(ssh, use_dns);
1038076ad2f8SDag-Erling Smørgrav 	ci.address = ssh_remote_ipaddr(ssh);
1039076ad2f8SDag-Erling Smørgrav 	ci.laddress = ssh_local_ipaddr(ssh);
1040076ad2f8SDag-Erling Smørgrav 	ci.lport = ssh_local_port(ssh);
104147dd1d1bSDag-Erling Smørgrav 	ci.rdomain = ssh_packet_rdomain_in(ssh);
1042462c32cbSDag-Erling Smørgrav 	return &ci;
1043462c32cbSDag-Erling Smørgrav }
1044462c32cbSDag-Erling Smørgrav 
1045333ee039SDag-Erling Smørgrav /*
1046333ee039SDag-Erling Smørgrav  * The strategy for the Match blocks is that the config file is parsed twice.
1047333ee039SDag-Erling Smørgrav  *
1048333ee039SDag-Erling Smørgrav  * The first time is at startup.  activep is initialized to 1 and the
1049333ee039SDag-Erling Smørgrav  * directives in the global context are processed and acted on.  Hitting a
1050333ee039SDag-Erling Smørgrav  * Match directive unsets activep and the directives inside the block are
1051333ee039SDag-Erling Smørgrav  * checked for syntax only.
1052333ee039SDag-Erling Smørgrav  *
1053333ee039SDag-Erling Smørgrav  * The second time is after a connection has been established but before
1054333ee039SDag-Erling Smørgrav  * authentication.  activep is initialized to 2 and global config directives
1055333ee039SDag-Erling Smørgrav  * are ignored since they have already been processed.  If the criteria in a
1056333ee039SDag-Erling Smørgrav  * Match block is met, activep is set and the subsequent directives
1057333ee039SDag-Erling Smørgrav  * processed and actioned until EOF or another Match block unsets it.  Any
1058333ee039SDag-Erling Smørgrav  * options set are copied into the main server config.
1059333ee039SDag-Erling Smørgrav  *
1060333ee039SDag-Erling Smørgrav  * Potential additions/improvements:
1061ca86bcf2SDag-Erling Smørgrav  *  - Add Match support for pre-kex directives, eg. Ciphers.
1062333ee039SDag-Erling Smørgrav  *
1063333ee039SDag-Erling Smørgrav  *  - Add a Tag directive (idea from David Leonard) ala pf, eg:
1064333ee039SDag-Erling Smørgrav  *	Match Address 192.168.0.*
1065333ee039SDag-Erling Smørgrav  *		Tag trusted
1066333ee039SDag-Erling Smørgrav  *	Match Group wheel
1067333ee039SDag-Erling Smørgrav  *		Tag trusted
1068333ee039SDag-Erling Smørgrav  *	Match Tag trusted
1069333ee039SDag-Erling Smørgrav  *		AllowTcpForwarding yes
1070333ee039SDag-Erling Smørgrav  *		GatewayPorts clientspecified
1071333ee039SDag-Erling Smørgrav  *		[...]
1072333ee039SDag-Erling Smørgrav  *
1073333ee039SDag-Erling Smørgrav  *  - Add a PermittedChannelRequests directive
1074333ee039SDag-Erling Smørgrav  *	Match Group shell
1075333ee039SDag-Erling Smørgrav  *		PermittedChannelRequests session,forwarded-tcpip
1076333ee039SDag-Erling Smørgrav  */
1077333ee039SDag-Erling Smørgrav 
1078333ee039SDag-Erling Smørgrav static int
1079333ee039SDag-Erling Smørgrav match_cfg_line_group(const char *grps, int line, const char *user)
1080333ee039SDag-Erling Smørgrav {
1081333ee039SDag-Erling Smørgrav 	int result = 0;
1082333ee039SDag-Erling Smørgrav 	struct passwd *pw;
1083333ee039SDag-Erling Smørgrav 
1084333ee039SDag-Erling Smørgrav 	if (user == NULL)
1085333ee039SDag-Erling Smørgrav 		goto out;
1086333ee039SDag-Erling Smørgrav 
1087333ee039SDag-Erling Smørgrav 	if ((pw = getpwnam(user)) == NULL) {
1088333ee039SDag-Erling Smørgrav 		debug("Can't match group at line %d because user %.100s does "
1089333ee039SDag-Erling Smørgrav 		    "not exist", line, user);
1090333ee039SDag-Erling Smørgrav 	} else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
1091333ee039SDag-Erling Smørgrav 		debug("Can't Match group because user %.100s not in any group "
1092333ee039SDag-Erling Smørgrav 		    "at line %d", user, line);
1093d4af9e69SDag-Erling Smørgrav 	} else if (ga_match_pattern_list(grps) != 1) {
1094d4af9e69SDag-Erling Smørgrav 		debug("user %.100s does not match group list %.100s at line %d",
1095d4af9e69SDag-Erling Smørgrav 		    user, grps, line);
1096333ee039SDag-Erling Smørgrav 	} else {
1097d4af9e69SDag-Erling Smørgrav 		debug("user %.100s matched group list %.100s at line %d", user,
1098d4af9e69SDag-Erling Smørgrav 		    grps, line);
1099333ee039SDag-Erling Smørgrav 		result = 1;
1100333ee039SDag-Erling Smørgrav 	}
1101333ee039SDag-Erling Smørgrav out:
1102333ee039SDag-Erling Smørgrav 	ga_free();
1103333ee039SDag-Erling Smørgrav 	return result;
1104333ee039SDag-Erling Smørgrav }
1105333ee039SDag-Erling Smørgrav 
110647dd1d1bSDag-Erling Smørgrav static void
110747dd1d1bSDag-Erling Smørgrav match_test_missing_fatal(const char *criteria, const char *attrib)
110847dd1d1bSDag-Erling Smørgrav {
110947dd1d1bSDag-Erling Smørgrav 	fatal("'Match %s' in configuration but '%s' not in connection "
111047dd1d1bSDag-Erling Smørgrav 	    "test specification.", criteria, attrib);
111147dd1d1bSDag-Erling Smørgrav }
111247dd1d1bSDag-Erling Smørgrav 
1113462c32cbSDag-Erling Smørgrav /*
11146888a9beSDag-Erling Smørgrav  * All of the attributes on a single Match line are ANDed together, so we need
1115f7167e0eSDag-Erling Smørgrav  * to check every attribute and set the result to zero if any attribute does
11166888a9beSDag-Erling Smørgrav  * not match.
1117462c32cbSDag-Erling Smørgrav  */
1118333ee039SDag-Erling Smørgrav static int
1119462c32cbSDag-Erling Smørgrav match_cfg_line(char **condition, int line, struct connection_info *ci)
1120333ee039SDag-Erling Smørgrav {
1121f7167e0eSDag-Erling Smørgrav 	int result = 1, attributes = 0, port;
1122333ee039SDag-Erling Smørgrav 	char *arg, *attrib, *cp = *condition;
1123333ee039SDag-Erling Smørgrav 
1124462c32cbSDag-Erling Smørgrav 	if (ci == NULL)
1125333ee039SDag-Erling Smørgrav 		debug3("checking syntax for 'Match %s'", cp);
1126333ee039SDag-Erling Smørgrav 	else
1127462c32cbSDag-Erling Smørgrav 		debug3("checking match for '%s' user %s host %s addr %s "
1128462c32cbSDag-Erling Smørgrav 		    "laddr %s lport %d", cp, ci->user ? ci->user : "(null)",
1129462c32cbSDag-Erling Smørgrav 		    ci->host ? ci->host : "(null)",
1130462c32cbSDag-Erling Smørgrav 		    ci->address ? ci->address : "(null)",
1131462c32cbSDag-Erling Smørgrav 		    ci->laddress ? ci->laddress : "(null)", ci->lport);
1132333ee039SDag-Erling Smørgrav 
1133333ee039SDag-Erling Smørgrav 	while ((attrib = strdelim(&cp)) && *attrib != '\0') {
113419261079SEd Maste 		/* Terminate on comment */
113519261079SEd Maste 		if (*attrib == '#') {
113619261079SEd Maste 			cp = NULL; /* mark all arguments consumed */
113719261079SEd Maste 			break;
113819261079SEd Maste 		}
113919261079SEd Maste 		arg = NULL;
1140f7167e0eSDag-Erling Smørgrav 		attributes++;
114119261079SEd Maste 		/* Criterion "all" has no argument and must appear alone */
1142f7167e0eSDag-Erling Smørgrav 		if (strcasecmp(attrib, "all") == 0) {
114319261079SEd Maste 			if (attributes > 1 || ((arg = strdelim(&cp)) != NULL &&
114419261079SEd Maste 			    *arg != '\0' && *arg != '#')) {
1145f7167e0eSDag-Erling Smørgrav 				error("'all' cannot be combined with other "
1146f7167e0eSDag-Erling Smørgrav 				    "Match attributes");
1147f7167e0eSDag-Erling Smørgrav 				return -1;
1148f7167e0eSDag-Erling Smørgrav 			}
114919261079SEd Maste 			if (arg != NULL && *arg == '#')
115019261079SEd Maste 				cp = NULL; /* mark all arguments consumed */
1151f7167e0eSDag-Erling Smørgrav 			*condition = cp;
1152f7167e0eSDag-Erling Smørgrav 			return 1;
1153f7167e0eSDag-Erling Smørgrav 		}
115419261079SEd Maste 		/* All other criteria require an argument */
115519261079SEd Maste 		if ((arg = strdelim(&cp)) == NULL ||
115619261079SEd Maste 		    *arg == '\0' || *arg == '#') {
1157333ee039SDag-Erling Smørgrav 			error("Missing Match criteria for %s", attrib);
1158333ee039SDag-Erling Smørgrav 			return -1;
1159333ee039SDag-Erling Smørgrav 		}
1160333ee039SDag-Erling Smørgrav 		if (strcasecmp(attrib, "user") == 0) {
116119261079SEd Maste 			if (ci == NULL || (ci->test && ci->user == NULL)) {
1162333ee039SDag-Erling Smørgrav 				result = 0;
1163333ee039SDag-Erling Smørgrav 				continue;
1164333ee039SDag-Erling Smørgrav 			}
116547dd1d1bSDag-Erling Smørgrav 			if (ci->user == NULL)
116647dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("User", "user");
116719261079SEd Maste 			if (match_usergroup_pattern_list(ci->user, arg) != 1)
1168333ee039SDag-Erling Smørgrav 				result = 0;
1169333ee039SDag-Erling Smørgrav 			else
1170333ee039SDag-Erling Smørgrav 				debug("user %.100s matched 'User %.100s' at "
1171462c32cbSDag-Erling Smørgrav 				    "line %d", ci->user, arg, line);
1172333ee039SDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "group") == 0) {
117319261079SEd Maste 			if (ci == NULL || (ci->test && ci->user == NULL)) {
1174462c32cbSDag-Erling Smørgrav 				result = 0;
1175462c32cbSDag-Erling Smørgrav 				continue;
1176462c32cbSDag-Erling Smørgrav 			}
117747dd1d1bSDag-Erling Smørgrav 			if (ci->user == NULL)
117847dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("Group", "user");
1179462c32cbSDag-Erling Smørgrav 			switch (match_cfg_line_group(arg, line, ci->user)) {
1180333ee039SDag-Erling Smørgrav 			case -1:
1181333ee039SDag-Erling Smørgrav 				return -1;
1182333ee039SDag-Erling Smørgrav 			case 0:
1183333ee039SDag-Erling Smørgrav 				result = 0;
1184333ee039SDag-Erling Smørgrav 			}
1185333ee039SDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "host") == 0) {
118619261079SEd Maste 			if (ci == NULL || (ci->test && ci->host == NULL)) {
1187333ee039SDag-Erling Smørgrav 				result = 0;
1188333ee039SDag-Erling Smørgrav 				continue;
1189333ee039SDag-Erling Smørgrav 			}
119047dd1d1bSDag-Erling Smørgrav 			if (ci->host == NULL)
119147dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("Host", "host");
1192557f75e5SDag-Erling Smørgrav 			if (match_hostname(ci->host, arg) != 1)
1193333ee039SDag-Erling Smørgrav 				result = 0;
1194333ee039SDag-Erling Smørgrav 			else
1195333ee039SDag-Erling Smørgrav 				debug("connection from %.100s matched 'Host "
1196462c32cbSDag-Erling Smørgrav 				    "%.100s' at line %d", ci->host, arg, line);
1197333ee039SDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "address") == 0) {
119819261079SEd Maste 			if (ci == NULL || (ci->test && ci->address == NULL)) {
119919261079SEd Maste 				if (addr_match_list(NULL, arg) != 0)
120019261079SEd Maste 					fatal("Invalid Match address argument "
120119261079SEd Maste 					    "'%s' at line %d", arg, line);
1202462c32cbSDag-Erling Smørgrav 				result = 0;
1203462c32cbSDag-Erling Smørgrav 				continue;
1204462c32cbSDag-Erling Smørgrav 			}
120547dd1d1bSDag-Erling Smørgrav 			if (ci->address == NULL)
120647dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("Address", "addr");
1207462c32cbSDag-Erling Smørgrav 			switch (addr_match_list(ci->address, arg)) {
1208d4af9e69SDag-Erling Smørgrav 			case 1:
1209333ee039SDag-Erling Smørgrav 				debug("connection from %.100s matched 'Address "
1210462c32cbSDag-Erling Smørgrav 				    "%.100s' at line %d", ci->address, arg, line);
1211d4af9e69SDag-Erling Smørgrav 				break;
1212d4af9e69SDag-Erling Smørgrav 			case 0:
1213d4af9e69SDag-Erling Smørgrav 			case -1:
1214d4af9e69SDag-Erling Smørgrav 				result = 0;
1215d4af9e69SDag-Erling Smørgrav 				break;
1216d4af9e69SDag-Erling Smørgrav 			case -2:
1217d4af9e69SDag-Erling Smørgrav 				return -1;
1218d4af9e69SDag-Erling Smørgrav 			}
1219462c32cbSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "localaddress") == 0){
122019261079SEd Maste 			if (ci == NULL || (ci->test && ci->laddress == NULL)) {
122119261079SEd Maste 				if (addr_match_list(NULL, arg) != 0)
122219261079SEd Maste 					fatal("Invalid Match localaddress "
122319261079SEd Maste 					    "argument '%s' at line %d", arg,
122419261079SEd Maste 					    line);
1225462c32cbSDag-Erling Smørgrav 				result = 0;
1226462c32cbSDag-Erling Smørgrav 				continue;
1227462c32cbSDag-Erling Smørgrav 			}
122847dd1d1bSDag-Erling Smørgrav 			if (ci->laddress == NULL)
122947dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("LocalAddress",
123047dd1d1bSDag-Erling Smørgrav 				    "laddr");
1231462c32cbSDag-Erling Smørgrav 			switch (addr_match_list(ci->laddress, arg)) {
1232462c32cbSDag-Erling Smørgrav 			case 1:
1233462c32cbSDag-Erling Smørgrav 				debug("connection from %.100s matched "
1234462c32cbSDag-Erling Smørgrav 				    "'LocalAddress %.100s' at line %d",
1235462c32cbSDag-Erling Smørgrav 				    ci->laddress, arg, line);
1236462c32cbSDag-Erling Smørgrav 				break;
1237462c32cbSDag-Erling Smørgrav 			case 0:
1238462c32cbSDag-Erling Smørgrav 			case -1:
1239462c32cbSDag-Erling Smørgrav 				result = 0;
1240462c32cbSDag-Erling Smørgrav 				break;
1241462c32cbSDag-Erling Smørgrav 			case -2:
1242462c32cbSDag-Erling Smørgrav 				return -1;
1243462c32cbSDag-Erling Smørgrav 			}
1244462c32cbSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "localport") == 0) {
1245462c32cbSDag-Erling Smørgrav 			if ((port = a2port(arg)) == -1) {
1246462c32cbSDag-Erling Smørgrav 				error("Invalid LocalPort '%s' on Match line",
1247462c32cbSDag-Erling Smørgrav 				    arg);
1248462c32cbSDag-Erling Smørgrav 				return -1;
1249462c32cbSDag-Erling Smørgrav 			}
125019261079SEd Maste 			if (ci == NULL || (ci->test && ci->lport == -1)) {
1251462c32cbSDag-Erling Smørgrav 				result = 0;
1252462c32cbSDag-Erling Smørgrav 				continue;
1253462c32cbSDag-Erling Smørgrav 			}
125447dd1d1bSDag-Erling Smørgrav 			if (ci->lport == 0)
125547dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("LocalPort", "lport");
1256462c32cbSDag-Erling Smørgrav 			/* TODO support port lists */
1257462c32cbSDag-Erling Smørgrav 			if (port == ci->lport)
1258462c32cbSDag-Erling Smørgrav 				debug("connection from %.100s matched "
1259462c32cbSDag-Erling Smørgrav 				    "'LocalPort %d' at line %d",
1260462c32cbSDag-Erling Smørgrav 				    ci->laddress, port, line);
1261462c32cbSDag-Erling Smørgrav 			else
1262462c32cbSDag-Erling Smørgrav 				result = 0;
126347dd1d1bSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "rdomain") == 0) {
126419261079SEd Maste 			if (ci == NULL || (ci->test && ci->rdomain == NULL)) {
126547dd1d1bSDag-Erling Smørgrav 				result = 0;
126647dd1d1bSDag-Erling Smørgrav 				continue;
126747dd1d1bSDag-Erling Smørgrav 			}
126819261079SEd Maste 			if (ci->rdomain == NULL)
126919261079SEd Maste 				match_test_missing_fatal("RDomain", "rdomain");
127047dd1d1bSDag-Erling Smørgrav 			if (match_pattern_list(ci->rdomain, arg, 0) != 1)
127147dd1d1bSDag-Erling Smørgrav 				result = 0;
127247dd1d1bSDag-Erling Smørgrav 			else
127347dd1d1bSDag-Erling Smørgrav 				debug("user %.100s matched 'RDomain %.100s' at "
127447dd1d1bSDag-Erling Smørgrav 				    "line %d", ci->rdomain, arg, line);
1275333ee039SDag-Erling Smørgrav 		} else {
1276333ee039SDag-Erling Smørgrav 			error("Unsupported Match attribute %s", attrib);
1277333ee039SDag-Erling Smørgrav 			return -1;
1278333ee039SDag-Erling Smørgrav 		}
1279333ee039SDag-Erling Smørgrav 	}
1280f7167e0eSDag-Erling Smørgrav 	if (attributes == 0) {
1281f7167e0eSDag-Erling Smørgrav 		error("One or more attributes required for Match");
1282f7167e0eSDag-Erling Smørgrav 		return -1;
1283f7167e0eSDag-Erling Smørgrav 	}
1284462c32cbSDag-Erling Smørgrav 	if (ci != NULL)
1285333ee039SDag-Erling Smørgrav 		debug3("match %sfound", result ? "" : "not ");
1286333ee039SDag-Erling Smørgrav 	*condition = cp;
1287333ee039SDag-Erling Smørgrav 	return result;
1288333ee039SDag-Erling Smørgrav }
1289333ee039SDag-Erling Smørgrav 
1290333ee039SDag-Erling Smørgrav #define WHITESPACE " \t\r\n"
1291333ee039SDag-Erling Smørgrav 
1292e146993eSDag-Erling Smørgrav /* Multistate option parsing */
1293e146993eSDag-Erling Smørgrav struct multistate {
1294e146993eSDag-Erling Smørgrav 	char *key;
1295e146993eSDag-Erling Smørgrav 	int value;
1296e146993eSDag-Erling Smørgrav };
129747dd1d1bSDag-Erling Smørgrav static const struct multistate multistate_flag[] = {
129847dd1d1bSDag-Erling Smørgrav 	{ "yes",			1 },
129947dd1d1bSDag-Erling Smørgrav 	{ "no",				0 },
130047dd1d1bSDag-Erling Smørgrav 	{ NULL, -1 }
130147dd1d1bSDag-Erling Smørgrav };
130219261079SEd Maste static const struct multistate multistate_ignore_rhosts[] = {
130319261079SEd Maste 	{ "yes",			IGNORE_RHOSTS_YES },
130419261079SEd Maste 	{ "no",				IGNORE_RHOSTS_NO },
130519261079SEd Maste 	{ "shosts-only",		IGNORE_RHOSTS_SHOSTS },
130619261079SEd Maste 	{ NULL, -1 }
130719261079SEd Maste };
1308e146993eSDag-Erling Smørgrav static const struct multistate multistate_addressfamily[] = {
1309e146993eSDag-Erling Smørgrav 	{ "inet",			AF_INET },
1310e146993eSDag-Erling Smørgrav 	{ "inet6",			AF_INET6 },
1311e146993eSDag-Erling Smørgrav 	{ "any",			AF_UNSPEC },
1312e146993eSDag-Erling Smørgrav 	{ NULL, -1 }
1313e146993eSDag-Erling Smørgrav };
1314e146993eSDag-Erling Smørgrav static const struct multistate multistate_permitrootlogin[] = {
1315e146993eSDag-Erling Smørgrav 	{ "without-password",		PERMIT_NO_PASSWD },
1316eccfee6eSDag-Erling Smørgrav 	{ "prohibit-password",		PERMIT_NO_PASSWD },
1317e146993eSDag-Erling Smørgrav 	{ "forced-commands-only",	PERMIT_FORCED_ONLY },
1318e146993eSDag-Erling Smørgrav 	{ "yes",			PERMIT_YES },
1319e146993eSDag-Erling Smørgrav 	{ "no",				PERMIT_NO },
1320e146993eSDag-Erling Smørgrav 	{ NULL, -1 }
1321e146993eSDag-Erling Smørgrav };
1322e146993eSDag-Erling Smørgrav static const struct multistate multistate_compression[] = {
132319261079SEd Maste #ifdef WITH_ZLIB
1324ca86bcf2SDag-Erling Smørgrav 	{ "yes",			COMP_DELAYED },
1325e146993eSDag-Erling Smørgrav 	{ "delayed",			COMP_DELAYED },
132619261079SEd Maste #endif
1327e146993eSDag-Erling Smørgrav 	{ "no",				COMP_NONE },
1328e146993eSDag-Erling Smørgrav 	{ NULL, -1 }
1329e146993eSDag-Erling Smørgrav };
1330e146993eSDag-Erling Smørgrav static const struct multistate multistate_gatewayports[] = {
1331e146993eSDag-Erling Smørgrav 	{ "clientspecified",		2 },
1332e146993eSDag-Erling Smørgrav 	{ "yes",			1 },
1333e146993eSDag-Erling Smørgrav 	{ "no",				0 },
1334e146993eSDag-Erling Smørgrav 	{ NULL, -1 }
1335e146993eSDag-Erling Smørgrav };
13366888a9beSDag-Erling Smørgrav static const struct multistate multistate_tcpfwd[] = {
13376888a9beSDag-Erling Smørgrav 	{ "yes",			FORWARD_ALLOW },
13386888a9beSDag-Erling Smørgrav 	{ "all",			FORWARD_ALLOW },
13396888a9beSDag-Erling Smørgrav 	{ "no",				FORWARD_DENY },
13406888a9beSDag-Erling Smørgrav 	{ "remote",			FORWARD_REMOTE },
13416888a9beSDag-Erling Smørgrav 	{ "local",			FORWARD_LOCAL },
13426888a9beSDag-Erling Smørgrav 	{ NULL, -1 }
13436888a9beSDag-Erling Smørgrav };
1344e146993eSDag-Erling Smørgrav 
134519261079SEd Maste static int
134619261079SEd Maste process_server_config_line_depth(ServerOptions *options, char *line,
1347462c32cbSDag-Erling Smørgrav     const char *filename, int linenum, int *activep,
134819261079SEd Maste     struct connection_info *connectinfo, int *inc_flags, int depth,
134919261079SEd Maste     struct include_list *includes)
1350511b41d2SMark Murray {
13511323ec57SEd Maste 	char *str, ***chararrayptr, **charptr, *arg, *arg2, *p, *keyword;
135219261079SEd Maste 	int cmdline = 0, *intptr, value, value2, n, port, oactive, r, found;
1353d4af9e69SDag-Erling Smørgrav 	SyslogFacility *log_facility_ptr;
1354d4af9e69SDag-Erling Smørgrav 	LogLevel *log_level_ptr;
1355511b41d2SMark Murray 	ServerOpCodes opcode;
1356190cef3dSDag-Erling Smørgrav 	u_int i, *uintptr, uvalue, flags = 0;
1357333ee039SDag-Erling Smørgrav 	size_t len;
1358e4a9863fSDag-Erling Smørgrav 	long long val64;
1359e146993eSDag-Erling Smørgrav 	const struct multistate *multistate_ptr;
136047dd1d1bSDag-Erling Smørgrav 	const char *errstr;
136119261079SEd Maste 	struct include_item *item;
136219261079SEd Maste 	glob_t gbuf;
136319261079SEd Maste 	char **oav = NULL, **av;
136419261079SEd Maste 	int oac = 0, ac;
136519261079SEd Maste 	int ret = -1;
1366511b41d2SMark Murray 
1367d93a896eSDag-Erling Smørgrav 	/* Strip trailing whitespace. Allow \f (form feed) at EOL only */
1368d93a896eSDag-Erling Smørgrav 	if ((len = strlen(line)) == 0)
1369d93a896eSDag-Erling Smørgrav 		return 0;
1370d93a896eSDag-Erling Smørgrav 	for (len--; len > 0; len--) {
1371d93a896eSDag-Erling Smørgrav 		if (strchr(WHITESPACE "\f", line[len]) == NULL)
1372d93a896eSDag-Erling Smørgrav 			break;
1373d93a896eSDag-Erling Smørgrav 		line[len] = '\0';
1374d93a896eSDag-Erling Smørgrav 	}
1375d93a896eSDag-Erling Smørgrav 
137619261079SEd Maste 	str = line;
137719261079SEd Maste 	if ((keyword = strdelim(&str)) == NULL)
1378333ee039SDag-Erling Smørgrav 		return 0;
1379c2d3a559SKris Kennaway 	/* Ignore leading whitespace */
138019261079SEd Maste 	if (*keyword == '\0')
138119261079SEd Maste 		keyword = strdelim(&str);
138219261079SEd Maste 	if (!keyword || !*keyword || *keyword == '#')
1383af12a3e7SDag-Erling Smørgrav 		return 0;
138419261079SEd Maste 	if (str == NULL || *str == '\0') {
138519261079SEd Maste 		error("%s line %d: no argument after keyword \"%s\"",
138619261079SEd Maste 		    filename, linenum, keyword);
138719261079SEd Maste 		return -1;
138819261079SEd Maste 	}
1389ca3176e7SBrian Feldman 	intptr = NULL;
1390ca3176e7SBrian Feldman 	charptr = NULL;
139119261079SEd Maste 	opcode = parse_token(keyword, filename, linenum, &flags);
139219261079SEd Maste 
139319261079SEd Maste 	if (argv_split(str, &oac, &oav, 1) != 0) {
139419261079SEd Maste 		error("%s line %d: invalid quotes", filename, linenum);
139519261079SEd Maste 		return -1;
139619261079SEd Maste 	}
139719261079SEd Maste 	ac = oac;
139819261079SEd Maste 	av = oav;
1399333ee039SDag-Erling Smørgrav 
1400333ee039SDag-Erling Smørgrav 	if (activep == NULL) { /* We are processing a command line directive */
1401333ee039SDag-Erling Smørgrav 		cmdline = 1;
1402333ee039SDag-Erling Smørgrav 		activep = &cmdline;
1403333ee039SDag-Erling Smørgrav 	}
140419261079SEd Maste 	if (*activep && opcode != sMatch && opcode != sInclude)
140519261079SEd Maste 		debug3("%s:%d setting %s %s", filename, linenum, keyword, str);
1406333ee039SDag-Erling Smørgrav 	if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
1407462c32cbSDag-Erling Smørgrav 		if (connectinfo == NULL) {
1408333ee039SDag-Erling Smørgrav 			fatal("%s line %d: Directive '%s' is not allowed "
140919261079SEd Maste 			    "within a Match block", filename, linenum, keyword);
1410333ee039SDag-Erling Smørgrav 		} else { /* this is a directive we have already processed */
141119261079SEd Maste 			ret = 0;
141219261079SEd Maste 			goto out;
1413333ee039SDag-Erling Smørgrav 		}
1414333ee039SDag-Erling Smørgrav 	}
1415333ee039SDag-Erling Smørgrav 
1416511b41d2SMark Murray 	switch (opcode) {
1417989dd127SDag-Erling Smørgrav 	/* Portable-specific options */
1418cf2b5f3bSDag-Erling Smørgrav 	case sUsePAM:
1419cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->use_pam;
1420989dd127SDag-Erling Smørgrav 		goto parse_flag;
1421989dd127SDag-Erling Smørgrav 
1422989dd127SDag-Erling Smørgrav 	/* Standard Options */
1423511b41d2SMark Murray 	case sBadOption:
142419261079SEd Maste 		goto out;
1425511b41d2SMark Murray 	case sPort:
1426511b41d2SMark Murray 		/* ignore ports from configfile if cmdline specifies ports */
142719261079SEd Maste 		if (options->ports_from_cmdline) {
142819261079SEd Maste 			argv_consume(&ac);
142919261079SEd Maste 			break;
143019261079SEd Maste 		}
1431511b41d2SMark Murray 		if (options->num_ports >= MAX_PORTS)
1432ca3176e7SBrian Feldman 			fatal("%s line %d: too many ports.",
1433511b41d2SMark Murray 			    filename, linenum);
143419261079SEd Maste 		arg = argv_next(&ac, &av);
1435c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1436ca3176e7SBrian Feldman 			fatal("%s line %d: missing port number.",
1437511b41d2SMark Murray 			    filename, linenum);
1438ca3176e7SBrian Feldman 		options->ports[options->num_ports++] = a2port(arg);
1439cce7d346SDag-Erling Smørgrav 		if (options->ports[options->num_ports-1] <= 0)
1440ca3176e7SBrian Feldman 			fatal("%s line %d: Badly formatted port number.",
1441ca3176e7SBrian Feldman 			    filename, linenum);
1442511b41d2SMark Murray 		break;
1443511b41d2SMark Murray 
1444511b41d2SMark Murray 	case sLoginGraceTime:
1445511b41d2SMark Murray 		intptr = &options->login_grace_time;
1446af12a3e7SDag-Erling Smørgrav  parse_time:
144719261079SEd Maste 		arg = argv_next(&ac, &av);
1448af12a3e7SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1449af12a3e7SDag-Erling Smørgrav 			fatal("%s line %d: missing time value.",
1450af12a3e7SDag-Erling Smørgrav 			    filename, linenum);
1451af12a3e7SDag-Erling Smørgrav 		if ((value = convtime(arg)) == -1)
1452af12a3e7SDag-Erling Smørgrav 			fatal("%s line %d: invalid time value.",
1453af12a3e7SDag-Erling Smørgrav 			    filename, linenum);
1454557f75e5SDag-Erling Smørgrav 		if (*activep && *intptr == -1)
1455af12a3e7SDag-Erling Smørgrav 			*intptr = value;
1456af12a3e7SDag-Erling Smørgrav 		break;
1457511b41d2SMark Murray 
1458511b41d2SMark Murray 	case sListenAddress:
145919261079SEd Maste 		arg = argv_next(&ac, &av);
1460aa49c926SDag-Erling Smørgrav 		if (arg == NULL || *arg == '\0')
1461aa49c926SDag-Erling Smørgrav 			fatal("%s line %d: missing address",
1462511b41d2SMark Murray 			    filename, linenum);
1463d4ecd108SDag-Erling Smørgrav 		/* check for bare IPv6 address: no "[]" and 2 or more ":" */
1464d4ecd108SDag-Erling Smørgrav 		if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL
1465d4ecd108SDag-Erling Smørgrav 		    && strchr(p+1, ':') != NULL) {
146647dd1d1bSDag-Erling Smørgrav 			port = 0;
146747dd1d1bSDag-Erling Smørgrav 			p = arg;
146847dd1d1bSDag-Erling Smørgrav 		} else {
146919261079SEd Maste 			arg2 = NULL;
14701323ec57SEd Maste 			p = hpdelim(&arg);
14711323ec57SEd Maste 			if (p == NULL)
1472aa49c926SDag-Erling Smørgrav 				fatal("%s line %d: bad address:port usage",
1473ca3176e7SBrian Feldman 				    filename, linenum);
1474aa49c926SDag-Erling Smørgrav 			p = cleanhostname(p);
1475aa49c926SDag-Erling Smørgrav 			if (arg == NULL)
1476aa49c926SDag-Erling Smørgrav 				port = 0;
1477cce7d346SDag-Erling Smørgrav 			else if ((port = a2port(arg)) <= 0)
147847dd1d1bSDag-Erling Smørgrav 				fatal("%s line %d: bad port number",
147947dd1d1bSDag-Erling Smørgrav 				    filename, linenum);
148047dd1d1bSDag-Erling Smørgrav 		}
148147dd1d1bSDag-Erling Smørgrav 		/* Optional routing table */
148247dd1d1bSDag-Erling Smørgrav 		arg2 = NULL;
148319261079SEd Maste 		if ((arg = argv_next(&ac, &av)) != NULL) {
148447dd1d1bSDag-Erling Smørgrav 			if (strcmp(arg, "rdomain") != 0 ||
148519261079SEd Maste 			    (arg2 = argv_next(&ac, &av)) == NULL)
148647dd1d1bSDag-Erling Smørgrav 				fatal("%s line %d: bad ListenAddress syntax",
148747dd1d1bSDag-Erling Smørgrav 				    filename, linenum);
148847dd1d1bSDag-Erling Smørgrav 			if (!valid_rdomain(arg2))
148947dd1d1bSDag-Erling Smørgrav 				fatal("%s line %d: bad routing domain",
149047dd1d1bSDag-Erling Smørgrav 				    filename, linenum);
149147dd1d1bSDag-Erling Smørgrav 		}
149247dd1d1bSDag-Erling Smørgrav 		queue_listen_addr(options, p, arg2, port);
1493aa49c926SDag-Erling Smørgrav 
1494aa49c926SDag-Erling Smørgrav 		break;
1495aa49c926SDag-Erling Smørgrav 
1496aa49c926SDag-Erling Smørgrav 	case sAddressFamily:
1497e146993eSDag-Erling Smørgrav 		intptr = &options->address_family;
1498e146993eSDag-Erling Smørgrav 		multistate_ptr = multistate_addressfamily;
1499e146993eSDag-Erling Smørgrav  parse_multistate:
150019261079SEd Maste 		arg = argv_next(&ac, &av);
1501d4ecd108SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1502e146993eSDag-Erling Smørgrav 			fatal("%s line %d: missing argument.",
1503d4ecd108SDag-Erling Smørgrav 			    filename, linenum);
1504e146993eSDag-Erling Smørgrav 		value = -1;
1505e146993eSDag-Erling Smørgrav 		for (i = 0; multistate_ptr[i].key != NULL; i++) {
1506e146993eSDag-Erling Smørgrav 			if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
1507e146993eSDag-Erling Smørgrav 				value = multistate_ptr[i].value;
1508e146993eSDag-Erling Smørgrav 				break;
1509e146993eSDag-Erling Smørgrav 			}
1510e146993eSDag-Erling Smørgrav 		}
1511e146993eSDag-Erling Smørgrav 		if (value == -1)
1512e146993eSDag-Erling Smørgrav 			fatal("%s line %d: unsupported option \"%s\".",
1513aa49c926SDag-Erling Smørgrav 			    filename, linenum, arg);
1514e146993eSDag-Erling Smørgrav 		if (*activep && *intptr == -1)
1515aa49c926SDag-Erling Smørgrav 			*intptr = value;
1516511b41d2SMark Murray 		break;
1517511b41d2SMark Murray 
1518511b41d2SMark Murray 	case sHostKeyFile:
151919261079SEd Maste 		arg = argv_next(&ac, &av);
1520ca3176e7SBrian Feldman 		if (!arg || *arg == '\0')
1521ca3176e7SBrian Feldman 			fatal("%s line %d: missing file name.",
1522e8aafc91SKris Kennaway 			    filename, linenum);
152319261079SEd Maste 		if (*activep) {
152419261079SEd Maste 			servconf_add_hostkey(filename, linenum,
152519261079SEd Maste 			    options, arg, 1);
152619261079SEd Maste 		}
1527e8aafc91SKris Kennaway 		break;
1528e8aafc91SKris Kennaway 
1529e4a9863fSDag-Erling Smørgrav 	case sHostKeyAgent:
1530e4a9863fSDag-Erling Smørgrav 		charptr = &options->host_key_agent;
153119261079SEd Maste 		arg = argv_next(&ac, &av);
1532e4a9863fSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1533e4a9863fSDag-Erling Smørgrav 			fatal("%s line %d: missing socket name.",
1534e4a9863fSDag-Erling Smørgrav 			    filename, linenum);
1535e4a9863fSDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
1536e4a9863fSDag-Erling Smørgrav 			*charptr = !strcmp(arg, SSH_AUTHSOCKET_ENV_NAME) ?
1537e4a9863fSDag-Erling Smørgrav 			    xstrdup(arg) : derelativise_path(arg);
1538e4a9863fSDag-Erling Smørgrav 		break;
1539e4a9863fSDag-Erling Smørgrav 
1540b15c8340SDag-Erling Smørgrav 	case sHostCertificate:
154119261079SEd Maste 		arg = argv_next(&ac, &av);
154247dd1d1bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
154347dd1d1bSDag-Erling Smørgrav 			fatal("%s line %d: missing file name.",
154447dd1d1bSDag-Erling Smørgrav 			    filename, linenum);
154547dd1d1bSDag-Erling Smørgrav 		if (*activep)
154647dd1d1bSDag-Erling Smørgrav 			servconf_add_hostcert(filename, linenum, options, arg);
154747dd1d1bSDag-Erling Smørgrav 		break;
1548b15c8340SDag-Erling Smørgrav 
1549e8aafc91SKris Kennaway 	case sPidFile:
1550e8aafc91SKris Kennaway 		charptr = &options->pid_file;
155147dd1d1bSDag-Erling Smørgrav  parse_filename:
155219261079SEd Maste 		arg = argv_next(&ac, &av);
155347dd1d1bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
155447dd1d1bSDag-Erling Smørgrav 			fatal("%s line %d: missing file name.",
155547dd1d1bSDag-Erling Smørgrav 			    filename, linenum);
155647dd1d1bSDag-Erling Smørgrav 		if (*activep && *charptr == NULL) {
155747dd1d1bSDag-Erling Smørgrav 			*charptr = derelativise_path(arg);
155847dd1d1bSDag-Erling Smørgrav 			/* increase optional counter */
155947dd1d1bSDag-Erling Smørgrav 			if (intptr != NULL)
156047dd1d1bSDag-Erling Smørgrav 				*intptr = *intptr + 1;
156147dd1d1bSDag-Erling Smørgrav 		}
156247dd1d1bSDag-Erling Smørgrav 		break;
1563511b41d2SMark Murray 
156419261079SEd Maste 	case sModuliFile:
156519261079SEd Maste 		charptr = &options->moduli_file;
156619261079SEd Maste 		goto parse_filename;
156719261079SEd Maste 
1568511b41d2SMark Murray 	case sPermitRootLogin:
1569511b41d2SMark Murray 		intptr = &options->permit_root_login;
1570e146993eSDag-Erling Smørgrav 		multistate_ptr = multistate_permitrootlogin;
1571e146993eSDag-Erling Smørgrav 		goto parse_multistate;
1572511b41d2SMark Murray 
1573511b41d2SMark Murray 	case sIgnoreRhosts:
1574511b41d2SMark Murray 		intptr = &options->ignore_rhosts;
157519261079SEd Maste 		multistate_ptr = multistate_ignore_rhosts;
157647dd1d1bSDag-Erling Smørgrav 		goto parse_multistate;
1577511b41d2SMark Murray 
1578511b41d2SMark Murray 	case sIgnoreUserKnownHosts:
1579511b41d2SMark Murray 		intptr = &options->ignore_user_known_hosts;
158019261079SEd Maste  parse_flag:
158119261079SEd Maste 		multistate_ptr = multistate_flag;
158219261079SEd Maste 		goto parse_multistate;
1583511b41d2SMark Murray 
1584ca3176e7SBrian Feldman 	case sHostbasedAuthentication:
1585ca3176e7SBrian Feldman 		intptr = &options->hostbased_authentication;
1586ca3176e7SBrian Feldman 		goto parse_flag;
1587ca3176e7SBrian Feldman 
1588ca3176e7SBrian Feldman 	case sHostbasedUsesNameFromPacketOnly:
1589ca3176e7SBrian Feldman 		intptr = &options->hostbased_uses_name_from_packet_only;
1590ca3176e7SBrian Feldman 		goto parse_flag;
1591ca3176e7SBrian Feldman 
159219261079SEd Maste 	case sHostbasedAcceptedAlgorithms:
159319261079SEd Maste 		charptr = &options->hostbased_accepted_algos;
159419261079SEd Maste  parse_pubkey_algos:
159519261079SEd Maste 		arg = argv_next(&ac, &av);
1596bc5531deSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1597bc5531deSDag-Erling Smørgrav 			fatal("%s line %d: Missing argument.",
1598bc5531deSDag-Erling Smørgrav 			    filename, linenum);
1599d93a896eSDag-Erling Smørgrav 		if (*arg != '-' &&
160019261079SEd Maste 		    !sshkey_names_valid2(*arg == '+' || *arg == '^' ?
160119261079SEd Maste 		    arg + 1 : arg, 1))
1602bc5531deSDag-Erling Smørgrav 			fatal("%s line %d: Bad key types '%s'.",
1603bc5531deSDag-Erling Smørgrav 			    filename, linenum, arg ? arg : "<NONE>");
1604bc5531deSDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
1605bc5531deSDag-Erling Smørgrav 			*charptr = xstrdup(arg);
1606bc5531deSDag-Erling Smørgrav 		break;
1607bc5531deSDag-Erling Smørgrav 
1608eccfee6eSDag-Erling Smørgrav 	case sHostKeyAlgorithms:
1609eccfee6eSDag-Erling Smørgrav 		charptr = &options->hostkeyalgorithms;
161019261079SEd Maste 		goto parse_pubkey_algos;
1611eccfee6eSDag-Erling Smørgrav 
16122f513db7SEd Maste 	case sCASignatureAlgorithms:
16132f513db7SEd Maste 		charptr = &options->ca_sign_algorithms;
161419261079SEd Maste 		goto parse_pubkey_algos;
16152f513db7SEd Maste 
1616ca3176e7SBrian Feldman 	case sPubkeyAuthentication:
1617ca3176e7SBrian Feldman 		intptr = &options->pubkey_authentication;
1618e8aafc91SKris Kennaway 		goto parse_flag;
1619cf2b5f3bSDag-Erling Smørgrav 
162019261079SEd Maste 	case sPubkeyAcceptedAlgorithms:
162119261079SEd Maste 		charptr = &options->pubkey_accepted_algos;
162219261079SEd Maste 		goto parse_pubkey_algos;
162319261079SEd Maste 
162419261079SEd Maste 	case sPubkeyAuthOptions:
162519261079SEd Maste 		intptr = &options->pubkey_auth_options;
162619261079SEd Maste 		value = 0;
162719261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
162819261079SEd Maste 			if (strcasecmp(arg, "none") == 0)
162919261079SEd Maste 				continue;
163019261079SEd Maste 			if (strcasecmp(arg, "touch-required") == 0)
163119261079SEd Maste 				value |= PUBKEYAUTH_TOUCH_REQUIRED;
163219261079SEd Maste 			else if (strcasecmp(arg, "verify-required") == 0)
163319261079SEd Maste 				value |= PUBKEYAUTH_VERIFY_REQUIRED;
163419261079SEd Maste 			else {
163519261079SEd Maste 				error("%s line %d: unsupported %s option %s",
163619261079SEd Maste 				    filename, linenum, keyword, arg);
163719261079SEd Maste 				goto out;
163819261079SEd Maste 			}
163919261079SEd Maste 		}
164019261079SEd Maste 		if (*activep && *intptr == -1)
164119261079SEd Maste 			*intptr = value;
164219261079SEd Maste 		break;
1643bc5531deSDag-Erling Smørgrav 
1644cb96ab36SAssar Westerlund 	case sKerberosAuthentication:
1645cb96ab36SAssar Westerlund 		intptr = &options->kerberos_authentication;
1646511b41d2SMark Murray 		goto parse_flag;
1647511b41d2SMark Murray 
1648af12a3e7SDag-Erling Smørgrav 	case sKerberosOrLocalPasswd:
1649af12a3e7SDag-Erling Smørgrav 		intptr = &options->kerberos_or_local_passwd;
1650511b41d2SMark Murray 		goto parse_flag;
1651511b41d2SMark Murray 
1652af12a3e7SDag-Erling Smørgrav 	case sKerberosTicketCleanup:
1653af12a3e7SDag-Erling Smørgrav 		intptr = &options->kerberos_ticket_cleanup;
1654511b41d2SMark Murray 		goto parse_flag;
1655cf2b5f3bSDag-Erling Smørgrav 
16561ec0d754SDag-Erling Smørgrav 	case sKerberosGetAFSToken:
16571ec0d754SDag-Erling Smørgrav 		intptr = &options->kerberos_get_afs_token;
16581ec0d754SDag-Erling Smørgrav 		goto parse_flag;
16591ec0d754SDag-Erling Smørgrav 
1660cf2b5f3bSDag-Erling Smørgrav 	case sGssAuthentication:
1661cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->gss_authentication;
1662fe5fd017SMark Murray 		goto parse_flag;
1663cf2b5f3bSDag-Erling Smørgrav 
1664cf2b5f3bSDag-Erling Smørgrav 	case sGssCleanupCreds:
1665cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->gss_cleanup_creds;
1666511b41d2SMark Murray 		goto parse_flag;
1667511b41d2SMark Murray 
1668557f75e5SDag-Erling Smørgrav 	case sGssStrictAcceptor:
1669557f75e5SDag-Erling Smørgrav 		intptr = &options->gss_strict_acceptor;
1670557f75e5SDag-Erling Smørgrav 		goto parse_flag;
1671557f75e5SDag-Erling Smørgrav 
1672511b41d2SMark Murray 	case sPasswordAuthentication:
1673511b41d2SMark Murray 		intptr = &options->password_authentication;
1674511b41d2SMark Murray 		goto parse_flag;
1675511b41d2SMark Murray 
167609958426SBrian Feldman 	case sKbdInteractiveAuthentication:
167709958426SBrian Feldman 		intptr = &options->kbd_interactive_authentication;
167809958426SBrian Feldman 		goto parse_flag;
167909958426SBrian Feldman 
1680511b41d2SMark Murray 	case sPrintMotd:
1681511b41d2SMark Murray 		intptr = &options->print_motd;
1682511b41d2SMark Murray 		goto parse_flag;
1683511b41d2SMark Murray 
1684ca3176e7SBrian Feldman 	case sPrintLastLog:
1685ca3176e7SBrian Feldman 		intptr = &options->print_lastlog;
1686ca3176e7SBrian Feldman 		goto parse_flag;
1687ca3176e7SBrian Feldman 
1688511b41d2SMark Murray 	case sX11Forwarding:
1689511b41d2SMark Murray 		intptr = &options->x11_forwarding;
1690511b41d2SMark Murray 		goto parse_flag;
1691511b41d2SMark Murray 
1692511b41d2SMark Murray 	case sX11DisplayOffset:
1693511b41d2SMark Murray 		intptr = &options->x11_display_offset;
1694ca86bcf2SDag-Erling Smørgrav  parse_int:
169519261079SEd Maste 		arg = argv_next(&ac, &av);
169647dd1d1bSDag-Erling Smørgrav 		if ((errstr = atoi_err(arg, &value)) != NULL)
169719261079SEd Maste 			fatal("%s line %d: %s integer value %s.",
169819261079SEd Maste 			    filename, linenum, keyword, errstr);
1699ca86bcf2SDag-Erling Smørgrav 		if (*activep && *intptr == -1)
1700ca86bcf2SDag-Erling Smørgrav 			*intptr = value;
1701ca86bcf2SDag-Erling Smørgrav 		break;
1702511b41d2SMark Murray 
1703af12a3e7SDag-Erling Smørgrav 	case sX11UseLocalhost:
1704af12a3e7SDag-Erling Smørgrav 		intptr = &options->x11_use_localhost;
1705af12a3e7SDag-Erling Smørgrav 		goto parse_flag;
1706af12a3e7SDag-Erling Smørgrav 
1707c2d3a559SKris Kennaway 	case sXAuthLocation:
1708c2d3a559SKris Kennaway 		charptr = &options->xauth_location;
1709c2d3a559SKris Kennaway 		goto parse_filename;
1710c2d3a559SKris Kennaway 
1711f7167e0eSDag-Erling Smørgrav 	case sPermitTTY:
1712f7167e0eSDag-Erling Smørgrav 		intptr = &options->permit_tty;
1713f7167e0eSDag-Erling Smørgrav 		goto parse_flag;
1714f7167e0eSDag-Erling Smørgrav 
1715a0ee8cc6SDag-Erling Smørgrav 	case sPermitUserRC:
1716a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->permit_user_rc;
1717a0ee8cc6SDag-Erling Smørgrav 		goto parse_flag;
1718a0ee8cc6SDag-Erling Smørgrav 
1719511b41d2SMark Murray 	case sStrictModes:
1720511b41d2SMark Murray 		intptr = &options->strict_modes;
1721511b41d2SMark Murray 		goto parse_flag;
1722511b41d2SMark Murray 
17231ec0d754SDag-Erling Smørgrav 	case sTCPKeepAlive:
17241ec0d754SDag-Erling Smørgrav 		intptr = &options->tcp_keep_alive;
1725511b41d2SMark Murray 		goto parse_flag;
1726511b41d2SMark Murray 
1727511b41d2SMark Murray 	case sEmptyPasswd:
1728511b41d2SMark Murray 		intptr = &options->permit_empty_passwd;
1729511b41d2SMark Murray 		goto parse_flag;
1730511b41d2SMark Murray 
1731f388f5efSDag-Erling Smørgrav 	case sPermitUserEnvironment:
1732f388f5efSDag-Erling Smørgrav 		intptr = &options->permit_user_env;
173319261079SEd Maste 		charptr = &options->permit_user_env_allowlist;
173419261079SEd Maste 		arg = argv_next(&ac, &av);
1735190cef3dSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
173619261079SEd Maste 			fatal("%s line %d: %s missing argument.",
173719261079SEd Maste 			    filename, linenum, keyword);
1738190cef3dSDag-Erling Smørgrav 		value = 0;
1739190cef3dSDag-Erling Smørgrav 		p = NULL;
1740190cef3dSDag-Erling Smørgrav 		if (strcmp(arg, "yes") == 0)
1741190cef3dSDag-Erling Smørgrav 			value = 1;
1742190cef3dSDag-Erling Smørgrav 		else if (strcmp(arg, "no") == 0)
1743190cef3dSDag-Erling Smørgrav 			value = 0;
1744190cef3dSDag-Erling Smørgrav 		else {
1745190cef3dSDag-Erling Smørgrav 			/* Pattern-list specified */
1746190cef3dSDag-Erling Smørgrav 			value = 1;
1747190cef3dSDag-Erling Smørgrav 			p = xstrdup(arg);
1748190cef3dSDag-Erling Smørgrav 		}
1749190cef3dSDag-Erling Smørgrav 		if (*activep && *intptr == -1) {
1750190cef3dSDag-Erling Smørgrav 			*intptr = value;
1751190cef3dSDag-Erling Smørgrav 			*charptr = p;
1752190cef3dSDag-Erling Smørgrav 			p = NULL;
1753190cef3dSDag-Erling Smørgrav 		}
1754190cef3dSDag-Erling Smørgrav 		free(p);
1755190cef3dSDag-Erling Smørgrav 		break;
1756f388f5efSDag-Erling Smørgrav 
175780628bacSDag-Erling Smørgrav 	case sCompression:
175880628bacSDag-Erling Smørgrav 		intptr = &options->compression;
1759e146993eSDag-Erling Smørgrav 		multistate_ptr = multistate_compression;
1760e146993eSDag-Erling Smørgrav 		goto parse_multistate;
176180628bacSDag-Erling Smørgrav 
1762e4a9863fSDag-Erling Smørgrav 	case sRekeyLimit:
176319261079SEd Maste 		arg = argv_next(&ac, &av);
1764e4a9863fSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
176519261079SEd Maste 			fatal("%s line %d: %s missing argument.",
176619261079SEd Maste 			    filename, linenum, keyword);
1767e4a9863fSDag-Erling Smørgrav 		if (strcmp(arg, "default") == 0) {
1768e4a9863fSDag-Erling Smørgrav 			val64 = 0;
1769e4a9863fSDag-Erling Smørgrav 		} else {
1770e4a9863fSDag-Erling Smørgrav 			if (scan_scaled(arg, &val64) == -1)
177119261079SEd Maste 				fatal("%.200s line %d: Bad %s number '%s': %s",
177219261079SEd Maste 				    filename, linenum, keyword,
177319261079SEd Maste 				    arg, strerror(errno));
1774e4a9863fSDag-Erling Smørgrav 			if (val64 != 0 && val64 < 16)
177519261079SEd Maste 				fatal("%.200s line %d: %s too small",
177619261079SEd Maste 				    filename, linenum, keyword);
1777e4a9863fSDag-Erling Smørgrav 		}
1778e4a9863fSDag-Erling Smørgrav 		if (*activep && options->rekey_limit == -1)
1779acc1a9efSDag-Erling Smørgrav 			options->rekey_limit = val64;
178019261079SEd Maste 		if (ac != 0) { /* optional rekey interval present */
178119261079SEd Maste 			if (strcmp(av[0], "none") == 0) {
178219261079SEd Maste 				(void)argv_next(&ac, &av);	/* discard */
1783e4a9863fSDag-Erling Smørgrav 				break;
1784e4a9863fSDag-Erling Smørgrav 			}
1785e4a9863fSDag-Erling Smørgrav 			intptr = &options->rekey_interval;
1786e4a9863fSDag-Erling Smørgrav 			goto parse_time;
1787e4a9863fSDag-Erling Smørgrav 		}
1788e4a9863fSDag-Erling Smørgrav 		break;
1789e4a9863fSDag-Erling Smørgrav 
1790e8aafc91SKris Kennaway 	case sGatewayPorts:
1791a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->fwd_opts.gateway_ports;
1792e146993eSDag-Erling Smørgrav 		multistate_ptr = multistate_gatewayports;
1793e146993eSDag-Erling Smørgrav 		goto parse_multistate;
1794e8aafc91SKris Kennaway 
1795cf2b5f3bSDag-Erling Smørgrav 	case sUseDNS:
1796cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->use_dns;
1797ca3176e7SBrian Feldman 		goto parse_flag;
1798ca3176e7SBrian Feldman 
1799511b41d2SMark Murray 	case sLogFacility:
1800d4af9e69SDag-Erling Smørgrav 		log_facility_ptr = &options->log_facility;
180119261079SEd Maste 		arg = argv_next(&ac, &av);
1802c2d3a559SKris Kennaway 		value = log_facility_number(arg);
1803af12a3e7SDag-Erling Smørgrav 		if (value == SYSLOG_FACILITY_NOT_SET)
1804ca3176e7SBrian Feldman 			fatal("%.200s line %d: unsupported log facility '%s'",
1805c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
1806d4af9e69SDag-Erling Smørgrav 		if (*log_facility_ptr == -1)
1807d4af9e69SDag-Erling Smørgrav 			*log_facility_ptr = (SyslogFacility) value;
1808511b41d2SMark Murray 		break;
1809511b41d2SMark Murray 
1810511b41d2SMark Murray 	case sLogLevel:
1811d4af9e69SDag-Erling Smørgrav 		log_level_ptr = &options->log_level;
181219261079SEd Maste 		arg = argv_next(&ac, &av);
1813c2d3a559SKris Kennaway 		value = log_level_number(arg);
1814af12a3e7SDag-Erling Smørgrav 		if (value == SYSLOG_LEVEL_NOT_SET)
1815ca3176e7SBrian Feldman 			fatal("%.200s line %d: unsupported log level '%s'",
1816c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
18174f52dfbbSDag-Erling Smørgrav 		if (*activep && *log_level_ptr == -1)
1818d4af9e69SDag-Erling Smørgrav 			*log_level_ptr = (LogLevel) value;
1819511b41d2SMark Murray 		break;
1820511b41d2SMark Murray 
182119261079SEd Maste 	case sLogVerbose:
182219261079SEd Maste 		found = options->num_log_verbose == 0;
182319261079SEd Maste 		i = 0;
182419261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
182519261079SEd Maste 			if (*arg == '\0') {
182619261079SEd Maste 				error("%s line %d: keyword %s empty argument",
182719261079SEd Maste 				    filename, linenum, keyword);
182819261079SEd Maste 				goto out;
182919261079SEd Maste 			}
183019261079SEd Maste 			/* Allow "none" only in first position */
183119261079SEd Maste 			if (strcasecmp(arg, "none") == 0) {
183219261079SEd Maste 				if (i > 0 || ac > 0) {
183319261079SEd Maste 					error("%s line %d: keyword %s \"none\" "
183419261079SEd Maste 					    "argument must appear alone.",
183519261079SEd Maste 					    filename, linenum, keyword);
183619261079SEd Maste 					goto out;
183719261079SEd Maste 				}
183819261079SEd Maste 			}
183919261079SEd Maste 			i++;
184019261079SEd Maste 			if (!found || !*activep)
184119261079SEd Maste 				continue;
184219261079SEd Maste 			opt_array_append(filename, linenum, keyword,
184319261079SEd Maste 			    &options->log_verbose, &options->num_log_verbose,
184419261079SEd Maste 			    arg);
184519261079SEd Maste 		}
184619261079SEd Maste 		break;
184719261079SEd Maste 
184809958426SBrian Feldman 	case sAllowTcpForwarding:
184909958426SBrian Feldman 		intptr = &options->allow_tcp_forwarding;
18506888a9beSDag-Erling Smørgrav 		multistate_ptr = multistate_tcpfwd;
18516888a9beSDag-Erling Smørgrav 		goto parse_multistate;
185209958426SBrian Feldman 
1853a0ee8cc6SDag-Erling Smørgrav 	case sAllowStreamLocalForwarding:
1854a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->allow_streamlocal_forwarding;
1855a0ee8cc6SDag-Erling Smørgrav 		multistate_ptr = multistate_tcpfwd;
1856a0ee8cc6SDag-Erling Smørgrav 		goto parse_multistate;
1857a0ee8cc6SDag-Erling Smørgrav 
1858d4af9e69SDag-Erling Smørgrav 	case sAllowAgentForwarding:
1859d4af9e69SDag-Erling Smørgrav 		intptr = &options->allow_agent_forwarding;
1860d4af9e69SDag-Erling Smørgrav 		goto parse_flag;
1861d4af9e69SDag-Erling Smørgrav 
1862ca86bcf2SDag-Erling Smørgrav 	case sDisableForwarding:
1863ca86bcf2SDag-Erling Smørgrav 		intptr = &options->disable_forwarding;
1864ca86bcf2SDag-Erling Smørgrav 		goto parse_flag;
1865ca86bcf2SDag-Erling Smørgrav 
1866511b41d2SMark Murray 	case sAllowUsers:
186719261079SEd Maste 		chararrayptr = &options->allow_users;
186819261079SEd Maste 		uintptr = &options->num_allow_users;
186919261079SEd Maste  parse_allowdenyusers:
187019261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
187119261079SEd Maste 			if (*arg == '\0' ||
187219261079SEd Maste 			    match_user(NULL, NULL, NULL, arg) == -1)
187319261079SEd Maste 				fatal("%s line %d: invalid %s pattern: \"%s\"",
187419261079SEd Maste 				    filename, linenum, keyword, arg);
1875462c32cbSDag-Erling Smørgrav 			if (!*activep)
1876462c32cbSDag-Erling Smørgrav 				continue;
187719261079SEd Maste 			opt_array_append(filename, linenum, keyword,
187819261079SEd Maste 			    chararrayptr, uintptr, arg);
1879511b41d2SMark Murray 		}
1880511b41d2SMark Murray 		break;
1881511b41d2SMark Murray 
1882511b41d2SMark Murray 	case sDenyUsers:
188319261079SEd Maste 		chararrayptr = &options->deny_users;
188419261079SEd Maste 		uintptr = &options->num_deny_users;
188519261079SEd Maste 		goto parse_allowdenyusers;
1886511b41d2SMark Murray 
1887511b41d2SMark Murray 	case sAllowGroups:
188819261079SEd Maste 		chararrayptr = &options->allow_groups;
188919261079SEd Maste 		uintptr = &options->num_allow_groups;
189019261079SEd Maste  parse_allowdenygroups:
189119261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
189219261079SEd Maste 			if (*arg == '\0')
189319261079SEd Maste 				fatal("%s line %d: empty %s pattern",
189419261079SEd Maste 				    filename, linenum, keyword);
1895462c32cbSDag-Erling Smørgrav 			if (!*activep)
1896462c32cbSDag-Erling Smørgrav 				continue;
189719261079SEd Maste 			opt_array_append(filename, linenum, keyword,
189819261079SEd Maste 			    chararrayptr, uintptr, arg);
1899511b41d2SMark Murray 		}
1900511b41d2SMark Murray 		break;
1901511b41d2SMark Murray 
1902511b41d2SMark Murray 	case sDenyGroups:
190319261079SEd Maste 		chararrayptr = &options->deny_groups;
190419261079SEd Maste 		uintptr = &options->num_deny_groups;
190519261079SEd Maste 		goto parse_allowdenygroups;
1906511b41d2SMark Murray 
1907e8aafc91SKris Kennaway 	case sCiphers:
190819261079SEd Maste 		arg = argv_next(&ac, &av);
1909c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
191019261079SEd Maste 			fatal("%s line %d: %s missing argument.",
191119261079SEd Maste 			    filename, linenum, keyword);
191219261079SEd Maste 		if (*arg != '-' &&
191319261079SEd Maste 		    !ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg))
1914e8aafc91SKris Kennaway 			fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
1915c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
1916e8aafc91SKris Kennaway 		if (options->ciphers == NULL)
1917c2d3a559SKris Kennaway 			options->ciphers = xstrdup(arg);
1918e8aafc91SKris Kennaway 		break;
1919e8aafc91SKris Kennaway 
1920ca3176e7SBrian Feldman 	case sMacs:
192119261079SEd Maste 		arg = argv_next(&ac, &av);
1922ca3176e7SBrian Feldman 		if (!arg || *arg == '\0')
192319261079SEd Maste 			fatal("%s line %d: %s missing argument.",
192419261079SEd Maste 			    filename, linenum, keyword);
192519261079SEd Maste 		if (*arg != '-' &&
192619261079SEd Maste 		    !mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg))
1927ca3176e7SBrian Feldman 			fatal("%s line %d: Bad SSH2 mac spec '%s'.",
1928ca3176e7SBrian Feldman 			    filename, linenum, arg ? arg : "<NONE>");
1929ca3176e7SBrian Feldman 		if (options->macs == NULL)
1930ca3176e7SBrian Feldman 			options->macs = xstrdup(arg);
1931ca3176e7SBrian Feldman 		break;
1932ca3176e7SBrian Feldman 
19334a421b63SDag-Erling Smørgrav 	case sKexAlgorithms:
193419261079SEd Maste 		arg = argv_next(&ac, &av);
19354a421b63SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
193619261079SEd Maste 			fatal("%s line %d: %s missing argument.",
193719261079SEd Maste 			    filename, linenum, keyword);
1938d93a896eSDag-Erling Smørgrav 		if (*arg != '-' &&
193919261079SEd Maste 		    !kex_names_valid(*arg == '+' || *arg == '^' ?
194019261079SEd Maste 		    arg + 1 : arg))
19414a421b63SDag-Erling Smørgrav 			fatal("%s line %d: Bad SSH2 KexAlgorithms '%s'.",
19424a421b63SDag-Erling Smørgrav 			    filename, linenum, arg ? arg : "<NONE>");
19434a421b63SDag-Erling Smørgrav 		if (options->kex_algorithms == NULL)
19444a421b63SDag-Erling Smørgrav 			options->kex_algorithms = xstrdup(arg);
19454a421b63SDag-Erling Smørgrav 		break;
19464a421b63SDag-Erling Smørgrav 
1947c2d3a559SKris Kennaway 	case sSubsystem:
1948c2d3a559SKris Kennaway 		if (options->num_subsystems >= MAX_SUBSYSTEMS) {
1949c2d3a559SKris Kennaway 			fatal("%s line %d: too many subsystems defined.",
1950c2d3a559SKris Kennaway 			    filename, linenum);
1951c2d3a559SKris Kennaway 		}
195219261079SEd Maste 		arg = argv_next(&ac, &av);
1953c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
195419261079SEd Maste 			fatal("%s line %d: %s missing argument.",
195519261079SEd Maste 			    filename, linenum, keyword);
1956333ee039SDag-Erling Smørgrav 		if (!*activep) {
195719261079SEd Maste 			arg = argv_next(&ac, &av);
1958333ee039SDag-Erling Smørgrav 			break;
1959333ee039SDag-Erling Smørgrav 		}
1960c2d3a559SKris Kennaway 		for (i = 0; i < options->num_subsystems; i++)
1961c2d3a559SKris Kennaway 			if (strcmp(arg, options->subsystem_name[i]) == 0)
196219261079SEd Maste 				fatal("%s line %d: Subsystem '%s' "
196319261079SEd Maste 				    "already defined.", filename, linenum, arg);
1964c2d3a559SKris Kennaway 		options->subsystem_name[options->num_subsystems] = xstrdup(arg);
196519261079SEd Maste 		arg = argv_next(&ac, &av);
1966c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1967c2d3a559SKris Kennaway 			fatal("%s line %d: Missing subsystem command.",
1968c2d3a559SKris Kennaway 			    filename, linenum);
1969c2d3a559SKris Kennaway 		options->subsystem_command[options->num_subsystems] = xstrdup(arg);
1970333ee039SDag-Erling Smørgrav 
1971333ee039SDag-Erling Smørgrav 		/* Collect arguments (separate to executable) */
1972333ee039SDag-Erling Smørgrav 		p = xstrdup(arg);
1973333ee039SDag-Erling Smørgrav 		len = strlen(p) + 1;
197419261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
1975333ee039SDag-Erling Smørgrav 			len += 1 + strlen(arg);
1976557f75e5SDag-Erling Smørgrav 			p = xreallocarray(p, 1, len);
1977333ee039SDag-Erling Smørgrav 			strlcat(p, " ", len);
1978333ee039SDag-Erling Smørgrav 			strlcat(p, arg, len);
1979333ee039SDag-Erling Smørgrav 		}
1980333ee039SDag-Erling Smørgrav 		options->subsystem_args[options->num_subsystems] = p;
1981c2d3a559SKris Kennaway 		options->num_subsystems++;
1982c2d3a559SKris Kennaway 		break;
1983c2d3a559SKris Kennaway 
1984c2d3a559SKris Kennaway 	case sMaxStartups:
198519261079SEd Maste 		arg = argv_next(&ac, &av);
1986c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
198719261079SEd Maste 			fatal("%s line %d: %s missing argument.",
198819261079SEd Maste 			    filename, linenum, keyword);
1989af12a3e7SDag-Erling Smørgrav 		if ((n = sscanf(arg, "%d:%d:%d",
1990c2d3a559SKris Kennaway 		    &options->max_startups_begin,
1991c2d3a559SKris Kennaway 		    &options->max_startups_rate,
1992af12a3e7SDag-Erling Smørgrav 		    &options->max_startups)) == 3) {
1993c2d3a559SKris Kennaway 			if (options->max_startups_begin >
1994c2d3a559SKris Kennaway 			    options->max_startups ||
1995c2d3a559SKris Kennaway 			    options->max_startups_rate > 100 ||
1996c2d3a559SKris Kennaway 			    options->max_startups_rate < 1)
199719261079SEd Maste 				fatal("%s line %d: Invalid %s spec.",
199819261079SEd Maste 				    filename, linenum, keyword);
1999af12a3e7SDag-Erling Smørgrav 		} else if (n != 1)
200019261079SEd Maste 			fatal("%s line %d: Invalid %s spec.",
200119261079SEd Maste 			    filename, linenum, keyword);
2002af12a3e7SDag-Erling Smørgrav 		else
2003af12a3e7SDag-Erling Smørgrav 			options->max_startups = options->max_startups_begin;
2004*f374ba41SEd Maste 		if (options->max_startups <= 0 ||
2005*f374ba41SEd Maste 		    options->max_startups_begin <= 0)
2006*f374ba41SEd Maste 			fatal("%s line %d: Invalid %s spec.",
2007*f374ba41SEd Maste 			    filename, linenum, keyword);
2008933ca70fSBrian Feldman 		break;
2009933ca70fSBrian Feldman 
201019261079SEd Maste 	case sPerSourceNetBlockSize:
201119261079SEd Maste 		arg = argv_next(&ac, &av);
201219261079SEd Maste 		if (!arg || *arg == '\0')
201319261079SEd Maste 			fatal("%s line %d: %s missing argument.",
201419261079SEd Maste 			    filename, linenum, keyword);
201519261079SEd Maste 		switch (n = sscanf(arg, "%d:%d", &value, &value2)) {
201619261079SEd Maste 		case 2:
201719261079SEd Maste 			if (value2 < 0 || value2 > 128)
201819261079SEd Maste 				n = -1;
201919261079SEd Maste 			/* FALLTHROUGH */
202019261079SEd Maste 		case 1:
202119261079SEd Maste 			if (value < 0 || value > 32)
202219261079SEd Maste 				n = -1;
202319261079SEd Maste 		}
202419261079SEd Maste 		if (n != 1 && n != 2)
202519261079SEd Maste 			fatal("%s line %d: Invalid %s spec.",
202619261079SEd Maste 			    filename, linenum, keyword);
202719261079SEd Maste 		if (*activep) {
202819261079SEd Maste 			options->per_source_masklen_ipv4 = value;
202919261079SEd Maste 			options->per_source_masklen_ipv6 = value2;
203019261079SEd Maste 		}
203119261079SEd Maste 		break;
203219261079SEd Maste 
203319261079SEd Maste 	case sPerSourceMaxStartups:
203419261079SEd Maste 		arg = argv_next(&ac, &av);
203519261079SEd Maste 		if (!arg || *arg == '\0')
203619261079SEd Maste 			fatal("%s line %d: %s missing argument.",
203719261079SEd Maste 			    filename, linenum, keyword);
203819261079SEd Maste 		if (strcmp(arg, "none") == 0) { /* no limit */
203919261079SEd Maste 			value = INT_MAX;
204019261079SEd Maste 		} else {
204119261079SEd Maste 			if ((errstr = atoi_err(arg, &value)) != NULL)
204219261079SEd Maste 				fatal("%s line %d: %s integer value %s.",
204319261079SEd Maste 				    filename, linenum, keyword, errstr);
204419261079SEd Maste 		}
204519261079SEd Maste 		if (*activep)
204619261079SEd Maste 			options->per_source_max_startups = value;
204719261079SEd Maste 		break;
204819261079SEd Maste 
204921e764dfSDag-Erling Smørgrav 	case sMaxAuthTries:
205021e764dfSDag-Erling Smørgrav 		intptr = &options->max_authtries;
205121e764dfSDag-Erling Smørgrav 		goto parse_int;
205221e764dfSDag-Erling Smørgrav 
2053d4af9e69SDag-Erling Smørgrav 	case sMaxSessions:
2054d4af9e69SDag-Erling Smørgrav 		intptr = &options->max_sessions;
2055d4af9e69SDag-Erling Smørgrav 		goto parse_int;
2056d4af9e69SDag-Erling Smørgrav 
2057ca3176e7SBrian Feldman 	case sBanner:
2058ca3176e7SBrian Feldman 		charptr = &options->banner;
2059ca3176e7SBrian Feldman 		goto parse_filename;
2060d4af9e69SDag-Erling Smørgrav 
2061af12a3e7SDag-Erling Smørgrav 	/*
2062af12a3e7SDag-Erling Smørgrav 	 * These options can contain %X options expanded at
2063af12a3e7SDag-Erling Smørgrav 	 * connect time, so that you can specify paths like:
2064af12a3e7SDag-Erling Smørgrav 	 *
2065af12a3e7SDag-Erling Smørgrav 	 * AuthorizedKeysFile	/etc/ssh_keys/%u
2066af12a3e7SDag-Erling Smørgrav 	 */
2067af12a3e7SDag-Erling Smørgrav 	case sAuthorizedKeysFile:
206819261079SEd Maste 		uvalue = options->num_authkeys_files;
206919261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
207019261079SEd Maste 			if (*arg == '\0') {
207119261079SEd Maste 				error("%s line %d: keyword %s empty argument",
207219261079SEd Maste 				    filename, linenum, keyword);
207319261079SEd Maste 				goto out;
207419261079SEd Maste 			}
207519261079SEd Maste 			arg2 = tilde_expand_filename(arg, getuid());
207619261079SEd Maste 			if (*activep && uvalue == 0) {
207719261079SEd Maste 				opt_array_append(filename, linenum, keyword,
207847dd1d1bSDag-Erling Smørgrav 				    &options->authorized_keys_files,
207919261079SEd Maste 				    &options->num_authkeys_files, arg2);
2080e146993eSDag-Erling Smørgrav 			}
208119261079SEd Maste 			free(arg2);
2082e146993eSDag-Erling Smørgrav 		}
208319261079SEd Maste 		break;
2084e146993eSDag-Erling Smørgrav 
2085e2f6069cSDag-Erling Smørgrav 	case sAuthorizedPrincipalsFile:
2086e2f6069cSDag-Erling Smørgrav 		charptr = &options->authorized_principals_file;
208719261079SEd Maste 		arg = argv_next(&ac, &av);
20888ad9b54aSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
208919261079SEd Maste 			fatal("%s line %d: %s missing argument.",
209019261079SEd Maste 			    filename, linenum, keyword);
20918ad9b54aSDag-Erling Smørgrav 		if (*activep && *charptr == NULL) {
20928ad9b54aSDag-Erling Smørgrav 			*charptr = tilde_expand_filename(arg, getuid());
20938ad9b54aSDag-Erling Smørgrav 			/* increase optional counter */
20948ad9b54aSDag-Erling Smørgrav 			if (intptr != NULL)
20958ad9b54aSDag-Erling Smørgrav 				*intptr = *intptr + 1;
20968ad9b54aSDag-Erling Smørgrav 		}
20978ad9b54aSDag-Erling Smørgrav 		break;
2098af12a3e7SDag-Erling Smørgrav 
2099ca3176e7SBrian Feldman 	case sClientAliveInterval:
2100ca3176e7SBrian Feldman 		intptr = &options->client_alive_interval;
2101af12a3e7SDag-Erling Smørgrav 		goto parse_time;
2102af12a3e7SDag-Erling Smørgrav 
2103ca3176e7SBrian Feldman 	case sClientAliveCountMax:
2104ca3176e7SBrian Feldman 		intptr = &options->client_alive_count_max;
2105ca3176e7SBrian Feldman 		goto parse_int;
2106af12a3e7SDag-Erling Smørgrav 
210721e764dfSDag-Erling Smørgrav 	case sAcceptEnv:
210819261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
210919261079SEd Maste 			if (*arg == '\0' || strchr(arg, '=') != NULL)
211021e764dfSDag-Erling Smørgrav 				fatal("%s line %d: Invalid environment name.",
211121e764dfSDag-Erling Smørgrav 				    filename, linenum);
2112333ee039SDag-Erling Smørgrav 			if (!*activep)
2113462c32cbSDag-Erling Smørgrav 				continue;
211419261079SEd Maste 			opt_array_append(filename, linenum, keyword,
211547dd1d1bSDag-Erling Smørgrav 			    &options->accept_env, &options->num_accept_env,
211647dd1d1bSDag-Erling Smørgrav 			    arg);
211721e764dfSDag-Erling Smørgrav 		}
211821e764dfSDag-Erling Smørgrav 		break;
211921e764dfSDag-Erling Smørgrav 
2120190cef3dSDag-Erling Smørgrav 	case sSetEnv:
2121190cef3dSDag-Erling Smørgrav 		uvalue = options->num_setenv;
212219261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
212319261079SEd Maste 			if (*arg == '\0' || strchr(arg, '=') == NULL)
2124190cef3dSDag-Erling Smørgrav 				fatal("%s line %d: Invalid environment.",
2125190cef3dSDag-Erling Smørgrav 				    filename, linenum);
2126190cef3dSDag-Erling Smørgrav 			if (!*activep || uvalue != 0)
2127190cef3dSDag-Erling Smørgrav 				continue;
212838a52bd3SEd Maste 			if (lookup_setenv_in_list(arg, options->setenv,
212938a52bd3SEd Maste 			    options->num_setenv) != NULL) {
213038a52bd3SEd Maste 				debug2("%s line %d: ignoring duplicate env "
213138a52bd3SEd Maste 				    "name \"%.64s\"", filename, linenum, arg);
213238a52bd3SEd Maste 				continue;
213338a52bd3SEd Maste 			}
213419261079SEd Maste 			opt_array_append(filename, linenum, keyword,
2135190cef3dSDag-Erling Smørgrav 			    &options->setenv, &options->num_setenv, arg);
2136190cef3dSDag-Erling Smørgrav 		}
2137190cef3dSDag-Erling Smørgrav 		break;
2138190cef3dSDag-Erling Smørgrav 
2139b74df5b2SDag-Erling Smørgrav 	case sPermitTunnel:
2140b74df5b2SDag-Erling Smørgrav 		intptr = &options->permit_tun;
214119261079SEd Maste 		arg = argv_next(&ac, &av);
2142b74df5b2SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
214319261079SEd Maste 			fatal("%s line %d: %s missing argument.",
214419261079SEd Maste 			    filename, linenum, keyword);
2145d4af9e69SDag-Erling Smørgrav 		value = -1;
2146d4af9e69SDag-Erling Smørgrav 		for (i = 0; tunmode_desc[i].val != -1; i++)
2147d4af9e69SDag-Erling Smørgrav 			if (strcmp(tunmode_desc[i].text, arg) == 0) {
2148d4af9e69SDag-Erling Smørgrav 				value = tunmode_desc[i].val;
2149d4af9e69SDag-Erling Smørgrav 				break;
2150d4af9e69SDag-Erling Smørgrav 			}
2151d4af9e69SDag-Erling Smørgrav 		if (value == -1)
215219261079SEd Maste 			fatal("%s line %d: bad %s argument %s",
215319261079SEd Maste 			    filename, linenum, keyword, arg);
2154557f75e5SDag-Erling Smørgrav 		if (*activep && *intptr == -1)
2155b74df5b2SDag-Erling Smørgrav 			*intptr = value;
2156b74df5b2SDag-Erling Smørgrav 		break;
2157b74df5b2SDag-Erling Smørgrav 
215819261079SEd Maste 	case sInclude:
215919261079SEd Maste 		if (cmdline) {
216019261079SEd Maste 			fatal("Include directive not supported as a "
216119261079SEd Maste 			    "command-line option");
216219261079SEd Maste 		}
216319261079SEd Maste 		value = 0;
216419261079SEd Maste 		while ((arg2 = argv_next(&ac, &av)) != NULL) {
216519261079SEd Maste 			if (*arg2 == '\0') {
216619261079SEd Maste 				error("%s line %d: keyword %s empty argument",
216719261079SEd Maste 				    filename, linenum, keyword);
216819261079SEd Maste 				goto out;
216919261079SEd Maste 			}
217019261079SEd Maste 			value++;
217119261079SEd Maste 			found = 0;
217219261079SEd Maste 			if (*arg2 != '/' && *arg2 != '~') {
217319261079SEd Maste 				xasprintf(&arg, "%s/%s", SSHDIR, arg2);
217419261079SEd Maste 			} else
217519261079SEd Maste 				arg = xstrdup(arg2);
217619261079SEd Maste 
217719261079SEd Maste 			/*
217819261079SEd Maste 			 * Don't let included files clobber the containing
217919261079SEd Maste 			 * file's Match state.
218019261079SEd Maste 			 */
218119261079SEd Maste 			oactive = *activep;
218219261079SEd Maste 
218319261079SEd Maste 			/* consult cache of include files */
218419261079SEd Maste 			TAILQ_FOREACH(item, includes, entry) {
218519261079SEd Maste 				if (strcmp(item->selector, arg) != 0)
218619261079SEd Maste 					continue;
218719261079SEd Maste 				if (item->filename != NULL) {
218819261079SEd Maste 					parse_server_config_depth(options,
218919261079SEd Maste 					    item->filename, item->contents,
219019261079SEd Maste 					    includes, connectinfo,
219119261079SEd Maste 					    (*inc_flags & SSHCFG_MATCH_ONLY
219219261079SEd Maste 					        ? SSHCFG_MATCH_ONLY : (oactive
219319261079SEd Maste 					            ? 0 : SSHCFG_NEVERMATCH)),
219419261079SEd Maste 					    activep, depth + 1);
219519261079SEd Maste 				}
219619261079SEd Maste 				found = 1;
219719261079SEd Maste 				*activep = oactive;
219819261079SEd Maste 			}
219919261079SEd Maste 			if (found != 0) {
220019261079SEd Maste 				free(arg);
220119261079SEd Maste 				continue;
220219261079SEd Maste 			}
220319261079SEd Maste 
220419261079SEd Maste 			/* requested glob was not in cache */
220519261079SEd Maste 			debug2("%s line %d: new include %s",
220619261079SEd Maste 			    filename, linenum, arg);
220719261079SEd Maste 			if ((r = glob(arg, 0, NULL, &gbuf)) != 0) {
220819261079SEd Maste 				if (r != GLOB_NOMATCH) {
220919261079SEd Maste 					fatal("%s line %d: include \"%s\" glob "
221019261079SEd Maste 					    "failed", filename, linenum, arg);
221119261079SEd Maste 				}
221219261079SEd Maste 				/*
221319261079SEd Maste 				 * If no entry matched then record a
221419261079SEd Maste 				 * placeholder to skip later glob calls.
221519261079SEd Maste 				 */
221619261079SEd Maste 				debug2("%s line %d: no match for %s",
221719261079SEd Maste 				    filename, linenum, arg);
221819261079SEd Maste 				item = xcalloc(1, sizeof(*item));
221919261079SEd Maste 				item->selector = strdup(arg);
222019261079SEd Maste 				TAILQ_INSERT_TAIL(includes,
222119261079SEd Maste 				    item, entry);
222219261079SEd Maste 			}
222319261079SEd Maste 			if (gbuf.gl_pathc > INT_MAX)
222419261079SEd Maste 				fatal_f("too many glob results");
222519261079SEd Maste 			for (n = 0; n < (int)gbuf.gl_pathc; n++) {
222619261079SEd Maste 				debug2("%s line %d: including %s",
222719261079SEd Maste 				    filename, linenum, gbuf.gl_pathv[n]);
222819261079SEd Maste 				item = xcalloc(1, sizeof(*item));
222919261079SEd Maste 				item->selector = strdup(arg);
223019261079SEd Maste 				item->filename = strdup(gbuf.gl_pathv[n]);
223119261079SEd Maste 				if ((item->contents = sshbuf_new()) == NULL)
223219261079SEd Maste 					fatal_f("sshbuf_new failed");
223319261079SEd Maste 				load_server_config(item->filename,
223419261079SEd Maste 				    item->contents);
223519261079SEd Maste 				parse_server_config_depth(options,
223619261079SEd Maste 				    item->filename, item->contents,
223719261079SEd Maste 				    includes, connectinfo,
223819261079SEd Maste 				    (*inc_flags & SSHCFG_MATCH_ONLY
223919261079SEd Maste 				        ? SSHCFG_MATCH_ONLY : (oactive
224019261079SEd Maste 				            ? 0 : SSHCFG_NEVERMATCH)),
224119261079SEd Maste 				    activep, depth + 1);
224219261079SEd Maste 				*activep = oactive;
224319261079SEd Maste 				TAILQ_INSERT_TAIL(includes, item, entry);
224419261079SEd Maste 			}
224519261079SEd Maste 			globfree(&gbuf);
224619261079SEd Maste 			free(arg);
224719261079SEd Maste 		}
224819261079SEd Maste 		if (value == 0) {
224919261079SEd Maste 			fatal("%s line %d: %s missing filename argument",
225019261079SEd Maste 			    filename, linenum, keyword);
225119261079SEd Maste 		}
225219261079SEd Maste 		break;
225319261079SEd Maste 
2254333ee039SDag-Erling Smørgrav 	case sMatch:
2255333ee039SDag-Erling Smørgrav 		if (cmdline)
2256333ee039SDag-Erling Smørgrav 			fatal("Match directive not supported as a command-line "
2257333ee039SDag-Erling Smørgrav 			    "option");
225819261079SEd Maste 		value = match_cfg_line(&str, linenum,
225919261079SEd Maste 		    (*inc_flags & SSHCFG_NEVERMATCH ? NULL : connectinfo));
2260333ee039SDag-Erling Smørgrav 		if (value < 0)
2261333ee039SDag-Erling Smørgrav 			fatal("%s line %d: Bad Match condition", filename,
2262333ee039SDag-Erling Smørgrav 			    linenum);
226319261079SEd Maste 		*activep = (*inc_flags & SSHCFG_NEVERMATCH) ? 0 : value;
226419261079SEd Maste 		/*
226519261079SEd Maste 		 * The MATCH_ONLY flag is applicable only until the first
226619261079SEd Maste 		 * match block.
226719261079SEd Maste 		 */
226819261079SEd Maste 		*inc_flags &= ~SSHCFG_MATCH_ONLY;
226919261079SEd Maste 		/*
227019261079SEd Maste 		 * If match_cfg_line() didn't consume all its arguments then
227119261079SEd Maste 		 * arrange for the extra arguments check below to fail.
227219261079SEd Maste 		 */
227319261079SEd Maste 		if (str == NULL || *str == '\0')
227419261079SEd Maste 			argv_consume(&ac);
2275333ee039SDag-Erling Smørgrav 		break;
2276333ee039SDag-Erling Smørgrav 
2277190cef3dSDag-Erling Smørgrav 	case sPermitListen:
2278333ee039SDag-Erling Smørgrav 	case sPermitOpen:
2279190cef3dSDag-Erling Smørgrav 		if (opcode == sPermitListen) {
2280190cef3dSDag-Erling Smørgrav 			uintptr = &options->num_permitted_listens;
2281190cef3dSDag-Erling Smørgrav 			chararrayptr = &options->permitted_listens;
2282190cef3dSDag-Erling Smørgrav 		} else {
2283190cef3dSDag-Erling Smørgrav 			uintptr = &options->num_permitted_opens;
2284190cef3dSDag-Erling Smørgrav 			chararrayptr = &options->permitted_opens;
2285190cef3dSDag-Erling Smørgrav 		}
228619261079SEd Maste 		arg = argv_next(&ac, &av);
2287333ee039SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
228819261079SEd Maste 			fatal("%s line %d: %s missing argument.",
228919261079SEd Maste 			    filename, linenum, keyword);
2290190cef3dSDag-Erling Smørgrav 		uvalue = *uintptr;	/* modified later */
22914f52dfbbSDag-Erling Smørgrav 		if (strcmp(arg, "any") == 0 || strcmp(arg, "none") == 0) {
2292190cef3dSDag-Erling Smørgrav 			if (*activep && uvalue == 0) {
2293190cef3dSDag-Erling Smørgrav 				*uintptr = 1;
2294190cef3dSDag-Erling Smørgrav 				*chararrayptr = xcalloc(1,
2295190cef3dSDag-Erling Smørgrav 				    sizeof(**chararrayptr));
2296190cef3dSDag-Erling Smørgrav 				(*chararrayptr)[0] = xstrdup(arg);
2297462c32cbSDag-Erling Smørgrav 			}
2298462c32cbSDag-Erling Smørgrav 			break;
2299462c32cbSDag-Erling Smørgrav 		}
230019261079SEd Maste 		for (; arg != NULL && *arg != '\0'; arg = argv_next(&ac, &av)) {
2301190cef3dSDag-Erling Smørgrav 			if (opcode == sPermitListen &&
2302190cef3dSDag-Erling Smørgrav 			    strchr(arg, ':') == NULL) {
2303190cef3dSDag-Erling Smørgrav 				/*
2304190cef3dSDag-Erling Smørgrav 				 * Allow bare port number for PermitListen
2305190cef3dSDag-Erling Smørgrav 				 * to indicate a wildcard listen host.
2306190cef3dSDag-Erling Smørgrav 				 */
2307190cef3dSDag-Erling Smørgrav 				xasprintf(&arg2, "*:%s", arg);
2308190cef3dSDag-Erling Smørgrav 			} else {
23094f52dfbbSDag-Erling Smørgrav 				arg2 = xstrdup(arg);
23101323ec57SEd Maste 				p = hpdelim(&arg);
23111323ec57SEd Maste 				if (p == NULL) {
231219261079SEd Maste 					fatal("%s line %d: %s missing host",
231319261079SEd Maste 					    filename, linenum, keyword);
2314190cef3dSDag-Erling Smørgrav 				}
2315333ee039SDag-Erling Smørgrav 				p = cleanhostname(p);
2316190cef3dSDag-Erling Smørgrav 			}
2317190cef3dSDag-Erling Smørgrav 			if (arg == NULL ||
2318190cef3dSDag-Erling Smørgrav 			    ((port = permitopen_port(arg)) < 0)) {
231919261079SEd Maste 				fatal("%s line %d: %s bad port number",
232019261079SEd Maste 				    filename, linenum, keyword);
2321190cef3dSDag-Erling Smørgrav 			}
2322190cef3dSDag-Erling Smørgrav 			if (*activep && uvalue == 0) {
232319261079SEd Maste 				opt_array_append(filename, linenum, keyword,
2324190cef3dSDag-Erling Smørgrav 				    chararrayptr, uintptr, arg2);
232547dd1d1bSDag-Erling Smørgrav 			}
23264f52dfbbSDag-Erling Smørgrav 			free(arg2);
2327333ee039SDag-Erling Smørgrav 		}
2328333ee039SDag-Erling Smørgrav 		break;
2329333ee039SDag-Erling Smørgrav 
2330333ee039SDag-Erling Smørgrav 	case sForceCommand:
233119261079SEd Maste 		if (str == NULL || *str == '\0')
233219261079SEd Maste 			fatal("%s line %d: %s missing argument.",
233319261079SEd Maste 			    filename, linenum, keyword);
233419261079SEd Maste 		len = strspn(str, WHITESPACE);
2335333ee039SDag-Erling Smørgrav 		if (*activep && options->adm_forced_command == NULL)
233619261079SEd Maste 			options->adm_forced_command = xstrdup(str + len);
233719261079SEd Maste 		argv_consume(&ac);
233819261079SEd Maste 		break;
2339333ee039SDag-Erling Smørgrav 
2340d4af9e69SDag-Erling Smørgrav 	case sChrootDirectory:
2341d4af9e69SDag-Erling Smørgrav 		charptr = &options->chroot_directory;
2342d4af9e69SDag-Erling Smørgrav 
234319261079SEd Maste 		arg = argv_next(&ac, &av);
2344d4af9e69SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
234519261079SEd Maste 			fatal("%s line %d: %s missing argument.",
234619261079SEd Maste 			    filename, linenum, keyword);
2347d4af9e69SDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
2348d4af9e69SDag-Erling Smørgrav 			*charptr = xstrdup(arg);
2349d4af9e69SDag-Erling Smørgrav 		break;
2350d4af9e69SDag-Erling Smørgrav 
2351b15c8340SDag-Erling Smørgrav 	case sTrustedUserCAKeys:
2352b15c8340SDag-Erling Smørgrav 		charptr = &options->trusted_user_ca_keys;
2353b15c8340SDag-Erling Smørgrav 		goto parse_filename;
2354b15c8340SDag-Erling Smørgrav 
2355b15c8340SDag-Erling Smørgrav 	case sRevokedKeys:
2356b15c8340SDag-Erling Smørgrav 		charptr = &options->revoked_keys_file;
2357b15c8340SDag-Erling Smørgrav 		goto parse_filename;
2358b15c8340SDag-Erling Smørgrav 
235919261079SEd Maste 	case sSecurityKeyProvider:
236019261079SEd Maste 		charptr = &options->sk_provider;
236119261079SEd Maste 		arg = argv_next(&ac, &av);
236219261079SEd Maste 		if (!arg || *arg == '\0')
236319261079SEd Maste 			fatal("%s line %d: %s missing argument.",
236419261079SEd Maste 			    filename, linenum, keyword);
236519261079SEd Maste 		if (*activep && *charptr == NULL) {
236619261079SEd Maste 			*charptr = strcasecmp(arg, "internal") == 0 ?
236719261079SEd Maste 			    xstrdup(arg) : derelativise_path(arg);
236819261079SEd Maste 			/* increase optional counter */
236919261079SEd Maste 			if (intptr != NULL)
237019261079SEd Maste 				*intptr = *intptr + 1;
237119261079SEd Maste 		}
237219261079SEd Maste 		break;
237319261079SEd Maste 
23744a421b63SDag-Erling Smørgrav 	case sIPQoS:
237519261079SEd Maste 		arg = argv_next(&ac, &av);
237619261079SEd Maste 		if (!arg || *arg == '\0')
237719261079SEd Maste 			fatal("%s line %d: %s missing argument.",
237819261079SEd Maste 			    filename, linenum, keyword);
23794a421b63SDag-Erling Smørgrav 		if ((value = parse_ipqos(arg)) == -1)
238019261079SEd Maste 			fatal("%s line %d: Bad %s value: %s",
238119261079SEd Maste 			    filename, linenum, keyword, arg);
238219261079SEd Maste 		arg = argv_next(&ac, &av);
23834a421b63SDag-Erling Smørgrav 		if (arg == NULL)
23844a421b63SDag-Erling Smørgrav 			value2 = value;
23854a421b63SDag-Erling Smørgrav 		else if ((value2 = parse_ipqos(arg)) == -1)
238619261079SEd Maste 			fatal("%s line %d: Bad %s value: %s",
238719261079SEd Maste 			    filename, linenum, keyword, arg);
23884a421b63SDag-Erling Smørgrav 		if (*activep) {
23894a421b63SDag-Erling Smørgrav 			options->ip_qos_interactive = value;
23904a421b63SDag-Erling Smørgrav 			options->ip_qos_bulk = value2;
23914a421b63SDag-Erling Smørgrav 		}
23924a421b63SDag-Erling Smørgrav 		break;
23934a421b63SDag-Erling Smørgrav 
2394db58a8e4SDag-Erling Smørgrav 	case sVersionAddendum:
239519261079SEd Maste 		if (str == NULL || *str == '\0')
239619261079SEd Maste 			fatal("%s line %d: %s missing argument.",
239719261079SEd Maste 			    filename, linenum, keyword);
239819261079SEd Maste 		len = strspn(str, WHITESPACE);
239919261079SEd Maste 		if (strchr(str + len, '\r') != NULL) {
240019261079SEd Maste 			fatal("%.200s line %d: Invalid %s argument",
240119261079SEd Maste 			    filename, linenum, keyword);
2402462c32cbSDag-Erling Smørgrav 		}
240319261079SEd Maste 		if ((arg = strchr(line, '#')) != NULL) {
240419261079SEd Maste 			*arg = '\0';
240519261079SEd Maste 			rtrim(line);
240619261079SEd Maste 		}
240719261079SEd Maste 		if (*activep && options->version_addendum == NULL) {
240819261079SEd Maste 			if (strcasecmp(str + len, "none") == 0)
240919261079SEd Maste 				options->version_addendum = xstrdup("");
241019261079SEd Maste 			else
241119261079SEd Maste 				options->version_addendum = xstrdup(str + len);
241219261079SEd Maste 		}
241319261079SEd Maste 		argv_consume(&ac);
241419261079SEd Maste 		break;
2415db58a8e4SDag-Erling Smørgrav 
24166888a9beSDag-Erling Smørgrav 	case sAuthorizedKeysCommand:
241719261079SEd Maste 		charptr = &options->authorized_keys_command;
241819261079SEd Maste  parse_command:
241919261079SEd Maste 		len = strspn(str, WHITESPACE);
242019261079SEd Maste 		if (str[len] != '/' && strcasecmp(str + len, "none") != 0) {
242119261079SEd Maste 			fatal("%.200s line %d: %s must be an absolute path",
242219261079SEd Maste 			    filename, linenum, keyword);
24236888a9beSDag-Erling Smørgrav 		}
242419261079SEd Maste 		if (*activep && options->authorized_keys_command == NULL)
242519261079SEd Maste 			*charptr = xstrdup(str + len);
242619261079SEd Maste 		argv_consume(&ac);
242719261079SEd Maste 		break;
24286888a9beSDag-Erling Smørgrav 
24296888a9beSDag-Erling Smørgrav 	case sAuthorizedKeysCommandUser:
24306888a9beSDag-Erling Smørgrav 		charptr = &options->authorized_keys_command_user;
243119261079SEd Maste  parse_localuser:
243219261079SEd Maste 		arg = argv_next(&ac, &av);
243319261079SEd Maste 		if (!arg || *arg == '\0') {
243419261079SEd Maste 			fatal("%s line %d: missing %s argument.",
243519261079SEd Maste 			    filename, linenum, keyword);
243619261079SEd Maste 		}
24376888a9beSDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
24386888a9beSDag-Erling Smørgrav 			*charptr = xstrdup(arg);
24396888a9beSDag-Erling Smørgrav 		break;
24406888a9beSDag-Erling Smørgrav 
2441557f75e5SDag-Erling Smørgrav 	case sAuthorizedPrincipalsCommand:
244219261079SEd Maste 		charptr = &options->authorized_principals_command;
244319261079SEd Maste 		goto parse_command;
2444557f75e5SDag-Erling Smørgrav 
2445557f75e5SDag-Erling Smørgrav 	case sAuthorizedPrincipalsCommandUser:
2446557f75e5SDag-Erling Smørgrav 		charptr = &options->authorized_principals_command_user;
244719261079SEd Maste 		goto parse_localuser;
2448557f75e5SDag-Erling Smørgrav 
24496888a9beSDag-Erling Smørgrav 	case sAuthenticationMethods:
245019261079SEd Maste 		found = options->num_auth_methods == 0;
2451076ad2f8SDag-Erling Smørgrav 		value = 0; /* seen "any" pseudo-method */
2452190cef3dSDag-Erling Smørgrav 		value2 = 0; /* successfully parsed any method */
245319261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
2454076ad2f8SDag-Erling Smørgrav 			if (strcmp(arg, "any") == 0) {
2455076ad2f8SDag-Erling Smørgrav 				if (options->num_auth_methods > 0) {
245619261079SEd Maste 					fatal("%s line %d: \"any\" must "
245719261079SEd Maste 					    "appear alone in %s",
245819261079SEd Maste 					    filename, linenum, keyword);
2459076ad2f8SDag-Erling Smørgrav 				}
2460076ad2f8SDag-Erling Smørgrav 				value = 1;
2461076ad2f8SDag-Erling Smørgrav 			} else if (value) {
2462076ad2f8SDag-Erling Smørgrav 				fatal("%s line %d: \"any\" must appear "
246319261079SEd Maste 				    "alone in %s", filename, linenum, keyword);
2464076ad2f8SDag-Erling Smørgrav 			} else if (auth2_methods_valid(arg, 0) != 0) {
246519261079SEd Maste 				fatal("%s line %d: invalid %s method list.",
246619261079SEd Maste 				    filename, linenum, keyword);
2467076ad2f8SDag-Erling Smørgrav 			}
2468076ad2f8SDag-Erling Smørgrav 			value2 = 1;
246919261079SEd Maste 			if (!found || !*activep)
2470557f75e5SDag-Erling Smørgrav 				continue;
247119261079SEd Maste 			opt_array_append(filename, linenum, keyword,
247247dd1d1bSDag-Erling Smørgrav 			    &options->auth_methods,
247347dd1d1bSDag-Erling Smørgrav 			    &options->num_auth_methods, arg);
24746888a9beSDag-Erling Smørgrav 		}
2475076ad2f8SDag-Erling Smørgrav 		if (value2 == 0) {
247619261079SEd Maste 			fatal("%s line %d: no %s specified",
247719261079SEd Maste 			    filename, linenum, keyword);
2478076ad2f8SDag-Erling Smørgrav 		}
247919261079SEd Maste 		break;
24806888a9beSDag-Erling Smørgrav 
2481a0ee8cc6SDag-Erling Smørgrav 	case sStreamLocalBindMask:
248219261079SEd Maste 		arg = argv_next(&ac, &av);
2483a0ee8cc6SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
248419261079SEd Maste 			fatal("%s line %d: %s missing argument.",
248519261079SEd Maste 			    filename, linenum, keyword);
2486a0ee8cc6SDag-Erling Smørgrav 		/* Parse mode in octal format */
2487a0ee8cc6SDag-Erling Smørgrav 		value = strtol(arg, &p, 8);
2488a0ee8cc6SDag-Erling Smørgrav 		if (arg == p || value < 0 || value > 0777)
248919261079SEd Maste 			fatal("%s line %d: Invalid %s.",
249019261079SEd Maste 			    filename, linenum, keyword);
2491557f75e5SDag-Erling Smørgrav 		if (*activep)
2492a0ee8cc6SDag-Erling Smørgrav 			options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
2493a0ee8cc6SDag-Erling Smørgrav 		break;
2494a0ee8cc6SDag-Erling Smørgrav 
2495a0ee8cc6SDag-Erling Smørgrav 	case sStreamLocalBindUnlink:
2496a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->fwd_opts.streamlocal_bind_unlink;
2497a0ee8cc6SDag-Erling Smørgrav 		goto parse_flag;
2498a0ee8cc6SDag-Erling Smørgrav 
2499bc5531deSDag-Erling Smørgrav 	case sFingerprintHash:
250019261079SEd Maste 		arg = argv_next(&ac, &av);
2501bc5531deSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
250219261079SEd Maste 			fatal("%s line %d: %s missing argument.",
250319261079SEd Maste 			    filename, linenum, keyword);
2504bc5531deSDag-Erling Smørgrav 		if ((value = ssh_digest_alg_by_name(arg)) == -1)
250519261079SEd Maste 			fatal("%.200s line %d: Invalid %s algorithm \"%s\".",
250619261079SEd Maste 			    filename, linenum, keyword, arg);
2507bc5531deSDag-Erling Smørgrav 		if (*activep)
2508bc5531deSDag-Erling Smørgrav 			options->fingerprint_hash = value;
2509bc5531deSDag-Erling Smørgrav 		break;
2510bc5531deSDag-Erling Smørgrav 
25114f52dfbbSDag-Erling Smørgrav 	case sExposeAuthInfo:
25124f52dfbbSDag-Erling Smørgrav 		intptr = &options->expose_userauth_info;
25134f52dfbbSDag-Erling Smørgrav 		goto parse_flag;
25144f52dfbbSDag-Erling Smørgrav 
251547dd1d1bSDag-Erling Smørgrav 	case sRDomain:
251619261079SEd Maste #if !defined(__OpenBSD__) && !defined(HAVE_SYS_SET_PROCESS_RDOMAIN)
251719261079SEd Maste 		fatal("%s line %d: setting RDomain not supported on this "
251819261079SEd Maste 		    "platform.", filename, linenum);
251919261079SEd Maste #endif
252047dd1d1bSDag-Erling Smørgrav 		charptr = &options->routing_domain;
252119261079SEd Maste 		arg = argv_next(&ac, &av);
252247dd1d1bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
252319261079SEd Maste 			fatal("%s line %d: %s missing argument.",
252419261079SEd Maste 			    filename, linenum, keyword);
252547dd1d1bSDag-Erling Smørgrav 		if (strcasecmp(arg, "none") != 0 && strcmp(arg, "%D") != 0 &&
252647dd1d1bSDag-Erling Smørgrav 		    !valid_rdomain(arg))
252719261079SEd Maste 			fatal("%s line %d: invalid routing domain",
252847dd1d1bSDag-Erling Smørgrav 			    filename, linenum);
252947dd1d1bSDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
253047dd1d1bSDag-Erling Smørgrav 			*charptr = xstrdup(arg);
253147dd1d1bSDag-Erling Smørgrav 		break;
253247dd1d1bSDag-Erling Smørgrav 
253338a52bd3SEd Maste 	case sRequiredRSASize:
253438a52bd3SEd Maste 		intptr = &options->required_rsa_size;
253538a52bd3SEd Maste 		goto parse_int;
253638a52bd3SEd Maste 
2537*f374ba41SEd Maste 	case sChannelTimeout:
2538*f374ba41SEd Maste 		uvalue = options->num_channel_timeouts;
2539*f374ba41SEd Maste 		i = 0;
2540*f374ba41SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
2541*f374ba41SEd Maste 			/* Allow "none" only in first position */
2542*f374ba41SEd Maste 			if (strcasecmp(arg, "none") == 0) {
2543*f374ba41SEd Maste 				if (i > 0 || ac > 0) {
2544*f374ba41SEd Maste 					error("%s line %d: keyword %s \"none\" "
2545*f374ba41SEd Maste 					    "argument must appear alone.",
2546*f374ba41SEd Maste 					    filename, linenum, keyword);
2547*f374ba41SEd Maste 					goto out;
2548*f374ba41SEd Maste 				}
2549*f374ba41SEd Maste 			} else if (parse_timeout(arg, NULL, NULL) != 0) {
2550*f374ba41SEd Maste 				fatal("%s line %d: invalid channel timeout %s",
2551*f374ba41SEd Maste 				    filename, linenum, arg);
2552*f374ba41SEd Maste 			}
2553*f374ba41SEd Maste 			if (!*activep || uvalue != 0)
2554*f374ba41SEd Maste 				continue;
2555*f374ba41SEd Maste 			opt_array_append(filename, linenum, keyword,
2556*f374ba41SEd Maste 			    &options->channel_timeouts,
2557*f374ba41SEd Maste 			    &options->num_channel_timeouts, arg);
2558*f374ba41SEd Maste 		}
2559*f374ba41SEd Maste 		break;
2560*f374ba41SEd Maste 
2561*f374ba41SEd Maste 	case sUnusedConnectionTimeout:
2562*f374ba41SEd Maste 		intptr = &options->unused_connection_timeout;
2563*f374ba41SEd Maste 		/* peek at first arg for "none" so we can reuse parse_time */
2564*f374ba41SEd Maste 		if (av[0] != NULL && strcasecmp(av[0], "none") == 0) {
2565*f374ba41SEd Maste 			(void)argv_next(&ac, &av); /* consume arg */
2566*f374ba41SEd Maste 			if (*activep)
2567*f374ba41SEd Maste 				*intptr = 0;
2568*f374ba41SEd Maste 			break;
2569*f374ba41SEd Maste 		}
2570*f374ba41SEd Maste 		goto parse_time;
2571*f374ba41SEd Maste 
2572b2af61ecSKurt Lidl 	case sUseBlacklist:
2573b2af61ecSKurt Lidl 		intptr = &options->use_blacklist;
2574b2af61ecSKurt Lidl 		goto parse_flag;
2575b2af61ecSKurt Lidl 
2576af12a3e7SDag-Erling Smørgrav 	case sDeprecated:
2577ca86bcf2SDag-Erling Smørgrav 	case sIgnore:
2578cf2b5f3bSDag-Erling Smørgrav 	case sUnsupported:
2579ca86bcf2SDag-Erling Smørgrav 		do_log2(opcode == sIgnore ?
2580ca86bcf2SDag-Erling Smørgrav 		    SYSLOG_LEVEL_DEBUG2 : SYSLOG_LEVEL_INFO,
2581ca86bcf2SDag-Erling Smørgrav 		    "%s line %d: %s option %s", filename, linenum,
258219261079SEd Maste 		    opcode == sUnsupported ? "Unsupported" : "Deprecated",
258319261079SEd Maste 		    keyword);
258419261079SEd Maste 		argv_consume(&ac);
2585af12a3e7SDag-Erling Smørgrav 		break;
2586af12a3e7SDag-Erling Smørgrav 
258742f71286SMark Murray 	default:
2588af12a3e7SDag-Erling Smørgrav 		fatal("%s line %d: Missing handler for opcode %s (%d)",
258919261079SEd Maste 		    filename, linenum, keyword, opcode);
2590511b41d2SMark Murray 	}
259119261079SEd Maste 	/* Check that there is no garbage at end of line. */
259219261079SEd Maste 	if (ac > 0) {
259319261079SEd Maste 		error("%.200s line %d: keyword %s extra arguments "
259419261079SEd Maste 		    "at end of line", filename, linenum, keyword);
259519261079SEd Maste 		goto out;
2596af12a3e7SDag-Erling Smørgrav 	}
2597af12a3e7SDag-Erling Smørgrav 
259819261079SEd Maste 	/* success */
259919261079SEd Maste 	ret = 0;
260019261079SEd Maste  out:
260119261079SEd Maste 	argv_free(oav, oac);
260219261079SEd Maste 	return ret;
260319261079SEd Maste }
260419261079SEd Maste 
260519261079SEd Maste int
260619261079SEd Maste process_server_config_line(ServerOptions *options, char *line,
260719261079SEd Maste     const char *filename, int linenum, int *activep,
260819261079SEd Maste     struct connection_info *connectinfo, struct include_list *includes)
260919261079SEd Maste {
261019261079SEd Maste 	int inc_flags = 0;
261119261079SEd Maste 
261219261079SEd Maste 	return process_server_config_line_depth(options, line, filename,
261319261079SEd Maste 	    linenum, activep, connectinfo, &inc_flags, 0, includes);
261419261079SEd Maste }
261519261079SEd Maste 
261619261079SEd Maste 
2617af12a3e7SDag-Erling Smørgrav /* Reads the server configuration file. */
2618af12a3e7SDag-Erling Smørgrav 
2619af12a3e7SDag-Erling Smørgrav void
2620190cef3dSDag-Erling Smørgrav load_server_config(const char *filename, struct sshbuf *conf)
2621af12a3e7SDag-Erling Smørgrav {
262219261079SEd Maste 	struct stat st;
2623190cef3dSDag-Erling Smørgrav 	char *line = NULL, *cp;
2624190cef3dSDag-Erling Smørgrav 	size_t linesize = 0;
2625a82e551fSDag-Erling Smørgrav 	FILE *f;
2626*f374ba41SEd Maste 	int r;
2627af12a3e7SDag-Erling Smørgrav 
262819261079SEd Maste 	debug2_f("filename %s", filename);
262921e764dfSDag-Erling Smørgrav 	if ((f = fopen(filename, "r")) == NULL) {
2630af12a3e7SDag-Erling Smørgrav 		perror(filename);
2631af12a3e7SDag-Erling Smørgrav 		exit(1);
2632af12a3e7SDag-Erling Smørgrav 	}
2633190cef3dSDag-Erling Smørgrav 	sshbuf_reset(conf);
263419261079SEd Maste 	/* grow buffer, so realloc is avoided for large config files */
263519261079SEd Maste 	if (fstat(fileno(f), &st) == 0 && st.st_size > 0 &&
263619261079SEd Maste 	    (r = sshbuf_allocate(conf, st.st_size)) != 0)
263719261079SEd Maste 		fatal_fr(r, "allocate");
2638190cef3dSDag-Erling Smørgrav 	while (getline(&line, &linesize, f) != -1) {
263921e764dfSDag-Erling Smørgrav 		/*
264019261079SEd Maste 		 * Strip whitespace
264121e764dfSDag-Erling Smørgrav 		 * NB - preserve newlines, they are needed to reproduce
264221e764dfSDag-Erling Smørgrav 		 * line numbers later for error messages
264321e764dfSDag-Erling Smørgrav 		 */
264421e764dfSDag-Erling Smørgrav 		cp = line + strspn(line, " \t\r");
2645190cef3dSDag-Erling Smørgrav 		if ((r = sshbuf_put(conf, cp, strlen(cp))) != 0)
264619261079SEd Maste 			fatal_fr(r, "sshbuf_put");
264721e764dfSDag-Erling Smørgrav 	}
2648190cef3dSDag-Erling Smørgrav 	free(line);
2649190cef3dSDag-Erling Smørgrav 	if ((r = sshbuf_put_u8(conf, 0)) != 0)
265019261079SEd Maste 		fatal_fr(r, "sshbuf_put_u8");
265121e764dfSDag-Erling Smørgrav 	fclose(f);
265219261079SEd Maste 	debug2_f("done config len = %zu", sshbuf_len(conf));
265321e764dfSDag-Erling Smørgrav }
265421e764dfSDag-Erling Smørgrav 
265521e764dfSDag-Erling Smørgrav void
2656462c32cbSDag-Erling Smørgrav parse_server_match_config(ServerOptions *options,
265719261079SEd Maste    struct include_list *includes, struct connection_info *connectinfo)
265821e764dfSDag-Erling Smørgrav {
2659333ee039SDag-Erling Smørgrav 	ServerOptions mo;
2660333ee039SDag-Erling Smørgrav 
2661333ee039SDag-Erling Smørgrav 	initialize_server_options(&mo);
266219261079SEd Maste 	parse_server_config(&mo, "reprocess config", cfg, includes,
266387c1498dSEd Maste 	    connectinfo, 0);
2664d4af9e69SDag-Erling Smørgrav 	copy_set_server_options(options, &mo, 0);
2665333ee039SDag-Erling Smørgrav }
2666333ee039SDag-Erling Smørgrav 
2667462c32cbSDag-Erling Smørgrav int parse_server_match_testspec(struct connection_info *ci, char *spec)
2668462c32cbSDag-Erling Smørgrav {
2669462c32cbSDag-Erling Smørgrav 	char *p;
2670462c32cbSDag-Erling Smørgrav 
2671462c32cbSDag-Erling Smørgrav 	while ((p = strsep(&spec, ",")) && *p != '\0') {
2672462c32cbSDag-Erling Smørgrav 		if (strncmp(p, "addr=", 5) == 0) {
2673462c32cbSDag-Erling Smørgrav 			ci->address = xstrdup(p + 5);
2674462c32cbSDag-Erling Smørgrav 		} else if (strncmp(p, "host=", 5) == 0) {
2675462c32cbSDag-Erling Smørgrav 			ci->host = xstrdup(p + 5);
2676462c32cbSDag-Erling Smørgrav 		} else if (strncmp(p, "user=", 5) == 0) {
2677462c32cbSDag-Erling Smørgrav 			ci->user = xstrdup(p + 5);
2678462c32cbSDag-Erling Smørgrav 		} else if (strncmp(p, "laddr=", 6) == 0) {
2679462c32cbSDag-Erling Smørgrav 			ci->laddress = xstrdup(p + 6);
268047dd1d1bSDag-Erling Smørgrav 		} else if (strncmp(p, "rdomain=", 8) == 0) {
268147dd1d1bSDag-Erling Smørgrav 			ci->rdomain = xstrdup(p + 8);
2682462c32cbSDag-Erling Smørgrav 		} else if (strncmp(p, "lport=", 6) == 0) {
2683462c32cbSDag-Erling Smørgrav 			ci->lport = a2port(p + 6);
2684462c32cbSDag-Erling Smørgrav 			if (ci->lport == -1) {
2685462c32cbSDag-Erling Smørgrav 				fprintf(stderr, "Invalid port '%s' in test mode"
2686462c32cbSDag-Erling Smørgrav 				    " specification %s\n", p+6, p);
2687462c32cbSDag-Erling Smørgrav 				return -1;
2688462c32cbSDag-Erling Smørgrav 			}
2689462c32cbSDag-Erling Smørgrav 		} else {
2690462c32cbSDag-Erling Smørgrav 			fprintf(stderr, "Invalid test mode specification %s\n",
2691462c32cbSDag-Erling Smørgrav 			    p);
2692462c32cbSDag-Erling Smørgrav 			return -1;
2693462c32cbSDag-Erling Smørgrav 		}
2694462c32cbSDag-Erling Smørgrav 	}
2695462c32cbSDag-Erling Smørgrav 	return 0;
2696462c32cbSDag-Erling Smørgrav }
2697462c32cbSDag-Erling Smørgrav 
2698462c32cbSDag-Erling Smørgrav /*
2699d4af9e69SDag-Erling Smørgrav  * Copy any supported values that are set.
2700d4af9e69SDag-Erling Smørgrav  *
27017aee6ffeSDag-Erling Smørgrav  * If the preauth flag is set, we do not bother copying the string or
2702d4af9e69SDag-Erling Smørgrav  * array values that are not used pre-authentication, because any that we
2703190cef3dSDag-Erling Smørgrav  * do use must be explicitly sent in mm_getpwnamallow().
2704d4af9e69SDag-Erling Smørgrav  */
2705333ee039SDag-Erling Smørgrav void
2706d4af9e69SDag-Erling Smørgrav copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
2707333ee039SDag-Erling Smørgrav {
2708f7167e0eSDag-Erling Smørgrav #define M_CP_INTOPT(n) do {\
2709f7167e0eSDag-Erling Smørgrav 	if (src->n != -1) \
2710f7167e0eSDag-Erling Smørgrav 		dst->n = src->n; \
2711f7167e0eSDag-Erling Smørgrav } while (0)
2712f7167e0eSDag-Erling Smørgrav 
2713d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(password_authentication);
2714d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(gss_authentication);
2715d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(pubkey_authentication);
271619261079SEd Maste 	M_CP_INTOPT(pubkey_auth_options);
2717d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(kerberos_authentication);
2718d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(hostbased_authentication);
2719e2f6069cSDag-Erling Smørgrav 	M_CP_INTOPT(hostbased_uses_name_from_packet_only);
2720d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(kbd_interactive_authentication);
2721d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(permit_root_login);
2722cce7d346SDag-Erling Smørgrav 	M_CP_INTOPT(permit_empty_passwd);
272319261079SEd Maste 	M_CP_INTOPT(ignore_rhosts);
2724d4af9e69SDag-Erling Smørgrav 
2725d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(allow_tcp_forwarding);
2726a0ee8cc6SDag-Erling Smørgrav 	M_CP_INTOPT(allow_streamlocal_forwarding);
2727d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(allow_agent_forwarding);
2728ca86bcf2SDag-Erling Smørgrav 	M_CP_INTOPT(disable_forwarding);
27294f52dfbbSDag-Erling Smørgrav 	M_CP_INTOPT(expose_userauth_info);
2730e2f6069cSDag-Erling Smørgrav 	M_CP_INTOPT(permit_tun);
2731a0ee8cc6SDag-Erling Smørgrav 	M_CP_INTOPT(fwd_opts.gateway_ports);
2732076ad2f8SDag-Erling Smørgrav 	M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink);
2733d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(x11_display_offset);
2734d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(x11_forwarding);
2735d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(x11_use_localhost);
2736f7167e0eSDag-Erling Smørgrav 	M_CP_INTOPT(permit_tty);
2737a0ee8cc6SDag-Erling Smørgrav 	M_CP_INTOPT(permit_user_rc);
2738d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(max_sessions);
2739d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(max_authtries);
2740ca86bcf2SDag-Erling Smørgrav 	M_CP_INTOPT(client_alive_count_max);
2741ca86bcf2SDag-Erling Smørgrav 	M_CP_INTOPT(client_alive_interval);
27424a421b63SDag-Erling Smørgrav 	M_CP_INTOPT(ip_qos_interactive);
27434a421b63SDag-Erling Smørgrav 	M_CP_INTOPT(ip_qos_bulk);
2744e4a9863fSDag-Erling Smørgrav 	M_CP_INTOPT(rekey_limit);
2745e4a9863fSDag-Erling Smørgrav 	M_CP_INTOPT(rekey_interval);
27464f52dfbbSDag-Erling Smørgrav 	M_CP_INTOPT(log_level);
274738a52bd3SEd Maste 	M_CP_INTOPT(required_rsa_size);
2748*f374ba41SEd Maste 	M_CP_INTOPT(unused_connection_timeout);
2749d4af9e69SDag-Erling Smørgrav 
2750076ad2f8SDag-Erling Smørgrav 	/*
2751076ad2f8SDag-Erling Smørgrav 	 * The bind_mask is a mode_t that may be unsigned, so we can't use
2752076ad2f8SDag-Erling Smørgrav 	 * M_CP_INTOPT - it does a signed comparison that causes compiler
2753076ad2f8SDag-Erling Smørgrav 	 * warnings.
2754076ad2f8SDag-Erling Smørgrav 	 */
2755076ad2f8SDag-Erling Smørgrav 	if (src->fwd_opts.streamlocal_bind_mask != (mode_t)-1) {
2756076ad2f8SDag-Erling Smørgrav 		dst->fwd_opts.streamlocal_bind_mask =
2757076ad2f8SDag-Erling Smørgrav 		    src->fwd_opts.streamlocal_bind_mask;
2758076ad2f8SDag-Erling Smørgrav 	}
2759076ad2f8SDag-Erling Smørgrav 
2760f7167e0eSDag-Erling Smørgrav 	/* M_CP_STROPT and M_CP_STRARRAYOPT should not appear before here */
2761f7167e0eSDag-Erling Smørgrav #define M_CP_STROPT(n) do {\
2762f7167e0eSDag-Erling Smørgrav 	if (src->n != NULL && dst->n != src->n) { \
2763f7167e0eSDag-Erling Smørgrav 		free(dst->n); \
2764f7167e0eSDag-Erling Smørgrav 		dst->n = src->n; \
2765f7167e0eSDag-Erling Smørgrav 	} \
2766f7167e0eSDag-Erling Smørgrav } while(0)
276747dd1d1bSDag-Erling Smørgrav #define M_CP_STRARRAYOPT(s, num_s) do {\
276847dd1d1bSDag-Erling Smørgrav 	u_int i; \
276947dd1d1bSDag-Erling Smørgrav 	if (src->num_s != 0) { \
277047dd1d1bSDag-Erling Smørgrav 		for (i = 0; i < dst->num_s; i++) \
277147dd1d1bSDag-Erling Smørgrav 			free(dst->s[i]); \
277247dd1d1bSDag-Erling Smørgrav 		free(dst->s); \
277347dd1d1bSDag-Erling Smørgrav 		dst->s = xcalloc(src->num_s, sizeof(*dst->s)); \
277447dd1d1bSDag-Erling Smørgrav 		for (i = 0; i < src->num_s; i++) \
277547dd1d1bSDag-Erling Smørgrav 			dst->s[i] = xstrdup(src->s[i]); \
277647dd1d1bSDag-Erling Smørgrav 		dst->num_s = src->num_s; \
27774f52dfbbSDag-Erling Smørgrav 	} \
27784f52dfbbSDag-Erling Smørgrav } while(0)
2779f7167e0eSDag-Erling Smørgrav 
2780e146993eSDag-Erling Smørgrav 	/* See comment in servconf.h */
2781e146993eSDag-Erling Smørgrav 	COPY_MATCH_STRING_OPTS();
2782e146993eSDag-Erling Smørgrav 
2783acc1a9efSDag-Erling Smørgrav 	/* Arguments that accept '+...' need to be expanded */
2784acc1a9efSDag-Erling Smørgrav 	assemble_algorithms(dst);
2785acc1a9efSDag-Erling Smørgrav 
2786e146993eSDag-Erling Smørgrav 	/*
2787e146993eSDag-Erling Smørgrav 	 * The only things that should be below this point are string options
2788e146993eSDag-Erling Smørgrav 	 * which are only used after authentication.
2789e146993eSDag-Erling Smørgrav 	 */
2790d4af9e69SDag-Erling Smørgrav 	if (preauth)
2791d4af9e69SDag-Erling Smørgrav 		return;
2792e146993eSDag-Erling Smørgrav 
2793acc1a9efSDag-Erling Smørgrav 	/* These options may be "none" to clear a global setting */
2794d4af9e69SDag-Erling Smørgrav 	M_CP_STROPT(adm_forced_command);
2795acc1a9efSDag-Erling Smørgrav 	if (option_clear_or_none(dst->adm_forced_command)) {
2796acc1a9efSDag-Erling Smørgrav 		free(dst->adm_forced_command);
2797acc1a9efSDag-Erling Smørgrav 		dst->adm_forced_command = NULL;
2798acc1a9efSDag-Erling Smørgrav 	}
2799d4af9e69SDag-Erling Smørgrav 	M_CP_STROPT(chroot_directory);
2800acc1a9efSDag-Erling Smørgrav 	if (option_clear_or_none(dst->chroot_directory)) {
2801acc1a9efSDag-Erling Smørgrav 		free(dst->chroot_directory);
2802acc1a9efSDag-Erling Smørgrav 		dst->chroot_directory = NULL;
2803acc1a9efSDag-Erling Smørgrav 	}
2804333ee039SDag-Erling Smørgrav }
2805d4af9e69SDag-Erling Smørgrav 
2806d4af9e69SDag-Erling Smørgrav #undef M_CP_INTOPT
2807d4af9e69SDag-Erling Smørgrav #undef M_CP_STROPT
2808e146993eSDag-Erling Smørgrav #undef M_CP_STRARRAYOPT
2809333ee039SDag-Erling Smørgrav 
281019261079SEd Maste #define SERVCONF_MAX_DEPTH	16
281119261079SEd Maste static void
281219261079SEd Maste parse_server_config_depth(ServerOptions *options, const char *filename,
281319261079SEd Maste     struct sshbuf *conf, struct include_list *includes,
281419261079SEd Maste     struct connection_info *connectinfo, int flags, int *activep, int depth)
2815333ee039SDag-Erling Smørgrav {
281619261079SEd Maste 	int linenum, bad_options = 0;
281721e764dfSDag-Erling Smørgrav 	char *cp, *obuf, *cbuf;
281821e764dfSDag-Erling Smørgrav 
281919261079SEd Maste 	if (depth < 0 || depth > SERVCONF_MAX_DEPTH)
282019261079SEd Maste 		fatal("Too many recursive configuration includes");
282119261079SEd Maste 
282219261079SEd Maste 	debug2_f("config %s len %zu%s", filename, sshbuf_len(conf),
282319261079SEd Maste 	    (flags & SSHCFG_NEVERMATCH ? " [checking syntax only]" : ""));
282421e764dfSDag-Erling Smørgrav 
2825076ad2f8SDag-Erling Smørgrav 	if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL)
282619261079SEd Maste 		fatal_f("sshbuf_dup_string failed");
282721e764dfSDag-Erling Smørgrav 	linenum = 1;
282821e764dfSDag-Erling Smørgrav 	while ((cp = strsep(&cbuf, "\n")) != NULL) {
282919261079SEd Maste 		if (process_server_config_line_depth(options, cp,
283019261079SEd Maste 		    filename, linenum++, activep, connectinfo, &flags,
283119261079SEd Maste 		    depth, includes) != 0)
2832af12a3e7SDag-Erling Smørgrav 			bad_options++;
2833511b41d2SMark Murray 	}
2834e4a9863fSDag-Erling Smørgrav 	free(obuf);
2835ca3176e7SBrian Feldman 	if (bad_options > 0)
2836af12a3e7SDag-Erling Smørgrav 		fatal("%s: terminating, %d bad configuration options",
2837511b41d2SMark Murray 		    filename, bad_options);
283819261079SEd Maste }
283919261079SEd Maste 
284019261079SEd Maste void
284119261079SEd Maste parse_server_config(ServerOptions *options, const char *filename,
284219261079SEd Maste     struct sshbuf *conf, struct include_list *includes,
284387c1498dSEd Maste     struct connection_info *connectinfo, int reexec)
284419261079SEd Maste {
284519261079SEd Maste 	int active = connectinfo ? 0 : 1;
284619261079SEd Maste 	parse_server_config_depth(options, filename, conf, includes,
284719261079SEd Maste 	    connectinfo, (connectinfo ? SSHCFG_MATCH_ONLY : 0), &active, 0);
284887c1498dSEd Maste 	if (!reexec)
2849557f75e5SDag-Erling Smørgrav 		process_queued_listen_addrs(options);
2850511b41d2SMark Murray }
2851d4af9e69SDag-Erling Smørgrav 
2852d4af9e69SDag-Erling Smørgrav static const char *
2853e146993eSDag-Erling Smørgrav fmt_multistate_int(int val, const struct multistate *m)
2854d4af9e69SDag-Erling Smørgrav {
2855e146993eSDag-Erling Smørgrav 	u_int i;
2856e146993eSDag-Erling Smørgrav 
2857e146993eSDag-Erling Smørgrav 	for (i = 0; m[i].key != NULL; i++) {
2858e146993eSDag-Erling Smørgrav 		if (m[i].value == val)
2859e146993eSDag-Erling Smørgrav 			return m[i].key;
2860e146993eSDag-Erling Smørgrav 	}
2861d4af9e69SDag-Erling Smørgrav 	return "UNKNOWN";
2862d4af9e69SDag-Erling Smørgrav }
2863e146993eSDag-Erling Smørgrav 
2864e146993eSDag-Erling Smørgrav static const char *
2865e146993eSDag-Erling Smørgrav fmt_intarg(ServerOpCodes code, int val)
2866e146993eSDag-Erling Smørgrav {
2867e146993eSDag-Erling Smørgrav 	if (val == -1)
2868e146993eSDag-Erling Smørgrav 		return "unset";
2869e146993eSDag-Erling Smørgrav 	switch (code) {
2870e146993eSDag-Erling Smørgrav 	case sAddressFamily:
2871e146993eSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_addressfamily);
2872e146993eSDag-Erling Smørgrav 	case sPermitRootLogin:
2873e146993eSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_permitrootlogin);
2874e146993eSDag-Erling Smørgrav 	case sGatewayPorts:
2875e146993eSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_gatewayports);
2876e146993eSDag-Erling Smørgrav 	case sCompression:
2877e146993eSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_compression);
28786888a9beSDag-Erling Smørgrav 	case sAllowTcpForwarding:
28796888a9beSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_tcpfwd);
2880a0ee8cc6SDag-Erling Smørgrav 	case sAllowStreamLocalForwarding:
2881a0ee8cc6SDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_tcpfwd);
288219261079SEd Maste 	case sIgnoreRhosts:
288319261079SEd Maste 		return fmt_multistate_int(val, multistate_ignore_rhosts);
2884bc5531deSDag-Erling Smørgrav 	case sFingerprintHash:
2885bc5531deSDag-Erling Smørgrav 		return ssh_digest_alg_name(val);
2886e146993eSDag-Erling Smørgrav 	default:
2887d4af9e69SDag-Erling Smørgrav 		switch (val) {
2888d4af9e69SDag-Erling Smørgrav 		case 0:
2889d4af9e69SDag-Erling Smørgrav 			return "no";
2890d4af9e69SDag-Erling Smørgrav 		case 1:
2891d4af9e69SDag-Erling Smørgrav 			return "yes";
2892e146993eSDag-Erling Smørgrav 		default:
2893d4af9e69SDag-Erling Smørgrav 			return "UNKNOWN";
2894d4af9e69SDag-Erling Smørgrav 		}
2895e146993eSDag-Erling Smørgrav 	}
2896e146993eSDag-Erling Smørgrav }
2897d4af9e69SDag-Erling Smørgrav 
2898d4af9e69SDag-Erling Smørgrav static void
2899d4af9e69SDag-Erling Smørgrav dump_cfg_int(ServerOpCodes code, int val)
2900d4af9e69SDag-Erling Smørgrav {
2901*f374ba41SEd Maste 	if (code == sUnusedConnectionTimeout && val == 0) {
2902*f374ba41SEd Maste 		printf("%s none\n", lookup_opcode_name(code));
2903*f374ba41SEd Maste 		return;
2904*f374ba41SEd Maste 	}
2905d4af9e69SDag-Erling Smørgrav 	printf("%s %d\n", lookup_opcode_name(code), val);
2906d4af9e69SDag-Erling Smørgrav }
2907d4af9e69SDag-Erling Smørgrav 
2908d4af9e69SDag-Erling Smørgrav static void
2909557f75e5SDag-Erling Smørgrav dump_cfg_oct(ServerOpCodes code, int val)
2910557f75e5SDag-Erling Smørgrav {
2911557f75e5SDag-Erling Smørgrav 	printf("%s 0%o\n", lookup_opcode_name(code), val);
2912557f75e5SDag-Erling Smørgrav }
2913557f75e5SDag-Erling Smørgrav 
2914557f75e5SDag-Erling Smørgrav static void
2915d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(ServerOpCodes code, int val)
2916d4af9e69SDag-Erling Smørgrav {
2917d4af9e69SDag-Erling Smørgrav 	printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
2918d4af9e69SDag-Erling Smørgrav }
2919d4af9e69SDag-Erling Smørgrav 
2920d4af9e69SDag-Erling Smørgrav static void
2921d4af9e69SDag-Erling Smørgrav dump_cfg_string(ServerOpCodes code, const char *val)
2922d4af9e69SDag-Erling Smørgrav {
2923bc5531deSDag-Erling Smørgrav 	printf("%s %s\n", lookup_opcode_name(code),
2924bc5531deSDag-Erling Smørgrav 	    val == NULL ? "none" : val);
2925d4af9e69SDag-Erling Smørgrav }
2926d4af9e69SDag-Erling Smørgrav 
2927d4af9e69SDag-Erling Smørgrav static void
2928d4af9e69SDag-Erling Smørgrav dump_cfg_strarray(ServerOpCodes code, u_int count, char **vals)
2929d4af9e69SDag-Erling Smørgrav {
2930d4af9e69SDag-Erling Smørgrav 	u_int i;
2931d4af9e69SDag-Erling Smørgrav 
2932d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < count; i++)
2933d4af9e69SDag-Erling Smørgrav 		printf("%s %s\n", lookup_opcode_name(code), vals[i]);
2934d4af9e69SDag-Erling Smørgrav }
2935d4af9e69SDag-Erling Smørgrav 
2936e146993eSDag-Erling Smørgrav static void
2937e146993eSDag-Erling Smørgrav dump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals)
2938e146993eSDag-Erling Smørgrav {
2939e146993eSDag-Erling Smørgrav 	u_int i;
2940e146993eSDag-Erling Smørgrav 
2941076ad2f8SDag-Erling Smørgrav 	if (count <= 0 && code != sAuthenticationMethods)
2942557f75e5SDag-Erling Smørgrav 		return;
2943e146993eSDag-Erling Smørgrav 	printf("%s", lookup_opcode_name(code));
2944e146993eSDag-Erling Smørgrav 	for (i = 0; i < count; i++)
2945e146993eSDag-Erling Smørgrav 		printf(" %s",  vals[i]);
2946076ad2f8SDag-Erling Smørgrav 	if (code == sAuthenticationMethods && count == 0)
2947076ad2f8SDag-Erling Smørgrav 		printf(" any");
2948*f374ba41SEd Maste 	else if (code == sChannelTimeout && count == 0)
2949*f374ba41SEd Maste 		printf(" none");
2950e146993eSDag-Erling Smørgrav 	printf("\n");
2951e146993eSDag-Erling Smørgrav }
2952e146993eSDag-Erling Smørgrav 
295347dd1d1bSDag-Erling Smørgrav static char *
295447dd1d1bSDag-Erling Smørgrav format_listen_addrs(struct listenaddr *la)
2955d4af9e69SDag-Erling Smørgrav {
295647dd1d1bSDag-Erling Smørgrav 	int r;
2957d4af9e69SDag-Erling Smørgrav 	struct addrinfo *ai;
295847dd1d1bSDag-Erling Smørgrav 	char addr[NI_MAXHOST], port[NI_MAXSERV];
2959557f75e5SDag-Erling Smørgrav 	char *laddr1 = xstrdup(""), *laddr2 = NULL;
2960d4af9e69SDag-Erling Smørgrav 
2961557f75e5SDag-Erling Smørgrav 	/*
2962557f75e5SDag-Erling Smørgrav 	 * ListenAddress must be after Port.  add_one_listen_addr pushes
2963557f75e5SDag-Erling Smørgrav 	 * addresses onto a stack, so to maintain ordering we need to
2964557f75e5SDag-Erling Smørgrav 	 * print these in reverse order.
2965557f75e5SDag-Erling Smørgrav 	 */
296647dd1d1bSDag-Erling Smørgrav 	for (ai = la->addrs; ai; ai = ai->ai_next) {
296747dd1d1bSDag-Erling Smørgrav 		if ((r = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
2968d4af9e69SDag-Erling Smørgrav 		    sizeof(addr), port, sizeof(port),
2969d4af9e69SDag-Erling Smørgrav 		    NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
297047dd1d1bSDag-Erling Smørgrav 			error("getnameinfo: %.100s", ssh_gai_strerror(r));
297147dd1d1bSDag-Erling Smørgrav 			continue;
297247dd1d1bSDag-Erling Smørgrav 		}
2973557f75e5SDag-Erling Smørgrav 		laddr2 = laddr1;
297447dd1d1bSDag-Erling Smørgrav 		if (ai->ai_family == AF_INET6) {
297547dd1d1bSDag-Erling Smørgrav 			xasprintf(&laddr1, "listenaddress [%s]:%s%s%s\n%s",
297647dd1d1bSDag-Erling Smørgrav 			    addr, port,
297747dd1d1bSDag-Erling Smørgrav 			    la->rdomain == NULL ? "" : " rdomain ",
297847dd1d1bSDag-Erling Smørgrav 			    la->rdomain == NULL ? "" : la->rdomain,
297947dd1d1bSDag-Erling Smørgrav 			    laddr2);
298047dd1d1bSDag-Erling Smørgrav 		} else {
298147dd1d1bSDag-Erling Smørgrav 			xasprintf(&laddr1, "listenaddress %s:%s%s%s\n%s",
298247dd1d1bSDag-Erling Smørgrav 			    addr, port,
298347dd1d1bSDag-Erling Smørgrav 			    la->rdomain == NULL ? "" : " rdomain ",
298447dd1d1bSDag-Erling Smørgrav 			    la->rdomain == NULL ? "" : la->rdomain,
298547dd1d1bSDag-Erling Smørgrav 			    laddr2);
298647dd1d1bSDag-Erling Smørgrav 		}
2987557f75e5SDag-Erling Smørgrav 		free(laddr2);
2988d4af9e69SDag-Erling Smørgrav 	}
298947dd1d1bSDag-Erling Smørgrav 	return laddr1;
2990d4af9e69SDag-Erling Smørgrav }
299147dd1d1bSDag-Erling Smørgrav 
299247dd1d1bSDag-Erling Smørgrav void
299347dd1d1bSDag-Erling Smørgrav dump_config(ServerOptions *o)
299447dd1d1bSDag-Erling Smørgrav {
299547dd1d1bSDag-Erling Smørgrav 	char *s;
299647dd1d1bSDag-Erling Smørgrav 	u_int i;
299747dd1d1bSDag-Erling Smørgrav 
299847dd1d1bSDag-Erling Smørgrav 	/* these are usually at the top of the config */
299947dd1d1bSDag-Erling Smørgrav 	for (i = 0; i < o->num_ports; i++)
300047dd1d1bSDag-Erling Smørgrav 		printf("port %d\n", o->ports[i]);
300147dd1d1bSDag-Erling Smørgrav 	dump_cfg_fmtint(sAddressFamily, o->address_family);
300247dd1d1bSDag-Erling Smørgrav 
300347dd1d1bSDag-Erling Smørgrav 	for (i = 0; i < o->num_listen_addrs; i++) {
300447dd1d1bSDag-Erling Smørgrav 		s = format_listen_addrs(&o->listen_addrs[i]);
300547dd1d1bSDag-Erling Smørgrav 		printf("%s", s);
300647dd1d1bSDag-Erling Smørgrav 		free(s);
300747dd1d1bSDag-Erling Smørgrav 	}
3008d4af9e69SDag-Erling Smørgrav 
3009d4af9e69SDag-Erling Smørgrav 	/* integer arguments */
3010cce7d346SDag-Erling Smørgrav #ifdef USE_PAM
3011557f75e5SDag-Erling Smørgrav 	dump_cfg_fmtint(sUsePAM, o->use_pam);
3012cce7d346SDag-Erling Smørgrav #endif
3013d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sLoginGraceTime, o->login_grace_time);
3014d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sX11DisplayOffset, o->x11_display_offset);
3015d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sMaxAuthTries, o->max_authtries);
3016cce7d346SDag-Erling Smørgrav 	dump_cfg_int(sMaxSessions, o->max_sessions);
3017d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
3018d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
301938a52bd3SEd Maste 	dump_cfg_int(sRequiredRSASize, o->required_rsa_size);
3020557f75e5SDag-Erling Smørgrav 	dump_cfg_oct(sStreamLocalBindMask, o->fwd_opts.streamlocal_bind_mask);
3021*f374ba41SEd Maste 	dump_cfg_int(sUnusedConnectionTimeout, o->unused_connection_timeout);
3022d4af9e69SDag-Erling Smørgrav 
3023d4af9e69SDag-Erling Smørgrav 	/* formatted integer arguments */
3024d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login);
3025d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sIgnoreRhosts, o->ignore_rhosts);
3026d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sIgnoreUserKnownHosts, o->ignore_user_known_hosts);
3027d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sHostbasedAuthentication, o->hostbased_authentication);
3028d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sHostbasedUsesNameFromPacketOnly,
3029d4af9e69SDag-Erling Smørgrav 	    o->hostbased_uses_name_from_packet_only);
3030d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPubkeyAuthentication, o->pubkey_authentication);
3031cce7d346SDag-Erling Smørgrav #ifdef KRB5
3032d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKerberosAuthentication, o->kerberos_authentication);
3033d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKerberosOrLocalPasswd, o->kerberos_or_local_passwd);
3034d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKerberosTicketCleanup, o->kerberos_ticket_cleanup);
3035cce7d346SDag-Erling Smørgrav # ifdef USE_AFS
3036d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
3037cce7d346SDag-Erling Smørgrav # endif
3038cce7d346SDag-Erling Smørgrav #endif
3039cce7d346SDag-Erling Smørgrav #ifdef GSSAPI
3040d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
3041d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
3042cce7d346SDag-Erling Smørgrav #endif
3043d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
3044d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKbdInteractiveAuthentication,
3045d4af9e69SDag-Erling Smørgrav 	    o->kbd_interactive_authentication);
3046d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPrintMotd, o->print_motd);
3047acc1a9efSDag-Erling Smørgrav #ifndef DISABLE_LASTLOG
3048d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPrintLastLog, o->print_lastlog);
3049acc1a9efSDag-Erling Smørgrav #endif
3050d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding);
3051d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost);
3052f7167e0eSDag-Erling Smørgrav 	dump_cfg_fmtint(sPermitTTY, o->permit_tty);
3053a0ee8cc6SDag-Erling Smørgrav 	dump_cfg_fmtint(sPermitUserRC, o->permit_user_rc);
3054d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sStrictModes, o->strict_modes);
3055d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive);
3056d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd);
3057d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sCompression, o->compression);
3058a0ee8cc6SDag-Erling Smørgrav 	dump_cfg_fmtint(sGatewayPorts, o->fwd_opts.gateway_ports);
3059d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sUseDNS, o->use_dns);
3060d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
3061557f75e5SDag-Erling Smørgrav 	dump_cfg_fmtint(sAllowAgentForwarding, o->allow_agent_forwarding);
3062ca86bcf2SDag-Erling Smørgrav 	dump_cfg_fmtint(sDisableForwarding, o->disable_forwarding);
3063a0ee8cc6SDag-Erling Smørgrav 	dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding);
3064076ad2f8SDag-Erling Smørgrav 	dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
3065bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash);
30664f52dfbbSDag-Erling Smørgrav 	dump_cfg_fmtint(sExposeAuthInfo, o->expose_userauth_info);
3067b2af61ecSKurt Lidl 	dump_cfg_fmtint(sUseBlacklist, o->use_blacklist);
3068d4af9e69SDag-Erling Smørgrav 
3069d4af9e69SDag-Erling Smørgrav 	/* string arguments */
3070d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sPidFile, o->pid_file);
307119261079SEd Maste 	dump_cfg_string(sModuliFile, o->moduli_file);
3072d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sXAuthLocation, o->xauth_location);
307319261079SEd Maste 	dump_cfg_string(sCiphers, o->ciphers);
307419261079SEd Maste 	dump_cfg_string(sMacs, o->macs);
3075d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sBanner, o->banner);
3076d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sForceCommand, o->adm_forced_command);
3077b15c8340SDag-Erling Smørgrav 	dump_cfg_string(sChrootDirectory, o->chroot_directory);
3078b15c8340SDag-Erling Smørgrav 	dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys);
3079b15c8340SDag-Erling Smørgrav 	dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
308019261079SEd Maste 	dump_cfg_string(sSecurityKeyProvider, o->sk_provider);
3081e2f6069cSDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedPrincipalsFile,
3082e2f6069cSDag-Erling Smørgrav 	    o->authorized_principals_file);
3083557f75e5SDag-Erling Smørgrav 	dump_cfg_string(sVersionAddendum, *o->version_addendum == '\0'
3084557f75e5SDag-Erling Smørgrav 	    ? "none" : o->version_addendum);
30856888a9beSDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command);
30866888a9beSDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedKeysCommandUser, o->authorized_keys_command_user);
3087557f75e5SDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedPrincipalsCommand, o->authorized_principals_command);
3088557f75e5SDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedPrincipalsCommandUser, o->authorized_principals_command_user);
3089e4a9863fSDag-Erling Smørgrav 	dump_cfg_string(sHostKeyAgent, o->host_key_agent);
309019261079SEd Maste 	dump_cfg_string(sKexAlgorithms, o->kex_algorithms);
309119261079SEd Maste 	dump_cfg_string(sCASignatureAlgorithms, o->ca_sign_algorithms);
309219261079SEd Maste 	dump_cfg_string(sHostbasedAcceptedAlgorithms, o->hostbased_accepted_algos);
309319261079SEd Maste 	dump_cfg_string(sHostKeyAlgorithms, o->hostkeyalgorithms);
309419261079SEd Maste 	dump_cfg_string(sPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos);
309519261079SEd Maste #if defined(__OpenBSD__) || defined(HAVE_SYS_SET_PROCESS_RDOMAIN)
309647dd1d1bSDag-Erling Smørgrav 	dump_cfg_string(sRDomain, o->routing_domain);
309719261079SEd Maste #endif
3098d4af9e69SDag-Erling Smørgrav 
3099d4af9e69SDag-Erling Smørgrav 	/* string arguments requiring a lookup */
3100d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sLogLevel, log_level_name(o->log_level));
3101d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sLogFacility, log_facility_name(o->log_facility));
3102d4af9e69SDag-Erling Smørgrav 
3103d4af9e69SDag-Erling Smørgrav 	/* string array arguments */
3104e146993eSDag-Erling Smørgrav 	dump_cfg_strarray_oneline(sAuthorizedKeysFile, o->num_authkeys_files,
3105e146993eSDag-Erling Smørgrav 	    o->authorized_keys_files);
3106d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sHostKeyFile, o->num_host_key_files,
3107d4af9e69SDag-Erling Smørgrav 	    o->host_key_files);
3108557f75e5SDag-Erling Smørgrav 	dump_cfg_strarray(sHostCertificate, o->num_host_cert_files,
3109b15c8340SDag-Erling Smørgrav 	    o->host_cert_files);
3110d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users);
3111d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users);
3112d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups);
3113d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sDenyGroups, o->num_deny_groups, o->deny_groups);
3114d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env);
3115190cef3dSDag-Erling Smørgrav 	dump_cfg_strarray(sSetEnv, o->num_setenv, o->setenv);
31166888a9beSDag-Erling Smørgrav 	dump_cfg_strarray_oneline(sAuthenticationMethods,
31176888a9beSDag-Erling Smørgrav 	    o->num_auth_methods, o->auth_methods);
311819261079SEd Maste 	dump_cfg_strarray_oneline(sLogVerbose,
311919261079SEd Maste 	    o->num_log_verbose, o->log_verbose);
3120*f374ba41SEd Maste 	dump_cfg_strarray_oneline(sChannelTimeout,
3121*f374ba41SEd Maste 	    o->num_channel_timeouts, o->channel_timeouts);
3122d4af9e69SDag-Erling Smørgrav 
3123d4af9e69SDag-Erling Smørgrav 	/* other arguments */
3124d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < o->num_subsystems; i++)
3125d4af9e69SDag-Erling Smørgrav 		printf("subsystem %s %s\n", o->subsystem_name[i],
3126d4af9e69SDag-Erling Smørgrav 		    o->subsystem_args[i]);
3127d4af9e69SDag-Erling Smørgrav 
3128d4af9e69SDag-Erling Smørgrav 	printf("maxstartups %d:%d:%d\n", o->max_startups_begin,
3129d4af9e69SDag-Erling Smørgrav 	    o->max_startups_rate, o->max_startups);
313019261079SEd Maste 	printf("persourcemaxstartups ");
313119261079SEd Maste 	if (o->per_source_max_startups == INT_MAX)
313219261079SEd Maste 		printf("none\n");
313319261079SEd Maste 	else
313419261079SEd Maste 		printf("%d\n", o->per_source_max_startups);
313519261079SEd Maste 	printf("persourcenetblocksize %d:%d\n", o->per_source_masklen_ipv4,
313619261079SEd Maste 	    o->per_source_masklen_ipv6);
3137d4af9e69SDag-Erling Smørgrav 
313847dd1d1bSDag-Erling Smørgrav 	s = NULL;
313947dd1d1bSDag-Erling Smørgrav 	for (i = 0; tunmode_desc[i].val != -1; i++) {
3140d4af9e69SDag-Erling Smørgrav 		if (tunmode_desc[i].val == o->permit_tun) {
3141d4af9e69SDag-Erling Smørgrav 			s = tunmode_desc[i].text;
3142d4af9e69SDag-Erling Smørgrav 			break;
3143d4af9e69SDag-Erling Smørgrav 		}
314447dd1d1bSDag-Erling Smørgrav 	}
3145d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sPermitTunnel, s);
3146d4af9e69SDag-Erling Smørgrav 
3147e146993eSDag-Erling Smørgrav 	printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
3148e146993eSDag-Erling Smørgrav 	printf("%s\n", iptos2str(o->ip_qos_bulk));
31494a421b63SDag-Erling Smørgrav 
3150acc1a9efSDag-Erling Smørgrav 	printf("rekeylimit %llu %d\n", (unsigned long long)o->rekey_limit,
3151e4a9863fSDag-Erling Smørgrav 	    o->rekey_interval);
3152e4a9863fSDag-Erling Smørgrav 
31534f52dfbbSDag-Erling Smørgrav 	printf("permitopen");
31544f52dfbbSDag-Erling Smørgrav 	if (o->num_permitted_opens == 0)
31554f52dfbbSDag-Erling Smørgrav 		printf(" any");
31564f52dfbbSDag-Erling Smørgrav 	else {
31574f52dfbbSDag-Erling Smørgrav 		for (i = 0; i < o->num_permitted_opens; i++)
31584f52dfbbSDag-Erling Smørgrav 			printf(" %s", o->permitted_opens[i]);
31594f52dfbbSDag-Erling Smørgrav 	}
31604f52dfbbSDag-Erling Smørgrav 	printf("\n");
3161190cef3dSDag-Erling Smørgrav 	printf("permitlisten");
3162190cef3dSDag-Erling Smørgrav 	if (o->num_permitted_listens == 0)
3163190cef3dSDag-Erling Smørgrav 		printf(" any");
3164190cef3dSDag-Erling Smørgrav 	else {
3165190cef3dSDag-Erling Smørgrav 		for (i = 0; i < o->num_permitted_listens; i++)
3166190cef3dSDag-Erling Smørgrav 			printf(" %s", o->permitted_listens[i]);
3167190cef3dSDag-Erling Smørgrav 	}
3168190cef3dSDag-Erling Smørgrav 	printf("\n");
3169190cef3dSDag-Erling Smørgrav 
317019261079SEd Maste 	if (o->permit_user_env_allowlist == NULL) {
3171190cef3dSDag-Erling Smørgrav 		dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
3172190cef3dSDag-Erling Smørgrav 	} else {
3173190cef3dSDag-Erling Smørgrav 		printf("permituserenvironment %s\n",
317419261079SEd Maste 		    o->permit_user_env_allowlist);
3175190cef3dSDag-Erling Smørgrav 	}
3176190cef3dSDag-Erling Smørgrav 
317719261079SEd Maste 	printf("pubkeyauthoptions");
317819261079SEd Maste 	if (o->pubkey_auth_options == 0)
317919261079SEd Maste 		printf(" none");
318019261079SEd Maste 	if (o->pubkey_auth_options & PUBKEYAUTH_TOUCH_REQUIRED)
318119261079SEd Maste 		printf(" touch-required");
318219261079SEd Maste 	if (o->pubkey_auth_options & PUBKEYAUTH_VERIFY_REQUIRED)
318319261079SEd Maste 		printf(" verify-required");
318419261079SEd Maste 	printf("\n");
3185d4af9e69SDag-Erling Smørgrav }
3186