xref: /freebsd/crypto/openssh/servconf.c (revision 1323ec571215a77ddd21294f0871979d5ad6b992)
1eccfee6eSDag-Erling Smørgrav 
2*1323ec57SEd Maste /* $OpenBSD: servconf.c,v 1.383 2022/02/08 08:59:12 dtucker 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"
15333ee039SDag-Erling Smørgrav __RCSID("$FreeBSD$");
16511b41d2SMark Murray 
17333ee039SDag-Erling Smørgrav #include <sys/types.h>
18333ee039SDag-Erling Smørgrav #include <sys/socket.h>
1919261079SEd Maste #include <sys/stat.h>
2019261079SEd Maste #ifdef __OpenBSD__
2147dd1d1bSDag-Erling Smørgrav #include <sys/sysctl.h>
2247dd1d1bSDag-Erling Smørgrav #endif
23333ee039SDag-Erling Smørgrav 
244a421b63SDag-Erling Smørgrav #include <netinet/in.h>
254a421b63SDag-Erling Smørgrav #include <netinet/in_systm.h>
264a421b63SDag-Erling Smørgrav #include <netinet/ip.h>
2747dd1d1bSDag-Erling Smørgrav #ifdef HAVE_NET_ROUTE_H
2847dd1d1bSDag-Erling Smørgrav #include <net/route.h>
2947dd1d1bSDag-Erling Smørgrav #endif
304a421b63SDag-Erling Smørgrav 
31e4a9863fSDag-Erling Smørgrav #include <ctype.h>
32333ee039SDag-Erling Smørgrav #include <netdb.h>
33333ee039SDag-Erling Smørgrav #include <pwd.h>
34333ee039SDag-Erling Smørgrav #include <stdio.h>
35333ee039SDag-Erling Smørgrav #include <stdlib.h>
36333ee039SDag-Erling Smørgrav #include <string.h>
37333ee039SDag-Erling Smørgrav #include <signal.h>
38333ee039SDag-Erling Smørgrav #include <unistd.h>
39bc5531deSDag-Erling Smørgrav #include <limits.h>
40333ee039SDag-Erling Smørgrav #include <stdarg.h>
41d4af9e69SDag-Erling Smørgrav #include <errno.h>
42e4a9863fSDag-Erling Smørgrav #ifdef HAVE_UTIL_H
43e4a9863fSDag-Erling Smørgrav #include <util.h>
44e4a9863fSDag-Erling Smørgrav #endif
4519261079SEd Maste #ifdef USE_SYSTEM_GLOB
4619261079SEd Maste # include <glob.h>
4719261079SEd Maste #else
4819261079SEd Maste # include "openbsd-compat/glob.h"
4919261079SEd Maste #endif
50333ee039SDag-Erling Smørgrav 
51d4af9e69SDag-Erling Smørgrav #include "openbsd-compat/sys-queue.h"
52333ee039SDag-Erling Smørgrav #include "xmalloc.h"
53511b41d2SMark Murray #include "ssh.h"
54ca3176e7SBrian Feldman #include "log.h"
55190cef3dSDag-Erling Smørgrav #include "sshbuf.h"
56a0ee8cc6SDag-Erling Smørgrav #include "misc.h"
57511b41d2SMark Murray #include "servconf.h"
58e8aafc91SKris Kennaway #include "compat.h"
59ca3176e7SBrian Feldman #include "pathnames.h"
60ca3176e7SBrian Feldman #include "cipher.h"
61190cef3dSDag-Erling Smørgrav #include "sshkey.h"
62ca3176e7SBrian Feldman #include "kex.h"
63ca3176e7SBrian Feldman #include "mac.h"
64333ee039SDag-Erling Smørgrav #include "match.h"
65333ee039SDag-Erling Smørgrav #include "channels.h"
66333ee039SDag-Erling Smørgrav #include "groupaccess.h"
67462c32cbSDag-Erling Smørgrav #include "canohost.h"
68462c32cbSDag-Erling Smørgrav #include "packet.h"
69190cef3dSDag-Erling Smørgrav #include "ssherr.h"
706888a9beSDag-Erling Smørgrav #include "hostfile.h"
716888a9beSDag-Erling Smørgrav #include "auth.h"
72bc5531deSDag-Erling Smørgrav #include "myproposal.h"
73bc5531deSDag-Erling Smørgrav #include "digest.h"
74b15c8340SDag-Erling Smørgrav #include "version.h"
75511b41d2SMark Murray 
7647dd1d1bSDag-Erling Smørgrav static void add_listen_addr(ServerOptions *, const char *,
7747dd1d1bSDag-Erling Smørgrav     const char *, int);
7847dd1d1bSDag-Erling Smørgrav static void add_one_listen_addr(ServerOptions *, const char *,
7947dd1d1bSDag-Erling Smørgrav     const char *, int);
8019261079SEd Maste static void parse_server_config_depth(ServerOptions *options,
8119261079SEd Maste     const char *filename, struct sshbuf *conf, struct include_list *includes,
8219261079SEd Maste     struct connection_info *connectinfo, int flags, int *activep, int depth);
83ca3176e7SBrian Feldman 
8480628bacSDag-Erling Smørgrav /* Use of privilege separation or not */
8580628bacSDag-Erling Smørgrav extern int use_privsep;
86190cef3dSDag-Erling Smørgrav extern struct sshbuf *cfg;
87511b41d2SMark Murray 
88511b41d2SMark Murray /* Initializes the server options to their default values. */
89511b41d2SMark Murray 
90511b41d2SMark Murray void
91511b41d2SMark Murray initialize_server_options(ServerOptions *options)
92511b41d2SMark Murray {
93511b41d2SMark Murray 	memset(options, 0, sizeof(*options));
94989dd127SDag-Erling Smørgrav 
95989dd127SDag-Erling Smørgrav 	/* Portable-specific options */
96cf2b5f3bSDag-Erling Smørgrav 	options->use_pam = -1;
97989dd127SDag-Erling Smørgrav 
98989dd127SDag-Erling Smørgrav 	/* Standard Options */
99511b41d2SMark Murray 	options->num_ports = 0;
100511b41d2SMark Murray 	options->ports_from_cmdline = 0;
101557f75e5SDag-Erling Smørgrav 	options->queued_listen_addrs = NULL;
102557f75e5SDag-Erling Smørgrav 	options->num_queued_listens = 0;
103511b41d2SMark Murray 	options->listen_addrs = NULL;
10447dd1d1bSDag-Erling Smørgrav 	options->num_listen_addrs = 0;
105aa49c926SDag-Erling Smørgrav 	options->address_family = -1;
10647dd1d1bSDag-Erling Smørgrav 	options->routing_domain = NULL;
107ca3176e7SBrian Feldman 	options->num_host_key_files = 0;
108b15c8340SDag-Erling Smørgrav 	options->num_host_cert_files = 0;
109e4a9863fSDag-Erling Smørgrav 	options->host_key_agent = NULL;
110e8aafc91SKris Kennaway 	options->pid_file = NULL;
111511b41d2SMark Murray 	options->login_grace_time = -1;
112ca3176e7SBrian Feldman 	options->permit_root_login = PERMIT_NOT_SET;
113511b41d2SMark Murray 	options->ignore_rhosts = -1;
114511b41d2SMark Murray 	options->ignore_user_known_hosts = -1;
115511b41d2SMark Murray 	options->print_motd = -1;
116ca3176e7SBrian Feldman 	options->print_lastlog = -1;
117511b41d2SMark Murray 	options->x11_forwarding = -1;
118511b41d2SMark Murray 	options->x11_display_offset = -1;
119af12a3e7SDag-Erling Smørgrav 	options->x11_use_localhost = -1;
120f7167e0eSDag-Erling Smørgrav 	options->permit_tty = -1;
121a0ee8cc6SDag-Erling Smørgrav 	options->permit_user_rc = -1;
122c2d3a559SKris Kennaway 	options->xauth_location = NULL;
123511b41d2SMark Murray 	options->strict_modes = -1;
1241ec0d754SDag-Erling Smørgrav 	options->tcp_keep_alive = -1;
125af12a3e7SDag-Erling Smørgrav 	options->log_facility = SYSLOG_FACILITY_NOT_SET;
126af12a3e7SDag-Erling Smørgrav 	options->log_level = SYSLOG_LEVEL_NOT_SET;
12719261079SEd Maste 	options->num_log_verbose = 0;
12819261079SEd Maste 	options->log_verbose = NULL;
129ca3176e7SBrian Feldman 	options->hostbased_authentication = -1;
130ca3176e7SBrian Feldman 	options->hostbased_uses_name_from_packet_only = -1;
13119261079SEd Maste 	options->hostbased_accepted_algos = NULL;
132eccfee6eSDag-Erling Smørgrav 	options->hostkeyalgorithms = NULL;
133ca3176e7SBrian Feldman 	options->pubkey_authentication = -1;
13419261079SEd Maste 	options->pubkey_auth_options = -1;
13519261079SEd Maste 	options->pubkey_accepted_algos = NULL;
136cb96ab36SAssar Westerlund 	options->kerberos_authentication = -1;
137af12a3e7SDag-Erling Smørgrav 	options->kerberos_or_local_passwd = -1;
138af12a3e7SDag-Erling Smørgrav 	options->kerberos_ticket_cleanup = -1;
1391ec0d754SDag-Erling Smørgrav 	options->kerberos_get_afs_token = -1;
140cf2b5f3bSDag-Erling Smørgrav 	options->gss_authentication=-1;
141cf2b5f3bSDag-Erling Smørgrav 	options->gss_cleanup_creds = -1;
142557f75e5SDag-Erling Smørgrav 	options->gss_strict_acceptor = -1;
143511b41d2SMark Murray 	options->password_authentication = -1;
14409958426SBrian Feldman 	options->kbd_interactive_authentication = -1;
145511b41d2SMark Murray 	options->permit_empty_passwd = -1;
146f388f5efSDag-Erling Smørgrav 	options->permit_user_env = -1;
14719261079SEd Maste 	options->permit_user_env_allowlist = NULL;
14880628bacSDag-Erling Smørgrav 	options->compression = -1;
149e4a9863fSDag-Erling Smørgrav 	options->rekey_limit = -1;
150e4a9863fSDag-Erling Smørgrav 	options->rekey_interval = -1;
15109958426SBrian Feldman 	options->allow_tcp_forwarding = -1;
152a0ee8cc6SDag-Erling Smørgrav 	options->allow_streamlocal_forwarding = -1;
153d4af9e69SDag-Erling Smørgrav 	options->allow_agent_forwarding = -1;
154511b41d2SMark Murray 	options->num_allow_users = 0;
155511b41d2SMark Murray 	options->num_deny_users = 0;
156511b41d2SMark Murray 	options->num_allow_groups = 0;
157511b41d2SMark Murray 	options->num_deny_groups = 0;
158e8aafc91SKris Kennaway 	options->ciphers = NULL;
159ca3176e7SBrian Feldman 	options->macs = NULL;
1604a421b63SDag-Erling Smørgrav 	options->kex_algorithms = NULL;
1612f513db7SEd Maste 	options->ca_sign_algorithms = NULL;
162a0ee8cc6SDag-Erling Smørgrav 	options->fwd_opts.gateway_ports = -1;
163a0ee8cc6SDag-Erling Smørgrav 	options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
164a0ee8cc6SDag-Erling Smørgrav 	options->fwd_opts.streamlocal_bind_unlink = -1;
165c2d3a559SKris Kennaway 	options->num_subsystems = 0;
166c2d3a559SKris Kennaway 	options->max_startups_begin = -1;
167c2d3a559SKris Kennaway 	options->max_startups_rate = -1;
168c2d3a559SKris Kennaway 	options->max_startups = -1;
16919261079SEd Maste 	options->per_source_max_startups = -1;
17019261079SEd Maste 	options->per_source_masklen_ipv4 = -1;
17119261079SEd Maste 	options->per_source_masklen_ipv6 = -1;
17221e764dfSDag-Erling Smørgrav 	options->max_authtries = -1;
173d4af9e69SDag-Erling Smørgrav 	options->max_sessions = -1;
174ca3176e7SBrian Feldman 	options->banner = NULL;
175cf2b5f3bSDag-Erling Smørgrav 	options->use_dns = -1;
176ca3176e7SBrian Feldman 	options->client_alive_interval = -1;
177ca3176e7SBrian Feldman 	options->client_alive_count_max = -1;
178e146993eSDag-Erling Smørgrav 	options->num_authkeys_files = 0;
17921e764dfSDag-Erling Smørgrav 	options->num_accept_env = 0;
180190cef3dSDag-Erling Smørgrav 	options->num_setenv = 0;
181b74df5b2SDag-Erling Smørgrav 	options->permit_tun = -1;
1824f52dfbbSDag-Erling Smørgrav 	options->permitted_opens = NULL;
183190cef3dSDag-Erling Smørgrav 	options->permitted_listens = NULL;
184333ee039SDag-Erling Smørgrav 	options->adm_forced_command = NULL;
185d4af9e69SDag-Erling Smørgrav 	options->chroot_directory = NULL;
1866888a9beSDag-Erling Smørgrav 	options->authorized_keys_command = NULL;
1876888a9beSDag-Erling Smørgrav 	options->authorized_keys_command_user = NULL;
188b15c8340SDag-Erling Smørgrav 	options->revoked_keys_file = NULL;
18919261079SEd Maste 	options->sk_provider = NULL;
190b15c8340SDag-Erling Smørgrav 	options->trusted_user_ca_keys = NULL;
191e2f6069cSDag-Erling Smørgrav 	options->authorized_principals_file = NULL;
192557f75e5SDag-Erling Smørgrav 	options->authorized_principals_command = NULL;
193557f75e5SDag-Erling Smørgrav 	options->authorized_principals_command_user = NULL;
1944a421b63SDag-Erling Smørgrav 	options->ip_qos_interactive = -1;
1954a421b63SDag-Erling Smørgrav 	options->ip_qos_bulk = -1;
196462c32cbSDag-Erling Smørgrav 	options->version_addendum = NULL;
197bc5531deSDag-Erling Smørgrav 	options->fingerprint_hash = -1;
198ca86bcf2SDag-Erling Smørgrav 	options->disable_forwarding = -1;
1994f52dfbbSDag-Erling Smørgrav 	options->expose_userauth_info = -1;
200b2af61ecSKurt Lidl 	options->use_blacklist = -1;
201bc5531deSDag-Erling Smørgrav }
202bc5531deSDag-Erling Smørgrav 
203bc5531deSDag-Erling Smørgrav /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
204bc5531deSDag-Erling Smørgrav static int
205bc5531deSDag-Erling Smørgrav option_clear_or_none(const char *o)
206bc5531deSDag-Erling Smørgrav {
207bc5531deSDag-Erling Smørgrav 	return o == NULL || strcasecmp(o, "none") == 0;
208511b41d2SMark Murray }
209511b41d2SMark Murray 
210acc1a9efSDag-Erling Smørgrav static void
211acc1a9efSDag-Erling Smørgrav assemble_algorithms(ServerOptions *o)
212acc1a9efSDag-Erling Smørgrav {
2132f513db7SEd Maste 	char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
21419261079SEd Maste 	char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig;
215190cef3dSDag-Erling Smørgrav 	int r;
216190cef3dSDag-Erling Smørgrav 
217190cef3dSDag-Erling Smørgrav 	all_cipher = cipher_alg_list(',', 0);
218190cef3dSDag-Erling Smørgrav 	all_mac = mac_alg_list(',');
219190cef3dSDag-Erling Smørgrav 	all_kex = kex_alg_list(',');
220190cef3dSDag-Erling Smørgrav 	all_key = sshkey_alg_list(0, 0, 1, ',');
2212f513db7SEd Maste 	all_sig = sshkey_alg_list(0, 1, 1, ',');
22219261079SEd Maste 	/* remove unsupported algos from default lists */
22319261079SEd Maste 	def_cipher = match_filter_allowlist(KEX_SERVER_ENCRYPT, all_cipher);
22419261079SEd Maste 	def_mac = match_filter_allowlist(KEX_SERVER_MAC, all_mac);
22519261079SEd Maste 	def_kex = match_filter_allowlist(KEX_SERVER_KEX, all_kex);
22619261079SEd Maste 	def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
22719261079SEd Maste 	def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig);
228190cef3dSDag-Erling Smørgrav #define ASSEMBLE(what, defaults, all) \
229190cef3dSDag-Erling Smørgrav 	do { \
230190cef3dSDag-Erling Smørgrav 		if ((r = kex_assemble_names(&o->what, defaults, all)) != 0) \
23119261079SEd Maste 			fatal_fr(r, "%s", #what); \
232190cef3dSDag-Erling Smørgrav 	} while (0)
23319261079SEd Maste 	ASSEMBLE(ciphers, def_cipher, all_cipher);
23419261079SEd Maste 	ASSEMBLE(macs, def_mac, all_mac);
23519261079SEd Maste 	ASSEMBLE(kex_algorithms, def_kex, all_kex);
23619261079SEd Maste 	ASSEMBLE(hostkeyalgorithms, def_key, all_key);
23719261079SEd Maste 	ASSEMBLE(hostbased_accepted_algos, def_key, all_key);
23819261079SEd Maste 	ASSEMBLE(pubkey_accepted_algos, def_key, all_key);
23919261079SEd Maste 	ASSEMBLE(ca_sign_algorithms, def_sig, all_sig);
240190cef3dSDag-Erling Smørgrav #undef ASSEMBLE
241190cef3dSDag-Erling Smørgrav 	free(all_cipher);
242190cef3dSDag-Erling Smørgrav 	free(all_mac);
243190cef3dSDag-Erling Smørgrav 	free(all_kex);
244190cef3dSDag-Erling Smørgrav 	free(all_key);
2452f513db7SEd Maste 	free(all_sig);
24619261079SEd Maste 	free(def_cipher);
24719261079SEd Maste 	free(def_mac);
24819261079SEd Maste 	free(def_kex);
24919261079SEd Maste 	free(def_key);
25019261079SEd Maste 	free(def_sig);
25147dd1d1bSDag-Erling Smørgrav }
25247dd1d1bSDag-Erling Smørgrav 
25347dd1d1bSDag-Erling Smørgrav static const char *defaultkey = "[default]";
25447dd1d1bSDag-Erling Smørgrav 
25547dd1d1bSDag-Erling Smørgrav void
25647dd1d1bSDag-Erling Smørgrav servconf_add_hostkey(const char *file, const int line,
25719261079SEd Maste     ServerOptions *options, const char *path, int userprovided)
25847dd1d1bSDag-Erling Smørgrav {
25947dd1d1bSDag-Erling Smørgrav 	char *apath = derelativise_path(path);
26047dd1d1bSDag-Erling Smørgrav 
26147dd1d1bSDag-Erling Smørgrav 	if (file == defaultkey && access(path, R_OK) != 0)
26247dd1d1bSDag-Erling Smørgrav 		return;
26319261079SEd Maste 	opt_array_append2(file, line, "HostKey",
26419261079SEd Maste 	    &options->host_key_files, &options->host_key_file_userprovided,
26519261079SEd Maste 	    &options->num_host_key_files, apath, userprovided);
26647dd1d1bSDag-Erling Smørgrav 	free(apath);
26747dd1d1bSDag-Erling Smørgrav }
26847dd1d1bSDag-Erling Smørgrav 
26947dd1d1bSDag-Erling Smørgrav void
27047dd1d1bSDag-Erling Smørgrav servconf_add_hostcert(const char *file, const int line,
27147dd1d1bSDag-Erling Smørgrav     ServerOptions *options, const char *path)
27247dd1d1bSDag-Erling Smørgrav {
27347dd1d1bSDag-Erling Smørgrav 	char *apath = derelativise_path(path);
27447dd1d1bSDag-Erling Smørgrav 
27519261079SEd Maste 	opt_array_append(file, line, "HostCertificate",
27647dd1d1bSDag-Erling Smørgrav 	    &options->host_cert_files, &options->num_host_cert_files, apath);
27747dd1d1bSDag-Erling Smørgrav 	free(apath);
27847dd1d1bSDag-Erling Smørgrav }
27947dd1d1bSDag-Erling Smørgrav 
280511b41d2SMark Murray void
281511b41d2SMark Murray fill_default_server_options(ServerOptions *options)
282511b41d2SMark Murray {
28347dd1d1bSDag-Erling Smørgrav 	u_int i;
284bc5531deSDag-Erling Smørgrav 
285989dd127SDag-Erling Smørgrav 	/* Portable-specific options */
286cf2b5f3bSDag-Erling Smørgrav 	if (options->use_pam == -1)
287f0477b26SDag-Erling Smørgrav 		options->use_pam = 1;
288989dd127SDag-Erling Smørgrav 
289989dd127SDag-Erling Smørgrav 	/* Standard Options */
290ca3176e7SBrian Feldman 	if (options->num_host_key_files == 0) {
291ca3176e7SBrian Feldman 		/* fill default hostkeys for protocols */
29247dd1d1bSDag-Erling Smørgrav 		servconf_add_hostkey(defaultkey, 0, options,
29319261079SEd Maste 		    _PATH_HOST_RSA_KEY_FILE, 0);
2944a421b63SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC
29547dd1d1bSDag-Erling Smørgrav 		servconf_add_hostkey(defaultkey, 0, options,
29619261079SEd Maste 		    _PATH_HOST_ECDSA_KEY_FILE, 0);
2974a421b63SDag-Erling Smørgrav #endif
29847dd1d1bSDag-Erling Smørgrav 		servconf_add_hostkey(defaultkey, 0, options,
29919261079SEd Maste 		    _PATH_HOST_ED25519_KEY_FILE, 0);
30047dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
30147dd1d1bSDag-Erling Smørgrav 		servconf_add_hostkey(defaultkey, 0, options,
30219261079SEd Maste 		    _PATH_HOST_XMSS_KEY_FILE, 0);
30347dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
304af12a3e7SDag-Erling Smørgrav 	}
305144a80bdSDag-Erling Smørgrav 	if (options->num_host_key_files == 0)
306144a80bdSDag-Erling Smørgrav 		fatal("No host key files found");
307b15c8340SDag-Erling Smørgrav 	/* No certificates by default */
308511b41d2SMark Murray 	if (options->num_ports == 0)
309511b41d2SMark Murray 		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
310557f75e5SDag-Erling Smørgrav 	if (options->address_family == -1)
311557f75e5SDag-Erling Smørgrav 		options->address_family = AF_UNSPEC;
312511b41d2SMark Murray 	if (options->listen_addrs == NULL)
31347dd1d1bSDag-Erling Smørgrav 		add_listen_addr(options, NULL, NULL, 0);
314e8aafc91SKris Kennaway 	if (options->pid_file == NULL)
315bc5531deSDag-Erling Smørgrav 		options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE);
31619261079SEd Maste 	if (options->moduli_file == NULL)
31719261079SEd Maste 		options->moduli_file = xstrdup(_PATH_DH_MODULI);
318511b41d2SMark Murray 	if (options->login_grace_time == -1)
319975616f0SDag-Erling Smørgrav 		options->login_grace_time = 120;
320ca3176e7SBrian Feldman 	if (options->permit_root_login == PERMIT_NOT_SET)
321975616f0SDag-Erling Smørgrav 		options->permit_root_login = PERMIT_NO;
322511b41d2SMark Murray 	if (options->ignore_rhosts == -1)
323fe5fd017SMark Murray 		options->ignore_rhosts = 1;
324511b41d2SMark Murray 	if (options->ignore_user_known_hosts == -1)
325511b41d2SMark Murray 		options->ignore_user_known_hosts = 0;
326511b41d2SMark Murray 	if (options->print_motd == -1)
327511b41d2SMark Murray 		options->print_motd = 1;
328ca3176e7SBrian Feldman 	if (options->print_lastlog == -1)
329ca3176e7SBrian Feldman 		options->print_lastlog = 1;
330511b41d2SMark Murray 	if (options->x11_forwarding == -1)
331975616f0SDag-Erling Smørgrav 		options->x11_forwarding = 1;
332511b41d2SMark Murray 	if (options->x11_display_offset == -1)
333fe5fd017SMark Murray 		options->x11_display_offset = 10;
334af12a3e7SDag-Erling Smørgrav 	if (options->x11_use_localhost == -1)
335af12a3e7SDag-Erling Smørgrav 		options->x11_use_localhost = 1;
336c2d3a559SKris Kennaway 	if (options->xauth_location == NULL)
337bc5531deSDag-Erling Smørgrav 		options->xauth_location = xstrdup(_PATH_XAUTH);
338f7167e0eSDag-Erling Smørgrav 	if (options->permit_tty == -1)
339f7167e0eSDag-Erling Smørgrav 		options->permit_tty = 1;
340a0ee8cc6SDag-Erling Smørgrav 	if (options->permit_user_rc == -1)
341a0ee8cc6SDag-Erling Smørgrav 		options->permit_user_rc = 1;
342511b41d2SMark Murray 	if (options->strict_modes == -1)
343511b41d2SMark Murray 		options->strict_modes = 1;
3441ec0d754SDag-Erling Smørgrav 	if (options->tcp_keep_alive == -1)
3451ec0d754SDag-Erling Smørgrav 		options->tcp_keep_alive = 1;
346af12a3e7SDag-Erling Smørgrav 	if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
347511b41d2SMark Murray 		options->log_facility = SYSLOG_FACILITY_AUTH;
348af12a3e7SDag-Erling Smørgrav 	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
349511b41d2SMark Murray 		options->log_level = SYSLOG_LEVEL_INFO;
350ca3176e7SBrian Feldman 	if (options->hostbased_authentication == -1)
351ca3176e7SBrian Feldman 		options->hostbased_authentication = 0;
352ca3176e7SBrian Feldman 	if (options->hostbased_uses_name_from_packet_only == -1)
353ca3176e7SBrian Feldman 		options->hostbased_uses_name_from_packet_only = 0;
354ca3176e7SBrian Feldman 	if (options->pubkey_authentication == -1)
355ca3176e7SBrian Feldman 		options->pubkey_authentication = 1;
35619261079SEd Maste 	if (options->pubkey_auth_options == -1)
35719261079SEd Maste 		options->pubkey_auth_options = 0;
358989dd127SDag-Erling Smørgrav 	if (options->kerberos_authentication == -1)
359cf2b5f3bSDag-Erling Smørgrav 		options->kerberos_authentication = 0;
360af12a3e7SDag-Erling Smørgrav 	if (options->kerberos_or_local_passwd == -1)
361af12a3e7SDag-Erling Smørgrav 		options->kerberos_or_local_passwd = 1;
362af12a3e7SDag-Erling Smørgrav 	if (options->kerberos_ticket_cleanup == -1)
363af12a3e7SDag-Erling Smørgrav 		options->kerberos_ticket_cleanup = 1;
3641ec0d754SDag-Erling Smørgrav 	if (options->kerberos_get_afs_token == -1)
3651ec0d754SDag-Erling Smørgrav 		options->kerberos_get_afs_token = 0;
366cf2b5f3bSDag-Erling Smørgrav 	if (options->gss_authentication == -1)
367cf2b5f3bSDag-Erling Smørgrav 		options->gss_authentication = 0;
368cf2b5f3bSDag-Erling Smørgrav 	if (options->gss_cleanup_creds == -1)
369cf2b5f3bSDag-Erling Smørgrav 		options->gss_cleanup_creds = 1;
370557f75e5SDag-Erling Smørgrav 	if (options->gss_strict_acceptor == -1)
371d93a896eSDag-Erling Smørgrav 		options->gss_strict_acceptor = 1;
372511b41d2SMark Murray 	if (options->password_authentication == -1)
373b909c84bSDag-Erling Smørgrav 		options->password_authentication = 0;
37409958426SBrian Feldman 	if (options->kbd_interactive_authentication == -1)
37519261079SEd Maste 		options->kbd_interactive_authentication = 1;
376511b41d2SMark Murray 	if (options->permit_empty_passwd == -1)
377fe5fd017SMark Murray 		options->permit_empty_passwd = 0;
378190cef3dSDag-Erling Smørgrav 	if (options->permit_user_env == -1) {
379f388f5efSDag-Erling Smørgrav 		options->permit_user_env = 0;
38019261079SEd Maste 		options->permit_user_env_allowlist = NULL;
381190cef3dSDag-Erling Smørgrav 	}
38280628bacSDag-Erling Smørgrav 	if (options->compression == -1)
38319261079SEd Maste #ifdef WITH_ZLIB
384d4ecd108SDag-Erling Smørgrav 		options->compression = COMP_DELAYED;
38519261079SEd Maste #else
38619261079SEd Maste 		options->compression = COMP_NONE;
38719261079SEd Maste #endif
38819261079SEd Maste 
389e4a9863fSDag-Erling Smørgrav 	if (options->rekey_limit == -1)
390e4a9863fSDag-Erling Smørgrav 		options->rekey_limit = 0;
391e4a9863fSDag-Erling Smørgrav 	if (options->rekey_interval == -1)
392e4a9863fSDag-Erling Smørgrav 		options->rekey_interval = 0;
39309958426SBrian Feldman 	if (options->allow_tcp_forwarding == -1)
3946888a9beSDag-Erling Smørgrav 		options->allow_tcp_forwarding = FORWARD_ALLOW;
395a0ee8cc6SDag-Erling Smørgrav 	if (options->allow_streamlocal_forwarding == -1)
396a0ee8cc6SDag-Erling Smørgrav 		options->allow_streamlocal_forwarding = FORWARD_ALLOW;
397d4af9e69SDag-Erling Smørgrav 	if (options->allow_agent_forwarding == -1)
398d4af9e69SDag-Erling Smørgrav 		options->allow_agent_forwarding = 1;
399a0ee8cc6SDag-Erling Smørgrav 	if (options->fwd_opts.gateway_ports == -1)
400a0ee8cc6SDag-Erling Smørgrav 		options->fwd_opts.gateway_ports = 0;
401c2d3a559SKris Kennaway 	if (options->max_startups == -1)
4026888a9beSDag-Erling Smørgrav 		options->max_startups = 100;
403c2d3a559SKris Kennaway 	if (options->max_startups_rate == -1)
4046888a9beSDag-Erling Smørgrav 		options->max_startups_rate = 30;		/* 30% */
405c2d3a559SKris Kennaway 	if (options->max_startups_begin == -1)
4066888a9beSDag-Erling Smørgrav 		options->max_startups_begin = 10;
40719261079SEd Maste 	if (options->per_source_max_startups == -1)
40819261079SEd Maste 		options->per_source_max_startups = INT_MAX;
40919261079SEd Maste 	if (options->per_source_masklen_ipv4 == -1)
41019261079SEd Maste 		options->per_source_masklen_ipv4 = 32;
41119261079SEd Maste 	if (options->per_source_masklen_ipv6 == -1)
41219261079SEd Maste 		options->per_source_masklen_ipv6 = 128;
41321e764dfSDag-Erling Smørgrav 	if (options->max_authtries == -1)
41421e764dfSDag-Erling Smørgrav 		options->max_authtries = DEFAULT_AUTH_FAIL_MAX;
415d4af9e69SDag-Erling Smørgrav 	if (options->max_sessions == -1)
416d4af9e69SDag-Erling Smørgrav 		options->max_sessions = DEFAULT_SESSIONS_MAX;
417cf2b5f3bSDag-Erling Smørgrav 	if (options->use_dns == -1)
418c4cd1fa4SDag-Erling Smørgrav 		options->use_dns = 1;
419ca3176e7SBrian Feldman 	if (options->client_alive_interval == -1)
420ca3176e7SBrian Feldman 		options->client_alive_interval = 0;
421ca3176e7SBrian Feldman 	if (options->client_alive_count_max == -1)
422ca3176e7SBrian Feldman 		options->client_alive_count_max = 3;
423e146993eSDag-Erling Smørgrav 	if (options->num_authkeys_files == 0) {
42419261079SEd Maste 		opt_array_append(defaultkey, 0, "AuthorizedKeysFiles",
42547dd1d1bSDag-Erling Smørgrav 		    &options->authorized_keys_files,
42647dd1d1bSDag-Erling Smørgrav 		    &options->num_authkeys_files,
42747dd1d1bSDag-Erling Smørgrav 		    _PATH_SSH_USER_PERMITTED_KEYS);
42819261079SEd Maste 		opt_array_append(defaultkey, 0, "AuthorizedKeysFiles",
42947dd1d1bSDag-Erling Smørgrav 		    &options->authorized_keys_files,
43047dd1d1bSDag-Erling Smørgrav 		    &options->num_authkeys_files,
43147dd1d1bSDag-Erling Smørgrav 		    _PATH_SSH_USER_PERMITTED_KEYS2);
432af12a3e7SDag-Erling Smørgrav 	}
433b74df5b2SDag-Erling Smørgrav 	if (options->permit_tun == -1)
434b74df5b2SDag-Erling Smørgrav 		options->permit_tun = SSH_TUNMODE_NO;
4354a421b63SDag-Erling Smørgrav 	if (options->ip_qos_interactive == -1)
436190cef3dSDag-Erling Smørgrav 		options->ip_qos_interactive = IPTOS_DSCP_AF21;
4374a421b63SDag-Erling Smørgrav 	if (options->ip_qos_bulk == -1)
438190cef3dSDag-Erling Smørgrav 		options->ip_qos_bulk = IPTOS_DSCP_CS1;
439462c32cbSDag-Erling Smørgrav 	if (options->version_addendum == NULL)
440462c32cbSDag-Erling Smørgrav 		options->version_addendum = xstrdup(SSH_VERSION_FREEBSD);
441a0ee8cc6SDag-Erling Smørgrav 	if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
442a0ee8cc6SDag-Erling Smørgrav 		options->fwd_opts.streamlocal_bind_mask = 0177;
443a0ee8cc6SDag-Erling Smørgrav 	if (options->fwd_opts.streamlocal_bind_unlink == -1)
444a0ee8cc6SDag-Erling Smørgrav 		options->fwd_opts.streamlocal_bind_unlink = 0;
445bc5531deSDag-Erling Smørgrav 	if (options->fingerprint_hash == -1)
446bc5531deSDag-Erling Smørgrav 		options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
447ca86bcf2SDag-Erling Smørgrav 	if (options->disable_forwarding == -1)
448ca86bcf2SDag-Erling Smørgrav 		options->disable_forwarding = 0;
4494f52dfbbSDag-Erling Smørgrav 	if (options->expose_userauth_info == -1)
4504f52dfbbSDag-Erling Smørgrav 		options->expose_userauth_info = 0;
45119261079SEd Maste 	if (options->sk_provider == NULL)
45219261079SEd Maste 		options->sk_provider = xstrdup("internal");
453b2af61ecSKurt Lidl 	if (options->use_blacklist == -1)
454b2af61ecSKurt Lidl 		options->use_blacklist = 0;
455eccfee6eSDag-Erling Smørgrav 
456acc1a9efSDag-Erling Smørgrav 	assemble_algorithms(options);
457eccfee6eSDag-Erling Smørgrav 
458acc1a9efSDag-Erling Smørgrav 	/* Turn privilege separation and sandboxing on by default */
459462c32cbSDag-Erling Smørgrav 	if (use_privsep == -1)
4602b1970f3SDag-Erling Smørgrav 		use_privsep = PRIVSEP_ON;
461462c32cbSDag-Erling Smørgrav 
462bc5531deSDag-Erling Smørgrav #define CLEAR_ON_NONE(v) \
463bc5531deSDag-Erling Smørgrav 	do { \
464bc5531deSDag-Erling Smørgrav 		if (option_clear_or_none(v)) { \
465bc5531deSDag-Erling Smørgrav 			free(v); \
466bc5531deSDag-Erling Smørgrav 			v = NULL; \
467bc5531deSDag-Erling Smørgrav 		} \
468bc5531deSDag-Erling Smørgrav 	} while(0)
469bc5531deSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->pid_file);
470bc5531deSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->xauth_location);
471bc5531deSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->banner);
472bc5531deSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->trusted_user_ca_keys);
473bc5531deSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->revoked_keys_file);
47419261079SEd Maste 	CLEAR_ON_NONE(options->sk_provider);
475557f75e5SDag-Erling Smørgrav 	CLEAR_ON_NONE(options->authorized_principals_file);
476acc1a9efSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->adm_forced_command);
477acc1a9efSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->chroot_directory);
47847dd1d1bSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->routing_domain);
47919261079SEd Maste 	CLEAR_ON_NONE(options->host_key_agent);
480bc5531deSDag-Erling Smørgrav 	for (i = 0; i < options->num_host_key_files; i++)
481bc5531deSDag-Erling Smørgrav 		CLEAR_ON_NONE(options->host_key_files[i]);
482bc5531deSDag-Erling Smørgrav 	for (i = 0; i < options->num_host_cert_files; i++)
483bc5531deSDag-Erling Smørgrav 		CLEAR_ON_NONE(options->host_cert_files[i]);
484bc5531deSDag-Erling Smørgrav #undef CLEAR_ON_NONE
485bc5531deSDag-Erling Smørgrav 
486076ad2f8SDag-Erling Smørgrav 	/* Similar handling for AuthenticationMethods=any */
487076ad2f8SDag-Erling Smørgrav 	if (options->num_auth_methods == 1 &&
488076ad2f8SDag-Erling Smørgrav 	    strcmp(options->auth_methods[0], "any") == 0) {
489076ad2f8SDag-Erling Smørgrav 		free(options->auth_methods[0]);
490076ad2f8SDag-Erling Smørgrav 		options->auth_methods[0] = NULL;
491076ad2f8SDag-Erling Smørgrav 		options->num_auth_methods = 0;
492076ad2f8SDag-Erling Smørgrav 	}
493511b41d2SMark Murray }
494511b41d2SMark Murray 
495511b41d2SMark Murray /* Keyword tokens. */
496511b41d2SMark Murray typedef enum {
497511b41d2SMark Murray 	sBadOption,		/* == unknown option */
498989dd127SDag-Erling Smørgrav 	/* Portable-specific options */
499cf2b5f3bSDag-Erling Smørgrav 	sUsePAM,
500989dd127SDag-Erling Smørgrav 	/* Standard Options */
501ca86bcf2SDag-Erling Smørgrav 	sPort, sHostKeyFile, sLoginGraceTime,
50219261079SEd Maste 	sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose,
503af12a3e7SDag-Erling Smørgrav 	sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
504e9e8876aSEd Maste 	sKerberosGetAFSToken, sPasswordAuthentication,
505e9e8876aSEd Maste 	sKbdInteractiveAuthentication, sListenAddress, sAddressFamily,
506ca3176e7SBrian Feldman 	sPrintMotd, sPrintLastLog, sIgnoreRhosts,
507af12a3e7SDag-Erling Smørgrav 	sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
508f7167e0eSDag-Erling Smørgrav 	sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive,
509ca86bcf2SDag-Erling Smørgrav 	sPermitUserEnvironment, sAllowTcpForwarding, sCompression,
510e4a9863fSDag-Erling Smørgrav 	sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
51119261079SEd Maste 	sIgnoreUserKnownHosts, sCiphers, sMacs, sPidFile, sModuliFile,
51219261079SEd Maste 	sGatewayPorts, sPubkeyAuthentication, sPubkeyAcceptedAlgorithms,
513bc5531deSDag-Erling Smørgrav 	sXAuthLocation, sSubsystem, sMaxStartups, sMaxAuthTries, sMaxSessions,
514cf2b5f3bSDag-Erling Smørgrav 	sBanner, sUseDNS, sHostbasedAuthentication,
51519261079SEd Maste 	sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedAlgorithms,
51619261079SEd Maste 	sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize,
517bc5531deSDag-Erling Smørgrav 	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
518557f75e5SDag-Erling Smørgrav 	sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
519190cef3dSDag-Erling Smørgrav 	sAcceptEnv, sSetEnv, sPermitTunnel,
520190cef3dSDag-Erling Smørgrav 	sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory,
521d4af9e69SDag-Erling Smørgrav 	sUsePrivilegeSeparation, sAllowAgentForwarding,
52219261079SEd Maste 	sHostCertificate, sInclude,
523e2f6069cSDag-Erling Smørgrav 	sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
524557f75e5SDag-Erling Smørgrav 	sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser,
5252f513db7SEd Maste 	sKexAlgorithms, sCASignatureAlgorithms, sIPQoS, sVersionAddendum,
5266888a9beSDag-Erling Smørgrav 	sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
527a0ee8cc6SDag-Erling Smørgrav 	sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
528a0ee8cc6SDag-Erling Smørgrav 	sStreamLocalBindMask, sStreamLocalBindUnlink,
529ca86bcf2SDag-Erling Smørgrav 	sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
53019261079SEd Maste 	sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider,
531b2af61ecSKurt Lidl 	sUseBlacklist,
532ca86bcf2SDag-Erling Smørgrav 	sDeprecated, sIgnore, sUnsupported
533511b41d2SMark Murray } ServerOpCodes;
534511b41d2SMark Murray 
53519261079SEd Maste #define SSHCFG_GLOBAL		0x01	/* allowed in main section of config */
536333ee039SDag-Erling Smørgrav #define SSHCFG_MATCH		0x02	/* allowed inside a Match section */
537333ee039SDag-Erling Smørgrav #define SSHCFG_ALL		(SSHCFG_GLOBAL|SSHCFG_MATCH)
53819261079SEd Maste #define SSHCFG_NEVERMATCH	0x04  /* Match never matches; internal only */
53919261079SEd Maste #define SSHCFG_MATCH_ONLY	0x08  /* Match only in conditional blocks; internal only */
540333ee039SDag-Erling Smørgrav 
541511b41d2SMark Murray /* Textual representation of the tokens. */
542511b41d2SMark Murray static struct {
543511b41d2SMark Murray 	const char *name;
544511b41d2SMark Murray 	ServerOpCodes opcode;
545333ee039SDag-Erling Smørgrav 	u_int flags;
546511b41d2SMark Murray } keywords[] = {
547989dd127SDag-Erling Smørgrav 	/* Portable-specific options */
548cf2b5f3bSDag-Erling Smørgrav #ifdef USE_PAM
549333ee039SDag-Erling Smørgrav 	{ "usepam", sUsePAM, SSHCFG_GLOBAL },
550cf2b5f3bSDag-Erling Smørgrav #else
551333ee039SDag-Erling Smørgrav 	{ "usepam", sUnsupported, SSHCFG_GLOBAL },
552975616f0SDag-Erling Smørgrav #endif
553333ee039SDag-Erling Smørgrav 	{ "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
554989dd127SDag-Erling Smørgrav 	/* Standard Options */
555333ee039SDag-Erling Smørgrav 	{ "port", sPort, SSHCFG_GLOBAL },
556333ee039SDag-Erling Smørgrav 	{ "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
557333ee039SDag-Erling Smørgrav 	{ "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL },		/* alias */
558e4a9863fSDag-Erling Smørgrav 	{ "hostkeyagent", sHostKeyAgent, SSHCFG_GLOBAL },
559333ee039SDag-Erling Smørgrav 	{ "pidfile", sPidFile, SSHCFG_GLOBAL },
56019261079SEd Maste 	{ "modulifile", sModuliFile, SSHCFG_GLOBAL },
561ca86bcf2SDag-Erling Smørgrav 	{ "serverkeybits", sDeprecated, SSHCFG_GLOBAL },
562333ee039SDag-Erling Smørgrav 	{ "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL },
563ca86bcf2SDag-Erling Smørgrav 	{ "keyregenerationinterval", sDeprecated, SSHCFG_GLOBAL },
564d4af9e69SDag-Erling Smørgrav 	{ "permitrootlogin", sPermitRootLogin, SSHCFG_ALL },
565333ee039SDag-Erling Smørgrav 	{ "syslogfacility", sLogFacility, SSHCFG_GLOBAL },
5664f52dfbbSDag-Erling Smørgrav 	{ "loglevel", sLogLevel, SSHCFG_ALL },
56719261079SEd Maste 	{ "logverbose", sLogVerbose, SSHCFG_ALL },
568333ee039SDag-Erling Smørgrav 	{ "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL },
569ca86bcf2SDag-Erling Smørgrav 	{ "rhostsrsaauthentication", sDeprecated, SSHCFG_ALL },
570d4af9e69SDag-Erling Smørgrav 	{ "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL },
571e2f6069cSDag-Erling Smørgrav 	{ "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_ALL },
57219261079SEd Maste 	{ "hostbasedacceptedalgorithms", sHostbasedAcceptedAlgorithms, SSHCFG_ALL },
57319261079SEd Maste 	{ "hostbasedacceptedkeytypes", sHostbasedAcceptedAlgorithms, SSHCFG_ALL }, /* obsolete */
574eccfee6eSDag-Erling Smørgrav 	{ "hostkeyalgorithms", sHostKeyAlgorithms, SSHCFG_GLOBAL },
575ca86bcf2SDag-Erling Smørgrav 	{ "rsaauthentication", sDeprecated, SSHCFG_ALL },
576d4af9e69SDag-Erling Smørgrav 	{ "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL },
57719261079SEd Maste 	{ "pubkeyacceptedalgorithms", sPubkeyAcceptedAlgorithms, SSHCFG_ALL },
57819261079SEd Maste 	{ "pubkeyacceptedkeytypes", sPubkeyAcceptedAlgorithms, SSHCFG_ALL }, /* obsolete */
57919261079SEd Maste 	{ "pubkeyauthoptions", sPubkeyAuthOptions, SSHCFG_ALL },
580333ee039SDag-Erling Smørgrav 	{ "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */
581cf2b5f3bSDag-Erling Smørgrav #ifdef KRB5
582d4af9e69SDag-Erling Smørgrav 	{ "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL },
583333ee039SDag-Erling Smørgrav 	{ "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL },
584333ee039SDag-Erling Smørgrav 	{ "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL },
5851ec0d754SDag-Erling Smørgrav #ifdef USE_AFS
586333ee039SDag-Erling Smørgrav 	{ "kerberosgetafstoken", sKerberosGetAFSToken, SSHCFG_GLOBAL },
5871ec0d754SDag-Erling Smørgrav #else
588333ee039SDag-Erling Smørgrav 	{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
5891ec0d754SDag-Erling Smørgrav #endif
590cf2b5f3bSDag-Erling Smørgrav #else
591d4af9e69SDag-Erling Smørgrav 	{ "kerberosauthentication", sUnsupported, SSHCFG_ALL },
592333ee039SDag-Erling Smørgrav 	{ "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
593333ee039SDag-Erling Smørgrav 	{ "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
594333ee039SDag-Erling Smørgrav 	{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
595cb96ab36SAssar Westerlund #endif
596333ee039SDag-Erling Smørgrav 	{ "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
597333ee039SDag-Erling Smørgrav 	{ "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
598cf2b5f3bSDag-Erling Smørgrav #ifdef GSSAPI
599d4af9e69SDag-Erling Smørgrav 	{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
600333ee039SDag-Erling Smørgrav 	{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
601557f75e5SDag-Erling Smørgrav 	{ "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
602cf2b5f3bSDag-Erling Smørgrav #else
603d4af9e69SDag-Erling Smørgrav 	{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
604333ee039SDag-Erling Smørgrav 	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
605557f75e5SDag-Erling Smørgrav 	{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
606511b41d2SMark Murray #endif
607d4af9e69SDag-Erling Smørgrav 	{ "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
608d4af9e69SDag-Erling Smørgrav 	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
60919261079SEd Maste 	{ "challengeresponseauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */
61019261079SEd Maste 	{ "skeyauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */
611333ee039SDag-Erling Smørgrav 	{ "checkmail", sDeprecated, SSHCFG_GLOBAL },
612333ee039SDag-Erling Smørgrav 	{ "listenaddress", sListenAddress, SSHCFG_GLOBAL },
613333ee039SDag-Erling Smørgrav 	{ "addressfamily", sAddressFamily, SSHCFG_GLOBAL },
614333ee039SDag-Erling Smørgrav 	{ "printmotd", sPrintMotd, SSHCFG_GLOBAL },
615acc1a9efSDag-Erling Smørgrav #ifdef DISABLE_LASTLOG
616acc1a9efSDag-Erling Smørgrav 	{ "printlastlog", sUnsupported, SSHCFG_GLOBAL },
617acc1a9efSDag-Erling Smørgrav #else
618333ee039SDag-Erling Smørgrav 	{ "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
619acc1a9efSDag-Erling Smørgrav #endif
62019261079SEd Maste 	{ "ignorerhosts", sIgnoreRhosts, SSHCFG_ALL },
621333ee039SDag-Erling Smørgrav 	{ "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
622333ee039SDag-Erling Smørgrav 	{ "x11forwarding", sX11Forwarding, SSHCFG_ALL },
623333ee039SDag-Erling Smørgrav 	{ "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
624333ee039SDag-Erling Smørgrav 	{ "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
625333ee039SDag-Erling Smørgrav 	{ "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
626333ee039SDag-Erling Smørgrav 	{ "strictmodes", sStrictModes, SSHCFG_GLOBAL },
627cce7d346SDag-Erling Smørgrav 	{ "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL },
628333ee039SDag-Erling Smørgrav 	{ "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
629ca86bcf2SDag-Erling Smørgrav 	{ "uselogin", sDeprecated, SSHCFG_GLOBAL },
630333ee039SDag-Erling Smørgrav 	{ "compression", sCompression, SSHCFG_GLOBAL },
631e4a9863fSDag-Erling Smørgrav 	{ "rekeylimit", sRekeyLimit, SSHCFG_ALL },
632333ee039SDag-Erling Smørgrav 	{ "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
633333ee039SDag-Erling Smørgrav 	{ "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL },	/* obsolete alias */
634333ee039SDag-Erling Smørgrav 	{ "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
635d4af9e69SDag-Erling Smørgrav 	{ "allowagentforwarding", sAllowAgentForwarding, SSHCFG_ALL },
636462c32cbSDag-Erling Smørgrav 	{ "allowusers", sAllowUsers, SSHCFG_ALL },
637462c32cbSDag-Erling Smørgrav 	{ "denyusers", sDenyUsers, SSHCFG_ALL },
638462c32cbSDag-Erling Smørgrav 	{ "allowgroups", sAllowGroups, SSHCFG_ALL },
639462c32cbSDag-Erling Smørgrav 	{ "denygroups", sDenyGroups, SSHCFG_ALL },
640333ee039SDag-Erling Smørgrav 	{ "ciphers", sCiphers, SSHCFG_GLOBAL },
641333ee039SDag-Erling Smørgrav 	{ "macs", sMacs, SSHCFG_GLOBAL },
642ca86bcf2SDag-Erling Smørgrav 	{ "protocol", sIgnore, SSHCFG_GLOBAL },
643333ee039SDag-Erling Smørgrav 	{ "gatewayports", sGatewayPorts, SSHCFG_ALL },
644333ee039SDag-Erling Smørgrav 	{ "subsystem", sSubsystem, SSHCFG_GLOBAL },
645333ee039SDag-Erling Smørgrav 	{ "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
64619261079SEd Maste 	{ "persourcemaxstartups", sPerSourceMaxStartups, SSHCFG_GLOBAL },
64719261079SEd Maste 	{ "persourcenetblocksize", sPerSourceNetBlockSize, SSHCFG_GLOBAL },
648d4af9e69SDag-Erling Smørgrav 	{ "maxauthtries", sMaxAuthTries, SSHCFG_ALL },
649d4af9e69SDag-Erling Smørgrav 	{ "maxsessions", sMaxSessions, SSHCFG_ALL },
650d4af9e69SDag-Erling Smørgrav 	{ "banner", sBanner, SSHCFG_ALL },
651333ee039SDag-Erling Smørgrav 	{ "usedns", sUseDNS, SSHCFG_GLOBAL },
652333ee039SDag-Erling Smørgrav 	{ "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
653333ee039SDag-Erling Smørgrav 	{ "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL },
654ca86bcf2SDag-Erling Smørgrav 	{ "clientaliveinterval", sClientAliveInterval, SSHCFG_ALL },
655ca86bcf2SDag-Erling Smørgrav 	{ "clientalivecountmax", sClientAliveCountMax, SSHCFG_ALL },
656e2f6069cSDag-Erling Smørgrav 	{ "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_ALL },
657e146993eSDag-Erling Smørgrav 	{ "authorizedkeysfile2", sDeprecated, SSHCFG_ALL },
658d93a896eSDag-Erling Smørgrav 	{ "useprivilegeseparation", sDeprecated, SSHCFG_GLOBAL},
659462c32cbSDag-Erling Smørgrav 	{ "acceptenv", sAcceptEnv, SSHCFG_ALL },
660190cef3dSDag-Erling Smørgrav 	{ "setenv", sSetEnv, SSHCFG_ALL },
661e2f6069cSDag-Erling Smørgrav 	{ "permittunnel", sPermitTunnel, SSHCFG_ALL },
662f7167e0eSDag-Erling Smørgrav 	{ "permittty", sPermitTTY, SSHCFG_ALL },
663a0ee8cc6SDag-Erling Smørgrav 	{ "permituserrc", sPermitUserRC, SSHCFG_ALL },
664333ee039SDag-Erling Smørgrav 	{ "match", sMatch, SSHCFG_ALL },
665333ee039SDag-Erling Smørgrav 	{ "permitopen", sPermitOpen, SSHCFG_ALL },
666190cef3dSDag-Erling Smørgrav 	{ "permitlisten", sPermitListen, SSHCFG_ALL },
667333ee039SDag-Erling Smørgrav 	{ "forcecommand", sForceCommand, SSHCFG_ALL },
668d4af9e69SDag-Erling Smørgrav 	{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
669b15c8340SDag-Erling Smørgrav 	{ "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
670b15c8340SDag-Erling Smørgrav 	{ "revokedkeys", sRevokedKeys, SSHCFG_ALL },
671b15c8340SDag-Erling Smørgrav 	{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
672e2f6069cSDag-Erling Smørgrav 	{ "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
6734a421b63SDag-Erling Smørgrav 	{ "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
67419261079SEd Maste 	{ "include", sInclude, SSHCFG_ALL },
6754a421b63SDag-Erling Smørgrav 	{ "ipqos", sIPQoS, SSHCFG_ALL },
6766888a9beSDag-Erling Smørgrav 	{ "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
6776888a9beSDag-Erling Smørgrav 	{ "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
678557f75e5SDag-Erling Smørgrav 	{ "authorizedprincipalscommand", sAuthorizedPrincipalsCommand, SSHCFG_ALL },
679557f75e5SDag-Erling Smørgrav 	{ "authorizedprincipalscommanduser", sAuthorizedPrincipalsCommandUser, SSHCFG_ALL },
680462c32cbSDag-Erling Smørgrav 	{ "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL },
6816888a9beSDag-Erling Smørgrav 	{ "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL },
682a0ee8cc6SDag-Erling Smørgrav 	{ "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_ALL },
683a0ee8cc6SDag-Erling Smørgrav 	{ "streamlocalbindunlink", sStreamLocalBindUnlink, SSHCFG_ALL },
684a0ee8cc6SDag-Erling Smørgrav 	{ "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL },
685bc5531deSDag-Erling Smørgrav 	{ "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL },
686ca86bcf2SDag-Erling Smørgrav 	{ "disableforwarding", sDisableForwarding, SSHCFG_ALL },
6874f52dfbbSDag-Erling Smørgrav 	{ "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL },
68847dd1d1bSDag-Erling Smørgrav 	{ "rdomain", sRDomain, SSHCFG_ALL },
6892f513db7SEd Maste 	{ "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL },
69019261079SEd Maste 	{ "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL },
691b2af61ecSKurt Lidl 	{ "useblacklist", sUseBlacklist, SSHCFG_GLOBAL },
692e426c743SEd Maste 	{ "useblocklist", sUseBlacklist, SSHCFG_GLOBAL }, /* alias */
6936f351346SDag-Erling Smørgrav 	{ "noneenabled", sUnsupported, SSHCFG_ALL },
6949860d96eSDag-Erling Smørgrav 	{ "hpndisabled", sDeprecated, SSHCFG_ALL },
6959860d96eSDag-Erling Smørgrav 	{ "hpnbuffersize", sDeprecated, SSHCFG_ALL },
6969860d96eSDag-Erling Smørgrav 	{ "tcprcvbufpoll", sDeprecated, SSHCFG_ALL },
697333ee039SDag-Erling Smørgrav 	{ NULL, sBadOption, 0 }
698511b41d2SMark Murray };
699511b41d2SMark Murray 
700d4af9e69SDag-Erling Smørgrav static struct {
701d4af9e69SDag-Erling Smørgrav 	int val;
702d4af9e69SDag-Erling Smørgrav 	char *text;
703d4af9e69SDag-Erling Smørgrav } tunmode_desc[] = {
704d4af9e69SDag-Erling Smørgrav 	{ SSH_TUNMODE_NO, "no" },
705d4af9e69SDag-Erling Smørgrav 	{ SSH_TUNMODE_POINTOPOINT, "point-to-point" },
706d4af9e69SDag-Erling Smørgrav 	{ SSH_TUNMODE_ETHERNET, "ethernet" },
707d4af9e69SDag-Erling Smørgrav 	{ SSH_TUNMODE_YES, "yes" },
708d4af9e69SDag-Erling Smørgrav 	{ -1, NULL }
709d4af9e69SDag-Erling Smørgrav };
710d4af9e69SDag-Erling Smørgrav 
711190cef3dSDag-Erling Smørgrav /* Returns an opcode name from its number */
712190cef3dSDag-Erling Smørgrav 
713190cef3dSDag-Erling Smørgrav static const char *
714190cef3dSDag-Erling Smørgrav lookup_opcode_name(ServerOpCodes code)
715190cef3dSDag-Erling Smørgrav {
716190cef3dSDag-Erling Smørgrav 	u_int i;
717190cef3dSDag-Erling Smørgrav 
718190cef3dSDag-Erling Smørgrav 	for (i = 0; keywords[i].name != NULL; i++)
719190cef3dSDag-Erling Smørgrav 		if (keywords[i].opcode == code)
720190cef3dSDag-Erling Smørgrav 			return(keywords[i].name);
721190cef3dSDag-Erling Smørgrav 	return "UNKNOWN";
722190cef3dSDag-Erling Smørgrav }
723190cef3dSDag-Erling Smørgrav 
724190cef3dSDag-Erling Smørgrav 
725511b41d2SMark Murray /*
726ca3176e7SBrian Feldman  * Returns the number of the token pointed to by cp or sBadOption.
727511b41d2SMark Murray  */
728511b41d2SMark Murray 
729511b41d2SMark Murray static ServerOpCodes
730511b41d2SMark Murray parse_token(const char *cp, const char *filename,
731333ee039SDag-Erling Smørgrav 	    int linenum, u_int *flags)
732511b41d2SMark Murray {
733ca3176e7SBrian Feldman 	u_int i;
734511b41d2SMark Murray 
735511b41d2SMark Murray 	for (i = 0; keywords[i].name; i++)
736333ee039SDag-Erling Smørgrav 		if (strcasecmp(cp, keywords[i].name) == 0) {
737333ee039SDag-Erling Smørgrav 			*flags = keywords[i].flags;
738511b41d2SMark Murray 			return keywords[i].opcode;
739333ee039SDag-Erling Smørgrav 		}
740511b41d2SMark Murray 
741ca3176e7SBrian Feldman 	error("%s: line %d: Bad configuration option: %s",
742511b41d2SMark Murray 	    filename, linenum, cp);
743511b41d2SMark Murray 	return sBadOption;
744511b41d2SMark Murray }
745511b41d2SMark Murray 
746b15c8340SDag-Erling Smørgrav char *
747b15c8340SDag-Erling Smørgrav derelativise_path(const char *path)
748b15c8340SDag-Erling Smørgrav {
749bc5531deSDag-Erling Smørgrav 	char *expanded, *ret, cwd[PATH_MAX];
750b15c8340SDag-Erling Smørgrav 
751bc5531deSDag-Erling Smørgrav 	if (strcasecmp(path, "none") == 0)
752bc5531deSDag-Erling Smørgrav 		return xstrdup("none");
753b15c8340SDag-Erling Smørgrav 	expanded = tilde_expand_filename(path, getuid());
75419261079SEd Maste 	if (path_absolute(expanded))
755b15c8340SDag-Erling Smørgrav 		return expanded;
7568ad9b54aSDag-Erling Smørgrav 	if (getcwd(cwd, sizeof(cwd)) == NULL)
75719261079SEd Maste 		fatal_f("getcwd: %s", strerror(errno));
758b15c8340SDag-Erling Smørgrav 	xasprintf(&ret, "%s/%s", cwd, expanded);
759e4a9863fSDag-Erling Smørgrav 	free(expanded);
760b15c8340SDag-Erling Smørgrav 	return ret;
761b15c8340SDag-Erling Smørgrav }
762b15c8340SDag-Erling Smørgrav 
763af12a3e7SDag-Erling Smørgrav static void
76447dd1d1bSDag-Erling Smørgrav add_listen_addr(ServerOptions *options, const char *addr,
76547dd1d1bSDag-Erling Smørgrav     const char *rdomain, int port)
766511b41d2SMark Murray {
767d4ecd108SDag-Erling Smørgrav 	u_int i;
768511b41d2SMark Murray 
76947dd1d1bSDag-Erling Smørgrav 	if (port > 0)
77047dd1d1bSDag-Erling Smørgrav 		add_one_listen_addr(options, addr, rdomain, port);
77147dd1d1bSDag-Erling Smørgrav 	else {
77247dd1d1bSDag-Erling Smørgrav 		for (i = 0; i < options->num_ports; i++) {
77347dd1d1bSDag-Erling Smørgrav 			add_one_listen_addr(options, addr, rdomain,
77447dd1d1bSDag-Erling Smørgrav 			    options->ports[i]);
77547dd1d1bSDag-Erling Smørgrav 		}
77647dd1d1bSDag-Erling Smørgrav 	}
777ca3176e7SBrian Feldman }
778ca3176e7SBrian Feldman 
779af12a3e7SDag-Erling Smørgrav static void
78047dd1d1bSDag-Erling Smørgrav add_one_listen_addr(ServerOptions *options, const char *addr,
78147dd1d1bSDag-Erling Smørgrav     const char *rdomain, int port)
782ca3176e7SBrian Feldman {
783ca3176e7SBrian Feldman 	struct addrinfo hints, *ai, *aitop;
784ca3176e7SBrian Feldman 	char strport[NI_MAXSERV];
785ca3176e7SBrian Feldman 	int gaierr;
78647dd1d1bSDag-Erling Smørgrav 	u_int i;
78747dd1d1bSDag-Erling Smørgrav 
78847dd1d1bSDag-Erling Smørgrav 	/* Find listen_addrs entry for this rdomain */
78947dd1d1bSDag-Erling Smørgrav 	for (i = 0; i < options->num_listen_addrs; i++) {
79047dd1d1bSDag-Erling Smørgrav 		if (rdomain == NULL && options->listen_addrs[i].rdomain == NULL)
79147dd1d1bSDag-Erling Smørgrav 			break;
79247dd1d1bSDag-Erling Smørgrav 		if (rdomain == NULL || options->listen_addrs[i].rdomain == NULL)
79347dd1d1bSDag-Erling Smørgrav 			continue;
79447dd1d1bSDag-Erling Smørgrav 		if (strcmp(rdomain, options->listen_addrs[i].rdomain) == 0)
79547dd1d1bSDag-Erling Smørgrav 			break;
79647dd1d1bSDag-Erling Smørgrav 	}
79747dd1d1bSDag-Erling Smørgrav 	if (i >= options->num_listen_addrs) {
79847dd1d1bSDag-Erling Smørgrav 		/* No entry for this rdomain; allocate one */
79947dd1d1bSDag-Erling Smørgrav 		if (i >= INT_MAX)
80019261079SEd Maste 			fatal_f("too many listen addresses");
80147dd1d1bSDag-Erling Smørgrav 		options->listen_addrs = xrecallocarray(options->listen_addrs,
80247dd1d1bSDag-Erling Smørgrav 		    options->num_listen_addrs, options->num_listen_addrs + 1,
80347dd1d1bSDag-Erling Smørgrav 		    sizeof(*options->listen_addrs));
80447dd1d1bSDag-Erling Smørgrav 		i = options->num_listen_addrs++;
80547dd1d1bSDag-Erling Smørgrav 		if (rdomain != NULL)
80647dd1d1bSDag-Erling Smørgrav 			options->listen_addrs[i].rdomain = xstrdup(rdomain);
80747dd1d1bSDag-Erling Smørgrav 	}
80847dd1d1bSDag-Erling Smørgrav 	/* options->listen_addrs[i] points to the addresses for this rdomain */
809ca3176e7SBrian Feldman 
810511b41d2SMark Murray 	memset(&hints, 0, sizeof(hints));
811aa49c926SDag-Erling Smørgrav 	hints.ai_family = options->address_family;
812511b41d2SMark Murray 	hints.ai_socktype = SOCK_STREAM;
813511b41d2SMark Murray 	hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
814cce7d346SDag-Erling Smørgrav 	snprintf(strport, sizeof strport, "%d", port);
815511b41d2SMark Murray 	if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
816ca3176e7SBrian Feldman 		fatal("bad addr or host: %s (%s)",
817511b41d2SMark Murray 		    addr ? addr : "<NULL>",
818d4af9e69SDag-Erling Smørgrav 		    ssh_gai_strerror(gaierr));
819511b41d2SMark Murray 	for (ai = aitop; ai->ai_next; ai = ai->ai_next)
820511b41d2SMark Murray 		;
82147dd1d1bSDag-Erling Smørgrav 	ai->ai_next = options->listen_addrs[i].addrs;
82247dd1d1bSDag-Erling Smørgrav 	options->listen_addrs[i].addrs = aitop;
82347dd1d1bSDag-Erling Smørgrav }
82447dd1d1bSDag-Erling Smørgrav 
82547dd1d1bSDag-Erling Smørgrav /* Returns nonzero if the routing domain name is valid */
82647dd1d1bSDag-Erling Smørgrav static int
82747dd1d1bSDag-Erling Smørgrav valid_rdomain(const char *name)
82847dd1d1bSDag-Erling Smørgrav {
82947dd1d1bSDag-Erling Smørgrav #if defined(HAVE_SYS_VALID_RDOMAIN)
83047dd1d1bSDag-Erling Smørgrav 	return sys_valid_rdomain(name);
83147dd1d1bSDag-Erling Smørgrav #elif defined(__OpenBSD__)
83247dd1d1bSDag-Erling Smørgrav 	const char *errstr;
83347dd1d1bSDag-Erling Smørgrav 	long long num;
83447dd1d1bSDag-Erling Smørgrav 	struct rt_tableinfo info;
83547dd1d1bSDag-Erling Smørgrav 	int mib[6];
83647dd1d1bSDag-Erling Smørgrav 	size_t miblen = sizeof(mib);
83747dd1d1bSDag-Erling Smørgrav 
83847dd1d1bSDag-Erling Smørgrav 	if (name == NULL)
83947dd1d1bSDag-Erling Smørgrav 		return 1;
84047dd1d1bSDag-Erling Smørgrav 
84147dd1d1bSDag-Erling Smørgrav 	num = strtonum(name, 0, 255, &errstr);
84247dd1d1bSDag-Erling Smørgrav 	if (errstr != NULL)
84347dd1d1bSDag-Erling Smørgrav 		return 0;
84447dd1d1bSDag-Erling Smørgrav 
84547dd1d1bSDag-Erling Smørgrav 	/* Check whether the table actually exists */
84647dd1d1bSDag-Erling Smørgrav 	memset(mib, 0, sizeof(mib));
84747dd1d1bSDag-Erling Smørgrav 	mib[0] = CTL_NET;
84847dd1d1bSDag-Erling Smørgrav 	mib[1] = PF_ROUTE;
84947dd1d1bSDag-Erling Smørgrav 	mib[4] = NET_RT_TABLE;
85047dd1d1bSDag-Erling Smørgrav 	mib[5] = (int)num;
85147dd1d1bSDag-Erling Smørgrav 	if (sysctl(mib, 6, &info, &miblen, NULL, 0) == -1)
85247dd1d1bSDag-Erling Smørgrav 		return 0;
85347dd1d1bSDag-Erling Smørgrav 
85447dd1d1bSDag-Erling Smørgrav 	return 1;
85547dd1d1bSDag-Erling Smørgrav #else /* defined(__OpenBSD__) */
85647dd1d1bSDag-Erling Smørgrav 	error("Routing domains are not supported on this platform");
85747dd1d1bSDag-Erling Smørgrav 	return 0;
85847dd1d1bSDag-Erling Smørgrav #endif
859511b41d2SMark Murray }
860511b41d2SMark Murray 
861557f75e5SDag-Erling Smørgrav /*
862557f75e5SDag-Erling Smørgrav  * Queue a ListenAddress to be processed once we have all of the Ports
863557f75e5SDag-Erling Smørgrav  * and AddressFamily options.
864557f75e5SDag-Erling Smørgrav  */
865557f75e5SDag-Erling Smørgrav static void
86647dd1d1bSDag-Erling Smørgrav queue_listen_addr(ServerOptions *options, const char *addr,
86747dd1d1bSDag-Erling Smørgrav     const char *rdomain, int port)
868557f75e5SDag-Erling Smørgrav {
86947dd1d1bSDag-Erling Smørgrav 	struct queued_listenaddr *qla;
87047dd1d1bSDag-Erling Smørgrav 
87147dd1d1bSDag-Erling Smørgrav 	options->queued_listen_addrs = xrecallocarray(
87247dd1d1bSDag-Erling Smørgrav 	    options->queued_listen_addrs,
87347dd1d1bSDag-Erling Smørgrav 	    options->num_queued_listens, options->num_queued_listens + 1,
87447dd1d1bSDag-Erling Smørgrav 	    sizeof(*options->queued_listen_addrs));
87547dd1d1bSDag-Erling Smørgrav 	qla = &options->queued_listen_addrs[options->num_queued_listens++];
87647dd1d1bSDag-Erling Smørgrav 	qla->addr = xstrdup(addr);
87747dd1d1bSDag-Erling Smørgrav 	qla->port = port;
87847dd1d1bSDag-Erling Smørgrav 	qla->rdomain = rdomain == NULL ? NULL : xstrdup(rdomain);
879557f75e5SDag-Erling Smørgrav }
880557f75e5SDag-Erling Smørgrav 
881557f75e5SDag-Erling Smørgrav /*
882557f75e5SDag-Erling Smørgrav  * Process queued (text) ListenAddress entries.
883557f75e5SDag-Erling Smørgrav  */
884557f75e5SDag-Erling Smørgrav static void
885557f75e5SDag-Erling Smørgrav process_queued_listen_addrs(ServerOptions *options)
886557f75e5SDag-Erling Smørgrav {
887557f75e5SDag-Erling Smørgrav 	u_int i;
88847dd1d1bSDag-Erling Smørgrav 	struct queued_listenaddr *qla;
889557f75e5SDag-Erling Smørgrav 
890557f75e5SDag-Erling Smørgrav 	if (options->num_ports == 0)
891557f75e5SDag-Erling Smørgrav 		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
892557f75e5SDag-Erling Smørgrav 	if (options->address_family == -1)
893557f75e5SDag-Erling Smørgrav 		options->address_family = AF_UNSPEC;
894557f75e5SDag-Erling Smørgrav 
895557f75e5SDag-Erling Smørgrav 	for (i = 0; i < options->num_queued_listens; i++) {
89647dd1d1bSDag-Erling Smørgrav 		qla = &options->queued_listen_addrs[i];
89747dd1d1bSDag-Erling Smørgrav 		add_listen_addr(options, qla->addr, qla->rdomain, qla->port);
89847dd1d1bSDag-Erling Smørgrav 		free(qla->addr);
89947dd1d1bSDag-Erling Smørgrav 		free(qla->rdomain);
900557f75e5SDag-Erling Smørgrav 	}
901557f75e5SDag-Erling Smørgrav 	free(options->queued_listen_addrs);
902557f75e5SDag-Erling Smørgrav 	options->queued_listen_addrs = NULL;
903557f75e5SDag-Erling Smørgrav 	options->num_queued_listens = 0;
904557f75e5SDag-Erling Smørgrav }
905557f75e5SDag-Erling Smørgrav 
9064f52dfbbSDag-Erling Smørgrav /*
907190cef3dSDag-Erling Smørgrav  * Inform channels layer of permitopen options for a single forwarding
908190cef3dSDag-Erling Smørgrav  * direction (local/remote).
909190cef3dSDag-Erling Smørgrav  */
910190cef3dSDag-Erling Smørgrav static void
911190cef3dSDag-Erling Smørgrav process_permitopen_list(struct ssh *ssh, ServerOpCodes opcode,
912190cef3dSDag-Erling Smørgrav     char **opens, u_int num_opens)
913190cef3dSDag-Erling Smørgrav {
914190cef3dSDag-Erling Smørgrav 	u_int i;
915190cef3dSDag-Erling Smørgrav 	int port;
916*1323ec57SEd Maste 	char *host, *arg, *oarg;
917190cef3dSDag-Erling Smørgrav 	int where = opcode == sPermitOpen ? FORWARD_LOCAL : FORWARD_REMOTE;
918190cef3dSDag-Erling Smørgrav 	const char *what = lookup_opcode_name(opcode);
919190cef3dSDag-Erling Smørgrav 
920190cef3dSDag-Erling Smørgrav 	channel_clear_permission(ssh, FORWARD_ADM, where);
921190cef3dSDag-Erling Smørgrav 	if (num_opens == 0)
922190cef3dSDag-Erling Smørgrav 		return; /* permit any */
923190cef3dSDag-Erling Smørgrav 
924190cef3dSDag-Erling Smørgrav 	/* handle keywords: "any" / "none" */
925190cef3dSDag-Erling Smørgrav 	if (num_opens == 1 && strcmp(opens[0], "any") == 0)
926190cef3dSDag-Erling Smørgrav 		return;
927190cef3dSDag-Erling Smørgrav 	if (num_opens == 1 && strcmp(opens[0], "none") == 0) {
928190cef3dSDag-Erling Smørgrav 		channel_disable_admin(ssh, where);
929190cef3dSDag-Erling Smørgrav 		return;
930190cef3dSDag-Erling Smørgrav 	}
931190cef3dSDag-Erling Smørgrav 	/* Otherwise treat it as a list of permitted host:port */
932190cef3dSDag-Erling Smørgrav 	for (i = 0; i < num_opens; i++) {
933190cef3dSDag-Erling Smørgrav 		oarg = arg = xstrdup(opens[i]);
934*1323ec57SEd Maste 		host = hpdelim(&arg);
935*1323ec57SEd Maste 		if (host == NULL)
93619261079SEd Maste 			fatal_f("missing host in %s", what);
937190cef3dSDag-Erling Smørgrav 		host = cleanhostname(host);
938190cef3dSDag-Erling Smørgrav 		if (arg == NULL || ((port = permitopen_port(arg)) < 0))
93919261079SEd Maste 			fatal_f("bad port number in %s", what);
940190cef3dSDag-Erling Smørgrav 		/* Send it to channels layer */
941190cef3dSDag-Erling Smørgrav 		channel_add_permission(ssh, FORWARD_ADM,
942190cef3dSDag-Erling Smørgrav 		    where, host, port);
943190cef3dSDag-Erling Smørgrav 		free(oarg);
944190cef3dSDag-Erling Smørgrav 	}
945190cef3dSDag-Erling Smørgrav }
946190cef3dSDag-Erling Smørgrav 
947190cef3dSDag-Erling Smørgrav /*
9484f52dfbbSDag-Erling Smørgrav  * Inform channels layer of permitopen options from configuration.
9494f52dfbbSDag-Erling Smørgrav  */
9504f52dfbbSDag-Erling Smørgrav void
9514f52dfbbSDag-Erling Smørgrav process_permitopen(struct ssh *ssh, ServerOptions *options)
9524f52dfbbSDag-Erling Smørgrav {
953190cef3dSDag-Erling Smørgrav 	process_permitopen_list(ssh, sPermitOpen,
954190cef3dSDag-Erling Smørgrav 	    options->permitted_opens, options->num_permitted_opens);
955190cef3dSDag-Erling Smørgrav 	process_permitopen_list(ssh, sPermitListen,
956190cef3dSDag-Erling Smørgrav 	    options->permitted_listens,
957190cef3dSDag-Erling Smørgrav 	    options->num_permitted_listens);
9584f52dfbbSDag-Erling Smørgrav }
9594f52dfbbSDag-Erling Smørgrav 
960462c32cbSDag-Erling Smørgrav struct connection_info *
96119261079SEd Maste get_connection_info(struct ssh *ssh, int populate, int use_dns)
962462c32cbSDag-Erling Smørgrav {
963462c32cbSDag-Erling Smørgrav 	static struct connection_info ci;
964462c32cbSDag-Erling Smørgrav 
96519261079SEd Maste 	if (ssh == NULL || !populate)
966462c32cbSDag-Erling Smørgrav 		return &ci;
967076ad2f8SDag-Erling Smørgrav 	ci.host = auth_get_canonical_hostname(ssh, use_dns);
968076ad2f8SDag-Erling Smørgrav 	ci.address = ssh_remote_ipaddr(ssh);
969076ad2f8SDag-Erling Smørgrav 	ci.laddress = ssh_local_ipaddr(ssh);
970076ad2f8SDag-Erling Smørgrav 	ci.lport = ssh_local_port(ssh);
97147dd1d1bSDag-Erling Smørgrav 	ci.rdomain = ssh_packet_rdomain_in(ssh);
972462c32cbSDag-Erling Smørgrav 	return &ci;
973462c32cbSDag-Erling Smørgrav }
974462c32cbSDag-Erling Smørgrav 
975333ee039SDag-Erling Smørgrav /*
976333ee039SDag-Erling Smørgrav  * The strategy for the Match blocks is that the config file is parsed twice.
977333ee039SDag-Erling Smørgrav  *
978333ee039SDag-Erling Smørgrav  * The first time is at startup.  activep is initialized to 1 and the
979333ee039SDag-Erling Smørgrav  * directives in the global context are processed and acted on.  Hitting a
980333ee039SDag-Erling Smørgrav  * Match directive unsets activep and the directives inside the block are
981333ee039SDag-Erling Smørgrav  * checked for syntax only.
982333ee039SDag-Erling Smørgrav  *
983333ee039SDag-Erling Smørgrav  * The second time is after a connection has been established but before
984333ee039SDag-Erling Smørgrav  * authentication.  activep is initialized to 2 and global config directives
985333ee039SDag-Erling Smørgrav  * are ignored since they have already been processed.  If the criteria in a
986333ee039SDag-Erling Smørgrav  * Match block is met, activep is set and the subsequent directives
987333ee039SDag-Erling Smørgrav  * processed and actioned until EOF or another Match block unsets it.  Any
988333ee039SDag-Erling Smørgrav  * options set are copied into the main server config.
989333ee039SDag-Erling Smørgrav  *
990333ee039SDag-Erling Smørgrav  * Potential additions/improvements:
991ca86bcf2SDag-Erling Smørgrav  *  - Add Match support for pre-kex directives, eg. Ciphers.
992333ee039SDag-Erling Smørgrav  *
993333ee039SDag-Erling Smørgrav  *  - Add a Tag directive (idea from David Leonard) ala pf, eg:
994333ee039SDag-Erling Smørgrav  *	Match Address 192.168.0.*
995333ee039SDag-Erling Smørgrav  *		Tag trusted
996333ee039SDag-Erling Smørgrav  *	Match Group wheel
997333ee039SDag-Erling Smørgrav  *		Tag trusted
998333ee039SDag-Erling Smørgrav  *	Match Tag trusted
999333ee039SDag-Erling Smørgrav  *		AllowTcpForwarding yes
1000333ee039SDag-Erling Smørgrav  *		GatewayPorts clientspecified
1001333ee039SDag-Erling Smørgrav  *		[...]
1002333ee039SDag-Erling Smørgrav  *
1003333ee039SDag-Erling Smørgrav  *  - Add a PermittedChannelRequests directive
1004333ee039SDag-Erling Smørgrav  *	Match Group shell
1005333ee039SDag-Erling Smørgrav  *		PermittedChannelRequests session,forwarded-tcpip
1006333ee039SDag-Erling Smørgrav  */
1007333ee039SDag-Erling Smørgrav 
1008333ee039SDag-Erling Smørgrav static int
1009333ee039SDag-Erling Smørgrav match_cfg_line_group(const char *grps, int line, const char *user)
1010333ee039SDag-Erling Smørgrav {
1011333ee039SDag-Erling Smørgrav 	int result = 0;
1012333ee039SDag-Erling Smørgrav 	struct passwd *pw;
1013333ee039SDag-Erling Smørgrav 
1014333ee039SDag-Erling Smørgrav 	if (user == NULL)
1015333ee039SDag-Erling Smørgrav 		goto out;
1016333ee039SDag-Erling Smørgrav 
1017333ee039SDag-Erling Smørgrav 	if ((pw = getpwnam(user)) == NULL) {
1018333ee039SDag-Erling Smørgrav 		debug("Can't match group at line %d because user %.100s does "
1019333ee039SDag-Erling Smørgrav 		    "not exist", line, user);
1020333ee039SDag-Erling Smørgrav 	} else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
1021333ee039SDag-Erling Smørgrav 		debug("Can't Match group because user %.100s not in any group "
1022333ee039SDag-Erling Smørgrav 		    "at line %d", user, line);
1023d4af9e69SDag-Erling Smørgrav 	} else if (ga_match_pattern_list(grps) != 1) {
1024d4af9e69SDag-Erling Smørgrav 		debug("user %.100s does not match group list %.100s at line %d",
1025d4af9e69SDag-Erling Smørgrav 		    user, grps, line);
1026333ee039SDag-Erling Smørgrav 	} else {
1027d4af9e69SDag-Erling Smørgrav 		debug("user %.100s matched group list %.100s at line %d", user,
1028d4af9e69SDag-Erling Smørgrav 		    grps, line);
1029333ee039SDag-Erling Smørgrav 		result = 1;
1030333ee039SDag-Erling Smørgrav 	}
1031333ee039SDag-Erling Smørgrav out:
1032333ee039SDag-Erling Smørgrav 	ga_free();
1033333ee039SDag-Erling Smørgrav 	return result;
1034333ee039SDag-Erling Smørgrav }
1035333ee039SDag-Erling Smørgrav 
103647dd1d1bSDag-Erling Smørgrav static void
103747dd1d1bSDag-Erling Smørgrav match_test_missing_fatal(const char *criteria, const char *attrib)
103847dd1d1bSDag-Erling Smørgrav {
103947dd1d1bSDag-Erling Smørgrav 	fatal("'Match %s' in configuration but '%s' not in connection "
104047dd1d1bSDag-Erling Smørgrav 	    "test specification.", criteria, attrib);
104147dd1d1bSDag-Erling Smørgrav }
104247dd1d1bSDag-Erling Smørgrav 
1043462c32cbSDag-Erling Smørgrav /*
10446888a9beSDag-Erling Smørgrav  * All of the attributes on a single Match line are ANDed together, so we need
1045f7167e0eSDag-Erling Smørgrav  * to check every attribute and set the result to zero if any attribute does
10466888a9beSDag-Erling Smørgrav  * not match.
1047462c32cbSDag-Erling Smørgrav  */
1048333ee039SDag-Erling Smørgrav static int
1049462c32cbSDag-Erling Smørgrav match_cfg_line(char **condition, int line, struct connection_info *ci)
1050333ee039SDag-Erling Smørgrav {
1051f7167e0eSDag-Erling Smørgrav 	int result = 1, attributes = 0, port;
1052333ee039SDag-Erling Smørgrav 	char *arg, *attrib, *cp = *condition;
1053333ee039SDag-Erling Smørgrav 
1054462c32cbSDag-Erling Smørgrav 	if (ci == NULL)
1055333ee039SDag-Erling Smørgrav 		debug3("checking syntax for 'Match %s'", cp);
1056333ee039SDag-Erling Smørgrav 	else
1057462c32cbSDag-Erling Smørgrav 		debug3("checking match for '%s' user %s host %s addr %s "
1058462c32cbSDag-Erling Smørgrav 		    "laddr %s lport %d", cp, ci->user ? ci->user : "(null)",
1059462c32cbSDag-Erling Smørgrav 		    ci->host ? ci->host : "(null)",
1060462c32cbSDag-Erling Smørgrav 		    ci->address ? ci->address : "(null)",
1061462c32cbSDag-Erling Smørgrav 		    ci->laddress ? ci->laddress : "(null)", ci->lport);
1062333ee039SDag-Erling Smørgrav 
1063333ee039SDag-Erling Smørgrav 	while ((attrib = strdelim(&cp)) && *attrib != '\0') {
106419261079SEd Maste 		/* Terminate on comment */
106519261079SEd Maste 		if (*attrib == '#') {
106619261079SEd Maste 			cp = NULL; /* mark all arguments consumed */
106719261079SEd Maste 			break;
106819261079SEd Maste 		}
106919261079SEd Maste 		arg = NULL;
1070f7167e0eSDag-Erling Smørgrav 		attributes++;
107119261079SEd Maste 		/* Criterion "all" has no argument and must appear alone */
1072f7167e0eSDag-Erling Smørgrav 		if (strcasecmp(attrib, "all") == 0) {
107319261079SEd Maste 			if (attributes > 1 || ((arg = strdelim(&cp)) != NULL &&
107419261079SEd Maste 			    *arg != '\0' && *arg != '#')) {
1075f7167e0eSDag-Erling Smørgrav 				error("'all' cannot be combined with other "
1076f7167e0eSDag-Erling Smørgrav 				    "Match attributes");
1077f7167e0eSDag-Erling Smørgrav 				return -1;
1078f7167e0eSDag-Erling Smørgrav 			}
107919261079SEd Maste 			if (arg != NULL && *arg == '#')
108019261079SEd Maste 				cp = NULL; /* mark all arguments consumed */
1081f7167e0eSDag-Erling Smørgrav 			*condition = cp;
1082f7167e0eSDag-Erling Smørgrav 			return 1;
1083f7167e0eSDag-Erling Smørgrav 		}
108419261079SEd Maste 		/* All other criteria require an argument */
108519261079SEd Maste 		if ((arg = strdelim(&cp)) == NULL ||
108619261079SEd Maste 		    *arg == '\0' || *arg == '#') {
1087333ee039SDag-Erling Smørgrav 			error("Missing Match criteria for %s", attrib);
1088333ee039SDag-Erling Smørgrav 			return -1;
1089333ee039SDag-Erling Smørgrav 		}
1090333ee039SDag-Erling Smørgrav 		if (strcasecmp(attrib, "user") == 0) {
109119261079SEd Maste 			if (ci == NULL || (ci->test && ci->user == NULL)) {
1092333ee039SDag-Erling Smørgrav 				result = 0;
1093333ee039SDag-Erling Smørgrav 				continue;
1094333ee039SDag-Erling Smørgrav 			}
109547dd1d1bSDag-Erling Smørgrav 			if (ci->user == NULL)
109647dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("User", "user");
109719261079SEd Maste 			if (match_usergroup_pattern_list(ci->user, arg) != 1)
1098333ee039SDag-Erling Smørgrav 				result = 0;
1099333ee039SDag-Erling Smørgrav 			else
1100333ee039SDag-Erling Smørgrav 				debug("user %.100s matched 'User %.100s' at "
1101462c32cbSDag-Erling Smørgrav 				    "line %d", ci->user, arg, line);
1102333ee039SDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "group") == 0) {
110319261079SEd Maste 			if (ci == NULL || (ci->test && ci->user == NULL)) {
1104462c32cbSDag-Erling Smørgrav 				result = 0;
1105462c32cbSDag-Erling Smørgrav 				continue;
1106462c32cbSDag-Erling Smørgrav 			}
110747dd1d1bSDag-Erling Smørgrav 			if (ci->user == NULL)
110847dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("Group", "user");
1109462c32cbSDag-Erling Smørgrav 			switch (match_cfg_line_group(arg, line, ci->user)) {
1110333ee039SDag-Erling Smørgrav 			case -1:
1111333ee039SDag-Erling Smørgrav 				return -1;
1112333ee039SDag-Erling Smørgrav 			case 0:
1113333ee039SDag-Erling Smørgrav 				result = 0;
1114333ee039SDag-Erling Smørgrav 			}
1115333ee039SDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "host") == 0) {
111619261079SEd Maste 			if (ci == NULL || (ci->test && ci->host == NULL)) {
1117333ee039SDag-Erling Smørgrav 				result = 0;
1118333ee039SDag-Erling Smørgrav 				continue;
1119333ee039SDag-Erling Smørgrav 			}
112047dd1d1bSDag-Erling Smørgrav 			if (ci->host == NULL)
112147dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("Host", "host");
1122557f75e5SDag-Erling Smørgrav 			if (match_hostname(ci->host, arg) != 1)
1123333ee039SDag-Erling Smørgrav 				result = 0;
1124333ee039SDag-Erling Smørgrav 			else
1125333ee039SDag-Erling Smørgrav 				debug("connection from %.100s matched 'Host "
1126462c32cbSDag-Erling Smørgrav 				    "%.100s' at line %d", ci->host, arg, line);
1127333ee039SDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "address") == 0) {
112819261079SEd Maste 			if (ci == NULL || (ci->test && ci->address == NULL)) {
112919261079SEd Maste 				if (addr_match_list(NULL, arg) != 0)
113019261079SEd Maste 					fatal("Invalid Match address argument "
113119261079SEd Maste 					    "'%s' at line %d", arg, line);
1132462c32cbSDag-Erling Smørgrav 				result = 0;
1133462c32cbSDag-Erling Smørgrav 				continue;
1134462c32cbSDag-Erling Smørgrav 			}
113547dd1d1bSDag-Erling Smørgrav 			if (ci->address == NULL)
113647dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("Address", "addr");
1137462c32cbSDag-Erling Smørgrav 			switch (addr_match_list(ci->address, arg)) {
1138d4af9e69SDag-Erling Smørgrav 			case 1:
1139333ee039SDag-Erling Smørgrav 				debug("connection from %.100s matched 'Address "
1140462c32cbSDag-Erling Smørgrav 				    "%.100s' at line %d", ci->address, arg, line);
1141d4af9e69SDag-Erling Smørgrav 				break;
1142d4af9e69SDag-Erling Smørgrav 			case 0:
1143d4af9e69SDag-Erling Smørgrav 			case -1:
1144d4af9e69SDag-Erling Smørgrav 				result = 0;
1145d4af9e69SDag-Erling Smørgrav 				break;
1146d4af9e69SDag-Erling Smørgrav 			case -2:
1147d4af9e69SDag-Erling Smørgrav 				return -1;
1148d4af9e69SDag-Erling Smørgrav 			}
1149462c32cbSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "localaddress") == 0){
115019261079SEd Maste 			if (ci == NULL || (ci->test && ci->laddress == NULL)) {
115119261079SEd Maste 				if (addr_match_list(NULL, arg) != 0)
115219261079SEd Maste 					fatal("Invalid Match localaddress "
115319261079SEd Maste 					    "argument '%s' at line %d", arg,
115419261079SEd Maste 					    line);
1155462c32cbSDag-Erling Smørgrav 				result = 0;
1156462c32cbSDag-Erling Smørgrav 				continue;
1157462c32cbSDag-Erling Smørgrav 			}
115847dd1d1bSDag-Erling Smørgrav 			if (ci->laddress == NULL)
115947dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("LocalAddress",
116047dd1d1bSDag-Erling Smørgrav 				    "laddr");
1161462c32cbSDag-Erling Smørgrav 			switch (addr_match_list(ci->laddress, arg)) {
1162462c32cbSDag-Erling Smørgrav 			case 1:
1163462c32cbSDag-Erling Smørgrav 				debug("connection from %.100s matched "
1164462c32cbSDag-Erling Smørgrav 				    "'LocalAddress %.100s' at line %d",
1165462c32cbSDag-Erling Smørgrav 				    ci->laddress, arg, line);
1166462c32cbSDag-Erling Smørgrav 				break;
1167462c32cbSDag-Erling Smørgrav 			case 0:
1168462c32cbSDag-Erling Smørgrav 			case -1:
1169462c32cbSDag-Erling Smørgrav 				result = 0;
1170462c32cbSDag-Erling Smørgrav 				break;
1171462c32cbSDag-Erling Smørgrav 			case -2:
1172462c32cbSDag-Erling Smørgrav 				return -1;
1173462c32cbSDag-Erling Smørgrav 			}
1174462c32cbSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "localport") == 0) {
1175462c32cbSDag-Erling Smørgrav 			if ((port = a2port(arg)) == -1) {
1176462c32cbSDag-Erling Smørgrav 				error("Invalid LocalPort '%s' on Match line",
1177462c32cbSDag-Erling Smørgrav 				    arg);
1178462c32cbSDag-Erling Smørgrav 				return -1;
1179462c32cbSDag-Erling Smørgrav 			}
118019261079SEd Maste 			if (ci == NULL || (ci->test && ci->lport == -1)) {
1181462c32cbSDag-Erling Smørgrav 				result = 0;
1182462c32cbSDag-Erling Smørgrav 				continue;
1183462c32cbSDag-Erling Smørgrav 			}
118447dd1d1bSDag-Erling Smørgrav 			if (ci->lport == 0)
118547dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("LocalPort", "lport");
1186462c32cbSDag-Erling Smørgrav 			/* TODO support port lists */
1187462c32cbSDag-Erling Smørgrav 			if (port == ci->lport)
1188462c32cbSDag-Erling Smørgrav 				debug("connection from %.100s matched "
1189462c32cbSDag-Erling Smørgrav 				    "'LocalPort %d' at line %d",
1190462c32cbSDag-Erling Smørgrav 				    ci->laddress, port, line);
1191462c32cbSDag-Erling Smørgrav 			else
1192462c32cbSDag-Erling Smørgrav 				result = 0;
119347dd1d1bSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "rdomain") == 0) {
119419261079SEd Maste 			if (ci == NULL || (ci->test && ci->rdomain == NULL)) {
119547dd1d1bSDag-Erling Smørgrav 				result = 0;
119647dd1d1bSDag-Erling Smørgrav 				continue;
119747dd1d1bSDag-Erling Smørgrav 			}
119819261079SEd Maste 			if (ci->rdomain == NULL)
119919261079SEd Maste 				match_test_missing_fatal("RDomain", "rdomain");
120047dd1d1bSDag-Erling Smørgrav 			if (match_pattern_list(ci->rdomain, arg, 0) != 1)
120147dd1d1bSDag-Erling Smørgrav 				result = 0;
120247dd1d1bSDag-Erling Smørgrav 			else
120347dd1d1bSDag-Erling Smørgrav 				debug("user %.100s matched 'RDomain %.100s' at "
120447dd1d1bSDag-Erling Smørgrav 				    "line %d", ci->rdomain, arg, line);
1205333ee039SDag-Erling Smørgrav 		} else {
1206333ee039SDag-Erling Smørgrav 			error("Unsupported Match attribute %s", attrib);
1207333ee039SDag-Erling Smørgrav 			return -1;
1208333ee039SDag-Erling Smørgrav 		}
1209333ee039SDag-Erling Smørgrav 	}
1210f7167e0eSDag-Erling Smørgrav 	if (attributes == 0) {
1211f7167e0eSDag-Erling Smørgrav 		error("One or more attributes required for Match");
1212f7167e0eSDag-Erling Smørgrav 		return -1;
1213f7167e0eSDag-Erling Smørgrav 	}
1214462c32cbSDag-Erling Smørgrav 	if (ci != NULL)
1215333ee039SDag-Erling Smørgrav 		debug3("match %sfound", result ? "" : "not ");
1216333ee039SDag-Erling Smørgrav 	*condition = cp;
1217333ee039SDag-Erling Smørgrav 	return result;
1218333ee039SDag-Erling Smørgrav }
1219333ee039SDag-Erling Smørgrav 
1220333ee039SDag-Erling Smørgrav #define WHITESPACE " \t\r\n"
1221333ee039SDag-Erling Smørgrav 
1222e146993eSDag-Erling Smørgrav /* Multistate option parsing */
1223e146993eSDag-Erling Smørgrav struct multistate {
1224e146993eSDag-Erling Smørgrav 	char *key;
1225e146993eSDag-Erling Smørgrav 	int value;
1226e146993eSDag-Erling Smørgrav };
122747dd1d1bSDag-Erling Smørgrav static const struct multistate multistate_flag[] = {
122847dd1d1bSDag-Erling Smørgrav 	{ "yes",			1 },
122947dd1d1bSDag-Erling Smørgrav 	{ "no",				0 },
123047dd1d1bSDag-Erling Smørgrav 	{ NULL, -1 }
123147dd1d1bSDag-Erling Smørgrav };
123219261079SEd Maste static const struct multistate multistate_ignore_rhosts[] = {
123319261079SEd Maste 	{ "yes",			IGNORE_RHOSTS_YES },
123419261079SEd Maste 	{ "no",				IGNORE_RHOSTS_NO },
123519261079SEd Maste 	{ "shosts-only",		IGNORE_RHOSTS_SHOSTS },
123619261079SEd Maste 	{ NULL, -1 }
123719261079SEd Maste };
1238e146993eSDag-Erling Smørgrav static const struct multistate multistate_addressfamily[] = {
1239e146993eSDag-Erling Smørgrav 	{ "inet",			AF_INET },
1240e146993eSDag-Erling Smørgrav 	{ "inet6",			AF_INET6 },
1241e146993eSDag-Erling Smørgrav 	{ "any",			AF_UNSPEC },
1242e146993eSDag-Erling Smørgrav 	{ NULL, -1 }
1243e146993eSDag-Erling Smørgrav };
1244e146993eSDag-Erling Smørgrav static const struct multistate multistate_permitrootlogin[] = {
1245e146993eSDag-Erling Smørgrav 	{ "without-password",		PERMIT_NO_PASSWD },
1246eccfee6eSDag-Erling Smørgrav 	{ "prohibit-password",		PERMIT_NO_PASSWD },
1247e146993eSDag-Erling Smørgrav 	{ "forced-commands-only",	PERMIT_FORCED_ONLY },
1248e146993eSDag-Erling Smørgrav 	{ "yes",			PERMIT_YES },
1249e146993eSDag-Erling Smørgrav 	{ "no",				PERMIT_NO },
1250e146993eSDag-Erling Smørgrav 	{ NULL, -1 }
1251e146993eSDag-Erling Smørgrav };
1252e146993eSDag-Erling Smørgrav static const struct multistate multistate_compression[] = {
125319261079SEd Maste #ifdef WITH_ZLIB
1254ca86bcf2SDag-Erling Smørgrav 	{ "yes",			COMP_DELAYED },
1255e146993eSDag-Erling Smørgrav 	{ "delayed",			COMP_DELAYED },
125619261079SEd Maste #endif
1257e146993eSDag-Erling Smørgrav 	{ "no",				COMP_NONE },
1258e146993eSDag-Erling Smørgrav 	{ NULL, -1 }
1259e146993eSDag-Erling Smørgrav };
1260e146993eSDag-Erling Smørgrav static const struct multistate multistate_gatewayports[] = {
1261e146993eSDag-Erling Smørgrav 	{ "clientspecified",		2 },
1262e146993eSDag-Erling Smørgrav 	{ "yes",			1 },
1263e146993eSDag-Erling Smørgrav 	{ "no",				0 },
1264e146993eSDag-Erling Smørgrav 	{ NULL, -1 }
1265e146993eSDag-Erling Smørgrav };
12666888a9beSDag-Erling Smørgrav static const struct multistate multistate_tcpfwd[] = {
12676888a9beSDag-Erling Smørgrav 	{ "yes",			FORWARD_ALLOW },
12686888a9beSDag-Erling Smørgrav 	{ "all",			FORWARD_ALLOW },
12696888a9beSDag-Erling Smørgrav 	{ "no",				FORWARD_DENY },
12706888a9beSDag-Erling Smørgrav 	{ "remote",			FORWARD_REMOTE },
12716888a9beSDag-Erling Smørgrav 	{ "local",			FORWARD_LOCAL },
12726888a9beSDag-Erling Smørgrav 	{ NULL, -1 }
12736888a9beSDag-Erling Smørgrav };
1274e146993eSDag-Erling Smørgrav 
127519261079SEd Maste static int
127619261079SEd Maste process_server_config_line_depth(ServerOptions *options, char *line,
1277462c32cbSDag-Erling Smørgrav     const char *filename, int linenum, int *activep,
127819261079SEd Maste     struct connection_info *connectinfo, int *inc_flags, int depth,
127919261079SEd Maste     struct include_list *includes)
1280511b41d2SMark Murray {
1281*1323ec57SEd Maste 	char *str, ***chararrayptr, **charptr, *arg, *arg2, *p, *keyword;
128219261079SEd Maste 	int cmdline = 0, *intptr, value, value2, n, port, oactive, r, found;
1283d4af9e69SDag-Erling Smørgrav 	SyslogFacility *log_facility_ptr;
1284d4af9e69SDag-Erling Smørgrav 	LogLevel *log_level_ptr;
1285511b41d2SMark Murray 	ServerOpCodes opcode;
1286190cef3dSDag-Erling Smørgrav 	u_int i, *uintptr, uvalue, flags = 0;
1287333ee039SDag-Erling Smørgrav 	size_t len;
1288e4a9863fSDag-Erling Smørgrav 	long long val64;
1289e146993eSDag-Erling Smørgrav 	const struct multistate *multistate_ptr;
129047dd1d1bSDag-Erling Smørgrav 	const char *errstr;
129119261079SEd Maste 	struct include_item *item;
129219261079SEd Maste 	glob_t gbuf;
129319261079SEd Maste 	char **oav = NULL, **av;
129419261079SEd Maste 	int oac = 0, ac;
129519261079SEd Maste 	int ret = -1;
1296511b41d2SMark Murray 
1297d93a896eSDag-Erling Smørgrav 	/* Strip trailing whitespace. Allow \f (form feed) at EOL only */
1298d93a896eSDag-Erling Smørgrav 	if ((len = strlen(line)) == 0)
1299d93a896eSDag-Erling Smørgrav 		return 0;
1300d93a896eSDag-Erling Smørgrav 	for (len--; len > 0; len--) {
1301d93a896eSDag-Erling Smørgrav 		if (strchr(WHITESPACE "\f", line[len]) == NULL)
1302d93a896eSDag-Erling Smørgrav 			break;
1303d93a896eSDag-Erling Smørgrav 		line[len] = '\0';
1304d93a896eSDag-Erling Smørgrav 	}
1305d93a896eSDag-Erling Smørgrav 
130619261079SEd Maste 	str = line;
130719261079SEd Maste 	if ((keyword = strdelim(&str)) == NULL)
1308333ee039SDag-Erling Smørgrav 		return 0;
1309c2d3a559SKris Kennaway 	/* Ignore leading whitespace */
131019261079SEd Maste 	if (*keyword == '\0')
131119261079SEd Maste 		keyword = strdelim(&str);
131219261079SEd Maste 	if (!keyword || !*keyword || *keyword == '#')
1313af12a3e7SDag-Erling Smørgrav 		return 0;
131419261079SEd Maste 	if (str == NULL || *str == '\0') {
131519261079SEd Maste 		error("%s line %d: no argument after keyword \"%s\"",
131619261079SEd Maste 		    filename, linenum, keyword);
131719261079SEd Maste 		return -1;
131819261079SEd Maste 	}
1319ca3176e7SBrian Feldman 	intptr = NULL;
1320ca3176e7SBrian Feldman 	charptr = NULL;
132119261079SEd Maste 	opcode = parse_token(keyword, filename, linenum, &flags);
132219261079SEd Maste 
132319261079SEd Maste 	if (argv_split(str, &oac, &oav, 1) != 0) {
132419261079SEd Maste 		error("%s line %d: invalid quotes", filename, linenum);
132519261079SEd Maste 		return -1;
132619261079SEd Maste 	}
132719261079SEd Maste 	ac = oac;
132819261079SEd Maste 	av = oav;
1329333ee039SDag-Erling Smørgrav 
1330333ee039SDag-Erling Smørgrav 	if (activep == NULL) { /* We are processing a command line directive */
1331333ee039SDag-Erling Smørgrav 		cmdline = 1;
1332333ee039SDag-Erling Smørgrav 		activep = &cmdline;
1333333ee039SDag-Erling Smørgrav 	}
133419261079SEd Maste 	if (*activep && opcode != sMatch && opcode != sInclude)
133519261079SEd Maste 		debug3("%s:%d setting %s %s", filename, linenum, keyword, str);
1336333ee039SDag-Erling Smørgrav 	if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
1337462c32cbSDag-Erling Smørgrav 		if (connectinfo == NULL) {
1338333ee039SDag-Erling Smørgrav 			fatal("%s line %d: Directive '%s' is not allowed "
133919261079SEd Maste 			    "within a Match block", filename, linenum, keyword);
1340333ee039SDag-Erling Smørgrav 		} else { /* this is a directive we have already processed */
134119261079SEd Maste 			ret = 0;
134219261079SEd Maste 			goto out;
1343333ee039SDag-Erling Smørgrav 		}
1344333ee039SDag-Erling Smørgrav 	}
1345333ee039SDag-Erling Smørgrav 
1346511b41d2SMark Murray 	switch (opcode) {
1347989dd127SDag-Erling Smørgrav 	/* Portable-specific options */
1348cf2b5f3bSDag-Erling Smørgrav 	case sUsePAM:
1349cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->use_pam;
1350989dd127SDag-Erling Smørgrav 		goto parse_flag;
1351989dd127SDag-Erling Smørgrav 
1352989dd127SDag-Erling Smørgrav 	/* Standard Options */
1353511b41d2SMark Murray 	case sBadOption:
135419261079SEd Maste 		goto out;
1355511b41d2SMark Murray 	case sPort:
1356511b41d2SMark Murray 		/* ignore ports from configfile if cmdline specifies ports */
135719261079SEd Maste 		if (options->ports_from_cmdline) {
135819261079SEd Maste 			argv_consume(&ac);
135919261079SEd Maste 			break;
136019261079SEd Maste 		}
1361511b41d2SMark Murray 		if (options->num_ports >= MAX_PORTS)
1362ca3176e7SBrian Feldman 			fatal("%s line %d: too many ports.",
1363511b41d2SMark Murray 			    filename, linenum);
136419261079SEd Maste 		arg = argv_next(&ac, &av);
1365c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1366ca3176e7SBrian Feldman 			fatal("%s line %d: missing port number.",
1367511b41d2SMark Murray 			    filename, linenum);
1368ca3176e7SBrian Feldman 		options->ports[options->num_ports++] = a2port(arg);
1369cce7d346SDag-Erling Smørgrav 		if (options->ports[options->num_ports-1] <= 0)
1370ca3176e7SBrian Feldman 			fatal("%s line %d: Badly formatted port number.",
1371ca3176e7SBrian Feldman 			    filename, linenum);
1372511b41d2SMark Murray 		break;
1373511b41d2SMark Murray 
1374511b41d2SMark Murray 	case sLoginGraceTime:
1375511b41d2SMark Murray 		intptr = &options->login_grace_time;
1376af12a3e7SDag-Erling Smørgrav  parse_time:
137719261079SEd Maste 		arg = argv_next(&ac, &av);
1378af12a3e7SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1379af12a3e7SDag-Erling Smørgrav 			fatal("%s line %d: missing time value.",
1380af12a3e7SDag-Erling Smørgrav 			    filename, linenum);
1381af12a3e7SDag-Erling Smørgrav 		if ((value = convtime(arg)) == -1)
1382af12a3e7SDag-Erling Smørgrav 			fatal("%s line %d: invalid time value.",
1383af12a3e7SDag-Erling Smørgrav 			    filename, linenum);
1384557f75e5SDag-Erling Smørgrav 		if (*activep && *intptr == -1)
1385af12a3e7SDag-Erling Smørgrav 			*intptr = value;
1386af12a3e7SDag-Erling Smørgrav 		break;
1387511b41d2SMark Murray 
1388511b41d2SMark Murray 	case sListenAddress:
138919261079SEd Maste 		arg = argv_next(&ac, &av);
1390aa49c926SDag-Erling Smørgrav 		if (arg == NULL || *arg == '\0')
1391aa49c926SDag-Erling Smørgrav 			fatal("%s line %d: missing address",
1392511b41d2SMark Murray 			    filename, linenum);
1393d4ecd108SDag-Erling Smørgrav 		/* check for bare IPv6 address: no "[]" and 2 or more ":" */
1394d4ecd108SDag-Erling Smørgrav 		if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL
1395d4ecd108SDag-Erling Smørgrav 		    && strchr(p+1, ':') != NULL) {
139647dd1d1bSDag-Erling Smørgrav 			port = 0;
139747dd1d1bSDag-Erling Smørgrav 			p = arg;
139847dd1d1bSDag-Erling Smørgrav 		} else {
139919261079SEd Maste 			arg2 = NULL;
1400*1323ec57SEd Maste 			p = hpdelim(&arg);
1401*1323ec57SEd Maste 			if (p == NULL)
1402aa49c926SDag-Erling Smørgrav 				fatal("%s line %d: bad address:port usage",
1403ca3176e7SBrian Feldman 				    filename, linenum);
1404aa49c926SDag-Erling Smørgrav 			p = cleanhostname(p);
1405aa49c926SDag-Erling Smørgrav 			if (arg == NULL)
1406aa49c926SDag-Erling Smørgrav 				port = 0;
1407cce7d346SDag-Erling Smørgrav 			else if ((port = a2port(arg)) <= 0)
140847dd1d1bSDag-Erling Smørgrav 				fatal("%s line %d: bad port number",
140947dd1d1bSDag-Erling Smørgrav 				    filename, linenum);
141047dd1d1bSDag-Erling Smørgrav 		}
141147dd1d1bSDag-Erling Smørgrav 		/* Optional routing table */
141247dd1d1bSDag-Erling Smørgrav 		arg2 = NULL;
141319261079SEd Maste 		if ((arg = argv_next(&ac, &av)) != NULL) {
141447dd1d1bSDag-Erling Smørgrav 			if (strcmp(arg, "rdomain") != 0 ||
141519261079SEd Maste 			    (arg2 = argv_next(&ac, &av)) == NULL)
141647dd1d1bSDag-Erling Smørgrav 				fatal("%s line %d: bad ListenAddress syntax",
141747dd1d1bSDag-Erling Smørgrav 				    filename, linenum);
141847dd1d1bSDag-Erling Smørgrav 			if (!valid_rdomain(arg2))
141947dd1d1bSDag-Erling Smørgrav 				fatal("%s line %d: bad routing domain",
142047dd1d1bSDag-Erling Smørgrav 				    filename, linenum);
142147dd1d1bSDag-Erling Smørgrav 		}
142247dd1d1bSDag-Erling Smørgrav 		queue_listen_addr(options, p, arg2, port);
1423aa49c926SDag-Erling Smørgrav 
1424aa49c926SDag-Erling Smørgrav 		break;
1425aa49c926SDag-Erling Smørgrav 
1426aa49c926SDag-Erling Smørgrav 	case sAddressFamily:
1427e146993eSDag-Erling Smørgrav 		intptr = &options->address_family;
1428e146993eSDag-Erling Smørgrav 		multistate_ptr = multistate_addressfamily;
1429e146993eSDag-Erling Smørgrav  parse_multistate:
143019261079SEd Maste 		arg = argv_next(&ac, &av);
1431d4ecd108SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1432e146993eSDag-Erling Smørgrav 			fatal("%s line %d: missing argument.",
1433d4ecd108SDag-Erling Smørgrav 			    filename, linenum);
1434e146993eSDag-Erling Smørgrav 		value = -1;
1435e146993eSDag-Erling Smørgrav 		for (i = 0; multistate_ptr[i].key != NULL; i++) {
1436e146993eSDag-Erling Smørgrav 			if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
1437e146993eSDag-Erling Smørgrav 				value = multistate_ptr[i].value;
1438e146993eSDag-Erling Smørgrav 				break;
1439e146993eSDag-Erling Smørgrav 			}
1440e146993eSDag-Erling Smørgrav 		}
1441e146993eSDag-Erling Smørgrav 		if (value == -1)
1442e146993eSDag-Erling Smørgrav 			fatal("%s line %d: unsupported option \"%s\".",
1443aa49c926SDag-Erling Smørgrav 			    filename, linenum, arg);
1444e146993eSDag-Erling Smørgrav 		if (*activep && *intptr == -1)
1445aa49c926SDag-Erling Smørgrav 			*intptr = value;
1446511b41d2SMark Murray 		break;
1447511b41d2SMark Murray 
1448511b41d2SMark Murray 	case sHostKeyFile:
144919261079SEd Maste 		arg = argv_next(&ac, &av);
1450ca3176e7SBrian Feldman 		if (!arg || *arg == '\0')
1451ca3176e7SBrian Feldman 			fatal("%s line %d: missing file name.",
1452e8aafc91SKris Kennaway 			    filename, linenum);
145319261079SEd Maste 		if (*activep) {
145419261079SEd Maste 			servconf_add_hostkey(filename, linenum,
145519261079SEd Maste 			    options, arg, 1);
145619261079SEd Maste 		}
1457e8aafc91SKris Kennaway 		break;
1458e8aafc91SKris Kennaway 
1459e4a9863fSDag-Erling Smørgrav 	case sHostKeyAgent:
1460e4a9863fSDag-Erling Smørgrav 		charptr = &options->host_key_agent;
146119261079SEd Maste 		arg = argv_next(&ac, &av);
1462e4a9863fSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1463e4a9863fSDag-Erling Smørgrav 			fatal("%s line %d: missing socket name.",
1464e4a9863fSDag-Erling Smørgrav 			    filename, linenum);
1465e4a9863fSDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
1466e4a9863fSDag-Erling Smørgrav 			*charptr = !strcmp(arg, SSH_AUTHSOCKET_ENV_NAME) ?
1467e4a9863fSDag-Erling Smørgrav 			    xstrdup(arg) : derelativise_path(arg);
1468e4a9863fSDag-Erling Smørgrav 		break;
1469e4a9863fSDag-Erling Smørgrav 
1470b15c8340SDag-Erling Smørgrav 	case sHostCertificate:
147119261079SEd Maste 		arg = argv_next(&ac, &av);
147247dd1d1bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
147347dd1d1bSDag-Erling Smørgrav 			fatal("%s line %d: missing file name.",
147447dd1d1bSDag-Erling Smørgrav 			    filename, linenum);
147547dd1d1bSDag-Erling Smørgrav 		if (*activep)
147647dd1d1bSDag-Erling Smørgrav 			servconf_add_hostcert(filename, linenum, options, arg);
147747dd1d1bSDag-Erling Smørgrav 		break;
1478b15c8340SDag-Erling Smørgrav 
1479e8aafc91SKris Kennaway 	case sPidFile:
1480e8aafc91SKris Kennaway 		charptr = &options->pid_file;
148147dd1d1bSDag-Erling Smørgrav  parse_filename:
148219261079SEd Maste 		arg = argv_next(&ac, &av);
148347dd1d1bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
148447dd1d1bSDag-Erling Smørgrav 			fatal("%s line %d: missing file name.",
148547dd1d1bSDag-Erling Smørgrav 			    filename, linenum);
148647dd1d1bSDag-Erling Smørgrav 		if (*activep && *charptr == NULL) {
148747dd1d1bSDag-Erling Smørgrav 			*charptr = derelativise_path(arg);
148847dd1d1bSDag-Erling Smørgrav 			/* increase optional counter */
148947dd1d1bSDag-Erling Smørgrav 			if (intptr != NULL)
149047dd1d1bSDag-Erling Smørgrav 				*intptr = *intptr + 1;
149147dd1d1bSDag-Erling Smørgrav 		}
149247dd1d1bSDag-Erling Smørgrav 		break;
1493511b41d2SMark Murray 
149419261079SEd Maste 	case sModuliFile:
149519261079SEd Maste 		charptr = &options->moduli_file;
149619261079SEd Maste 		goto parse_filename;
149719261079SEd Maste 
1498511b41d2SMark Murray 	case sPermitRootLogin:
1499511b41d2SMark Murray 		intptr = &options->permit_root_login;
1500e146993eSDag-Erling Smørgrav 		multistate_ptr = multistate_permitrootlogin;
1501e146993eSDag-Erling Smørgrav 		goto parse_multistate;
1502511b41d2SMark Murray 
1503511b41d2SMark Murray 	case sIgnoreRhosts:
1504511b41d2SMark Murray 		intptr = &options->ignore_rhosts;
150519261079SEd Maste 		multistate_ptr = multistate_ignore_rhosts;
150647dd1d1bSDag-Erling Smørgrav 		goto parse_multistate;
1507511b41d2SMark Murray 
1508511b41d2SMark Murray 	case sIgnoreUserKnownHosts:
1509511b41d2SMark Murray 		intptr = &options->ignore_user_known_hosts;
151019261079SEd Maste  parse_flag:
151119261079SEd Maste 		multistate_ptr = multistate_flag;
151219261079SEd Maste 		goto parse_multistate;
1513511b41d2SMark Murray 
1514ca3176e7SBrian Feldman 	case sHostbasedAuthentication:
1515ca3176e7SBrian Feldman 		intptr = &options->hostbased_authentication;
1516ca3176e7SBrian Feldman 		goto parse_flag;
1517ca3176e7SBrian Feldman 
1518ca3176e7SBrian Feldman 	case sHostbasedUsesNameFromPacketOnly:
1519ca3176e7SBrian Feldman 		intptr = &options->hostbased_uses_name_from_packet_only;
1520ca3176e7SBrian Feldman 		goto parse_flag;
1521ca3176e7SBrian Feldman 
152219261079SEd Maste 	case sHostbasedAcceptedAlgorithms:
152319261079SEd Maste 		charptr = &options->hostbased_accepted_algos;
152419261079SEd Maste  parse_pubkey_algos:
152519261079SEd Maste 		arg = argv_next(&ac, &av);
1526bc5531deSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1527bc5531deSDag-Erling Smørgrav 			fatal("%s line %d: Missing argument.",
1528bc5531deSDag-Erling Smørgrav 			    filename, linenum);
1529d93a896eSDag-Erling Smørgrav 		if (*arg != '-' &&
153019261079SEd Maste 		    !sshkey_names_valid2(*arg == '+' || *arg == '^' ?
153119261079SEd Maste 		    arg + 1 : arg, 1))
1532bc5531deSDag-Erling Smørgrav 			fatal("%s line %d: Bad key types '%s'.",
1533bc5531deSDag-Erling Smørgrav 			    filename, linenum, arg ? arg : "<NONE>");
1534bc5531deSDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
1535bc5531deSDag-Erling Smørgrav 			*charptr = xstrdup(arg);
1536bc5531deSDag-Erling Smørgrav 		break;
1537bc5531deSDag-Erling Smørgrav 
1538eccfee6eSDag-Erling Smørgrav 	case sHostKeyAlgorithms:
1539eccfee6eSDag-Erling Smørgrav 		charptr = &options->hostkeyalgorithms;
154019261079SEd Maste 		goto parse_pubkey_algos;
1541eccfee6eSDag-Erling Smørgrav 
15422f513db7SEd Maste 	case sCASignatureAlgorithms:
15432f513db7SEd Maste 		charptr = &options->ca_sign_algorithms;
154419261079SEd Maste 		goto parse_pubkey_algos;
15452f513db7SEd Maste 
1546ca3176e7SBrian Feldman 	case sPubkeyAuthentication:
1547ca3176e7SBrian Feldman 		intptr = &options->pubkey_authentication;
1548e8aafc91SKris Kennaway 		goto parse_flag;
1549cf2b5f3bSDag-Erling Smørgrav 
155019261079SEd Maste 	case sPubkeyAcceptedAlgorithms:
155119261079SEd Maste 		charptr = &options->pubkey_accepted_algos;
155219261079SEd Maste 		goto parse_pubkey_algos;
155319261079SEd Maste 
155419261079SEd Maste 	case sPubkeyAuthOptions:
155519261079SEd Maste 		intptr = &options->pubkey_auth_options;
155619261079SEd Maste 		value = 0;
155719261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
155819261079SEd Maste 			if (strcasecmp(arg, "none") == 0)
155919261079SEd Maste 				continue;
156019261079SEd Maste 			if (strcasecmp(arg, "touch-required") == 0)
156119261079SEd Maste 				value |= PUBKEYAUTH_TOUCH_REQUIRED;
156219261079SEd Maste 			else if (strcasecmp(arg, "verify-required") == 0)
156319261079SEd Maste 				value |= PUBKEYAUTH_VERIFY_REQUIRED;
156419261079SEd Maste 			else {
156519261079SEd Maste 				error("%s line %d: unsupported %s option %s",
156619261079SEd Maste 				    filename, linenum, keyword, arg);
156719261079SEd Maste 				goto out;
156819261079SEd Maste 			}
156919261079SEd Maste 		}
157019261079SEd Maste 		if (*activep && *intptr == -1)
157119261079SEd Maste 			*intptr = value;
157219261079SEd Maste 		break;
1573bc5531deSDag-Erling Smørgrav 
1574cb96ab36SAssar Westerlund 	case sKerberosAuthentication:
1575cb96ab36SAssar Westerlund 		intptr = &options->kerberos_authentication;
1576511b41d2SMark Murray 		goto parse_flag;
1577511b41d2SMark Murray 
1578af12a3e7SDag-Erling Smørgrav 	case sKerberosOrLocalPasswd:
1579af12a3e7SDag-Erling Smørgrav 		intptr = &options->kerberos_or_local_passwd;
1580511b41d2SMark Murray 		goto parse_flag;
1581511b41d2SMark Murray 
1582af12a3e7SDag-Erling Smørgrav 	case sKerberosTicketCleanup:
1583af12a3e7SDag-Erling Smørgrav 		intptr = &options->kerberos_ticket_cleanup;
1584511b41d2SMark Murray 		goto parse_flag;
1585cf2b5f3bSDag-Erling Smørgrav 
15861ec0d754SDag-Erling Smørgrav 	case sKerberosGetAFSToken:
15871ec0d754SDag-Erling Smørgrav 		intptr = &options->kerberos_get_afs_token;
15881ec0d754SDag-Erling Smørgrav 		goto parse_flag;
15891ec0d754SDag-Erling Smørgrav 
1590cf2b5f3bSDag-Erling Smørgrav 	case sGssAuthentication:
1591cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->gss_authentication;
1592fe5fd017SMark Murray 		goto parse_flag;
1593cf2b5f3bSDag-Erling Smørgrav 
1594cf2b5f3bSDag-Erling Smørgrav 	case sGssCleanupCreds:
1595cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->gss_cleanup_creds;
1596511b41d2SMark Murray 		goto parse_flag;
1597511b41d2SMark Murray 
1598557f75e5SDag-Erling Smørgrav 	case sGssStrictAcceptor:
1599557f75e5SDag-Erling Smørgrav 		intptr = &options->gss_strict_acceptor;
1600557f75e5SDag-Erling Smørgrav 		goto parse_flag;
1601557f75e5SDag-Erling Smørgrav 
1602511b41d2SMark Murray 	case sPasswordAuthentication:
1603511b41d2SMark Murray 		intptr = &options->password_authentication;
1604511b41d2SMark Murray 		goto parse_flag;
1605511b41d2SMark Murray 
160609958426SBrian Feldman 	case sKbdInteractiveAuthentication:
160709958426SBrian Feldman 		intptr = &options->kbd_interactive_authentication;
160809958426SBrian Feldman 		goto parse_flag;
160909958426SBrian Feldman 
1610511b41d2SMark Murray 	case sPrintMotd:
1611511b41d2SMark Murray 		intptr = &options->print_motd;
1612511b41d2SMark Murray 		goto parse_flag;
1613511b41d2SMark Murray 
1614ca3176e7SBrian Feldman 	case sPrintLastLog:
1615ca3176e7SBrian Feldman 		intptr = &options->print_lastlog;
1616ca3176e7SBrian Feldman 		goto parse_flag;
1617ca3176e7SBrian Feldman 
1618511b41d2SMark Murray 	case sX11Forwarding:
1619511b41d2SMark Murray 		intptr = &options->x11_forwarding;
1620511b41d2SMark Murray 		goto parse_flag;
1621511b41d2SMark Murray 
1622511b41d2SMark Murray 	case sX11DisplayOffset:
1623511b41d2SMark Murray 		intptr = &options->x11_display_offset;
1624ca86bcf2SDag-Erling Smørgrav  parse_int:
162519261079SEd Maste 		arg = argv_next(&ac, &av);
162647dd1d1bSDag-Erling Smørgrav 		if ((errstr = atoi_err(arg, &value)) != NULL)
162719261079SEd Maste 			fatal("%s line %d: %s integer value %s.",
162819261079SEd Maste 			    filename, linenum, keyword, errstr);
1629ca86bcf2SDag-Erling Smørgrav 		if (*activep && *intptr == -1)
1630ca86bcf2SDag-Erling Smørgrav 			*intptr = value;
1631ca86bcf2SDag-Erling Smørgrav 		break;
1632511b41d2SMark Murray 
1633af12a3e7SDag-Erling Smørgrav 	case sX11UseLocalhost:
1634af12a3e7SDag-Erling Smørgrav 		intptr = &options->x11_use_localhost;
1635af12a3e7SDag-Erling Smørgrav 		goto parse_flag;
1636af12a3e7SDag-Erling Smørgrav 
1637c2d3a559SKris Kennaway 	case sXAuthLocation:
1638c2d3a559SKris Kennaway 		charptr = &options->xauth_location;
1639c2d3a559SKris Kennaway 		goto parse_filename;
1640c2d3a559SKris Kennaway 
1641f7167e0eSDag-Erling Smørgrav 	case sPermitTTY:
1642f7167e0eSDag-Erling Smørgrav 		intptr = &options->permit_tty;
1643f7167e0eSDag-Erling Smørgrav 		goto parse_flag;
1644f7167e0eSDag-Erling Smørgrav 
1645a0ee8cc6SDag-Erling Smørgrav 	case sPermitUserRC:
1646a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->permit_user_rc;
1647a0ee8cc6SDag-Erling Smørgrav 		goto parse_flag;
1648a0ee8cc6SDag-Erling Smørgrav 
1649511b41d2SMark Murray 	case sStrictModes:
1650511b41d2SMark Murray 		intptr = &options->strict_modes;
1651511b41d2SMark Murray 		goto parse_flag;
1652511b41d2SMark Murray 
16531ec0d754SDag-Erling Smørgrav 	case sTCPKeepAlive:
16541ec0d754SDag-Erling Smørgrav 		intptr = &options->tcp_keep_alive;
1655511b41d2SMark Murray 		goto parse_flag;
1656511b41d2SMark Murray 
1657511b41d2SMark Murray 	case sEmptyPasswd:
1658511b41d2SMark Murray 		intptr = &options->permit_empty_passwd;
1659511b41d2SMark Murray 		goto parse_flag;
1660511b41d2SMark Murray 
1661f388f5efSDag-Erling Smørgrav 	case sPermitUserEnvironment:
1662f388f5efSDag-Erling Smørgrav 		intptr = &options->permit_user_env;
166319261079SEd Maste 		charptr = &options->permit_user_env_allowlist;
166419261079SEd Maste 		arg = argv_next(&ac, &av);
1665190cef3dSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
166619261079SEd Maste 			fatal("%s line %d: %s missing argument.",
166719261079SEd Maste 			    filename, linenum, keyword);
1668190cef3dSDag-Erling Smørgrav 		value = 0;
1669190cef3dSDag-Erling Smørgrav 		p = NULL;
1670190cef3dSDag-Erling Smørgrav 		if (strcmp(arg, "yes") == 0)
1671190cef3dSDag-Erling Smørgrav 			value = 1;
1672190cef3dSDag-Erling Smørgrav 		else if (strcmp(arg, "no") == 0)
1673190cef3dSDag-Erling Smørgrav 			value = 0;
1674190cef3dSDag-Erling Smørgrav 		else {
1675190cef3dSDag-Erling Smørgrav 			/* Pattern-list specified */
1676190cef3dSDag-Erling Smørgrav 			value = 1;
1677190cef3dSDag-Erling Smørgrav 			p = xstrdup(arg);
1678190cef3dSDag-Erling Smørgrav 		}
1679190cef3dSDag-Erling Smørgrav 		if (*activep && *intptr == -1) {
1680190cef3dSDag-Erling Smørgrav 			*intptr = value;
1681190cef3dSDag-Erling Smørgrav 			*charptr = p;
1682190cef3dSDag-Erling Smørgrav 			p = NULL;
1683190cef3dSDag-Erling Smørgrav 		}
1684190cef3dSDag-Erling Smørgrav 		free(p);
1685190cef3dSDag-Erling Smørgrav 		break;
1686f388f5efSDag-Erling Smørgrav 
168780628bacSDag-Erling Smørgrav 	case sCompression:
168880628bacSDag-Erling Smørgrav 		intptr = &options->compression;
1689e146993eSDag-Erling Smørgrav 		multistate_ptr = multistate_compression;
1690e146993eSDag-Erling Smørgrav 		goto parse_multistate;
169180628bacSDag-Erling Smørgrav 
1692e4a9863fSDag-Erling Smørgrav 	case sRekeyLimit:
169319261079SEd Maste 		arg = argv_next(&ac, &av);
1694e4a9863fSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
169519261079SEd Maste 			fatal("%s line %d: %s missing argument.",
169619261079SEd Maste 			    filename, linenum, keyword);
1697e4a9863fSDag-Erling Smørgrav 		if (strcmp(arg, "default") == 0) {
1698e4a9863fSDag-Erling Smørgrav 			val64 = 0;
1699e4a9863fSDag-Erling Smørgrav 		} else {
1700e4a9863fSDag-Erling Smørgrav 			if (scan_scaled(arg, &val64) == -1)
170119261079SEd Maste 				fatal("%.200s line %d: Bad %s number '%s': %s",
170219261079SEd Maste 				    filename, linenum, keyword,
170319261079SEd Maste 				    arg, strerror(errno));
1704e4a9863fSDag-Erling Smørgrav 			if (val64 != 0 && val64 < 16)
170519261079SEd Maste 				fatal("%.200s line %d: %s too small",
170619261079SEd Maste 				    filename, linenum, keyword);
1707e4a9863fSDag-Erling Smørgrav 		}
1708e4a9863fSDag-Erling Smørgrav 		if (*activep && options->rekey_limit == -1)
1709acc1a9efSDag-Erling Smørgrav 			options->rekey_limit = val64;
171019261079SEd Maste 		if (ac != 0) { /* optional rekey interval present */
171119261079SEd Maste 			if (strcmp(av[0], "none") == 0) {
171219261079SEd Maste 				(void)argv_next(&ac, &av);	/* discard */
1713e4a9863fSDag-Erling Smørgrav 				break;
1714e4a9863fSDag-Erling Smørgrav 			}
1715e4a9863fSDag-Erling Smørgrav 			intptr = &options->rekey_interval;
1716e4a9863fSDag-Erling Smørgrav 			goto parse_time;
1717e4a9863fSDag-Erling Smørgrav 		}
1718e4a9863fSDag-Erling Smørgrav 		break;
1719e4a9863fSDag-Erling Smørgrav 
1720e8aafc91SKris Kennaway 	case sGatewayPorts:
1721a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->fwd_opts.gateway_ports;
1722e146993eSDag-Erling Smørgrav 		multistate_ptr = multistate_gatewayports;
1723e146993eSDag-Erling Smørgrav 		goto parse_multistate;
1724e8aafc91SKris Kennaway 
1725cf2b5f3bSDag-Erling Smørgrav 	case sUseDNS:
1726cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->use_dns;
1727ca3176e7SBrian Feldman 		goto parse_flag;
1728ca3176e7SBrian Feldman 
1729511b41d2SMark Murray 	case sLogFacility:
1730d4af9e69SDag-Erling Smørgrav 		log_facility_ptr = &options->log_facility;
173119261079SEd Maste 		arg = argv_next(&ac, &av);
1732c2d3a559SKris Kennaway 		value = log_facility_number(arg);
1733af12a3e7SDag-Erling Smørgrav 		if (value == SYSLOG_FACILITY_NOT_SET)
1734ca3176e7SBrian Feldman 			fatal("%.200s line %d: unsupported log facility '%s'",
1735c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
1736d4af9e69SDag-Erling Smørgrav 		if (*log_facility_ptr == -1)
1737d4af9e69SDag-Erling Smørgrav 			*log_facility_ptr = (SyslogFacility) value;
1738511b41d2SMark Murray 		break;
1739511b41d2SMark Murray 
1740511b41d2SMark Murray 	case sLogLevel:
1741d4af9e69SDag-Erling Smørgrav 		log_level_ptr = &options->log_level;
174219261079SEd Maste 		arg = argv_next(&ac, &av);
1743c2d3a559SKris Kennaway 		value = log_level_number(arg);
1744af12a3e7SDag-Erling Smørgrav 		if (value == SYSLOG_LEVEL_NOT_SET)
1745ca3176e7SBrian Feldman 			fatal("%.200s line %d: unsupported log level '%s'",
1746c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
17474f52dfbbSDag-Erling Smørgrav 		if (*activep && *log_level_ptr == -1)
1748d4af9e69SDag-Erling Smørgrav 			*log_level_ptr = (LogLevel) value;
1749511b41d2SMark Murray 		break;
1750511b41d2SMark Murray 
175119261079SEd Maste 	case sLogVerbose:
175219261079SEd Maste 		found = options->num_log_verbose == 0;
175319261079SEd Maste 		i = 0;
175419261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
175519261079SEd Maste 			if (*arg == '\0') {
175619261079SEd Maste 				error("%s line %d: keyword %s empty argument",
175719261079SEd Maste 				    filename, linenum, keyword);
175819261079SEd Maste 				goto out;
175919261079SEd Maste 			}
176019261079SEd Maste 			/* Allow "none" only in first position */
176119261079SEd Maste 			if (strcasecmp(arg, "none") == 0) {
176219261079SEd Maste 				if (i > 0 || ac > 0) {
176319261079SEd Maste 					error("%s line %d: keyword %s \"none\" "
176419261079SEd Maste 					    "argument must appear alone.",
176519261079SEd Maste 					    filename, linenum, keyword);
176619261079SEd Maste 					goto out;
176719261079SEd Maste 				}
176819261079SEd Maste 			}
176919261079SEd Maste 			i++;
177019261079SEd Maste 			if (!found || !*activep)
177119261079SEd Maste 				continue;
177219261079SEd Maste 			opt_array_append(filename, linenum, keyword,
177319261079SEd Maste 			    &options->log_verbose, &options->num_log_verbose,
177419261079SEd Maste 			    arg);
177519261079SEd Maste 		}
177619261079SEd Maste 		break;
177719261079SEd Maste 
177809958426SBrian Feldman 	case sAllowTcpForwarding:
177909958426SBrian Feldman 		intptr = &options->allow_tcp_forwarding;
17806888a9beSDag-Erling Smørgrav 		multistate_ptr = multistate_tcpfwd;
17816888a9beSDag-Erling Smørgrav 		goto parse_multistate;
178209958426SBrian Feldman 
1783a0ee8cc6SDag-Erling Smørgrav 	case sAllowStreamLocalForwarding:
1784a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->allow_streamlocal_forwarding;
1785a0ee8cc6SDag-Erling Smørgrav 		multistate_ptr = multistate_tcpfwd;
1786a0ee8cc6SDag-Erling Smørgrav 		goto parse_multistate;
1787a0ee8cc6SDag-Erling Smørgrav 
1788d4af9e69SDag-Erling Smørgrav 	case sAllowAgentForwarding:
1789d4af9e69SDag-Erling Smørgrav 		intptr = &options->allow_agent_forwarding;
1790d4af9e69SDag-Erling Smørgrav 		goto parse_flag;
1791d4af9e69SDag-Erling Smørgrav 
1792ca86bcf2SDag-Erling Smørgrav 	case sDisableForwarding:
1793ca86bcf2SDag-Erling Smørgrav 		intptr = &options->disable_forwarding;
1794ca86bcf2SDag-Erling Smørgrav 		goto parse_flag;
1795ca86bcf2SDag-Erling Smørgrav 
1796511b41d2SMark Murray 	case sAllowUsers:
179719261079SEd Maste 		chararrayptr = &options->allow_users;
179819261079SEd Maste 		uintptr = &options->num_allow_users;
179919261079SEd Maste  parse_allowdenyusers:
180019261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
180119261079SEd Maste 			if (*arg == '\0' ||
180219261079SEd Maste 			    match_user(NULL, NULL, NULL, arg) == -1)
180319261079SEd Maste 				fatal("%s line %d: invalid %s pattern: \"%s\"",
180419261079SEd Maste 				    filename, linenum, keyword, arg);
1805462c32cbSDag-Erling Smørgrav 			if (!*activep)
1806462c32cbSDag-Erling Smørgrav 				continue;
180719261079SEd Maste 			opt_array_append(filename, linenum, keyword,
180819261079SEd Maste 			    chararrayptr, uintptr, arg);
1809511b41d2SMark Murray 		}
1810511b41d2SMark Murray 		break;
1811511b41d2SMark Murray 
1812511b41d2SMark Murray 	case sDenyUsers:
181319261079SEd Maste 		chararrayptr = &options->deny_users;
181419261079SEd Maste 		uintptr = &options->num_deny_users;
181519261079SEd Maste 		goto parse_allowdenyusers;
1816511b41d2SMark Murray 
1817511b41d2SMark Murray 	case sAllowGroups:
181819261079SEd Maste 		chararrayptr = &options->allow_groups;
181919261079SEd Maste 		uintptr = &options->num_allow_groups;
182019261079SEd Maste  parse_allowdenygroups:
182119261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
182219261079SEd Maste 			if (*arg == '\0')
182319261079SEd Maste 				fatal("%s line %d: empty %s pattern",
182419261079SEd Maste 				    filename, linenum, keyword);
1825462c32cbSDag-Erling Smørgrav 			if (!*activep)
1826462c32cbSDag-Erling Smørgrav 				continue;
182719261079SEd Maste 			opt_array_append(filename, linenum, keyword,
182819261079SEd Maste 			    chararrayptr, uintptr, arg);
1829511b41d2SMark Murray 		}
1830511b41d2SMark Murray 		break;
1831511b41d2SMark Murray 
1832511b41d2SMark Murray 	case sDenyGroups:
183319261079SEd Maste 		chararrayptr = &options->deny_groups;
183419261079SEd Maste 		uintptr = &options->num_deny_groups;
183519261079SEd Maste 		goto parse_allowdenygroups;
1836511b41d2SMark Murray 
1837e8aafc91SKris Kennaway 	case sCiphers:
183819261079SEd Maste 		arg = argv_next(&ac, &av);
1839c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
184019261079SEd Maste 			fatal("%s line %d: %s missing argument.",
184119261079SEd Maste 			    filename, linenum, keyword);
184219261079SEd Maste 		if (*arg != '-' &&
184319261079SEd Maste 		    !ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg))
1844e8aafc91SKris Kennaway 			fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
1845c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
1846e8aafc91SKris Kennaway 		if (options->ciphers == NULL)
1847c2d3a559SKris Kennaway 			options->ciphers = xstrdup(arg);
1848e8aafc91SKris Kennaway 		break;
1849e8aafc91SKris Kennaway 
1850ca3176e7SBrian Feldman 	case sMacs:
185119261079SEd Maste 		arg = argv_next(&ac, &av);
1852ca3176e7SBrian Feldman 		if (!arg || *arg == '\0')
185319261079SEd Maste 			fatal("%s line %d: %s missing argument.",
185419261079SEd Maste 			    filename, linenum, keyword);
185519261079SEd Maste 		if (*arg != '-' &&
185619261079SEd Maste 		    !mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg))
1857ca3176e7SBrian Feldman 			fatal("%s line %d: Bad SSH2 mac spec '%s'.",
1858ca3176e7SBrian Feldman 			    filename, linenum, arg ? arg : "<NONE>");
1859ca3176e7SBrian Feldman 		if (options->macs == NULL)
1860ca3176e7SBrian Feldman 			options->macs = xstrdup(arg);
1861ca3176e7SBrian Feldman 		break;
1862ca3176e7SBrian Feldman 
18634a421b63SDag-Erling Smørgrav 	case sKexAlgorithms:
186419261079SEd Maste 		arg = argv_next(&ac, &av);
18654a421b63SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
186619261079SEd Maste 			fatal("%s line %d: %s missing argument.",
186719261079SEd Maste 			    filename, linenum, keyword);
1868d93a896eSDag-Erling Smørgrav 		if (*arg != '-' &&
186919261079SEd Maste 		    !kex_names_valid(*arg == '+' || *arg == '^' ?
187019261079SEd Maste 		    arg + 1 : arg))
18714a421b63SDag-Erling Smørgrav 			fatal("%s line %d: Bad SSH2 KexAlgorithms '%s'.",
18724a421b63SDag-Erling Smørgrav 			    filename, linenum, arg ? arg : "<NONE>");
18734a421b63SDag-Erling Smørgrav 		if (options->kex_algorithms == NULL)
18744a421b63SDag-Erling Smørgrav 			options->kex_algorithms = xstrdup(arg);
18754a421b63SDag-Erling Smørgrav 		break;
18764a421b63SDag-Erling Smørgrav 
1877c2d3a559SKris Kennaway 	case sSubsystem:
1878c2d3a559SKris Kennaway 		if (options->num_subsystems >= MAX_SUBSYSTEMS) {
1879c2d3a559SKris Kennaway 			fatal("%s line %d: too many subsystems defined.",
1880c2d3a559SKris Kennaway 			    filename, linenum);
1881c2d3a559SKris Kennaway 		}
188219261079SEd Maste 		arg = argv_next(&ac, &av);
1883c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
188419261079SEd Maste 			fatal("%s line %d: %s missing argument.",
188519261079SEd Maste 			    filename, linenum, keyword);
1886333ee039SDag-Erling Smørgrav 		if (!*activep) {
188719261079SEd Maste 			arg = argv_next(&ac, &av);
1888333ee039SDag-Erling Smørgrav 			break;
1889333ee039SDag-Erling Smørgrav 		}
1890c2d3a559SKris Kennaway 		for (i = 0; i < options->num_subsystems; i++)
1891c2d3a559SKris Kennaway 			if (strcmp(arg, options->subsystem_name[i]) == 0)
189219261079SEd Maste 				fatal("%s line %d: Subsystem '%s' "
189319261079SEd Maste 				    "already defined.", filename, linenum, arg);
1894c2d3a559SKris Kennaway 		options->subsystem_name[options->num_subsystems] = xstrdup(arg);
189519261079SEd Maste 		arg = argv_next(&ac, &av);
1896c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1897c2d3a559SKris Kennaway 			fatal("%s line %d: Missing subsystem command.",
1898c2d3a559SKris Kennaway 			    filename, linenum);
1899c2d3a559SKris Kennaway 		options->subsystem_command[options->num_subsystems] = xstrdup(arg);
1900333ee039SDag-Erling Smørgrav 
1901333ee039SDag-Erling Smørgrav 		/* Collect arguments (separate to executable) */
1902333ee039SDag-Erling Smørgrav 		p = xstrdup(arg);
1903333ee039SDag-Erling Smørgrav 		len = strlen(p) + 1;
190419261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
1905333ee039SDag-Erling Smørgrav 			len += 1 + strlen(arg);
1906557f75e5SDag-Erling Smørgrav 			p = xreallocarray(p, 1, len);
1907333ee039SDag-Erling Smørgrav 			strlcat(p, " ", len);
1908333ee039SDag-Erling Smørgrav 			strlcat(p, arg, len);
1909333ee039SDag-Erling Smørgrav 		}
1910333ee039SDag-Erling Smørgrav 		options->subsystem_args[options->num_subsystems] = p;
1911c2d3a559SKris Kennaway 		options->num_subsystems++;
1912c2d3a559SKris Kennaway 		break;
1913c2d3a559SKris Kennaway 
1914c2d3a559SKris Kennaway 	case sMaxStartups:
191519261079SEd Maste 		arg = argv_next(&ac, &av);
1916c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
191719261079SEd Maste 			fatal("%s line %d: %s missing argument.",
191819261079SEd Maste 			    filename, linenum, keyword);
1919af12a3e7SDag-Erling Smørgrav 		if ((n = sscanf(arg, "%d:%d:%d",
1920c2d3a559SKris Kennaway 		    &options->max_startups_begin,
1921c2d3a559SKris Kennaway 		    &options->max_startups_rate,
1922af12a3e7SDag-Erling Smørgrav 		    &options->max_startups)) == 3) {
1923c2d3a559SKris Kennaway 			if (options->max_startups_begin >
1924c2d3a559SKris Kennaway 			    options->max_startups ||
1925c2d3a559SKris Kennaway 			    options->max_startups_rate > 100 ||
1926c2d3a559SKris Kennaway 			    options->max_startups_rate < 1)
192719261079SEd Maste 				fatal("%s line %d: Invalid %s spec.",
192819261079SEd Maste 				    filename, linenum, keyword);
1929af12a3e7SDag-Erling Smørgrav 		} else if (n != 1)
193019261079SEd Maste 			fatal("%s line %d: Invalid %s spec.",
193119261079SEd Maste 			    filename, linenum, keyword);
1932af12a3e7SDag-Erling Smørgrav 		else
1933af12a3e7SDag-Erling Smørgrav 			options->max_startups = options->max_startups_begin;
1934933ca70fSBrian Feldman 		break;
1935933ca70fSBrian Feldman 
193619261079SEd Maste 	case sPerSourceNetBlockSize:
193719261079SEd Maste 		arg = argv_next(&ac, &av);
193819261079SEd Maste 		if (!arg || *arg == '\0')
193919261079SEd Maste 			fatal("%s line %d: %s missing argument.",
194019261079SEd Maste 			    filename, linenum, keyword);
194119261079SEd Maste 		switch (n = sscanf(arg, "%d:%d", &value, &value2)) {
194219261079SEd Maste 		case 2:
194319261079SEd Maste 			if (value2 < 0 || value2 > 128)
194419261079SEd Maste 				n = -1;
194519261079SEd Maste 			/* FALLTHROUGH */
194619261079SEd Maste 		case 1:
194719261079SEd Maste 			if (value < 0 || value > 32)
194819261079SEd Maste 				n = -1;
194919261079SEd Maste 		}
195019261079SEd Maste 		if (n != 1 && n != 2)
195119261079SEd Maste 			fatal("%s line %d: Invalid %s spec.",
195219261079SEd Maste 			    filename, linenum, keyword);
195319261079SEd Maste 		if (*activep) {
195419261079SEd Maste 			options->per_source_masklen_ipv4 = value;
195519261079SEd Maste 			options->per_source_masklen_ipv6 = value2;
195619261079SEd Maste 		}
195719261079SEd Maste 		break;
195819261079SEd Maste 
195919261079SEd Maste 	case sPerSourceMaxStartups:
196019261079SEd Maste 		arg = argv_next(&ac, &av);
196119261079SEd Maste 		if (!arg || *arg == '\0')
196219261079SEd Maste 			fatal("%s line %d: %s missing argument.",
196319261079SEd Maste 			    filename, linenum, keyword);
196419261079SEd Maste 		if (strcmp(arg, "none") == 0) { /* no limit */
196519261079SEd Maste 			value = INT_MAX;
196619261079SEd Maste 		} else {
196719261079SEd Maste 			if ((errstr = atoi_err(arg, &value)) != NULL)
196819261079SEd Maste 				fatal("%s line %d: %s integer value %s.",
196919261079SEd Maste 				    filename, linenum, keyword, errstr);
197019261079SEd Maste 		}
197119261079SEd Maste 		if (*activep)
197219261079SEd Maste 			options->per_source_max_startups = value;
197319261079SEd Maste 		break;
197419261079SEd Maste 
197521e764dfSDag-Erling Smørgrav 	case sMaxAuthTries:
197621e764dfSDag-Erling Smørgrav 		intptr = &options->max_authtries;
197721e764dfSDag-Erling Smørgrav 		goto parse_int;
197821e764dfSDag-Erling Smørgrav 
1979d4af9e69SDag-Erling Smørgrav 	case sMaxSessions:
1980d4af9e69SDag-Erling Smørgrav 		intptr = &options->max_sessions;
1981d4af9e69SDag-Erling Smørgrav 		goto parse_int;
1982d4af9e69SDag-Erling Smørgrav 
1983ca3176e7SBrian Feldman 	case sBanner:
1984ca3176e7SBrian Feldman 		charptr = &options->banner;
1985ca3176e7SBrian Feldman 		goto parse_filename;
1986d4af9e69SDag-Erling Smørgrav 
1987af12a3e7SDag-Erling Smørgrav 	/*
1988af12a3e7SDag-Erling Smørgrav 	 * These options can contain %X options expanded at
1989af12a3e7SDag-Erling Smørgrav 	 * connect time, so that you can specify paths like:
1990af12a3e7SDag-Erling Smørgrav 	 *
1991af12a3e7SDag-Erling Smørgrav 	 * AuthorizedKeysFile	/etc/ssh_keys/%u
1992af12a3e7SDag-Erling Smørgrav 	 */
1993af12a3e7SDag-Erling Smørgrav 	case sAuthorizedKeysFile:
199419261079SEd Maste 		uvalue = options->num_authkeys_files;
199519261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
199619261079SEd Maste 			if (*arg == '\0') {
199719261079SEd Maste 				error("%s line %d: keyword %s empty argument",
199819261079SEd Maste 				    filename, linenum, keyword);
199919261079SEd Maste 				goto out;
200019261079SEd Maste 			}
200119261079SEd Maste 			arg2 = tilde_expand_filename(arg, getuid());
200219261079SEd Maste 			if (*activep && uvalue == 0) {
200319261079SEd Maste 				opt_array_append(filename, linenum, keyword,
200447dd1d1bSDag-Erling Smørgrav 				    &options->authorized_keys_files,
200519261079SEd Maste 				    &options->num_authkeys_files, arg2);
2006e146993eSDag-Erling Smørgrav 			}
200719261079SEd Maste 			free(arg2);
2008e146993eSDag-Erling Smørgrav 		}
200919261079SEd Maste 		break;
2010e146993eSDag-Erling Smørgrav 
2011e2f6069cSDag-Erling Smørgrav 	case sAuthorizedPrincipalsFile:
2012e2f6069cSDag-Erling Smørgrav 		charptr = &options->authorized_principals_file;
201319261079SEd Maste 		arg = argv_next(&ac, &av);
20148ad9b54aSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
201519261079SEd Maste 			fatal("%s line %d: %s missing argument.",
201619261079SEd Maste 			    filename, linenum, keyword);
20178ad9b54aSDag-Erling Smørgrav 		if (*activep && *charptr == NULL) {
20188ad9b54aSDag-Erling Smørgrav 			*charptr = tilde_expand_filename(arg, getuid());
20198ad9b54aSDag-Erling Smørgrav 			/* increase optional counter */
20208ad9b54aSDag-Erling Smørgrav 			if (intptr != NULL)
20218ad9b54aSDag-Erling Smørgrav 				*intptr = *intptr + 1;
20228ad9b54aSDag-Erling Smørgrav 		}
20238ad9b54aSDag-Erling Smørgrav 		break;
2024af12a3e7SDag-Erling Smørgrav 
2025ca3176e7SBrian Feldman 	case sClientAliveInterval:
2026ca3176e7SBrian Feldman 		intptr = &options->client_alive_interval;
2027af12a3e7SDag-Erling Smørgrav 		goto parse_time;
2028af12a3e7SDag-Erling Smørgrav 
2029ca3176e7SBrian Feldman 	case sClientAliveCountMax:
2030ca3176e7SBrian Feldman 		intptr = &options->client_alive_count_max;
2031ca3176e7SBrian Feldman 		goto parse_int;
2032af12a3e7SDag-Erling Smørgrav 
203321e764dfSDag-Erling Smørgrav 	case sAcceptEnv:
203419261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
203519261079SEd Maste 			if (*arg == '\0' || strchr(arg, '=') != NULL)
203621e764dfSDag-Erling Smørgrav 				fatal("%s line %d: Invalid environment name.",
203721e764dfSDag-Erling Smørgrav 				    filename, linenum);
2038333ee039SDag-Erling Smørgrav 			if (!*activep)
2039462c32cbSDag-Erling Smørgrav 				continue;
204019261079SEd Maste 			opt_array_append(filename, linenum, keyword,
204147dd1d1bSDag-Erling Smørgrav 			    &options->accept_env, &options->num_accept_env,
204247dd1d1bSDag-Erling Smørgrav 			    arg);
204321e764dfSDag-Erling Smørgrav 		}
204421e764dfSDag-Erling Smørgrav 		break;
204521e764dfSDag-Erling Smørgrav 
2046190cef3dSDag-Erling Smørgrav 	case sSetEnv:
2047190cef3dSDag-Erling Smørgrav 		uvalue = options->num_setenv;
204819261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
204919261079SEd Maste 			if (*arg == '\0' || strchr(arg, '=') == NULL)
2050190cef3dSDag-Erling Smørgrav 				fatal("%s line %d: Invalid environment.",
2051190cef3dSDag-Erling Smørgrav 				    filename, linenum);
2052190cef3dSDag-Erling Smørgrav 			if (!*activep || uvalue != 0)
2053190cef3dSDag-Erling Smørgrav 				continue;
205419261079SEd Maste 			opt_array_append(filename, linenum, keyword,
2055190cef3dSDag-Erling Smørgrav 			    &options->setenv, &options->num_setenv, arg);
2056190cef3dSDag-Erling Smørgrav 		}
2057190cef3dSDag-Erling Smørgrav 		break;
2058190cef3dSDag-Erling Smørgrav 
2059b74df5b2SDag-Erling Smørgrav 	case sPermitTunnel:
2060b74df5b2SDag-Erling Smørgrav 		intptr = &options->permit_tun;
206119261079SEd Maste 		arg = argv_next(&ac, &av);
2062b74df5b2SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
206319261079SEd Maste 			fatal("%s line %d: %s missing argument.",
206419261079SEd Maste 			    filename, linenum, keyword);
2065d4af9e69SDag-Erling Smørgrav 		value = -1;
2066d4af9e69SDag-Erling Smørgrav 		for (i = 0; tunmode_desc[i].val != -1; i++)
2067d4af9e69SDag-Erling Smørgrav 			if (strcmp(tunmode_desc[i].text, arg) == 0) {
2068d4af9e69SDag-Erling Smørgrav 				value = tunmode_desc[i].val;
2069d4af9e69SDag-Erling Smørgrav 				break;
2070d4af9e69SDag-Erling Smørgrav 			}
2071d4af9e69SDag-Erling Smørgrav 		if (value == -1)
207219261079SEd Maste 			fatal("%s line %d: bad %s argument %s",
207319261079SEd Maste 			    filename, linenum, keyword, arg);
2074557f75e5SDag-Erling Smørgrav 		if (*activep && *intptr == -1)
2075b74df5b2SDag-Erling Smørgrav 			*intptr = value;
2076b74df5b2SDag-Erling Smørgrav 		break;
2077b74df5b2SDag-Erling Smørgrav 
207819261079SEd Maste 	case sInclude:
207919261079SEd Maste 		if (cmdline) {
208019261079SEd Maste 			fatal("Include directive not supported as a "
208119261079SEd Maste 			    "command-line option");
208219261079SEd Maste 		}
208319261079SEd Maste 		value = 0;
208419261079SEd Maste 		while ((arg2 = argv_next(&ac, &av)) != NULL) {
208519261079SEd Maste 			if (*arg2 == '\0') {
208619261079SEd Maste 				error("%s line %d: keyword %s empty argument",
208719261079SEd Maste 				    filename, linenum, keyword);
208819261079SEd Maste 				goto out;
208919261079SEd Maste 			}
209019261079SEd Maste 			value++;
209119261079SEd Maste 			found = 0;
209219261079SEd Maste 			if (*arg2 != '/' && *arg2 != '~') {
209319261079SEd Maste 				xasprintf(&arg, "%s/%s", SSHDIR, arg2);
209419261079SEd Maste 			} else
209519261079SEd Maste 				arg = xstrdup(arg2);
209619261079SEd Maste 
209719261079SEd Maste 			/*
209819261079SEd Maste 			 * Don't let included files clobber the containing
209919261079SEd Maste 			 * file's Match state.
210019261079SEd Maste 			 */
210119261079SEd Maste 			oactive = *activep;
210219261079SEd Maste 
210319261079SEd Maste 			/* consult cache of include files */
210419261079SEd Maste 			TAILQ_FOREACH(item, includes, entry) {
210519261079SEd Maste 				if (strcmp(item->selector, arg) != 0)
210619261079SEd Maste 					continue;
210719261079SEd Maste 				if (item->filename != NULL) {
210819261079SEd Maste 					parse_server_config_depth(options,
210919261079SEd Maste 					    item->filename, item->contents,
211019261079SEd Maste 					    includes, connectinfo,
211119261079SEd Maste 					    (*inc_flags & SSHCFG_MATCH_ONLY
211219261079SEd Maste 					        ? SSHCFG_MATCH_ONLY : (oactive
211319261079SEd Maste 					            ? 0 : SSHCFG_NEVERMATCH)),
211419261079SEd Maste 					    activep, depth + 1);
211519261079SEd Maste 				}
211619261079SEd Maste 				found = 1;
211719261079SEd Maste 				*activep = oactive;
211819261079SEd Maste 			}
211919261079SEd Maste 			if (found != 0) {
212019261079SEd Maste 				free(arg);
212119261079SEd Maste 				continue;
212219261079SEd Maste 			}
212319261079SEd Maste 
212419261079SEd Maste 			/* requested glob was not in cache */
212519261079SEd Maste 			debug2("%s line %d: new include %s",
212619261079SEd Maste 			    filename, linenum, arg);
212719261079SEd Maste 			if ((r = glob(arg, 0, NULL, &gbuf)) != 0) {
212819261079SEd Maste 				if (r != GLOB_NOMATCH) {
212919261079SEd Maste 					fatal("%s line %d: include \"%s\" glob "
213019261079SEd Maste 					    "failed", filename, linenum, arg);
213119261079SEd Maste 				}
213219261079SEd Maste 				/*
213319261079SEd Maste 				 * If no entry matched then record a
213419261079SEd Maste 				 * placeholder to skip later glob calls.
213519261079SEd Maste 				 */
213619261079SEd Maste 				debug2("%s line %d: no match for %s",
213719261079SEd Maste 				    filename, linenum, arg);
213819261079SEd Maste 				item = xcalloc(1, sizeof(*item));
213919261079SEd Maste 				item->selector = strdup(arg);
214019261079SEd Maste 				TAILQ_INSERT_TAIL(includes,
214119261079SEd Maste 				    item, entry);
214219261079SEd Maste 			}
214319261079SEd Maste 			if (gbuf.gl_pathc > INT_MAX)
214419261079SEd Maste 				fatal_f("too many glob results");
214519261079SEd Maste 			for (n = 0; n < (int)gbuf.gl_pathc; n++) {
214619261079SEd Maste 				debug2("%s line %d: including %s",
214719261079SEd Maste 				    filename, linenum, gbuf.gl_pathv[n]);
214819261079SEd Maste 				item = xcalloc(1, sizeof(*item));
214919261079SEd Maste 				item->selector = strdup(arg);
215019261079SEd Maste 				item->filename = strdup(gbuf.gl_pathv[n]);
215119261079SEd Maste 				if ((item->contents = sshbuf_new()) == NULL)
215219261079SEd Maste 					fatal_f("sshbuf_new failed");
215319261079SEd Maste 				load_server_config(item->filename,
215419261079SEd Maste 				    item->contents);
215519261079SEd Maste 				parse_server_config_depth(options,
215619261079SEd Maste 				    item->filename, item->contents,
215719261079SEd Maste 				    includes, connectinfo,
215819261079SEd Maste 				    (*inc_flags & SSHCFG_MATCH_ONLY
215919261079SEd Maste 				        ? SSHCFG_MATCH_ONLY : (oactive
216019261079SEd Maste 				            ? 0 : SSHCFG_NEVERMATCH)),
216119261079SEd Maste 				    activep, depth + 1);
216219261079SEd Maste 				*activep = oactive;
216319261079SEd Maste 				TAILQ_INSERT_TAIL(includes, item, entry);
216419261079SEd Maste 			}
216519261079SEd Maste 			globfree(&gbuf);
216619261079SEd Maste 			free(arg);
216719261079SEd Maste 		}
216819261079SEd Maste 		if (value == 0) {
216919261079SEd Maste 			fatal("%s line %d: %s missing filename argument",
217019261079SEd Maste 			    filename, linenum, keyword);
217119261079SEd Maste 		}
217219261079SEd Maste 		break;
217319261079SEd Maste 
2174333ee039SDag-Erling Smørgrav 	case sMatch:
2175333ee039SDag-Erling Smørgrav 		if (cmdline)
2176333ee039SDag-Erling Smørgrav 			fatal("Match directive not supported as a command-line "
2177333ee039SDag-Erling Smørgrav 			    "option");
217819261079SEd Maste 		value = match_cfg_line(&str, linenum,
217919261079SEd Maste 		    (*inc_flags & SSHCFG_NEVERMATCH ? NULL : connectinfo));
2180333ee039SDag-Erling Smørgrav 		if (value < 0)
2181333ee039SDag-Erling Smørgrav 			fatal("%s line %d: Bad Match condition", filename,
2182333ee039SDag-Erling Smørgrav 			    linenum);
218319261079SEd Maste 		*activep = (*inc_flags & SSHCFG_NEVERMATCH) ? 0 : value;
218419261079SEd Maste 		/*
218519261079SEd Maste 		 * The MATCH_ONLY flag is applicable only until the first
218619261079SEd Maste 		 * match block.
218719261079SEd Maste 		 */
218819261079SEd Maste 		*inc_flags &= ~SSHCFG_MATCH_ONLY;
218919261079SEd Maste 		/*
219019261079SEd Maste 		 * If match_cfg_line() didn't consume all its arguments then
219119261079SEd Maste 		 * arrange for the extra arguments check below to fail.
219219261079SEd Maste 		 */
219319261079SEd Maste 		if (str == NULL || *str == '\0')
219419261079SEd Maste 			argv_consume(&ac);
2195333ee039SDag-Erling Smørgrav 		break;
2196333ee039SDag-Erling Smørgrav 
2197190cef3dSDag-Erling Smørgrav 	case sPermitListen:
2198333ee039SDag-Erling Smørgrav 	case sPermitOpen:
2199190cef3dSDag-Erling Smørgrav 		if (opcode == sPermitListen) {
2200190cef3dSDag-Erling Smørgrav 			uintptr = &options->num_permitted_listens;
2201190cef3dSDag-Erling Smørgrav 			chararrayptr = &options->permitted_listens;
2202190cef3dSDag-Erling Smørgrav 		} else {
2203190cef3dSDag-Erling Smørgrav 			uintptr = &options->num_permitted_opens;
2204190cef3dSDag-Erling Smørgrav 			chararrayptr = &options->permitted_opens;
2205190cef3dSDag-Erling Smørgrav 		}
220619261079SEd Maste 		arg = argv_next(&ac, &av);
2207333ee039SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
220819261079SEd Maste 			fatal("%s line %d: %s missing argument.",
220919261079SEd Maste 			    filename, linenum, keyword);
2210190cef3dSDag-Erling Smørgrav 		uvalue = *uintptr;	/* modified later */
22114f52dfbbSDag-Erling Smørgrav 		if (strcmp(arg, "any") == 0 || strcmp(arg, "none") == 0) {
2212190cef3dSDag-Erling Smørgrav 			if (*activep && uvalue == 0) {
2213190cef3dSDag-Erling Smørgrav 				*uintptr = 1;
2214190cef3dSDag-Erling Smørgrav 				*chararrayptr = xcalloc(1,
2215190cef3dSDag-Erling Smørgrav 				    sizeof(**chararrayptr));
2216190cef3dSDag-Erling Smørgrav 				(*chararrayptr)[0] = xstrdup(arg);
2217462c32cbSDag-Erling Smørgrav 			}
2218462c32cbSDag-Erling Smørgrav 			break;
2219462c32cbSDag-Erling Smørgrav 		}
222019261079SEd Maste 		for (; arg != NULL && *arg != '\0'; arg = argv_next(&ac, &av)) {
2221190cef3dSDag-Erling Smørgrav 			if (opcode == sPermitListen &&
2222190cef3dSDag-Erling Smørgrav 			    strchr(arg, ':') == NULL) {
2223190cef3dSDag-Erling Smørgrav 				/*
2224190cef3dSDag-Erling Smørgrav 				 * Allow bare port number for PermitListen
2225190cef3dSDag-Erling Smørgrav 				 * to indicate a wildcard listen host.
2226190cef3dSDag-Erling Smørgrav 				 */
2227190cef3dSDag-Erling Smørgrav 				xasprintf(&arg2, "*:%s", arg);
2228190cef3dSDag-Erling Smørgrav 			} else {
22294f52dfbbSDag-Erling Smørgrav 				arg2 = xstrdup(arg);
2230*1323ec57SEd Maste 				p = hpdelim(&arg);
2231*1323ec57SEd Maste 				if (p == NULL) {
223219261079SEd Maste 					fatal("%s line %d: %s missing host",
223319261079SEd Maste 					    filename, linenum, keyword);
2234190cef3dSDag-Erling Smørgrav 				}
2235333ee039SDag-Erling Smørgrav 				p = cleanhostname(p);
2236190cef3dSDag-Erling Smørgrav 			}
2237190cef3dSDag-Erling Smørgrav 			if (arg == NULL ||
2238190cef3dSDag-Erling Smørgrav 			    ((port = permitopen_port(arg)) < 0)) {
223919261079SEd Maste 				fatal("%s line %d: %s bad port number",
224019261079SEd Maste 				    filename, linenum, keyword);
2241190cef3dSDag-Erling Smørgrav 			}
2242190cef3dSDag-Erling Smørgrav 			if (*activep && uvalue == 0) {
224319261079SEd Maste 				opt_array_append(filename, linenum, keyword,
2244190cef3dSDag-Erling Smørgrav 				    chararrayptr, uintptr, arg2);
224547dd1d1bSDag-Erling Smørgrav 			}
22464f52dfbbSDag-Erling Smørgrav 			free(arg2);
2247333ee039SDag-Erling Smørgrav 		}
2248333ee039SDag-Erling Smørgrav 		break;
2249333ee039SDag-Erling Smørgrav 
2250333ee039SDag-Erling Smørgrav 	case sForceCommand:
225119261079SEd Maste 		if (str == NULL || *str == '\0')
225219261079SEd Maste 			fatal("%s line %d: %s missing argument.",
225319261079SEd Maste 			    filename, linenum, keyword);
225419261079SEd Maste 		len = strspn(str, WHITESPACE);
2255333ee039SDag-Erling Smørgrav 		if (*activep && options->adm_forced_command == NULL)
225619261079SEd Maste 			options->adm_forced_command = xstrdup(str + len);
225719261079SEd Maste 		argv_consume(&ac);
225819261079SEd Maste 		break;
2259333ee039SDag-Erling Smørgrav 
2260d4af9e69SDag-Erling Smørgrav 	case sChrootDirectory:
2261d4af9e69SDag-Erling Smørgrav 		charptr = &options->chroot_directory;
2262d4af9e69SDag-Erling Smørgrav 
226319261079SEd Maste 		arg = argv_next(&ac, &av);
2264d4af9e69SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
226519261079SEd Maste 			fatal("%s line %d: %s missing argument.",
226619261079SEd Maste 			    filename, linenum, keyword);
2267d4af9e69SDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
2268d4af9e69SDag-Erling Smørgrav 			*charptr = xstrdup(arg);
2269d4af9e69SDag-Erling Smørgrav 		break;
2270d4af9e69SDag-Erling Smørgrav 
2271b15c8340SDag-Erling Smørgrav 	case sTrustedUserCAKeys:
2272b15c8340SDag-Erling Smørgrav 		charptr = &options->trusted_user_ca_keys;
2273b15c8340SDag-Erling Smørgrav 		goto parse_filename;
2274b15c8340SDag-Erling Smørgrav 
2275b15c8340SDag-Erling Smørgrav 	case sRevokedKeys:
2276b15c8340SDag-Erling Smørgrav 		charptr = &options->revoked_keys_file;
2277b15c8340SDag-Erling Smørgrav 		goto parse_filename;
2278b15c8340SDag-Erling Smørgrav 
227919261079SEd Maste 	case sSecurityKeyProvider:
228019261079SEd Maste 		charptr = &options->sk_provider;
228119261079SEd Maste 		arg = argv_next(&ac, &av);
228219261079SEd Maste 		if (!arg || *arg == '\0')
228319261079SEd Maste 			fatal("%s line %d: %s missing argument.",
228419261079SEd Maste 			    filename, linenum, keyword);
228519261079SEd Maste 		if (*activep && *charptr == NULL) {
228619261079SEd Maste 			*charptr = strcasecmp(arg, "internal") == 0 ?
228719261079SEd Maste 			    xstrdup(arg) : derelativise_path(arg);
228819261079SEd Maste 			/* increase optional counter */
228919261079SEd Maste 			if (intptr != NULL)
229019261079SEd Maste 				*intptr = *intptr + 1;
229119261079SEd Maste 		}
229219261079SEd Maste 		break;
229319261079SEd Maste 
22944a421b63SDag-Erling Smørgrav 	case sIPQoS:
229519261079SEd Maste 		arg = argv_next(&ac, &av);
229619261079SEd Maste 		if (!arg || *arg == '\0')
229719261079SEd Maste 			fatal("%s line %d: %s missing argument.",
229819261079SEd Maste 			    filename, linenum, keyword);
22994a421b63SDag-Erling Smørgrav 		if ((value = parse_ipqos(arg)) == -1)
230019261079SEd Maste 			fatal("%s line %d: Bad %s value: %s",
230119261079SEd Maste 			    filename, linenum, keyword, arg);
230219261079SEd Maste 		arg = argv_next(&ac, &av);
23034a421b63SDag-Erling Smørgrav 		if (arg == NULL)
23044a421b63SDag-Erling Smørgrav 			value2 = value;
23054a421b63SDag-Erling Smørgrav 		else if ((value2 = parse_ipqos(arg)) == -1)
230619261079SEd Maste 			fatal("%s line %d: Bad %s value: %s",
230719261079SEd Maste 			    filename, linenum, keyword, arg);
23084a421b63SDag-Erling Smørgrav 		if (*activep) {
23094a421b63SDag-Erling Smørgrav 			options->ip_qos_interactive = value;
23104a421b63SDag-Erling Smørgrav 			options->ip_qos_bulk = value2;
23114a421b63SDag-Erling Smørgrav 		}
23124a421b63SDag-Erling Smørgrav 		break;
23134a421b63SDag-Erling Smørgrav 
2314db58a8e4SDag-Erling Smørgrav 	case sVersionAddendum:
231519261079SEd Maste 		if (str == NULL || *str == '\0')
231619261079SEd Maste 			fatal("%s line %d: %s missing argument.",
231719261079SEd Maste 			    filename, linenum, keyword);
231819261079SEd Maste 		len = strspn(str, WHITESPACE);
231919261079SEd Maste 		if (strchr(str + len, '\r') != NULL) {
232019261079SEd Maste 			fatal("%.200s line %d: Invalid %s argument",
232119261079SEd Maste 			    filename, linenum, keyword);
2322462c32cbSDag-Erling Smørgrav 		}
232319261079SEd Maste 		if ((arg = strchr(line, '#')) != NULL) {
232419261079SEd Maste 			*arg = '\0';
232519261079SEd Maste 			rtrim(line);
232619261079SEd Maste 		}
232719261079SEd Maste 		if (*activep && options->version_addendum == NULL) {
232819261079SEd Maste 			if (strcasecmp(str + len, "none") == 0)
232919261079SEd Maste 				options->version_addendum = xstrdup("");
233019261079SEd Maste 			else
233119261079SEd Maste 				options->version_addendum = xstrdup(str + len);
233219261079SEd Maste 		}
233319261079SEd Maste 		argv_consume(&ac);
233419261079SEd Maste 		break;
2335db58a8e4SDag-Erling Smørgrav 
23366888a9beSDag-Erling Smørgrav 	case sAuthorizedKeysCommand:
233719261079SEd Maste 		charptr = &options->authorized_keys_command;
233819261079SEd Maste  parse_command:
233919261079SEd Maste 		len = strspn(str, WHITESPACE);
234019261079SEd Maste 		if (str[len] != '/' && strcasecmp(str + len, "none") != 0) {
234119261079SEd Maste 			fatal("%.200s line %d: %s must be an absolute path",
234219261079SEd Maste 			    filename, linenum, keyword);
23436888a9beSDag-Erling Smørgrav 		}
234419261079SEd Maste 		if (*activep && options->authorized_keys_command == NULL)
234519261079SEd Maste 			*charptr = xstrdup(str + len);
234619261079SEd Maste 		argv_consume(&ac);
234719261079SEd Maste 		break;
23486888a9beSDag-Erling Smørgrav 
23496888a9beSDag-Erling Smørgrav 	case sAuthorizedKeysCommandUser:
23506888a9beSDag-Erling Smørgrav 		charptr = &options->authorized_keys_command_user;
235119261079SEd Maste  parse_localuser:
235219261079SEd Maste 		arg = argv_next(&ac, &av);
235319261079SEd Maste 		if (!arg || *arg == '\0') {
235419261079SEd Maste 			fatal("%s line %d: missing %s argument.",
235519261079SEd Maste 			    filename, linenum, keyword);
235619261079SEd Maste 		}
23576888a9beSDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
23586888a9beSDag-Erling Smørgrav 			*charptr = xstrdup(arg);
23596888a9beSDag-Erling Smørgrav 		break;
23606888a9beSDag-Erling Smørgrav 
2361557f75e5SDag-Erling Smørgrav 	case sAuthorizedPrincipalsCommand:
236219261079SEd Maste 		charptr = &options->authorized_principals_command;
236319261079SEd Maste 		goto parse_command;
2364557f75e5SDag-Erling Smørgrav 
2365557f75e5SDag-Erling Smørgrav 	case sAuthorizedPrincipalsCommandUser:
2366557f75e5SDag-Erling Smørgrav 		charptr = &options->authorized_principals_command_user;
236719261079SEd Maste 		goto parse_localuser;
2368557f75e5SDag-Erling Smørgrav 
23696888a9beSDag-Erling Smørgrav 	case sAuthenticationMethods:
237019261079SEd Maste 		found = options->num_auth_methods == 0;
2371076ad2f8SDag-Erling Smørgrav 		value = 0; /* seen "any" pseudo-method */
2372190cef3dSDag-Erling Smørgrav 		value2 = 0; /* successfully parsed any method */
237319261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
2374076ad2f8SDag-Erling Smørgrav 			if (strcmp(arg, "any") == 0) {
2375076ad2f8SDag-Erling Smørgrav 				if (options->num_auth_methods > 0) {
237619261079SEd Maste 					fatal("%s line %d: \"any\" must "
237719261079SEd Maste 					    "appear alone in %s",
237819261079SEd Maste 					    filename, linenum, keyword);
2379076ad2f8SDag-Erling Smørgrav 				}
2380076ad2f8SDag-Erling Smørgrav 				value = 1;
2381076ad2f8SDag-Erling Smørgrav 			} else if (value) {
2382076ad2f8SDag-Erling Smørgrav 				fatal("%s line %d: \"any\" must appear "
238319261079SEd Maste 				    "alone in %s", filename, linenum, keyword);
2384076ad2f8SDag-Erling Smørgrav 			} else if (auth2_methods_valid(arg, 0) != 0) {
238519261079SEd Maste 				fatal("%s line %d: invalid %s method list.",
238619261079SEd Maste 				    filename, linenum, keyword);
2387076ad2f8SDag-Erling Smørgrav 			}
2388076ad2f8SDag-Erling Smørgrav 			value2 = 1;
238919261079SEd Maste 			if (!found || !*activep)
2390557f75e5SDag-Erling Smørgrav 				continue;
239119261079SEd Maste 			opt_array_append(filename, linenum, keyword,
239247dd1d1bSDag-Erling Smørgrav 			    &options->auth_methods,
239347dd1d1bSDag-Erling Smørgrav 			    &options->num_auth_methods, arg);
23946888a9beSDag-Erling Smørgrav 		}
2395076ad2f8SDag-Erling Smørgrav 		if (value2 == 0) {
239619261079SEd Maste 			fatal("%s line %d: no %s specified",
239719261079SEd Maste 			    filename, linenum, keyword);
2398076ad2f8SDag-Erling Smørgrav 		}
239919261079SEd Maste 		break;
24006888a9beSDag-Erling Smørgrav 
2401a0ee8cc6SDag-Erling Smørgrav 	case sStreamLocalBindMask:
240219261079SEd Maste 		arg = argv_next(&ac, &av);
2403a0ee8cc6SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
240419261079SEd Maste 			fatal("%s line %d: %s missing argument.",
240519261079SEd Maste 			    filename, linenum, keyword);
2406a0ee8cc6SDag-Erling Smørgrav 		/* Parse mode in octal format */
2407a0ee8cc6SDag-Erling Smørgrav 		value = strtol(arg, &p, 8);
2408a0ee8cc6SDag-Erling Smørgrav 		if (arg == p || value < 0 || value > 0777)
240919261079SEd Maste 			fatal("%s line %d: Invalid %s.",
241019261079SEd Maste 			    filename, linenum, keyword);
2411557f75e5SDag-Erling Smørgrav 		if (*activep)
2412a0ee8cc6SDag-Erling Smørgrav 			options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
2413a0ee8cc6SDag-Erling Smørgrav 		break;
2414a0ee8cc6SDag-Erling Smørgrav 
2415a0ee8cc6SDag-Erling Smørgrav 	case sStreamLocalBindUnlink:
2416a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->fwd_opts.streamlocal_bind_unlink;
2417a0ee8cc6SDag-Erling Smørgrav 		goto parse_flag;
2418a0ee8cc6SDag-Erling Smørgrav 
2419bc5531deSDag-Erling Smørgrav 	case sFingerprintHash:
242019261079SEd Maste 		arg = argv_next(&ac, &av);
2421bc5531deSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
242219261079SEd Maste 			fatal("%s line %d: %s missing argument.",
242319261079SEd Maste 			    filename, linenum, keyword);
2424bc5531deSDag-Erling Smørgrav 		if ((value = ssh_digest_alg_by_name(arg)) == -1)
242519261079SEd Maste 			fatal("%.200s line %d: Invalid %s algorithm \"%s\".",
242619261079SEd Maste 			    filename, linenum, keyword, arg);
2427bc5531deSDag-Erling Smørgrav 		if (*activep)
2428bc5531deSDag-Erling Smørgrav 			options->fingerprint_hash = value;
2429bc5531deSDag-Erling Smørgrav 		break;
2430bc5531deSDag-Erling Smørgrav 
24314f52dfbbSDag-Erling Smørgrav 	case sExposeAuthInfo:
24324f52dfbbSDag-Erling Smørgrav 		intptr = &options->expose_userauth_info;
24334f52dfbbSDag-Erling Smørgrav 		goto parse_flag;
24344f52dfbbSDag-Erling Smørgrav 
243547dd1d1bSDag-Erling Smørgrav 	case sRDomain:
243619261079SEd Maste #if !defined(__OpenBSD__) && !defined(HAVE_SYS_SET_PROCESS_RDOMAIN)
243719261079SEd Maste 		fatal("%s line %d: setting RDomain not supported on this "
243819261079SEd Maste 		    "platform.", filename, linenum);
243919261079SEd Maste #endif
244047dd1d1bSDag-Erling Smørgrav 		charptr = &options->routing_domain;
244119261079SEd Maste 		arg = argv_next(&ac, &av);
244247dd1d1bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
244319261079SEd Maste 			fatal("%s line %d: %s missing argument.",
244419261079SEd Maste 			    filename, linenum, keyword);
244547dd1d1bSDag-Erling Smørgrav 		if (strcasecmp(arg, "none") != 0 && strcmp(arg, "%D") != 0 &&
244647dd1d1bSDag-Erling Smørgrav 		    !valid_rdomain(arg))
244719261079SEd Maste 			fatal("%s line %d: invalid routing domain",
244847dd1d1bSDag-Erling Smørgrav 			    filename, linenum);
244947dd1d1bSDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
245047dd1d1bSDag-Erling Smørgrav 			*charptr = xstrdup(arg);
245147dd1d1bSDag-Erling Smørgrav 		break;
245247dd1d1bSDag-Erling Smørgrav 
2453b2af61ecSKurt Lidl 	case sUseBlacklist:
2454b2af61ecSKurt Lidl 		intptr = &options->use_blacklist;
2455b2af61ecSKurt Lidl 		goto parse_flag;
2456b2af61ecSKurt Lidl 
2457af12a3e7SDag-Erling Smørgrav 	case sDeprecated:
2458ca86bcf2SDag-Erling Smørgrav 	case sIgnore:
2459cf2b5f3bSDag-Erling Smørgrav 	case sUnsupported:
2460ca86bcf2SDag-Erling Smørgrav 		do_log2(opcode == sIgnore ?
2461ca86bcf2SDag-Erling Smørgrav 		    SYSLOG_LEVEL_DEBUG2 : SYSLOG_LEVEL_INFO,
2462ca86bcf2SDag-Erling Smørgrav 		    "%s line %d: %s option %s", filename, linenum,
246319261079SEd Maste 		    opcode == sUnsupported ? "Unsupported" : "Deprecated",
246419261079SEd Maste 		    keyword);
246519261079SEd Maste 		argv_consume(&ac);
2466af12a3e7SDag-Erling Smørgrav 		break;
2467af12a3e7SDag-Erling Smørgrav 
246842f71286SMark Murray 	default:
2469af12a3e7SDag-Erling Smørgrav 		fatal("%s line %d: Missing handler for opcode %s (%d)",
247019261079SEd Maste 		    filename, linenum, keyword, opcode);
2471511b41d2SMark Murray 	}
247219261079SEd Maste 	/* Check that there is no garbage at end of line. */
247319261079SEd Maste 	if (ac > 0) {
247419261079SEd Maste 		error("%.200s line %d: keyword %s extra arguments "
247519261079SEd Maste 		    "at end of line", filename, linenum, keyword);
247619261079SEd Maste 		goto out;
2477af12a3e7SDag-Erling Smørgrav 	}
2478af12a3e7SDag-Erling Smørgrav 
247919261079SEd Maste 	/* success */
248019261079SEd Maste 	ret = 0;
248119261079SEd Maste  out:
248219261079SEd Maste 	argv_free(oav, oac);
248319261079SEd Maste 	return ret;
248419261079SEd Maste }
248519261079SEd Maste 
248619261079SEd Maste int
248719261079SEd Maste process_server_config_line(ServerOptions *options, char *line,
248819261079SEd Maste     const char *filename, int linenum, int *activep,
248919261079SEd Maste     struct connection_info *connectinfo, struct include_list *includes)
249019261079SEd Maste {
249119261079SEd Maste 	int inc_flags = 0;
249219261079SEd Maste 
249319261079SEd Maste 	return process_server_config_line_depth(options, line, filename,
249419261079SEd Maste 	    linenum, activep, connectinfo, &inc_flags, 0, includes);
249519261079SEd Maste }
249619261079SEd Maste 
249719261079SEd Maste 
2498af12a3e7SDag-Erling Smørgrav /* Reads the server configuration file. */
2499af12a3e7SDag-Erling Smørgrav 
2500af12a3e7SDag-Erling Smørgrav void
2501190cef3dSDag-Erling Smørgrav load_server_config(const char *filename, struct sshbuf *conf)
2502af12a3e7SDag-Erling Smørgrav {
250319261079SEd Maste 	struct stat st;
2504190cef3dSDag-Erling Smørgrav 	char *line = NULL, *cp;
2505190cef3dSDag-Erling Smørgrav 	size_t linesize = 0;
2506a82e551fSDag-Erling Smørgrav 	FILE *f;
2507190cef3dSDag-Erling Smørgrav 	int r, lineno = 0;
2508af12a3e7SDag-Erling Smørgrav 
250919261079SEd Maste 	debug2_f("filename %s", filename);
251021e764dfSDag-Erling Smørgrav 	if ((f = fopen(filename, "r")) == NULL) {
2511af12a3e7SDag-Erling Smørgrav 		perror(filename);
2512af12a3e7SDag-Erling Smørgrav 		exit(1);
2513af12a3e7SDag-Erling Smørgrav 	}
2514190cef3dSDag-Erling Smørgrav 	sshbuf_reset(conf);
251519261079SEd Maste 	/* grow buffer, so realloc is avoided for large config files */
251619261079SEd Maste 	if (fstat(fileno(f), &st) == 0 && st.st_size > 0 &&
251719261079SEd Maste 	    (r = sshbuf_allocate(conf, st.st_size)) != 0)
251819261079SEd Maste 		fatal_fr(r, "allocate");
2519190cef3dSDag-Erling Smørgrav 	while (getline(&line, &linesize, f) != -1) {
2520462c32cbSDag-Erling Smørgrav 		lineno++;
252121e764dfSDag-Erling Smørgrav 		/*
252219261079SEd Maste 		 * Strip whitespace
252321e764dfSDag-Erling Smørgrav 		 * NB - preserve newlines, they are needed to reproduce
252421e764dfSDag-Erling Smørgrav 		 * line numbers later for error messages
252521e764dfSDag-Erling Smørgrav 		 */
252621e764dfSDag-Erling Smørgrav 		cp = line + strspn(line, " \t\r");
2527190cef3dSDag-Erling Smørgrav 		if ((r = sshbuf_put(conf, cp, strlen(cp))) != 0)
252819261079SEd Maste 			fatal_fr(r, "sshbuf_put");
252921e764dfSDag-Erling Smørgrav 	}
2530190cef3dSDag-Erling Smørgrav 	free(line);
2531190cef3dSDag-Erling Smørgrav 	if ((r = sshbuf_put_u8(conf, 0)) != 0)
253219261079SEd Maste 		fatal_fr(r, "sshbuf_put_u8");
253321e764dfSDag-Erling Smørgrav 	fclose(f);
253419261079SEd Maste 	debug2_f("done config len = %zu", sshbuf_len(conf));
253521e764dfSDag-Erling Smørgrav }
253621e764dfSDag-Erling Smørgrav 
253721e764dfSDag-Erling Smørgrav void
2538462c32cbSDag-Erling Smørgrav parse_server_match_config(ServerOptions *options,
253919261079SEd Maste    struct include_list *includes, struct connection_info *connectinfo)
254021e764dfSDag-Erling Smørgrav {
2541333ee039SDag-Erling Smørgrav 	ServerOptions mo;
2542333ee039SDag-Erling Smørgrav 
2543333ee039SDag-Erling Smørgrav 	initialize_server_options(&mo);
254419261079SEd Maste 	parse_server_config(&mo, "reprocess config", cfg, includes,
254519261079SEd Maste 	    connectinfo);
2546d4af9e69SDag-Erling Smørgrav 	copy_set_server_options(options, &mo, 0);
2547333ee039SDag-Erling Smørgrav }
2548333ee039SDag-Erling Smørgrav 
2549462c32cbSDag-Erling Smørgrav int parse_server_match_testspec(struct connection_info *ci, char *spec)
2550462c32cbSDag-Erling Smørgrav {
2551462c32cbSDag-Erling Smørgrav 	char *p;
2552462c32cbSDag-Erling Smørgrav 
2553462c32cbSDag-Erling Smørgrav 	while ((p = strsep(&spec, ",")) && *p != '\0') {
2554462c32cbSDag-Erling Smørgrav 		if (strncmp(p, "addr=", 5) == 0) {
2555462c32cbSDag-Erling Smørgrav 			ci->address = xstrdup(p + 5);
2556462c32cbSDag-Erling Smørgrav 		} else if (strncmp(p, "host=", 5) == 0) {
2557462c32cbSDag-Erling Smørgrav 			ci->host = xstrdup(p + 5);
2558462c32cbSDag-Erling Smørgrav 		} else if (strncmp(p, "user=", 5) == 0) {
2559462c32cbSDag-Erling Smørgrav 			ci->user = xstrdup(p + 5);
2560462c32cbSDag-Erling Smørgrav 		} else if (strncmp(p, "laddr=", 6) == 0) {
2561462c32cbSDag-Erling Smørgrav 			ci->laddress = xstrdup(p + 6);
256247dd1d1bSDag-Erling Smørgrav 		} else if (strncmp(p, "rdomain=", 8) == 0) {
256347dd1d1bSDag-Erling Smørgrav 			ci->rdomain = xstrdup(p + 8);
2564462c32cbSDag-Erling Smørgrav 		} else if (strncmp(p, "lport=", 6) == 0) {
2565462c32cbSDag-Erling Smørgrav 			ci->lport = a2port(p + 6);
2566462c32cbSDag-Erling Smørgrav 			if (ci->lport == -1) {
2567462c32cbSDag-Erling Smørgrav 				fprintf(stderr, "Invalid port '%s' in test mode"
2568462c32cbSDag-Erling Smørgrav 				    " specification %s\n", p+6, p);
2569462c32cbSDag-Erling Smørgrav 				return -1;
2570462c32cbSDag-Erling Smørgrav 			}
2571462c32cbSDag-Erling Smørgrav 		} else {
2572462c32cbSDag-Erling Smørgrav 			fprintf(stderr, "Invalid test mode specification %s\n",
2573462c32cbSDag-Erling Smørgrav 			    p);
2574462c32cbSDag-Erling Smørgrav 			return -1;
2575462c32cbSDag-Erling Smørgrav 		}
2576462c32cbSDag-Erling Smørgrav 	}
2577462c32cbSDag-Erling Smørgrav 	return 0;
2578462c32cbSDag-Erling Smørgrav }
2579462c32cbSDag-Erling Smørgrav 
2580462c32cbSDag-Erling Smørgrav /*
2581d4af9e69SDag-Erling Smørgrav  * Copy any supported values that are set.
2582d4af9e69SDag-Erling Smørgrav  *
25837aee6ffeSDag-Erling Smørgrav  * If the preauth flag is set, we do not bother copying the string or
2584d4af9e69SDag-Erling Smørgrav  * array values that are not used pre-authentication, because any that we
2585190cef3dSDag-Erling Smørgrav  * do use must be explicitly sent in mm_getpwnamallow().
2586d4af9e69SDag-Erling Smørgrav  */
2587333ee039SDag-Erling Smørgrav void
2588d4af9e69SDag-Erling Smørgrav copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
2589333ee039SDag-Erling Smørgrav {
2590f7167e0eSDag-Erling Smørgrav #define M_CP_INTOPT(n) do {\
2591f7167e0eSDag-Erling Smørgrav 	if (src->n != -1) \
2592f7167e0eSDag-Erling Smørgrav 		dst->n = src->n; \
2593f7167e0eSDag-Erling Smørgrav } while (0)
2594f7167e0eSDag-Erling Smørgrav 
2595d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(password_authentication);
2596d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(gss_authentication);
2597d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(pubkey_authentication);
259819261079SEd Maste 	M_CP_INTOPT(pubkey_auth_options);
2599d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(kerberos_authentication);
2600d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(hostbased_authentication);
2601e2f6069cSDag-Erling Smørgrav 	M_CP_INTOPT(hostbased_uses_name_from_packet_only);
2602d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(kbd_interactive_authentication);
2603d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(permit_root_login);
2604cce7d346SDag-Erling Smørgrav 	M_CP_INTOPT(permit_empty_passwd);
260519261079SEd Maste 	M_CP_INTOPT(ignore_rhosts);
2606d4af9e69SDag-Erling Smørgrav 
2607d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(allow_tcp_forwarding);
2608a0ee8cc6SDag-Erling Smørgrav 	M_CP_INTOPT(allow_streamlocal_forwarding);
2609d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(allow_agent_forwarding);
2610ca86bcf2SDag-Erling Smørgrav 	M_CP_INTOPT(disable_forwarding);
26114f52dfbbSDag-Erling Smørgrav 	M_CP_INTOPT(expose_userauth_info);
2612e2f6069cSDag-Erling Smørgrav 	M_CP_INTOPT(permit_tun);
2613a0ee8cc6SDag-Erling Smørgrav 	M_CP_INTOPT(fwd_opts.gateway_ports);
2614076ad2f8SDag-Erling Smørgrav 	M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink);
2615d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(x11_display_offset);
2616d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(x11_forwarding);
2617d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(x11_use_localhost);
2618f7167e0eSDag-Erling Smørgrav 	M_CP_INTOPT(permit_tty);
2619a0ee8cc6SDag-Erling Smørgrav 	M_CP_INTOPT(permit_user_rc);
2620d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(max_sessions);
2621d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(max_authtries);
2622ca86bcf2SDag-Erling Smørgrav 	M_CP_INTOPT(client_alive_count_max);
2623ca86bcf2SDag-Erling Smørgrav 	M_CP_INTOPT(client_alive_interval);
26244a421b63SDag-Erling Smørgrav 	M_CP_INTOPT(ip_qos_interactive);
26254a421b63SDag-Erling Smørgrav 	M_CP_INTOPT(ip_qos_bulk);
2626e4a9863fSDag-Erling Smørgrav 	M_CP_INTOPT(rekey_limit);
2627e4a9863fSDag-Erling Smørgrav 	M_CP_INTOPT(rekey_interval);
26284f52dfbbSDag-Erling Smørgrav 	M_CP_INTOPT(log_level);
2629d4af9e69SDag-Erling Smørgrav 
2630076ad2f8SDag-Erling Smørgrav 	/*
2631076ad2f8SDag-Erling Smørgrav 	 * The bind_mask is a mode_t that may be unsigned, so we can't use
2632076ad2f8SDag-Erling Smørgrav 	 * M_CP_INTOPT - it does a signed comparison that causes compiler
2633076ad2f8SDag-Erling Smørgrav 	 * warnings.
2634076ad2f8SDag-Erling Smørgrav 	 */
2635076ad2f8SDag-Erling Smørgrav 	if (src->fwd_opts.streamlocal_bind_mask != (mode_t)-1) {
2636076ad2f8SDag-Erling Smørgrav 		dst->fwd_opts.streamlocal_bind_mask =
2637076ad2f8SDag-Erling Smørgrav 		    src->fwd_opts.streamlocal_bind_mask;
2638076ad2f8SDag-Erling Smørgrav 	}
2639076ad2f8SDag-Erling Smørgrav 
2640f7167e0eSDag-Erling Smørgrav 	/* M_CP_STROPT and M_CP_STRARRAYOPT should not appear before here */
2641f7167e0eSDag-Erling Smørgrav #define M_CP_STROPT(n) do {\
2642f7167e0eSDag-Erling Smørgrav 	if (src->n != NULL && dst->n != src->n) { \
2643f7167e0eSDag-Erling Smørgrav 		free(dst->n); \
2644f7167e0eSDag-Erling Smørgrav 		dst->n = src->n; \
2645f7167e0eSDag-Erling Smørgrav 	} \
2646f7167e0eSDag-Erling Smørgrav } while(0)
264747dd1d1bSDag-Erling Smørgrav #define M_CP_STRARRAYOPT(s, num_s) do {\
264847dd1d1bSDag-Erling Smørgrav 	u_int i; \
264947dd1d1bSDag-Erling Smørgrav 	if (src->num_s != 0) { \
265047dd1d1bSDag-Erling Smørgrav 		for (i = 0; i < dst->num_s; i++) \
265147dd1d1bSDag-Erling Smørgrav 			free(dst->s[i]); \
265247dd1d1bSDag-Erling Smørgrav 		free(dst->s); \
265347dd1d1bSDag-Erling Smørgrav 		dst->s = xcalloc(src->num_s, sizeof(*dst->s)); \
265447dd1d1bSDag-Erling Smørgrav 		for (i = 0; i < src->num_s; i++) \
265547dd1d1bSDag-Erling Smørgrav 			dst->s[i] = xstrdup(src->s[i]); \
265647dd1d1bSDag-Erling Smørgrav 		dst->num_s = src->num_s; \
26574f52dfbbSDag-Erling Smørgrav 	} \
26584f52dfbbSDag-Erling Smørgrav } while(0)
2659f7167e0eSDag-Erling Smørgrav 
2660e146993eSDag-Erling Smørgrav 	/* See comment in servconf.h */
2661e146993eSDag-Erling Smørgrav 	COPY_MATCH_STRING_OPTS();
2662e146993eSDag-Erling Smørgrav 
2663acc1a9efSDag-Erling Smørgrav 	/* Arguments that accept '+...' need to be expanded */
2664acc1a9efSDag-Erling Smørgrav 	assemble_algorithms(dst);
2665acc1a9efSDag-Erling Smørgrav 
2666e146993eSDag-Erling Smørgrav 	/*
2667e146993eSDag-Erling Smørgrav 	 * The only things that should be below this point are string options
2668e146993eSDag-Erling Smørgrav 	 * which are only used after authentication.
2669e146993eSDag-Erling Smørgrav 	 */
2670d4af9e69SDag-Erling Smørgrav 	if (preauth)
2671d4af9e69SDag-Erling Smørgrav 		return;
2672e146993eSDag-Erling Smørgrav 
2673acc1a9efSDag-Erling Smørgrav 	/* These options may be "none" to clear a global setting */
2674d4af9e69SDag-Erling Smørgrav 	M_CP_STROPT(adm_forced_command);
2675acc1a9efSDag-Erling Smørgrav 	if (option_clear_or_none(dst->adm_forced_command)) {
2676acc1a9efSDag-Erling Smørgrav 		free(dst->adm_forced_command);
2677acc1a9efSDag-Erling Smørgrav 		dst->adm_forced_command = NULL;
2678acc1a9efSDag-Erling Smørgrav 	}
2679d4af9e69SDag-Erling Smørgrav 	M_CP_STROPT(chroot_directory);
2680acc1a9efSDag-Erling Smørgrav 	if (option_clear_or_none(dst->chroot_directory)) {
2681acc1a9efSDag-Erling Smørgrav 		free(dst->chroot_directory);
2682acc1a9efSDag-Erling Smørgrav 		dst->chroot_directory = NULL;
2683acc1a9efSDag-Erling Smørgrav 	}
2684333ee039SDag-Erling Smørgrav }
2685d4af9e69SDag-Erling Smørgrav 
2686d4af9e69SDag-Erling Smørgrav #undef M_CP_INTOPT
2687d4af9e69SDag-Erling Smørgrav #undef M_CP_STROPT
2688e146993eSDag-Erling Smørgrav #undef M_CP_STRARRAYOPT
2689333ee039SDag-Erling Smørgrav 
269019261079SEd Maste #define SERVCONF_MAX_DEPTH	16
269119261079SEd Maste static void
269219261079SEd Maste parse_server_config_depth(ServerOptions *options, const char *filename,
269319261079SEd Maste     struct sshbuf *conf, struct include_list *includes,
269419261079SEd Maste     struct connection_info *connectinfo, int flags, int *activep, int depth)
2695333ee039SDag-Erling Smørgrav {
269619261079SEd Maste 	int linenum, bad_options = 0;
269721e764dfSDag-Erling Smørgrav 	char *cp, *obuf, *cbuf;
269821e764dfSDag-Erling Smørgrav 
269919261079SEd Maste 	if (depth < 0 || depth > SERVCONF_MAX_DEPTH)
270019261079SEd Maste 		fatal("Too many recursive configuration includes");
270119261079SEd Maste 
270219261079SEd Maste 	debug2_f("config %s len %zu%s", filename, sshbuf_len(conf),
270319261079SEd Maste 	    (flags & SSHCFG_NEVERMATCH ? " [checking syntax only]" : ""));
270421e764dfSDag-Erling Smørgrav 
2705076ad2f8SDag-Erling Smørgrav 	if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL)
270619261079SEd Maste 		fatal_f("sshbuf_dup_string failed");
270721e764dfSDag-Erling Smørgrav 	linenum = 1;
270821e764dfSDag-Erling Smørgrav 	while ((cp = strsep(&cbuf, "\n")) != NULL) {
270919261079SEd Maste 		if (process_server_config_line_depth(options, cp,
271019261079SEd Maste 		    filename, linenum++, activep, connectinfo, &flags,
271119261079SEd Maste 		    depth, includes) != 0)
2712af12a3e7SDag-Erling Smørgrav 			bad_options++;
2713511b41d2SMark Murray 	}
2714e4a9863fSDag-Erling Smørgrav 	free(obuf);
2715ca3176e7SBrian Feldman 	if (bad_options > 0)
2716af12a3e7SDag-Erling Smørgrav 		fatal("%s: terminating, %d bad configuration options",
2717511b41d2SMark Murray 		    filename, bad_options);
271819261079SEd Maste }
271919261079SEd Maste 
272019261079SEd Maste void
272119261079SEd Maste parse_server_config(ServerOptions *options, const char *filename,
272219261079SEd Maste     struct sshbuf *conf, struct include_list *includes,
272319261079SEd Maste     struct connection_info *connectinfo)
272419261079SEd Maste {
272519261079SEd Maste 	int active = connectinfo ? 0 : 1;
272619261079SEd Maste 	parse_server_config_depth(options, filename, conf, includes,
272719261079SEd Maste 	    connectinfo, (connectinfo ? SSHCFG_MATCH_ONLY : 0), &active, 0);
2728557f75e5SDag-Erling Smørgrav 	process_queued_listen_addrs(options);
2729511b41d2SMark Murray }
2730d4af9e69SDag-Erling Smørgrav 
2731d4af9e69SDag-Erling Smørgrav static const char *
2732e146993eSDag-Erling Smørgrav fmt_multistate_int(int val, const struct multistate *m)
2733d4af9e69SDag-Erling Smørgrav {
2734e146993eSDag-Erling Smørgrav 	u_int i;
2735e146993eSDag-Erling Smørgrav 
2736e146993eSDag-Erling Smørgrav 	for (i = 0; m[i].key != NULL; i++) {
2737e146993eSDag-Erling Smørgrav 		if (m[i].value == val)
2738e146993eSDag-Erling Smørgrav 			return m[i].key;
2739e146993eSDag-Erling Smørgrav 	}
2740d4af9e69SDag-Erling Smørgrav 	return "UNKNOWN";
2741d4af9e69SDag-Erling Smørgrav }
2742e146993eSDag-Erling Smørgrav 
2743e146993eSDag-Erling Smørgrav static const char *
2744e146993eSDag-Erling Smørgrav fmt_intarg(ServerOpCodes code, int val)
2745e146993eSDag-Erling Smørgrav {
2746e146993eSDag-Erling Smørgrav 	if (val == -1)
2747e146993eSDag-Erling Smørgrav 		return "unset";
2748e146993eSDag-Erling Smørgrav 	switch (code) {
2749e146993eSDag-Erling Smørgrav 	case sAddressFamily:
2750e146993eSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_addressfamily);
2751e146993eSDag-Erling Smørgrav 	case sPermitRootLogin:
2752e146993eSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_permitrootlogin);
2753e146993eSDag-Erling Smørgrav 	case sGatewayPorts:
2754e146993eSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_gatewayports);
2755e146993eSDag-Erling Smørgrav 	case sCompression:
2756e146993eSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_compression);
27576888a9beSDag-Erling Smørgrav 	case sAllowTcpForwarding:
27586888a9beSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_tcpfwd);
2759a0ee8cc6SDag-Erling Smørgrav 	case sAllowStreamLocalForwarding:
2760a0ee8cc6SDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_tcpfwd);
276119261079SEd Maste 	case sIgnoreRhosts:
276219261079SEd Maste 		return fmt_multistate_int(val, multistate_ignore_rhosts);
2763bc5531deSDag-Erling Smørgrav 	case sFingerprintHash:
2764bc5531deSDag-Erling Smørgrav 		return ssh_digest_alg_name(val);
2765e146993eSDag-Erling Smørgrav 	default:
2766d4af9e69SDag-Erling Smørgrav 		switch (val) {
2767d4af9e69SDag-Erling Smørgrav 		case 0:
2768d4af9e69SDag-Erling Smørgrav 			return "no";
2769d4af9e69SDag-Erling Smørgrav 		case 1:
2770d4af9e69SDag-Erling Smørgrav 			return "yes";
2771e146993eSDag-Erling Smørgrav 		default:
2772d4af9e69SDag-Erling Smørgrav 			return "UNKNOWN";
2773d4af9e69SDag-Erling Smørgrav 		}
2774e146993eSDag-Erling Smørgrav 	}
2775e146993eSDag-Erling Smørgrav }
2776d4af9e69SDag-Erling Smørgrav 
2777d4af9e69SDag-Erling Smørgrav static void
2778d4af9e69SDag-Erling Smørgrav dump_cfg_int(ServerOpCodes code, int val)
2779d4af9e69SDag-Erling Smørgrav {
2780d4af9e69SDag-Erling Smørgrav 	printf("%s %d\n", lookup_opcode_name(code), val);
2781d4af9e69SDag-Erling Smørgrav }
2782d4af9e69SDag-Erling Smørgrav 
2783d4af9e69SDag-Erling Smørgrav static void
2784557f75e5SDag-Erling Smørgrav dump_cfg_oct(ServerOpCodes code, int val)
2785557f75e5SDag-Erling Smørgrav {
2786557f75e5SDag-Erling Smørgrav 	printf("%s 0%o\n", lookup_opcode_name(code), val);
2787557f75e5SDag-Erling Smørgrav }
2788557f75e5SDag-Erling Smørgrav 
2789557f75e5SDag-Erling Smørgrav static void
2790d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(ServerOpCodes code, int val)
2791d4af9e69SDag-Erling Smørgrav {
2792d4af9e69SDag-Erling Smørgrav 	printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
2793d4af9e69SDag-Erling Smørgrav }
2794d4af9e69SDag-Erling Smørgrav 
2795d4af9e69SDag-Erling Smørgrav static void
2796d4af9e69SDag-Erling Smørgrav dump_cfg_string(ServerOpCodes code, const char *val)
2797d4af9e69SDag-Erling Smørgrav {
2798bc5531deSDag-Erling Smørgrav 	printf("%s %s\n", lookup_opcode_name(code),
2799bc5531deSDag-Erling Smørgrav 	    val == NULL ? "none" : val);
2800d4af9e69SDag-Erling Smørgrav }
2801d4af9e69SDag-Erling Smørgrav 
2802d4af9e69SDag-Erling Smørgrav static void
2803d4af9e69SDag-Erling Smørgrav dump_cfg_strarray(ServerOpCodes code, u_int count, char **vals)
2804d4af9e69SDag-Erling Smørgrav {
2805d4af9e69SDag-Erling Smørgrav 	u_int i;
2806d4af9e69SDag-Erling Smørgrav 
2807d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < count; i++)
2808d4af9e69SDag-Erling Smørgrav 		printf("%s %s\n", lookup_opcode_name(code), vals[i]);
2809d4af9e69SDag-Erling Smørgrav }
2810d4af9e69SDag-Erling Smørgrav 
2811e146993eSDag-Erling Smørgrav static void
2812e146993eSDag-Erling Smørgrav dump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals)
2813e146993eSDag-Erling Smørgrav {
2814e146993eSDag-Erling Smørgrav 	u_int i;
2815e146993eSDag-Erling Smørgrav 
2816076ad2f8SDag-Erling Smørgrav 	if (count <= 0 && code != sAuthenticationMethods)
2817557f75e5SDag-Erling Smørgrav 		return;
2818e146993eSDag-Erling Smørgrav 	printf("%s", lookup_opcode_name(code));
2819e146993eSDag-Erling Smørgrav 	for (i = 0; i < count; i++)
2820e146993eSDag-Erling Smørgrav 		printf(" %s",  vals[i]);
2821076ad2f8SDag-Erling Smørgrav 	if (code == sAuthenticationMethods && count == 0)
2822076ad2f8SDag-Erling Smørgrav 		printf(" any");
2823e146993eSDag-Erling Smørgrav 	printf("\n");
2824e146993eSDag-Erling Smørgrav }
2825e146993eSDag-Erling Smørgrav 
282647dd1d1bSDag-Erling Smørgrav static char *
282747dd1d1bSDag-Erling Smørgrav format_listen_addrs(struct listenaddr *la)
2828d4af9e69SDag-Erling Smørgrav {
282947dd1d1bSDag-Erling Smørgrav 	int r;
2830d4af9e69SDag-Erling Smørgrav 	struct addrinfo *ai;
283147dd1d1bSDag-Erling Smørgrav 	char addr[NI_MAXHOST], port[NI_MAXSERV];
2832557f75e5SDag-Erling Smørgrav 	char *laddr1 = xstrdup(""), *laddr2 = NULL;
2833d4af9e69SDag-Erling Smørgrav 
2834557f75e5SDag-Erling Smørgrav 	/*
2835557f75e5SDag-Erling Smørgrav 	 * ListenAddress must be after Port.  add_one_listen_addr pushes
2836557f75e5SDag-Erling Smørgrav 	 * addresses onto a stack, so to maintain ordering we need to
2837557f75e5SDag-Erling Smørgrav 	 * print these in reverse order.
2838557f75e5SDag-Erling Smørgrav 	 */
283947dd1d1bSDag-Erling Smørgrav 	for (ai = la->addrs; ai; ai = ai->ai_next) {
284047dd1d1bSDag-Erling Smørgrav 		if ((r = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
2841d4af9e69SDag-Erling Smørgrav 		    sizeof(addr), port, sizeof(port),
2842d4af9e69SDag-Erling Smørgrav 		    NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
284347dd1d1bSDag-Erling Smørgrav 			error("getnameinfo: %.100s", ssh_gai_strerror(r));
284447dd1d1bSDag-Erling Smørgrav 			continue;
284547dd1d1bSDag-Erling Smørgrav 		}
2846557f75e5SDag-Erling Smørgrav 		laddr2 = laddr1;
284747dd1d1bSDag-Erling Smørgrav 		if (ai->ai_family == AF_INET6) {
284847dd1d1bSDag-Erling Smørgrav 			xasprintf(&laddr1, "listenaddress [%s]:%s%s%s\n%s",
284947dd1d1bSDag-Erling Smørgrav 			    addr, port,
285047dd1d1bSDag-Erling Smørgrav 			    la->rdomain == NULL ? "" : " rdomain ",
285147dd1d1bSDag-Erling Smørgrav 			    la->rdomain == NULL ? "" : la->rdomain,
285247dd1d1bSDag-Erling Smørgrav 			    laddr2);
285347dd1d1bSDag-Erling Smørgrav 		} else {
285447dd1d1bSDag-Erling Smørgrav 			xasprintf(&laddr1, "listenaddress %s:%s%s%s\n%s",
285547dd1d1bSDag-Erling Smørgrav 			    addr, port,
285647dd1d1bSDag-Erling Smørgrav 			    la->rdomain == NULL ? "" : " rdomain ",
285747dd1d1bSDag-Erling Smørgrav 			    la->rdomain == NULL ? "" : la->rdomain,
285847dd1d1bSDag-Erling Smørgrav 			    laddr2);
285947dd1d1bSDag-Erling Smørgrav 		}
2860557f75e5SDag-Erling Smørgrav 		free(laddr2);
2861d4af9e69SDag-Erling Smørgrav 	}
286247dd1d1bSDag-Erling Smørgrav 	return laddr1;
2863d4af9e69SDag-Erling Smørgrav }
286447dd1d1bSDag-Erling Smørgrav 
286547dd1d1bSDag-Erling Smørgrav void
286647dd1d1bSDag-Erling Smørgrav dump_config(ServerOptions *o)
286747dd1d1bSDag-Erling Smørgrav {
286847dd1d1bSDag-Erling Smørgrav 	char *s;
286947dd1d1bSDag-Erling Smørgrav 	u_int i;
287047dd1d1bSDag-Erling Smørgrav 
287147dd1d1bSDag-Erling Smørgrav 	/* these are usually at the top of the config */
287247dd1d1bSDag-Erling Smørgrav 	for (i = 0; i < o->num_ports; i++)
287347dd1d1bSDag-Erling Smørgrav 		printf("port %d\n", o->ports[i]);
287447dd1d1bSDag-Erling Smørgrav 	dump_cfg_fmtint(sAddressFamily, o->address_family);
287547dd1d1bSDag-Erling Smørgrav 
287647dd1d1bSDag-Erling Smørgrav 	for (i = 0; i < o->num_listen_addrs; i++) {
287747dd1d1bSDag-Erling Smørgrav 		s = format_listen_addrs(&o->listen_addrs[i]);
287847dd1d1bSDag-Erling Smørgrav 		printf("%s", s);
287947dd1d1bSDag-Erling Smørgrav 		free(s);
288047dd1d1bSDag-Erling Smørgrav 	}
2881d4af9e69SDag-Erling Smørgrav 
2882d4af9e69SDag-Erling Smørgrav 	/* integer arguments */
2883cce7d346SDag-Erling Smørgrav #ifdef USE_PAM
2884557f75e5SDag-Erling Smørgrav 	dump_cfg_fmtint(sUsePAM, o->use_pam);
2885cce7d346SDag-Erling Smørgrav #endif
2886d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sLoginGraceTime, o->login_grace_time);
2887d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sX11DisplayOffset, o->x11_display_offset);
2888d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sMaxAuthTries, o->max_authtries);
2889cce7d346SDag-Erling Smørgrav 	dump_cfg_int(sMaxSessions, o->max_sessions);
2890d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
2891d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
2892557f75e5SDag-Erling Smørgrav 	dump_cfg_oct(sStreamLocalBindMask, o->fwd_opts.streamlocal_bind_mask);
2893d4af9e69SDag-Erling Smørgrav 
2894d4af9e69SDag-Erling Smørgrav 	/* formatted integer arguments */
2895d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login);
2896d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sIgnoreRhosts, o->ignore_rhosts);
2897d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sIgnoreUserKnownHosts, o->ignore_user_known_hosts);
2898d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sHostbasedAuthentication, o->hostbased_authentication);
2899d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sHostbasedUsesNameFromPacketOnly,
2900d4af9e69SDag-Erling Smørgrav 	    o->hostbased_uses_name_from_packet_only);
2901d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPubkeyAuthentication, o->pubkey_authentication);
2902cce7d346SDag-Erling Smørgrav #ifdef KRB5
2903d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKerberosAuthentication, o->kerberos_authentication);
2904d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKerberosOrLocalPasswd, o->kerberos_or_local_passwd);
2905d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKerberosTicketCleanup, o->kerberos_ticket_cleanup);
2906cce7d346SDag-Erling Smørgrav # ifdef USE_AFS
2907d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
2908cce7d346SDag-Erling Smørgrav # endif
2909cce7d346SDag-Erling Smørgrav #endif
2910cce7d346SDag-Erling Smørgrav #ifdef GSSAPI
2911d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
2912d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
2913cce7d346SDag-Erling Smørgrav #endif
2914d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
2915d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKbdInteractiveAuthentication,
2916d4af9e69SDag-Erling Smørgrav 	    o->kbd_interactive_authentication);
2917d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPrintMotd, o->print_motd);
2918acc1a9efSDag-Erling Smørgrav #ifndef DISABLE_LASTLOG
2919d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPrintLastLog, o->print_lastlog);
2920acc1a9efSDag-Erling Smørgrav #endif
2921d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding);
2922d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost);
2923f7167e0eSDag-Erling Smørgrav 	dump_cfg_fmtint(sPermitTTY, o->permit_tty);
2924a0ee8cc6SDag-Erling Smørgrav 	dump_cfg_fmtint(sPermitUserRC, o->permit_user_rc);
2925d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sStrictModes, o->strict_modes);
2926d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive);
2927d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd);
2928d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sCompression, o->compression);
2929a0ee8cc6SDag-Erling Smørgrav 	dump_cfg_fmtint(sGatewayPorts, o->fwd_opts.gateway_ports);
2930d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sUseDNS, o->use_dns);
2931d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
2932557f75e5SDag-Erling Smørgrav 	dump_cfg_fmtint(sAllowAgentForwarding, o->allow_agent_forwarding);
2933ca86bcf2SDag-Erling Smørgrav 	dump_cfg_fmtint(sDisableForwarding, o->disable_forwarding);
2934a0ee8cc6SDag-Erling Smørgrav 	dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding);
2935076ad2f8SDag-Erling Smørgrav 	dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
2936bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash);
29374f52dfbbSDag-Erling Smørgrav 	dump_cfg_fmtint(sExposeAuthInfo, o->expose_userauth_info);
2938b2af61ecSKurt Lidl 	dump_cfg_fmtint(sUseBlacklist, o->use_blacklist);
2939d4af9e69SDag-Erling Smørgrav 
2940d4af9e69SDag-Erling Smørgrav 	/* string arguments */
2941d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sPidFile, o->pid_file);
294219261079SEd Maste 	dump_cfg_string(sModuliFile, o->moduli_file);
2943d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sXAuthLocation, o->xauth_location);
294419261079SEd Maste 	dump_cfg_string(sCiphers, o->ciphers);
294519261079SEd Maste 	dump_cfg_string(sMacs, o->macs);
2946d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sBanner, o->banner);
2947d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sForceCommand, o->adm_forced_command);
2948b15c8340SDag-Erling Smørgrav 	dump_cfg_string(sChrootDirectory, o->chroot_directory);
2949b15c8340SDag-Erling Smørgrav 	dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys);
2950b15c8340SDag-Erling Smørgrav 	dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
295119261079SEd Maste 	dump_cfg_string(sSecurityKeyProvider, o->sk_provider);
2952e2f6069cSDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedPrincipalsFile,
2953e2f6069cSDag-Erling Smørgrav 	    o->authorized_principals_file);
2954557f75e5SDag-Erling Smørgrav 	dump_cfg_string(sVersionAddendum, *o->version_addendum == '\0'
2955557f75e5SDag-Erling Smørgrav 	    ? "none" : o->version_addendum);
29566888a9beSDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command);
29576888a9beSDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedKeysCommandUser, o->authorized_keys_command_user);
2958557f75e5SDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedPrincipalsCommand, o->authorized_principals_command);
2959557f75e5SDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedPrincipalsCommandUser, o->authorized_principals_command_user);
2960e4a9863fSDag-Erling Smørgrav 	dump_cfg_string(sHostKeyAgent, o->host_key_agent);
296119261079SEd Maste 	dump_cfg_string(sKexAlgorithms, o->kex_algorithms);
296219261079SEd Maste 	dump_cfg_string(sCASignatureAlgorithms, o->ca_sign_algorithms);
296319261079SEd Maste 	dump_cfg_string(sHostbasedAcceptedAlgorithms, o->hostbased_accepted_algos);
296419261079SEd Maste 	dump_cfg_string(sHostKeyAlgorithms, o->hostkeyalgorithms);
296519261079SEd Maste 	dump_cfg_string(sPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos);
296619261079SEd Maste #if defined(__OpenBSD__) || defined(HAVE_SYS_SET_PROCESS_RDOMAIN)
296747dd1d1bSDag-Erling Smørgrav 	dump_cfg_string(sRDomain, o->routing_domain);
296819261079SEd Maste #endif
2969d4af9e69SDag-Erling Smørgrav 
2970d4af9e69SDag-Erling Smørgrav 	/* string arguments requiring a lookup */
2971d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sLogLevel, log_level_name(o->log_level));
2972d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sLogFacility, log_facility_name(o->log_facility));
2973d4af9e69SDag-Erling Smørgrav 
2974d4af9e69SDag-Erling Smørgrav 	/* string array arguments */
2975e146993eSDag-Erling Smørgrav 	dump_cfg_strarray_oneline(sAuthorizedKeysFile, o->num_authkeys_files,
2976e146993eSDag-Erling Smørgrav 	    o->authorized_keys_files);
2977d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sHostKeyFile, o->num_host_key_files,
2978d4af9e69SDag-Erling Smørgrav 	    o->host_key_files);
2979557f75e5SDag-Erling Smørgrav 	dump_cfg_strarray(sHostCertificate, o->num_host_cert_files,
2980b15c8340SDag-Erling Smørgrav 	    o->host_cert_files);
2981d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users);
2982d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users);
2983d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups);
2984d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sDenyGroups, o->num_deny_groups, o->deny_groups);
2985d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env);
2986190cef3dSDag-Erling Smørgrav 	dump_cfg_strarray(sSetEnv, o->num_setenv, o->setenv);
29876888a9beSDag-Erling Smørgrav 	dump_cfg_strarray_oneline(sAuthenticationMethods,
29886888a9beSDag-Erling Smørgrav 	    o->num_auth_methods, o->auth_methods);
298919261079SEd Maste 	dump_cfg_strarray_oneline(sLogVerbose,
299019261079SEd Maste 	    o->num_log_verbose, o->log_verbose);
2991d4af9e69SDag-Erling Smørgrav 
2992d4af9e69SDag-Erling Smørgrav 	/* other arguments */
2993d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < o->num_subsystems; i++)
2994d4af9e69SDag-Erling Smørgrav 		printf("subsystem %s %s\n", o->subsystem_name[i],
2995d4af9e69SDag-Erling Smørgrav 		    o->subsystem_args[i]);
2996d4af9e69SDag-Erling Smørgrav 
2997d4af9e69SDag-Erling Smørgrav 	printf("maxstartups %d:%d:%d\n", o->max_startups_begin,
2998d4af9e69SDag-Erling Smørgrav 	    o->max_startups_rate, o->max_startups);
299919261079SEd Maste 	printf("persourcemaxstartups ");
300019261079SEd Maste 	if (o->per_source_max_startups == INT_MAX)
300119261079SEd Maste 		printf("none\n");
300219261079SEd Maste 	else
300319261079SEd Maste 		printf("%d\n", o->per_source_max_startups);
300419261079SEd Maste 	printf("persourcenetblocksize %d:%d\n", o->per_source_masklen_ipv4,
300519261079SEd Maste 	    o->per_source_masklen_ipv6);
3006d4af9e69SDag-Erling Smørgrav 
300747dd1d1bSDag-Erling Smørgrav 	s = NULL;
300847dd1d1bSDag-Erling Smørgrav 	for (i = 0; tunmode_desc[i].val != -1; i++) {
3009d4af9e69SDag-Erling Smørgrav 		if (tunmode_desc[i].val == o->permit_tun) {
3010d4af9e69SDag-Erling Smørgrav 			s = tunmode_desc[i].text;
3011d4af9e69SDag-Erling Smørgrav 			break;
3012d4af9e69SDag-Erling Smørgrav 		}
301347dd1d1bSDag-Erling Smørgrav 	}
3014d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sPermitTunnel, s);
3015d4af9e69SDag-Erling Smørgrav 
3016e146993eSDag-Erling Smørgrav 	printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
3017e146993eSDag-Erling Smørgrav 	printf("%s\n", iptos2str(o->ip_qos_bulk));
30184a421b63SDag-Erling Smørgrav 
3019acc1a9efSDag-Erling Smørgrav 	printf("rekeylimit %llu %d\n", (unsigned long long)o->rekey_limit,
3020e4a9863fSDag-Erling Smørgrav 	    o->rekey_interval);
3021e4a9863fSDag-Erling Smørgrav 
30224f52dfbbSDag-Erling Smørgrav 	printf("permitopen");
30234f52dfbbSDag-Erling Smørgrav 	if (o->num_permitted_opens == 0)
30244f52dfbbSDag-Erling Smørgrav 		printf(" any");
30254f52dfbbSDag-Erling Smørgrav 	else {
30264f52dfbbSDag-Erling Smørgrav 		for (i = 0; i < o->num_permitted_opens; i++)
30274f52dfbbSDag-Erling Smørgrav 			printf(" %s", o->permitted_opens[i]);
30284f52dfbbSDag-Erling Smørgrav 	}
30294f52dfbbSDag-Erling Smørgrav 	printf("\n");
3030190cef3dSDag-Erling Smørgrav 	printf("permitlisten");
3031190cef3dSDag-Erling Smørgrav 	if (o->num_permitted_listens == 0)
3032190cef3dSDag-Erling Smørgrav 		printf(" any");
3033190cef3dSDag-Erling Smørgrav 	else {
3034190cef3dSDag-Erling Smørgrav 		for (i = 0; i < o->num_permitted_listens; i++)
3035190cef3dSDag-Erling Smørgrav 			printf(" %s", o->permitted_listens[i]);
3036190cef3dSDag-Erling Smørgrav 	}
3037190cef3dSDag-Erling Smørgrav 	printf("\n");
3038190cef3dSDag-Erling Smørgrav 
303919261079SEd Maste 	if (o->permit_user_env_allowlist == NULL) {
3040190cef3dSDag-Erling Smørgrav 		dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
3041190cef3dSDag-Erling Smørgrav 	} else {
3042190cef3dSDag-Erling Smørgrav 		printf("permituserenvironment %s\n",
304319261079SEd Maste 		    o->permit_user_env_allowlist);
3044190cef3dSDag-Erling Smørgrav 	}
3045190cef3dSDag-Erling Smørgrav 
304619261079SEd Maste 	printf("pubkeyauthoptions");
304719261079SEd Maste 	if (o->pubkey_auth_options == 0)
304819261079SEd Maste 		printf(" none");
304919261079SEd Maste 	if (o->pubkey_auth_options & PUBKEYAUTH_TOUCH_REQUIRED)
305019261079SEd Maste 		printf(" touch-required");
305119261079SEd Maste 	if (o->pubkey_auth_options & PUBKEYAUTH_VERIFY_REQUIRED)
305219261079SEd Maste 		printf(" verify-required");
305319261079SEd Maste 	printf("\n");
3054d4af9e69SDag-Erling Smørgrav }
3055