xref: /freebsd/crypto/openssh/servconf.c (revision 0ae642c7dd0c2cfd965a22bf73876cd26cceadd2)
1*0ae642c7SEd Maste /* $OpenBSD: servconf.c,v 1.419 2024/09/25 01:24:04 djm Exp $ */
2511b41d2SMark Murray /*
3511b41d2SMark Murray  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4511b41d2SMark Murray  *                    All rights reserved
5511b41d2SMark Murray  *
6c2d3a559SKris Kennaway  * As far as I am concerned, the code I have written for this software
7c2d3a559SKris Kennaway  * can be used freely for any purpose.  Any derived versions of this
8c2d3a559SKris Kennaway  * software must be clearly marked as such, and if the derived work is
9c2d3a559SKris Kennaway  * incompatible with the protocol description in the RFC file, it must be
10c2d3a559SKris Kennaway  * called by a name other than "ssh" or "Secure Shell".
11511b41d2SMark Murray  */
12511b41d2SMark Murray 
13511b41d2SMark Murray #include "includes.h"
14511b41d2SMark Murray 
15333ee039SDag-Erling Smørgrav #include <sys/types.h>
16333ee039SDag-Erling Smørgrav #include <sys/socket.h>
1719261079SEd Maste #include <sys/stat.h>
1819261079SEd Maste #ifdef __OpenBSD__
1947dd1d1bSDag-Erling Smørgrav #include <sys/sysctl.h>
2047dd1d1bSDag-Erling Smørgrav #endif
21333ee039SDag-Erling Smørgrav 
224a421b63SDag-Erling Smørgrav #include <netinet/in.h>
234a421b63SDag-Erling Smørgrav #include <netinet/in_systm.h>
244a421b63SDag-Erling Smørgrav #include <netinet/ip.h>
2547dd1d1bSDag-Erling Smørgrav #ifdef HAVE_NET_ROUTE_H
2647dd1d1bSDag-Erling Smørgrav #include <net/route.h>
2747dd1d1bSDag-Erling Smørgrav #endif
284a421b63SDag-Erling Smørgrav 
29e4a9863fSDag-Erling Smørgrav #include <ctype.h>
30333ee039SDag-Erling Smørgrav #include <netdb.h>
31333ee039SDag-Erling Smørgrav #include <pwd.h>
32333ee039SDag-Erling Smørgrav #include <stdio.h>
33333ee039SDag-Erling Smørgrav #include <stdlib.h>
34333ee039SDag-Erling Smørgrav #include <string.h>
35333ee039SDag-Erling Smørgrav #include <signal.h>
36333ee039SDag-Erling Smørgrav #include <unistd.h>
37bc5531deSDag-Erling Smørgrav #include <limits.h>
38333ee039SDag-Erling Smørgrav #include <stdarg.h>
39d4af9e69SDag-Erling Smørgrav #include <errno.h>
40e4a9863fSDag-Erling Smørgrav #ifdef HAVE_UTIL_H
41e4a9863fSDag-Erling Smørgrav #include <util.h>
42e4a9863fSDag-Erling Smørgrav #endif
4319261079SEd Maste #ifdef USE_SYSTEM_GLOB
4419261079SEd Maste # include <glob.h>
4519261079SEd Maste #else
4619261079SEd Maste # include "openbsd-compat/glob.h"
4719261079SEd Maste #endif
48333ee039SDag-Erling Smørgrav 
49d4af9e69SDag-Erling Smørgrav #include "openbsd-compat/sys-queue.h"
50333ee039SDag-Erling Smørgrav #include "xmalloc.h"
51511b41d2SMark Murray #include "ssh.h"
52ca3176e7SBrian Feldman #include "log.h"
53190cef3dSDag-Erling Smørgrav #include "sshbuf.h"
54a0ee8cc6SDag-Erling Smørgrav #include "misc.h"
55511b41d2SMark Murray #include "servconf.h"
56ca3176e7SBrian Feldman #include "pathnames.h"
57ca3176e7SBrian Feldman #include "cipher.h"
58190cef3dSDag-Erling Smørgrav #include "sshkey.h"
59ca3176e7SBrian Feldman #include "kex.h"
60ca3176e7SBrian Feldman #include "mac.h"
61333ee039SDag-Erling Smørgrav #include "match.h"
62333ee039SDag-Erling Smørgrav #include "channels.h"
63333ee039SDag-Erling Smørgrav #include "groupaccess.h"
64462c32cbSDag-Erling Smørgrav #include "canohost.h"
65462c32cbSDag-Erling Smørgrav #include "packet.h"
66190cef3dSDag-Erling Smørgrav #include "ssherr.h"
676888a9beSDag-Erling Smørgrav #include "hostfile.h"
686888a9beSDag-Erling Smørgrav #include "auth.h"
69bc5531deSDag-Erling Smørgrav #include "myproposal.h"
70bc5531deSDag-Erling Smørgrav #include "digest.h"
71b15c8340SDag-Erling Smørgrav #include "version.h"
72511b41d2SMark Murray 
730fdf8faeSEd Maste #if !defined(SSHD_PAM_SERVICE)
740fdf8faeSEd Maste # define SSHD_PAM_SERVICE		"sshd"
750fdf8faeSEd Maste #endif
760fdf8faeSEd Maste 
7747dd1d1bSDag-Erling Smørgrav static void add_listen_addr(ServerOptions *, const char *,
7847dd1d1bSDag-Erling Smørgrav     const char *, int);
7947dd1d1bSDag-Erling Smørgrav static void add_one_listen_addr(ServerOptions *, const char *,
8047dd1d1bSDag-Erling Smørgrav     const char *, int);
8119261079SEd Maste static void parse_server_config_depth(ServerOptions *options,
8219261079SEd Maste     const char *filename, struct sshbuf *conf, struct include_list *includes,
8319261079SEd Maste     struct connection_info *connectinfo, int flags, int *activep, int depth);
84ca3176e7SBrian Feldman 
85190cef3dSDag-Erling Smørgrav extern struct sshbuf *cfg;
86511b41d2SMark Murray 
87511b41d2SMark Murray /* Initializes the server options to their default values. */
88511b41d2SMark Murray 
89511b41d2SMark Murray void
initialize_server_options(ServerOptions * options)90511b41d2SMark Murray initialize_server_options(ServerOptions *options)
91511b41d2SMark Murray {
92511b41d2SMark Murray 	memset(options, 0, sizeof(*options));
93989dd127SDag-Erling Smørgrav 
94989dd127SDag-Erling Smørgrav 	/* Portable-specific options */
95cf2b5f3bSDag-Erling Smørgrav 	options->use_pam = -1;
960fdf8faeSEd Maste 	options->pam_service_name = NULL;
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;
1720fdf8faeSEd Maste 	options->per_source_penalty_exempt = NULL;
1730fdf8faeSEd Maste 	options->per_source_penalty.enabled = -1;
1740fdf8faeSEd Maste 	options->per_source_penalty.max_sources4 = -1;
1750fdf8faeSEd Maste 	options->per_source_penalty.max_sources6 = -1;
1760fdf8faeSEd Maste 	options->per_source_penalty.overflow_mode = -1;
1770fdf8faeSEd Maste 	options->per_source_penalty.overflow_mode6 = -1;
1780fdf8faeSEd Maste 	options->per_source_penalty.penalty_crash = -1;
1790fdf8faeSEd Maste 	options->per_source_penalty.penalty_authfail = -1;
1800fdf8faeSEd Maste 	options->per_source_penalty.penalty_noauth = -1;
1810fdf8faeSEd Maste 	options->per_source_penalty.penalty_grace = -1;
1823d9fd9fcSEd Maste 	options->per_source_penalty.penalty_refuseconnection = -1;
1830fdf8faeSEd Maste 	options->per_source_penalty.penalty_max = -1;
1840fdf8faeSEd Maste 	options->per_source_penalty.penalty_min = -1;
18521e764dfSDag-Erling Smørgrav 	options->max_authtries = -1;
186d4af9e69SDag-Erling Smørgrav 	options->max_sessions = -1;
187ca3176e7SBrian Feldman 	options->banner = NULL;
188cf2b5f3bSDag-Erling Smørgrav 	options->use_dns = -1;
189ca3176e7SBrian Feldman 	options->client_alive_interval = -1;
190ca3176e7SBrian Feldman 	options->client_alive_count_max = -1;
191e146993eSDag-Erling Smørgrav 	options->num_authkeys_files = 0;
19221e764dfSDag-Erling Smørgrav 	options->num_accept_env = 0;
193190cef3dSDag-Erling Smørgrav 	options->num_setenv = 0;
194b74df5b2SDag-Erling Smørgrav 	options->permit_tun = -1;
1954f52dfbbSDag-Erling Smørgrav 	options->permitted_opens = NULL;
196190cef3dSDag-Erling Smørgrav 	options->permitted_listens = NULL;
197333ee039SDag-Erling Smørgrav 	options->adm_forced_command = NULL;
198d4af9e69SDag-Erling Smørgrav 	options->chroot_directory = NULL;
1996888a9beSDag-Erling Smørgrav 	options->authorized_keys_command = NULL;
2006888a9beSDag-Erling Smørgrav 	options->authorized_keys_command_user = NULL;
201b15c8340SDag-Erling Smørgrav 	options->revoked_keys_file = NULL;
20219261079SEd Maste 	options->sk_provider = NULL;
203b15c8340SDag-Erling Smørgrav 	options->trusted_user_ca_keys = NULL;
204e2f6069cSDag-Erling Smørgrav 	options->authorized_principals_file = NULL;
205557f75e5SDag-Erling Smørgrav 	options->authorized_principals_command = NULL;
206557f75e5SDag-Erling Smørgrav 	options->authorized_principals_command_user = NULL;
2074a421b63SDag-Erling Smørgrav 	options->ip_qos_interactive = -1;
2084a421b63SDag-Erling Smørgrav 	options->ip_qos_bulk = -1;
209462c32cbSDag-Erling Smørgrav 	options->version_addendum = NULL;
210bc5531deSDag-Erling Smørgrav 	options->fingerprint_hash = -1;
211ca86bcf2SDag-Erling Smørgrav 	options->disable_forwarding = -1;
2124f52dfbbSDag-Erling Smørgrav 	options->expose_userauth_info = -1;
21338a52bd3SEd Maste 	options->required_rsa_size = -1;
214f374ba41SEd Maste 	options->channel_timeouts = NULL;
215f374ba41SEd Maste 	options->num_channel_timeouts = 0;
216f374ba41SEd Maste 	options->unused_connection_timeout = -1;
2170fdf8faeSEd Maste 	options->sshd_session_path = NULL;
2183d9fd9fcSEd Maste 	options->refuse_connection = -1;
219b2af61ecSKurt Lidl 	options->use_blacklist = -1;
220bc5531deSDag-Erling Smørgrav }
221bc5531deSDag-Erling Smørgrav 
222bc5531deSDag-Erling Smørgrav /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
223bc5531deSDag-Erling Smørgrav static int
option_clear_or_none(const char * o)224bc5531deSDag-Erling Smørgrav option_clear_or_none(const char *o)
225bc5531deSDag-Erling Smørgrav {
226bc5531deSDag-Erling Smørgrav 	return o == NULL || strcasecmp(o, "none") == 0;
227511b41d2SMark Murray }
228511b41d2SMark Murray 
229acc1a9efSDag-Erling Smørgrav static void
assemble_algorithms(ServerOptions * o)230acc1a9efSDag-Erling Smørgrav assemble_algorithms(ServerOptions *o)
231acc1a9efSDag-Erling Smørgrav {
2322f513db7SEd Maste 	char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
23319261079SEd Maste 	char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig;
234190cef3dSDag-Erling Smørgrav 	int r;
235190cef3dSDag-Erling Smørgrav 
236190cef3dSDag-Erling Smørgrav 	all_cipher = cipher_alg_list(',', 0);
237190cef3dSDag-Erling Smørgrav 	all_mac = mac_alg_list(',');
238190cef3dSDag-Erling Smørgrav 	all_kex = kex_alg_list(',');
239190cef3dSDag-Erling Smørgrav 	all_key = sshkey_alg_list(0, 0, 1, ',');
2402f513db7SEd Maste 	all_sig = sshkey_alg_list(0, 1, 1, ',');
24119261079SEd Maste 	/* remove unsupported algos from default lists */
24219261079SEd Maste 	def_cipher = match_filter_allowlist(KEX_SERVER_ENCRYPT, all_cipher);
24319261079SEd Maste 	def_mac = match_filter_allowlist(KEX_SERVER_MAC, all_mac);
24419261079SEd Maste 	def_kex = match_filter_allowlist(KEX_SERVER_KEX, all_kex);
24519261079SEd Maste 	def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
24619261079SEd Maste 	def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig);
247190cef3dSDag-Erling Smørgrav #define ASSEMBLE(what, defaults, all) \
248190cef3dSDag-Erling Smørgrav 	do { \
249190cef3dSDag-Erling Smørgrav 		if ((r = kex_assemble_names(&o->what, defaults, all)) != 0) \
25019261079SEd Maste 			fatal_fr(r, "%s", #what); \
251190cef3dSDag-Erling Smørgrav 	} while (0)
25219261079SEd Maste 	ASSEMBLE(ciphers, def_cipher, all_cipher);
25319261079SEd Maste 	ASSEMBLE(macs, def_mac, all_mac);
25419261079SEd Maste 	ASSEMBLE(kex_algorithms, def_kex, all_kex);
25519261079SEd Maste 	ASSEMBLE(hostkeyalgorithms, def_key, all_key);
25619261079SEd Maste 	ASSEMBLE(hostbased_accepted_algos, def_key, all_key);
25719261079SEd Maste 	ASSEMBLE(pubkey_accepted_algos, def_key, all_key);
25819261079SEd Maste 	ASSEMBLE(ca_sign_algorithms, def_sig, all_sig);
259190cef3dSDag-Erling Smørgrav #undef ASSEMBLE
260190cef3dSDag-Erling Smørgrav 	free(all_cipher);
261190cef3dSDag-Erling Smørgrav 	free(all_mac);
262190cef3dSDag-Erling Smørgrav 	free(all_kex);
263190cef3dSDag-Erling Smørgrav 	free(all_key);
2642f513db7SEd Maste 	free(all_sig);
26519261079SEd Maste 	free(def_cipher);
26619261079SEd Maste 	free(def_mac);
26719261079SEd Maste 	free(def_kex);
26819261079SEd Maste 	free(def_key);
26919261079SEd Maste 	free(def_sig);
27047dd1d1bSDag-Erling Smørgrav }
27147dd1d1bSDag-Erling Smørgrav 
27247dd1d1bSDag-Erling Smørgrav static const char *defaultkey = "[default]";
27347dd1d1bSDag-Erling Smørgrav 
27447dd1d1bSDag-Erling Smørgrav void
servconf_add_hostkey(const char * file,const int line,ServerOptions * options,const char * path,int userprovided)27547dd1d1bSDag-Erling Smørgrav servconf_add_hostkey(const char *file, const int line,
27619261079SEd Maste     ServerOptions *options, const char *path, int userprovided)
27747dd1d1bSDag-Erling Smørgrav {
27847dd1d1bSDag-Erling Smørgrav 	char *apath = derelativise_path(path);
27947dd1d1bSDag-Erling Smørgrav 
28047dd1d1bSDag-Erling Smørgrav 	if (file == defaultkey && access(path, R_OK) != 0)
28147dd1d1bSDag-Erling Smørgrav 		return;
28219261079SEd Maste 	opt_array_append2(file, line, "HostKey",
28319261079SEd Maste 	    &options->host_key_files, &options->host_key_file_userprovided,
28419261079SEd Maste 	    &options->num_host_key_files, apath, userprovided);
28547dd1d1bSDag-Erling Smørgrav 	free(apath);
28647dd1d1bSDag-Erling Smørgrav }
28747dd1d1bSDag-Erling Smørgrav 
28847dd1d1bSDag-Erling Smørgrav void
servconf_add_hostcert(const char * file,const int line,ServerOptions * options,const char * path)28947dd1d1bSDag-Erling Smørgrav servconf_add_hostcert(const char *file, const int line,
29047dd1d1bSDag-Erling Smørgrav     ServerOptions *options, const char *path)
29147dd1d1bSDag-Erling Smørgrav {
29247dd1d1bSDag-Erling Smørgrav 	char *apath = derelativise_path(path);
29347dd1d1bSDag-Erling Smørgrav 
29419261079SEd Maste 	opt_array_append(file, line, "HostCertificate",
29547dd1d1bSDag-Erling Smørgrav 	    &options->host_cert_files, &options->num_host_cert_files, apath);
29647dd1d1bSDag-Erling Smørgrav 	free(apath);
29747dd1d1bSDag-Erling Smørgrav }
29847dd1d1bSDag-Erling Smørgrav 
299511b41d2SMark Murray void
fill_default_server_options(ServerOptions * options)300511b41d2SMark Murray fill_default_server_options(ServerOptions *options)
301511b41d2SMark Murray {
30247dd1d1bSDag-Erling Smørgrav 	u_int i;
303bc5531deSDag-Erling Smørgrav 
304989dd127SDag-Erling Smørgrav 	/* Portable-specific options */
305cf2b5f3bSDag-Erling Smørgrav 	if (options->use_pam == -1)
306f0477b26SDag-Erling Smørgrav 		options->use_pam = 1;
3070fdf8faeSEd Maste 	if (options->pam_service_name == NULL)
3080fdf8faeSEd Maste 		options->pam_service_name = xstrdup(SSHD_PAM_SERVICE);
309989dd127SDag-Erling Smørgrav 
310989dd127SDag-Erling Smørgrav 	/* Standard Options */
311ca3176e7SBrian Feldman 	if (options->num_host_key_files == 0) {
312ca3176e7SBrian Feldman 		/* fill default hostkeys for protocols */
31347dd1d1bSDag-Erling Smørgrav 		servconf_add_hostkey(defaultkey, 0, options,
31419261079SEd Maste 		    _PATH_HOST_RSA_KEY_FILE, 0);
3154a421b63SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC
31647dd1d1bSDag-Erling Smørgrav 		servconf_add_hostkey(defaultkey, 0, options,
31719261079SEd Maste 		    _PATH_HOST_ECDSA_KEY_FILE, 0);
3184a421b63SDag-Erling Smørgrav #endif
31947dd1d1bSDag-Erling Smørgrav 		servconf_add_hostkey(defaultkey, 0, options,
32019261079SEd Maste 		    _PATH_HOST_ED25519_KEY_FILE, 0);
32147dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
32247dd1d1bSDag-Erling Smørgrav 		servconf_add_hostkey(defaultkey, 0, options,
32319261079SEd Maste 		    _PATH_HOST_XMSS_KEY_FILE, 0);
32447dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
325af12a3e7SDag-Erling Smørgrav 	}
326144a80bdSDag-Erling Smørgrav 	if (options->num_host_key_files == 0)
327144a80bdSDag-Erling Smørgrav 		fatal("No host key files found");
328b15c8340SDag-Erling Smørgrav 	/* No certificates by default */
329511b41d2SMark Murray 	if (options->num_ports == 0)
330511b41d2SMark Murray 		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
331557f75e5SDag-Erling Smørgrav 	if (options->address_family == -1)
332557f75e5SDag-Erling Smørgrav 		options->address_family = AF_UNSPEC;
333511b41d2SMark Murray 	if (options->listen_addrs == NULL)
33447dd1d1bSDag-Erling Smørgrav 		add_listen_addr(options, NULL, NULL, 0);
335e8aafc91SKris Kennaway 	if (options->pid_file == NULL)
336bc5531deSDag-Erling Smørgrav 		options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE);
33719261079SEd Maste 	if (options->moduli_file == NULL)
33819261079SEd Maste 		options->moduli_file = xstrdup(_PATH_DH_MODULI);
339511b41d2SMark Murray 	if (options->login_grace_time == -1)
340975616f0SDag-Erling Smørgrav 		options->login_grace_time = 120;
341ca3176e7SBrian Feldman 	if (options->permit_root_login == PERMIT_NOT_SET)
342975616f0SDag-Erling Smørgrav 		options->permit_root_login = PERMIT_NO;
343511b41d2SMark Murray 	if (options->ignore_rhosts == -1)
344fe5fd017SMark Murray 		options->ignore_rhosts = 1;
345511b41d2SMark Murray 	if (options->ignore_user_known_hosts == -1)
346511b41d2SMark Murray 		options->ignore_user_known_hosts = 0;
347511b41d2SMark Murray 	if (options->print_motd == -1)
348511b41d2SMark Murray 		options->print_motd = 1;
349ca3176e7SBrian Feldman 	if (options->print_lastlog == -1)
350ca3176e7SBrian Feldman 		options->print_lastlog = 1;
351511b41d2SMark Murray 	if (options->x11_forwarding == -1)
35277934b7aSEd Maste 		options->x11_forwarding = 0;
353511b41d2SMark Murray 	if (options->x11_display_offset == -1)
354fe5fd017SMark Murray 		options->x11_display_offset = 10;
355af12a3e7SDag-Erling Smørgrav 	if (options->x11_use_localhost == -1)
356af12a3e7SDag-Erling Smørgrav 		options->x11_use_localhost = 1;
357c2d3a559SKris Kennaway 	if (options->xauth_location == NULL)
358bc5531deSDag-Erling Smørgrav 		options->xauth_location = xstrdup(_PATH_XAUTH);
359f7167e0eSDag-Erling Smørgrav 	if (options->permit_tty == -1)
360f7167e0eSDag-Erling Smørgrav 		options->permit_tty = 1;
361a0ee8cc6SDag-Erling Smørgrav 	if (options->permit_user_rc == -1)
362a0ee8cc6SDag-Erling Smørgrav 		options->permit_user_rc = 1;
363511b41d2SMark Murray 	if (options->strict_modes == -1)
364511b41d2SMark Murray 		options->strict_modes = 1;
3651ec0d754SDag-Erling Smørgrav 	if (options->tcp_keep_alive == -1)
3661ec0d754SDag-Erling Smørgrav 		options->tcp_keep_alive = 1;
367af12a3e7SDag-Erling Smørgrav 	if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
368511b41d2SMark Murray 		options->log_facility = SYSLOG_FACILITY_AUTH;
369af12a3e7SDag-Erling Smørgrav 	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
370511b41d2SMark Murray 		options->log_level = SYSLOG_LEVEL_INFO;
371ca3176e7SBrian Feldman 	if (options->hostbased_authentication == -1)
372ca3176e7SBrian Feldman 		options->hostbased_authentication = 0;
373ca3176e7SBrian Feldman 	if (options->hostbased_uses_name_from_packet_only == -1)
374ca3176e7SBrian Feldman 		options->hostbased_uses_name_from_packet_only = 0;
375ca3176e7SBrian Feldman 	if (options->pubkey_authentication == -1)
376ca3176e7SBrian Feldman 		options->pubkey_authentication = 1;
37719261079SEd Maste 	if (options->pubkey_auth_options == -1)
37819261079SEd Maste 		options->pubkey_auth_options = 0;
379989dd127SDag-Erling Smørgrav 	if (options->kerberos_authentication == -1)
380cf2b5f3bSDag-Erling Smørgrav 		options->kerberos_authentication = 0;
381af12a3e7SDag-Erling Smørgrav 	if (options->kerberos_or_local_passwd == -1)
382af12a3e7SDag-Erling Smørgrav 		options->kerberos_or_local_passwd = 1;
383af12a3e7SDag-Erling Smørgrav 	if (options->kerberos_ticket_cleanup == -1)
384af12a3e7SDag-Erling Smørgrav 		options->kerberos_ticket_cleanup = 1;
3851ec0d754SDag-Erling Smørgrav 	if (options->kerberos_get_afs_token == -1)
3861ec0d754SDag-Erling Smørgrav 		options->kerberos_get_afs_token = 0;
387cf2b5f3bSDag-Erling Smørgrav 	if (options->gss_authentication == -1)
388cf2b5f3bSDag-Erling Smørgrav 		options->gss_authentication = 0;
389cf2b5f3bSDag-Erling Smørgrav 	if (options->gss_cleanup_creds == -1)
390cf2b5f3bSDag-Erling Smørgrav 		options->gss_cleanup_creds = 1;
391557f75e5SDag-Erling Smørgrav 	if (options->gss_strict_acceptor == -1)
392d93a896eSDag-Erling Smørgrav 		options->gss_strict_acceptor = 1;
393511b41d2SMark Murray 	if (options->password_authentication == -1)
394b909c84bSDag-Erling Smørgrav 		options->password_authentication = 0;
39509958426SBrian Feldman 	if (options->kbd_interactive_authentication == -1)
39619261079SEd Maste 		options->kbd_interactive_authentication = 1;
397511b41d2SMark Murray 	if (options->permit_empty_passwd == -1)
398fe5fd017SMark Murray 		options->permit_empty_passwd = 0;
399190cef3dSDag-Erling Smørgrav 	if (options->permit_user_env == -1) {
400f388f5efSDag-Erling Smørgrav 		options->permit_user_env = 0;
40119261079SEd Maste 		options->permit_user_env_allowlist = NULL;
402190cef3dSDag-Erling Smørgrav 	}
40380628bacSDag-Erling Smørgrav 	if (options->compression == -1)
40419261079SEd Maste #ifdef WITH_ZLIB
405d4ecd108SDag-Erling Smørgrav 		options->compression = COMP_DELAYED;
40619261079SEd Maste #else
40719261079SEd Maste 		options->compression = COMP_NONE;
40819261079SEd Maste #endif
40919261079SEd Maste 
410e4a9863fSDag-Erling Smørgrav 	if (options->rekey_limit == -1)
411e4a9863fSDag-Erling Smørgrav 		options->rekey_limit = 0;
412e4a9863fSDag-Erling Smørgrav 	if (options->rekey_interval == -1)
413e4a9863fSDag-Erling Smørgrav 		options->rekey_interval = 0;
41409958426SBrian Feldman 	if (options->allow_tcp_forwarding == -1)
4156888a9beSDag-Erling Smørgrav 		options->allow_tcp_forwarding = FORWARD_ALLOW;
416a0ee8cc6SDag-Erling Smørgrav 	if (options->allow_streamlocal_forwarding == -1)
417a0ee8cc6SDag-Erling Smørgrav 		options->allow_streamlocal_forwarding = FORWARD_ALLOW;
418d4af9e69SDag-Erling Smørgrav 	if (options->allow_agent_forwarding == -1)
419d4af9e69SDag-Erling Smørgrav 		options->allow_agent_forwarding = 1;
420a0ee8cc6SDag-Erling Smørgrav 	if (options->fwd_opts.gateway_ports == -1)
421a0ee8cc6SDag-Erling Smørgrav 		options->fwd_opts.gateway_ports = 0;
422c2d3a559SKris Kennaway 	if (options->max_startups == -1)
4236888a9beSDag-Erling Smørgrav 		options->max_startups = 100;
424c2d3a559SKris Kennaway 	if (options->max_startups_rate == -1)
4256888a9beSDag-Erling Smørgrav 		options->max_startups_rate = 30;		/* 30% */
426c2d3a559SKris Kennaway 	if (options->max_startups_begin == -1)
4276888a9beSDag-Erling Smørgrav 		options->max_startups_begin = 10;
42819261079SEd Maste 	if (options->per_source_max_startups == -1)
42919261079SEd Maste 		options->per_source_max_startups = INT_MAX;
43019261079SEd Maste 	if (options->per_source_masklen_ipv4 == -1)
43119261079SEd Maste 		options->per_source_masklen_ipv4 = 32;
43219261079SEd Maste 	if (options->per_source_masklen_ipv6 == -1)
43319261079SEd Maste 		options->per_source_masklen_ipv6 = 128;
4340fdf8faeSEd Maste 	if (options->per_source_penalty.enabled == -1)
4350fdf8faeSEd Maste 		options->per_source_penalty.enabled = 1;
4360fdf8faeSEd Maste 	if (options->per_source_penalty.max_sources4 == -1)
4370fdf8faeSEd Maste 		options->per_source_penalty.max_sources4 = 65536;
4380fdf8faeSEd Maste 	if (options->per_source_penalty.max_sources6 == -1)
4390fdf8faeSEd Maste 		options->per_source_penalty.max_sources6 = 65536;
4400fdf8faeSEd Maste 	if (options->per_source_penalty.overflow_mode == -1)
4410fdf8faeSEd Maste 		options->per_source_penalty.overflow_mode = PER_SOURCE_PENALTY_OVERFLOW_PERMISSIVE;
4420fdf8faeSEd Maste 	if (options->per_source_penalty.overflow_mode6 == -1)
4430fdf8faeSEd Maste 		options->per_source_penalty.overflow_mode6 = options->per_source_penalty.overflow_mode;
4440fdf8faeSEd Maste 	if (options->per_source_penalty.penalty_crash == -1)
4450fdf8faeSEd Maste 		options->per_source_penalty.penalty_crash = 90;
4460fdf8faeSEd Maste 	if (options->per_source_penalty.penalty_grace == -1)
4473d9fd9fcSEd Maste 		options->per_source_penalty.penalty_grace = 10;
4480fdf8faeSEd Maste 	if (options->per_source_penalty.penalty_authfail == -1)
4490fdf8faeSEd Maste 		options->per_source_penalty.penalty_authfail = 5;
4500fdf8faeSEd Maste 	if (options->per_source_penalty.penalty_noauth == -1)
4510fdf8faeSEd Maste 		options->per_source_penalty.penalty_noauth = 1;
4523d9fd9fcSEd Maste 	if (options->per_source_penalty.penalty_refuseconnection == -1)
4533d9fd9fcSEd Maste 		options->per_source_penalty.penalty_refuseconnection = 10;
4540fdf8faeSEd Maste 	if (options->per_source_penalty.penalty_min == -1)
4550fdf8faeSEd Maste 		options->per_source_penalty.penalty_min = 15;
4560fdf8faeSEd Maste 	if (options->per_source_penalty.penalty_max == -1)
4570fdf8faeSEd Maste 		options->per_source_penalty.penalty_max = 600;
45821e764dfSDag-Erling Smørgrav 	if (options->max_authtries == -1)
45921e764dfSDag-Erling Smørgrav 		options->max_authtries = DEFAULT_AUTH_FAIL_MAX;
460d4af9e69SDag-Erling Smørgrav 	if (options->max_sessions == -1)
461d4af9e69SDag-Erling Smørgrav 		options->max_sessions = DEFAULT_SESSIONS_MAX;
462cf2b5f3bSDag-Erling Smørgrav 	if (options->use_dns == -1)
463c4cd1fa4SDag-Erling Smørgrav 		options->use_dns = 1;
464ca3176e7SBrian Feldman 	if (options->client_alive_interval == -1)
465ca3176e7SBrian Feldman 		options->client_alive_interval = 0;
466ca3176e7SBrian Feldman 	if (options->client_alive_count_max == -1)
467ca3176e7SBrian Feldman 		options->client_alive_count_max = 3;
468e146993eSDag-Erling Smørgrav 	if (options->num_authkeys_files == 0) {
46919261079SEd Maste 		opt_array_append(defaultkey, 0, "AuthorizedKeysFiles",
47047dd1d1bSDag-Erling Smørgrav 		    &options->authorized_keys_files,
47147dd1d1bSDag-Erling Smørgrav 		    &options->num_authkeys_files,
47247dd1d1bSDag-Erling Smørgrav 		    _PATH_SSH_USER_PERMITTED_KEYS);
47319261079SEd Maste 		opt_array_append(defaultkey, 0, "AuthorizedKeysFiles",
47447dd1d1bSDag-Erling Smørgrav 		    &options->authorized_keys_files,
47547dd1d1bSDag-Erling Smørgrav 		    &options->num_authkeys_files,
47647dd1d1bSDag-Erling Smørgrav 		    _PATH_SSH_USER_PERMITTED_KEYS2);
477af12a3e7SDag-Erling Smørgrav 	}
478b74df5b2SDag-Erling Smørgrav 	if (options->permit_tun == -1)
479b74df5b2SDag-Erling Smørgrav 		options->permit_tun = SSH_TUNMODE_NO;
4804a421b63SDag-Erling Smørgrav 	if (options->ip_qos_interactive == -1)
481190cef3dSDag-Erling Smørgrav 		options->ip_qos_interactive = IPTOS_DSCP_AF21;
4824a421b63SDag-Erling Smørgrav 	if (options->ip_qos_bulk == -1)
483190cef3dSDag-Erling Smørgrav 		options->ip_qos_bulk = IPTOS_DSCP_CS1;
484462c32cbSDag-Erling Smørgrav 	if (options->version_addendum == NULL)
485462c32cbSDag-Erling Smørgrav 		options->version_addendum = xstrdup(SSH_VERSION_FREEBSD);
486a0ee8cc6SDag-Erling Smørgrav 	if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
487a0ee8cc6SDag-Erling Smørgrav 		options->fwd_opts.streamlocal_bind_mask = 0177;
488a0ee8cc6SDag-Erling Smørgrav 	if (options->fwd_opts.streamlocal_bind_unlink == -1)
489a0ee8cc6SDag-Erling Smørgrav 		options->fwd_opts.streamlocal_bind_unlink = 0;
490bc5531deSDag-Erling Smørgrav 	if (options->fingerprint_hash == -1)
491bc5531deSDag-Erling Smørgrav 		options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
492ca86bcf2SDag-Erling Smørgrav 	if (options->disable_forwarding == -1)
493ca86bcf2SDag-Erling Smørgrav 		options->disable_forwarding = 0;
4944f52dfbbSDag-Erling Smørgrav 	if (options->expose_userauth_info == -1)
4954f52dfbbSDag-Erling Smørgrav 		options->expose_userauth_info = 0;
49619261079SEd Maste 	if (options->sk_provider == NULL)
49719261079SEd Maste 		options->sk_provider = xstrdup("internal");
49838a52bd3SEd Maste 	if (options->required_rsa_size == -1)
49938a52bd3SEd Maste 		options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
500f374ba41SEd Maste 	if (options->unused_connection_timeout == -1)
501f374ba41SEd Maste 		options->unused_connection_timeout = 0;
5020fdf8faeSEd Maste 	if (options->sshd_session_path == NULL)
5030fdf8faeSEd Maste 		options->sshd_session_path = xstrdup(_PATH_SSHD_SESSION);
5043d9fd9fcSEd Maste 	if (options->refuse_connection == -1)
5053d9fd9fcSEd Maste 		options->refuse_connection = 0;
506b2af61ecSKurt Lidl 	if (options->use_blacklist == -1)
507b2af61ecSKurt Lidl 		options->use_blacklist = 0;
508eccfee6eSDag-Erling Smørgrav 
509acc1a9efSDag-Erling Smørgrav 	assemble_algorithms(options);
510eccfee6eSDag-Erling Smørgrav 
511bc5531deSDag-Erling Smørgrav #define CLEAR_ON_NONE(v) \
512bc5531deSDag-Erling Smørgrav 	do { \
513bc5531deSDag-Erling Smørgrav 		if (option_clear_or_none(v)) { \
514bc5531deSDag-Erling Smørgrav 			free(v); \
515bc5531deSDag-Erling Smørgrav 			v = NULL; \
516bc5531deSDag-Erling Smørgrav 		} \
517bc5531deSDag-Erling Smørgrav 	} while(0)
518f374ba41SEd Maste #define CLEAR_ON_NONE_ARRAY(v, nv, none) \
519f374ba41SEd Maste 	do { \
520f374ba41SEd Maste 		if (options->nv == 1 && \
521f374ba41SEd Maste 		    strcasecmp(options->v[0], none) == 0) { \
522f374ba41SEd Maste 			free(options->v[0]); \
523f374ba41SEd Maste 			free(options->v); \
524f374ba41SEd Maste 			options->v = NULL; \
525f374ba41SEd Maste 			options->nv = 0; \
526f374ba41SEd Maste 		} \
527f374ba41SEd Maste 	} while (0)
528bc5531deSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->pid_file);
529bc5531deSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->xauth_location);
530bc5531deSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->banner);
531bc5531deSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->trusted_user_ca_keys);
532bc5531deSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->revoked_keys_file);
53319261079SEd Maste 	CLEAR_ON_NONE(options->sk_provider);
534557f75e5SDag-Erling Smørgrav 	CLEAR_ON_NONE(options->authorized_principals_file);
535acc1a9efSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->adm_forced_command);
536acc1a9efSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->chroot_directory);
53747dd1d1bSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->routing_domain);
53819261079SEd Maste 	CLEAR_ON_NONE(options->host_key_agent);
5390fdf8faeSEd Maste 	CLEAR_ON_NONE(options->per_source_penalty_exempt);
540f374ba41SEd Maste 
541bc5531deSDag-Erling Smørgrav 	for (i = 0; i < options->num_host_key_files; i++)
542bc5531deSDag-Erling Smørgrav 		CLEAR_ON_NONE(options->host_key_files[i]);
543bc5531deSDag-Erling Smørgrav 	for (i = 0; i < options->num_host_cert_files; i++)
544bc5531deSDag-Erling Smørgrav 		CLEAR_ON_NONE(options->host_cert_files[i]);
545bc5531deSDag-Erling Smørgrav 
546f374ba41SEd Maste 	CLEAR_ON_NONE_ARRAY(channel_timeouts, num_channel_timeouts, "none");
547f374ba41SEd Maste 	CLEAR_ON_NONE_ARRAY(auth_methods, num_auth_methods, "any");
548f374ba41SEd Maste #undef CLEAR_ON_NONE
549f374ba41SEd Maste #undef CLEAR_ON_NONE_ARRAY
550511b41d2SMark Murray }
551511b41d2SMark Murray 
552511b41d2SMark Murray /* Keyword tokens. */
553511b41d2SMark Murray typedef enum {
554511b41d2SMark Murray 	sBadOption,		/* == unknown option */
555989dd127SDag-Erling Smørgrav 	/* Portable-specific options */
5560fdf8faeSEd Maste 	sUsePAM, sPAMServiceName,
557989dd127SDag-Erling Smørgrav 	/* Standard Options */
558ca86bcf2SDag-Erling Smørgrav 	sPort, sHostKeyFile, sLoginGraceTime,
55919261079SEd Maste 	sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose,
560af12a3e7SDag-Erling Smørgrav 	sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
561e9e8876aSEd Maste 	sKerberosGetAFSToken, sPasswordAuthentication,
562e9e8876aSEd Maste 	sKbdInteractiveAuthentication, sListenAddress, sAddressFamily,
563ca3176e7SBrian Feldman 	sPrintMotd, sPrintLastLog, sIgnoreRhosts,
564af12a3e7SDag-Erling Smørgrav 	sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
565f7167e0eSDag-Erling Smørgrav 	sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive,
566ca86bcf2SDag-Erling Smørgrav 	sPermitUserEnvironment, sAllowTcpForwarding, sCompression,
567e4a9863fSDag-Erling Smørgrav 	sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
56819261079SEd Maste 	sIgnoreUserKnownHosts, sCiphers, sMacs, sPidFile, sModuliFile,
56919261079SEd Maste 	sGatewayPorts, sPubkeyAuthentication, sPubkeyAcceptedAlgorithms,
570bc5531deSDag-Erling Smørgrav 	sXAuthLocation, sSubsystem, sMaxStartups, sMaxAuthTries, sMaxSessions,
571cf2b5f3bSDag-Erling Smørgrav 	sBanner, sUseDNS, sHostbasedAuthentication,
57219261079SEd Maste 	sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedAlgorithms,
57319261079SEd Maste 	sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize,
5740fdf8faeSEd Maste 	sPerSourcePenalties, sPerSourcePenaltyExemptList,
575bc5531deSDag-Erling Smørgrav 	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
576557f75e5SDag-Erling Smørgrav 	sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
577190cef3dSDag-Erling Smørgrav 	sAcceptEnv, sSetEnv, sPermitTunnel,
578190cef3dSDag-Erling Smørgrav 	sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory,
579d4af9e69SDag-Erling Smørgrav 	sUsePrivilegeSeparation, sAllowAgentForwarding,
58019261079SEd Maste 	sHostCertificate, sInclude,
581e2f6069cSDag-Erling Smørgrav 	sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
582557f75e5SDag-Erling Smørgrav 	sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser,
5832f513db7SEd Maste 	sKexAlgorithms, sCASignatureAlgorithms, sIPQoS, sVersionAddendum,
5846888a9beSDag-Erling Smørgrav 	sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
585a0ee8cc6SDag-Erling Smørgrav 	sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
586a0ee8cc6SDag-Erling Smørgrav 	sStreamLocalBindMask, sStreamLocalBindUnlink,
587ca86bcf2SDag-Erling Smørgrav 	sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
58819261079SEd Maste 	sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider,
589f374ba41SEd Maste 	sRequiredRSASize, sChannelTimeout, sUnusedConnectionTimeout,
5903d9fd9fcSEd Maste 	sSshdSessionPath, sRefuseConnection,
591b2af61ecSKurt Lidl 	sUseBlacklist,
592ca86bcf2SDag-Erling Smørgrav 	sDeprecated, sIgnore, sUnsupported
593511b41d2SMark Murray } ServerOpCodes;
594511b41d2SMark Murray 
59519261079SEd Maste #define SSHCFG_GLOBAL		0x01	/* allowed in main section of config */
596333ee039SDag-Erling Smørgrav #define SSHCFG_MATCH		0x02	/* allowed inside a Match section */
597333ee039SDag-Erling Smørgrav #define SSHCFG_ALL		(SSHCFG_GLOBAL|SSHCFG_MATCH)
59819261079SEd Maste #define SSHCFG_NEVERMATCH	0x04  /* Match never matches; internal only */
59919261079SEd Maste #define SSHCFG_MATCH_ONLY	0x08  /* Match only in conditional blocks; internal only */
600333ee039SDag-Erling Smørgrav 
601511b41d2SMark Murray /* Textual representation of the tokens. */
602511b41d2SMark Murray static struct {
603511b41d2SMark Murray 	const char *name;
604511b41d2SMark Murray 	ServerOpCodes opcode;
605333ee039SDag-Erling Smørgrav 	u_int flags;
606511b41d2SMark Murray } keywords[] = {
607989dd127SDag-Erling Smørgrav 	/* Portable-specific options */
608cf2b5f3bSDag-Erling Smørgrav #ifdef USE_PAM
609333ee039SDag-Erling Smørgrav 	{ "usepam", sUsePAM, SSHCFG_GLOBAL },
6100fdf8faeSEd Maste 	{ "pamservicename", sPAMServiceName, SSHCFG_ALL },
611cf2b5f3bSDag-Erling Smørgrav #else
612333ee039SDag-Erling Smørgrav 	{ "usepam", sUnsupported, SSHCFG_GLOBAL },
6130fdf8faeSEd Maste 	{ "pamservicename", sUnsupported, SSHCFG_ALL },
614975616f0SDag-Erling Smørgrav #endif
615333ee039SDag-Erling Smørgrav 	{ "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
616989dd127SDag-Erling Smørgrav 	/* Standard Options */
617333ee039SDag-Erling Smørgrav 	{ "port", sPort, SSHCFG_GLOBAL },
618333ee039SDag-Erling Smørgrav 	{ "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
619333ee039SDag-Erling Smørgrav 	{ "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL },		/* alias */
620e4a9863fSDag-Erling Smørgrav 	{ "hostkeyagent", sHostKeyAgent, SSHCFG_GLOBAL },
621333ee039SDag-Erling Smørgrav 	{ "pidfile", sPidFile, SSHCFG_GLOBAL },
62219261079SEd Maste 	{ "modulifile", sModuliFile, SSHCFG_GLOBAL },
623ca86bcf2SDag-Erling Smørgrav 	{ "serverkeybits", sDeprecated, SSHCFG_GLOBAL },
624333ee039SDag-Erling Smørgrav 	{ "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL },
625ca86bcf2SDag-Erling Smørgrav 	{ "keyregenerationinterval", sDeprecated, SSHCFG_GLOBAL },
626d4af9e69SDag-Erling Smørgrav 	{ "permitrootlogin", sPermitRootLogin, SSHCFG_ALL },
627333ee039SDag-Erling Smørgrav 	{ "syslogfacility", sLogFacility, SSHCFG_GLOBAL },
6284f52dfbbSDag-Erling Smørgrav 	{ "loglevel", sLogLevel, SSHCFG_ALL },
62919261079SEd Maste 	{ "logverbose", sLogVerbose, SSHCFG_ALL },
630333ee039SDag-Erling Smørgrav 	{ "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL },
631ca86bcf2SDag-Erling Smørgrav 	{ "rhostsrsaauthentication", sDeprecated, SSHCFG_ALL },
632d4af9e69SDag-Erling Smørgrav 	{ "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL },
633e2f6069cSDag-Erling Smørgrav 	{ "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_ALL },
63419261079SEd Maste 	{ "hostbasedacceptedalgorithms", sHostbasedAcceptedAlgorithms, SSHCFG_ALL },
63519261079SEd Maste 	{ "hostbasedacceptedkeytypes", sHostbasedAcceptedAlgorithms, SSHCFG_ALL }, /* obsolete */
636eccfee6eSDag-Erling Smørgrav 	{ "hostkeyalgorithms", sHostKeyAlgorithms, SSHCFG_GLOBAL },
637ca86bcf2SDag-Erling Smørgrav 	{ "rsaauthentication", sDeprecated, SSHCFG_ALL },
638d4af9e69SDag-Erling Smørgrav 	{ "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL },
63919261079SEd Maste 	{ "pubkeyacceptedalgorithms", sPubkeyAcceptedAlgorithms, SSHCFG_ALL },
64019261079SEd Maste 	{ "pubkeyacceptedkeytypes", sPubkeyAcceptedAlgorithms, SSHCFG_ALL }, /* obsolete */
64119261079SEd Maste 	{ "pubkeyauthoptions", sPubkeyAuthOptions, SSHCFG_ALL },
642333ee039SDag-Erling Smørgrav 	{ "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */
643cf2b5f3bSDag-Erling Smørgrav #ifdef KRB5
644d4af9e69SDag-Erling Smørgrav 	{ "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL },
645333ee039SDag-Erling Smørgrav 	{ "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL },
646333ee039SDag-Erling Smørgrav 	{ "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL },
6471ec0d754SDag-Erling Smørgrav #ifdef USE_AFS
648333ee039SDag-Erling Smørgrav 	{ "kerberosgetafstoken", sKerberosGetAFSToken, SSHCFG_GLOBAL },
6491ec0d754SDag-Erling Smørgrav #else
650333ee039SDag-Erling Smørgrav 	{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
6511ec0d754SDag-Erling Smørgrav #endif
652cf2b5f3bSDag-Erling Smørgrav #else
653d4af9e69SDag-Erling Smørgrav 	{ "kerberosauthentication", sUnsupported, SSHCFG_ALL },
654333ee039SDag-Erling Smørgrav 	{ "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
655333ee039SDag-Erling Smørgrav 	{ "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
656333ee039SDag-Erling Smørgrav 	{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
657cb96ab36SAssar Westerlund #endif
658333ee039SDag-Erling Smørgrav 	{ "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
659333ee039SDag-Erling Smørgrav 	{ "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
660cf2b5f3bSDag-Erling Smørgrav #ifdef GSSAPI
661d4af9e69SDag-Erling Smørgrav 	{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
662333ee039SDag-Erling Smørgrav 	{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
663557f75e5SDag-Erling Smørgrav 	{ "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
664cf2b5f3bSDag-Erling Smørgrav #else
665d4af9e69SDag-Erling Smørgrav 	{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
666333ee039SDag-Erling Smørgrav 	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
667557f75e5SDag-Erling Smørgrav 	{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
668511b41d2SMark Murray #endif
669d4af9e69SDag-Erling Smørgrav 	{ "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
670d4af9e69SDag-Erling Smørgrav 	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
67119261079SEd Maste 	{ "challengeresponseauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */
67219261079SEd Maste 	{ "skeyauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */
673333ee039SDag-Erling Smørgrav 	{ "checkmail", sDeprecated, SSHCFG_GLOBAL },
674333ee039SDag-Erling Smørgrav 	{ "listenaddress", sListenAddress, SSHCFG_GLOBAL },
675333ee039SDag-Erling Smørgrav 	{ "addressfamily", sAddressFamily, SSHCFG_GLOBAL },
676333ee039SDag-Erling Smørgrav 	{ "printmotd", sPrintMotd, SSHCFG_GLOBAL },
677acc1a9efSDag-Erling Smørgrav #ifdef DISABLE_LASTLOG
678acc1a9efSDag-Erling Smørgrav 	{ "printlastlog", sUnsupported, SSHCFG_GLOBAL },
679acc1a9efSDag-Erling Smørgrav #else
680333ee039SDag-Erling Smørgrav 	{ "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
681acc1a9efSDag-Erling Smørgrav #endif
68219261079SEd Maste 	{ "ignorerhosts", sIgnoreRhosts, SSHCFG_ALL },
683333ee039SDag-Erling Smørgrav 	{ "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
684333ee039SDag-Erling Smørgrav 	{ "x11forwarding", sX11Forwarding, SSHCFG_ALL },
685333ee039SDag-Erling Smørgrav 	{ "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
686333ee039SDag-Erling Smørgrav 	{ "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
687333ee039SDag-Erling Smørgrav 	{ "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
688333ee039SDag-Erling Smørgrav 	{ "strictmodes", sStrictModes, SSHCFG_GLOBAL },
689cce7d346SDag-Erling Smørgrav 	{ "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL },
690333ee039SDag-Erling Smørgrav 	{ "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
691ca86bcf2SDag-Erling Smørgrav 	{ "uselogin", sDeprecated, SSHCFG_GLOBAL },
692333ee039SDag-Erling Smørgrav 	{ "compression", sCompression, SSHCFG_GLOBAL },
693e4a9863fSDag-Erling Smørgrav 	{ "rekeylimit", sRekeyLimit, SSHCFG_ALL },
694333ee039SDag-Erling Smørgrav 	{ "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
695333ee039SDag-Erling Smørgrav 	{ "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL },	/* obsolete alias */
696333ee039SDag-Erling Smørgrav 	{ "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
697d4af9e69SDag-Erling Smørgrav 	{ "allowagentforwarding", sAllowAgentForwarding, SSHCFG_ALL },
698462c32cbSDag-Erling Smørgrav 	{ "allowusers", sAllowUsers, SSHCFG_ALL },
699462c32cbSDag-Erling Smørgrav 	{ "denyusers", sDenyUsers, SSHCFG_ALL },
700462c32cbSDag-Erling Smørgrav 	{ "allowgroups", sAllowGroups, SSHCFG_ALL },
701462c32cbSDag-Erling Smørgrav 	{ "denygroups", sDenyGroups, SSHCFG_ALL },
702333ee039SDag-Erling Smørgrav 	{ "ciphers", sCiphers, SSHCFG_GLOBAL },
703333ee039SDag-Erling Smørgrav 	{ "macs", sMacs, SSHCFG_GLOBAL },
704ca86bcf2SDag-Erling Smørgrav 	{ "protocol", sIgnore, SSHCFG_GLOBAL },
705333ee039SDag-Erling Smørgrav 	{ "gatewayports", sGatewayPorts, SSHCFG_ALL },
706edf85781SEd Maste 	{ "subsystem", sSubsystem, SSHCFG_ALL },
707333ee039SDag-Erling Smørgrav 	{ "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
70819261079SEd Maste 	{ "persourcemaxstartups", sPerSourceMaxStartups, SSHCFG_GLOBAL },
70919261079SEd Maste 	{ "persourcenetblocksize", sPerSourceNetBlockSize, SSHCFG_GLOBAL },
7100fdf8faeSEd Maste 	{ "persourcepenalties", sPerSourcePenalties, SSHCFG_GLOBAL },
7110fdf8faeSEd Maste 	{ "persourcepenaltyexemptlist", sPerSourcePenaltyExemptList, SSHCFG_GLOBAL },
712d4af9e69SDag-Erling Smørgrav 	{ "maxauthtries", sMaxAuthTries, SSHCFG_ALL },
713d4af9e69SDag-Erling Smørgrav 	{ "maxsessions", sMaxSessions, SSHCFG_ALL },
714d4af9e69SDag-Erling Smørgrav 	{ "banner", sBanner, SSHCFG_ALL },
715333ee039SDag-Erling Smørgrav 	{ "usedns", sUseDNS, SSHCFG_GLOBAL },
716333ee039SDag-Erling Smørgrav 	{ "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
717333ee039SDag-Erling Smørgrav 	{ "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL },
718ca86bcf2SDag-Erling Smørgrav 	{ "clientaliveinterval", sClientAliveInterval, SSHCFG_ALL },
719ca86bcf2SDag-Erling Smørgrav 	{ "clientalivecountmax", sClientAliveCountMax, SSHCFG_ALL },
720e2f6069cSDag-Erling Smørgrav 	{ "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_ALL },
721e146993eSDag-Erling Smørgrav 	{ "authorizedkeysfile2", sDeprecated, SSHCFG_ALL },
722d93a896eSDag-Erling Smørgrav 	{ "useprivilegeseparation", sDeprecated, SSHCFG_GLOBAL},
723462c32cbSDag-Erling Smørgrav 	{ "acceptenv", sAcceptEnv, SSHCFG_ALL },
724190cef3dSDag-Erling Smørgrav 	{ "setenv", sSetEnv, SSHCFG_ALL },
725e2f6069cSDag-Erling Smørgrav 	{ "permittunnel", sPermitTunnel, SSHCFG_ALL },
726f7167e0eSDag-Erling Smørgrav 	{ "permittty", sPermitTTY, SSHCFG_ALL },
727a0ee8cc6SDag-Erling Smørgrav 	{ "permituserrc", sPermitUserRC, SSHCFG_ALL },
728333ee039SDag-Erling Smørgrav 	{ "match", sMatch, SSHCFG_ALL },
729333ee039SDag-Erling Smørgrav 	{ "permitopen", sPermitOpen, SSHCFG_ALL },
730190cef3dSDag-Erling Smørgrav 	{ "permitlisten", sPermitListen, SSHCFG_ALL },
731333ee039SDag-Erling Smørgrav 	{ "forcecommand", sForceCommand, SSHCFG_ALL },
732d4af9e69SDag-Erling Smørgrav 	{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
733b15c8340SDag-Erling Smørgrav 	{ "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
734b15c8340SDag-Erling Smørgrav 	{ "revokedkeys", sRevokedKeys, SSHCFG_ALL },
735b15c8340SDag-Erling Smørgrav 	{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
736e2f6069cSDag-Erling Smørgrav 	{ "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
7374a421b63SDag-Erling Smørgrav 	{ "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
73819261079SEd Maste 	{ "include", sInclude, SSHCFG_ALL },
7394a421b63SDag-Erling Smørgrav 	{ "ipqos", sIPQoS, SSHCFG_ALL },
7406888a9beSDag-Erling Smørgrav 	{ "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
7416888a9beSDag-Erling Smørgrav 	{ "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
742557f75e5SDag-Erling Smørgrav 	{ "authorizedprincipalscommand", sAuthorizedPrincipalsCommand, SSHCFG_ALL },
743557f75e5SDag-Erling Smørgrav 	{ "authorizedprincipalscommanduser", sAuthorizedPrincipalsCommandUser, SSHCFG_ALL },
744462c32cbSDag-Erling Smørgrav 	{ "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL },
7456888a9beSDag-Erling Smørgrav 	{ "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL },
746a0ee8cc6SDag-Erling Smørgrav 	{ "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_ALL },
747a0ee8cc6SDag-Erling Smørgrav 	{ "streamlocalbindunlink", sStreamLocalBindUnlink, SSHCFG_ALL },
748a0ee8cc6SDag-Erling Smørgrav 	{ "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL },
749bc5531deSDag-Erling Smørgrav 	{ "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL },
750ca86bcf2SDag-Erling Smørgrav 	{ "disableforwarding", sDisableForwarding, SSHCFG_ALL },
7514f52dfbbSDag-Erling Smørgrav 	{ "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL },
75247dd1d1bSDag-Erling Smørgrav 	{ "rdomain", sRDomain, SSHCFG_ALL },
7532f513db7SEd Maste 	{ "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL },
75419261079SEd Maste 	{ "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL },
75538a52bd3SEd Maste 	{ "requiredrsasize", sRequiredRSASize, SSHCFG_ALL },
756f374ba41SEd Maste 	{ "channeltimeout", sChannelTimeout, SSHCFG_ALL },
757f374ba41SEd Maste 	{ "unusedconnectiontimeout", sUnusedConnectionTimeout, SSHCFG_ALL },
7580fdf8faeSEd Maste 	{ "sshdsessionpath", sSshdSessionPath, SSHCFG_GLOBAL },
7593d9fd9fcSEd Maste 	{ "refuseconnection", sRefuseConnection, SSHCFG_ALL },
760b2af61ecSKurt Lidl 	{ "useblacklist", sUseBlacklist, SSHCFG_GLOBAL },
761e426c743SEd Maste 	{ "useblocklist", sUseBlacklist, SSHCFG_GLOBAL }, /* alias */
762a93cbba2SEd Maste 
763333ee039SDag-Erling Smørgrav 	{ NULL, sBadOption, 0 }
764511b41d2SMark Murray };
765511b41d2SMark Murray 
766d4af9e69SDag-Erling Smørgrav static struct {
767d4af9e69SDag-Erling Smørgrav 	int val;
768d4af9e69SDag-Erling Smørgrav 	char *text;
769d4af9e69SDag-Erling Smørgrav } tunmode_desc[] = {
770d4af9e69SDag-Erling Smørgrav 	{ SSH_TUNMODE_NO, "no" },
771d4af9e69SDag-Erling Smørgrav 	{ SSH_TUNMODE_POINTOPOINT, "point-to-point" },
772d4af9e69SDag-Erling Smørgrav 	{ SSH_TUNMODE_ETHERNET, "ethernet" },
773d4af9e69SDag-Erling Smørgrav 	{ SSH_TUNMODE_YES, "yes" },
774d4af9e69SDag-Erling Smørgrav 	{ -1, NULL }
775d4af9e69SDag-Erling Smørgrav };
776d4af9e69SDag-Erling Smørgrav 
777190cef3dSDag-Erling Smørgrav /* Returns an opcode name from its number */
778190cef3dSDag-Erling Smørgrav 
779190cef3dSDag-Erling Smørgrav static const char *
lookup_opcode_name(ServerOpCodes code)780190cef3dSDag-Erling Smørgrav lookup_opcode_name(ServerOpCodes code)
781190cef3dSDag-Erling Smørgrav {
782190cef3dSDag-Erling Smørgrav 	u_int i;
783190cef3dSDag-Erling Smørgrav 
784190cef3dSDag-Erling Smørgrav 	for (i = 0; keywords[i].name != NULL; i++)
785190cef3dSDag-Erling Smørgrav 		if (keywords[i].opcode == code)
786190cef3dSDag-Erling Smørgrav 			return(keywords[i].name);
787190cef3dSDag-Erling Smørgrav 	return "UNKNOWN";
788190cef3dSDag-Erling Smørgrav }
789190cef3dSDag-Erling Smørgrav 
790190cef3dSDag-Erling Smørgrav 
791511b41d2SMark Murray /*
792ca3176e7SBrian Feldman  * Returns the number of the token pointed to by cp or sBadOption.
793511b41d2SMark Murray  */
794511b41d2SMark Murray 
795511b41d2SMark Murray static ServerOpCodes
parse_token(const char * cp,const char * filename,int linenum,u_int * flags)796511b41d2SMark Murray parse_token(const char *cp, const char *filename,
797333ee039SDag-Erling Smørgrav 	    int linenum, u_int *flags)
798511b41d2SMark Murray {
799ca3176e7SBrian Feldman 	u_int i;
800511b41d2SMark Murray 
801511b41d2SMark Murray 	for (i = 0; keywords[i].name; i++)
802333ee039SDag-Erling Smørgrav 		if (strcasecmp(cp, keywords[i].name) == 0) {
803333ee039SDag-Erling Smørgrav 			*flags = keywords[i].flags;
804511b41d2SMark Murray 			return keywords[i].opcode;
805333ee039SDag-Erling Smørgrav 		}
806511b41d2SMark Murray 
807ca3176e7SBrian Feldman 	error("%s: line %d: Bad configuration option: %s",
808511b41d2SMark Murray 	    filename, linenum, cp);
809511b41d2SMark Murray 	return sBadOption;
810511b41d2SMark Murray }
811511b41d2SMark Murray 
812b15c8340SDag-Erling Smørgrav char *
derelativise_path(const char * path)813b15c8340SDag-Erling Smørgrav derelativise_path(const char *path)
814b15c8340SDag-Erling Smørgrav {
815bc5531deSDag-Erling Smørgrav 	char *expanded, *ret, cwd[PATH_MAX];
816b15c8340SDag-Erling Smørgrav 
817bc5531deSDag-Erling Smørgrav 	if (strcasecmp(path, "none") == 0)
818bc5531deSDag-Erling Smørgrav 		return xstrdup("none");
819b15c8340SDag-Erling Smørgrav 	expanded = tilde_expand_filename(path, getuid());
82019261079SEd Maste 	if (path_absolute(expanded))
821b15c8340SDag-Erling Smørgrav 		return expanded;
8228ad9b54aSDag-Erling Smørgrav 	if (getcwd(cwd, sizeof(cwd)) == NULL)
82319261079SEd Maste 		fatal_f("getcwd: %s", strerror(errno));
824b15c8340SDag-Erling Smørgrav 	xasprintf(&ret, "%s/%s", cwd, expanded);
825e4a9863fSDag-Erling Smørgrav 	free(expanded);
826b15c8340SDag-Erling Smørgrav 	return ret;
827b15c8340SDag-Erling Smørgrav }
828b15c8340SDag-Erling Smørgrav 
829af12a3e7SDag-Erling Smørgrav static void
add_listen_addr(ServerOptions * options,const char * addr,const char * rdomain,int port)83047dd1d1bSDag-Erling Smørgrav add_listen_addr(ServerOptions *options, const char *addr,
83147dd1d1bSDag-Erling Smørgrav     const char *rdomain, int port)
832511b41d2SMark Murray {
833d4ecd108SDag-Erling Smørgrav 	u_int i;
834511b41d2SMark Murray 
83547dd1d1bSDag-Erling Smørgrav 	if (port > 0)
83647dd1d1bSDag-Erling Smørgrav 		add_one_listen_addr(options, addr, rdomain, port);
83747dd1d1bSDag-Erling Smørgrav 	else {
83847dd1d1bSDag-Erling Smørgrav 		for (i = 0; i < options->num_ports; i++) {
83947dd1d1bSDag-Erling Smørgrav 			add_one_listen_addr(options, addr, rdomain,
84047dd1d1bSDag-Erling Smørgrav 			    options->ports[i]);
84147dd1d1bSDag-Erling Smørgrav 		}
84247dd1d1bSDag-Erling Smørgrav 	}
843ca3176e7SBrian Feldman }
844ca3176e7SBrian Feldman 
845af12a3e7SDag-Erling Smørgrav static void
add_one_listen_addr(ServerOptions * options,const char * addr,const char * rdomain,int port)84647dd1d1bSDag-Erling Smørgrav add_one_listen_addr(ServerOptions *options, const char *addr,
84747dd1d1bSDag-Erling Smørgrav     const char *rdomain, int port)
848ca3176e7SBrian Feldman {
849ca3176e7SBrian Feldman 	struct addrinfo hints, *ai, *aitop;
850ca3176e7SBrian Feldman 	char strport[NI_MAXSERV];
851ca3176e7SBrian Feldman 	int gaierr;
85247dd1d1bSDag-Erling Smørgrav 	u_int i;
85347dd1d1bSDag-Erling Smørgrav 
85447dd1d1bSDag-Erling Smørgrav 	/* Find listen_addrs entry for this rdomain */
85547dd1d1bSDag-Erling Smørgrav 	for (i = 0; i < options->num_listen_addrs; i++) {
85647dd1d1bSDag-Erling Smørgrav 		if (rdomain == NULL && options->listen_addrs[i].rdomain == NULL)
85747dd1d1bSDag-Erling Smørgrav 			break;
85847dd1d1bSDag-Erling Smørgrav 		if (rdomain == NULL || options->listen_addrs[i].rdomain == NULL)
85947dd1d1bSDag-Erling Smørgrav 			continue;
86047dd1d1bSDag-Erling Smørgrav 		if (strcmp(rdomain, options->listen_addrs[i].rdomain) == 0)
86147dd1d1bSDag-Erling Smørgrav 			break;
86247dd1d1bSDag-Erling Smørgrav 	}
86347dd1d1bSDag-Erling Smørgrav 	if (i >= options->num_listen_addrs) {
86447dd1d1bSDag-Erling Smørgrav 		/* No entry for this rdomain; allocate one */
86547dd1d1bSDag-Erling Smørgrav 		if (i >= INT_MAX)
86619261079SEd Maste 			fatal_f("too many listen addresses");
86747dd1d1bSDag-Erling Smørgrav 		options->listen_addrs = xrecallocarray(options->listen_addrs,
86847dd1d1bSDag-Erling Smørgrav 		    options->num_listen_addrs, options->num_listen_addrs + 1,
86947dd1d1bSDag-Erling Smørgrav 		    sizeof(*options->listen_addrs));
87047dd1d1bSDag-Erling Smørgrav 		i = options->num_listen_addrs++;
87147dd1d1bSDag-Erling Smørgrav 		if (rdomain != NULL)
87247dd1d1bSDag-Erling Smørgrav 			options->listen_addrs[i].rdomain = xstrdup(rdomain);
87347dd1d1bSDag-Erling Smørgrav 	}
87447dd1d1bSDag-Erling Smørgrav 	/* options->listen_addrs[i] points to the addresses for this rdomain */
875ca3176e7SBrian Feldman 
876511b41d2SMark Murray 	memset(&hints, 0, sizeof(hints));
877aa49c926SDag-Erling Smørgrav 	hints.ai_family = options->address_family;
878511b41d2SMark Murray 	hints.ai_socktype = SOCK_STREAM;
879511b41d2SMark Murray 	hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
880cce7d346SDag-Erling Smørgrav 	snprintf(strport, sizeof strport, "%d", port);
881511b41d2SMark Murray 	if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
882ca3176e7SBrian Feldman 		fatal("bad addr or host: %s (%s)",
883511b41d2SMark Murray 		    addr ? addr : "<NULL>",
884d4af9e69SDag-Erling Smørgrav 		    ssh_gai_strerror(gaierr));
885511b41d2SMark Murray 	for (ai = aitop; ai->ai_next; ai = ai->ai_next)
886511b41d2SMark Murray 		;
88747dd1d1bSDag-Erling Smørgrav 	ai->ai_next = options->listen_addrs[i].addrs;
88847dd1d1bSDag-Erling Smørgrav 	options->listen_addrs[i].addrs = aitop;
88947dd1d1bSDag-Erling Smørgrav }
89047dd1d1bSDag-Erling Smørgrav 
89147dd1d1bSDag-Erling Smørgrav /* Returns nonzero if the routing domain name is valid */
89247dd1d1bSDag-Erling Smørgrav static int
valid_rdomain(const char * name)89347dd1d1bSDag-Erling Smørgrav valid_rdomain(const char *name)
89447dd1d1bSDag-Erling Smørgrav {
89547dd1d1bSDag-Erling Smørgrav #if defined(HAVE_SYS_VALID_RDOMAIN)
89647dd1d1bSDag-Erling Smørgrav 	return sys_valid_rdomain(name);
89747dd1d1bSDag-Erling Smørgrav #elif defined(__OpenBSD__)
89847dd1d1bSDag-Erling Smørgrav 	const char *errstr;
89947dd1d1bSDag-Erling Smørgrav 	long long num;
90047dd1d1bSDag-Erling Smørgrav 	struct rt_tableinfo info;
90147dd1d1bSDag-Erling Smørgrav 	int mib[6];
90247dd1d1bSDag-Erling Smørgrav 	size_t miblen = sizeof(mib);
90347dd1d1bSDag-Erling Smørgrav 
90447dd1d1bSDag-Erling Smørgrav 	if (name == NULL)
90547dd1d1bSDag-Erling Smørgrav 		return 1;
90647dd1d1bSDag-Erling Smørgrav 
90747dd1d1bSDag-Erling Smørgrav 	num = strtonum(name, 0, 255, &errstr);
90847dd1d1bSDag-Erling Smørgrav 	if (errstr != NULL)
90947dd1d1bSDag-Erling Smørgrav 		return 0;
91047dd1d1bSDag-Erling Smørgrav 
91147dd1d1bSDag-Erling Smørgrav 	/* Check whether the table actually exists */
91247dd1d1bSDag-Erling Smørgrav 	memset(mib, 0, sizeof(mib));
91347dd1d1bSDag-Erling Smørgrav 	mib[0] = CTL_NET;
91447dd1d1bSDag-Erling Smørgrav 	mib[1] = PF_ROUTE;
91547dd1d1bSDag-Erling Smørgrav 	mib[4] = NET_RT_TABLE;
91647dd1d1bSDag-Erling Smørgrav 	mib[5] = (int)num;
91747dd1d1bSDag-Erling Smørgrav 	if (sysctl(mib, 6, &info, &miblen, NULL, 0) == -1)
91847dd1d1bSDag-Erling Smørgrav 		return 0;
91947dd1d1bSDag-Erling Smørgrav 
92047dd1d1bSDag-Erling Smørgrav 	return 1;
92147dd1d1bSDag-Erling Smørgrav #else /* defined(__OpenBSD__) */
92247dd1d1bSDag-Erling Smørgrav 	error("Routing domains are not supported on this platform");
92347dd1d1bSDag-Erling Smørgrav 	return 0;
92447dd1d1bSDag-Erling Smørgrav #endif
925511b41d2SMark Murray }
926511b41d2SMark Murray 
927557f75e5SDag-Erling Smørgrav /*
928557f75e5SDag-Erling Smørgrav  * Queue a ListenAddress to be processed once we have all of the Ports
929557f75e5SDag-Erling Smørgrav  * and AddressFamily options.
930557f75e5SDag-Erling Smørgrav  */
931557f75e5SDag-Erling Smørgrav static void
queue_listen_addr(ServerOptions * options,const char * addr,const char * rdomain,int port)93247dd1d1bSDag-Erling Smørgrav queue_listen_addr(ServerOptions *options, const char *addr,
93347dd1d1bSDag-Erling Smørgrav     const char *rdomain, int port)
934557f75e5SDag-Erling Smørgrav {
93547dd1d1bSDag-Erling Smørgrav 	struct queued_listenaddr *qla;
93647dd1d1bSDag-Erling Smørgrav 
93747dd1d1bSDag-Erling Smørgrav 	options->queued_listen_addrs = xrecallocarray(
93847dd1d1bSDag-Erling Smørgrav 	    options->queued_listen_addrs,
93947dd1d1bSDag-Erling Smørgrav 	    options->num_queued_listens, options->num_queued_listens + 1,
94047dd1d1bSDag-Erling Smørgrav 	    sizeof(*options->queued_listen_addrs));
94147dd1d1bSDag-Erling Smørgrav 	qla = &options->queued_listen_addrs[options->num_queued_listens++];
94247dd1d1bSDag-Erling Smørgrav 	qla->addr = xstrdup(addr);
94347dd1d1bSDag-Erling Smørgrav 	qla->port = port;
94447dd1d1bSDag-Erling Smørgrav 	qla->rdomain = rdomain == NULL ? NULL : xstrdup(rdomain);
945557f75e5SDag-Erling Smørgrav }
946557f75e5SDag-Erling Smørgrav 
947557f75e5SDag-Erling Smørgrav /*
948557f75e5SDag-Erling Smørgrav  * Process queued (text) ListenAddress entries.
949557f75e5SDag-Erling Smørgrav  */
950557f75e5SDag-Erling Smørgrav static void
process_queued_listen_addrs(ServerOptions * options)951557f75e5SDag-Erling Smørgrav process_queued_listen_addrs(ServerOptions *options)
952557f75e5SDag-Erling Smørgrav {
953557f75e5SDag-Erling Smørgrav 	u_int i;
95447dd1d1bSDag-Erling Smørgrav 	struct queued_listenaddr *qla;
955557f75e5SDag-Erling Smørgrav 
956557f75e5SDag-Erling Smørgrav 	if (options->num_ports == 0)
957557f75e5SDag-Erling Smørgrav 		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
958557f75e5SDag-Erling Smørgrav 	if (options->address_family == -1)
959557f75e5SDag-Erling Smørgrav 		options->address_family = AF_UNSPEC;
960557f75e5SDag-Erling Smørgrav 
961557f75e5SDag-Erling Smørgrav 	for (i = 0; i < options->num_queued_listens; i++) {
96247dd1d1bSDag-Erling Smørgrav 		qla = &options->queued_listen_addrs[i];
96347dd1d1bSDag-Erling Smørgrav 		add_listen_addr(options, qla->addr, qla->rdomain, qla->port);
96447dd1d1bSDag-Erling Smørgrav 		free(qla->addr);
96547dd1d1bSDag-Erling Smørgrav 		free(qla->rdomain);
966557f75e5SDag-Erling Smørgrav 	}
967557f75e5SDag-Erling Smørgrav 	free(options->queued_listen_addrs);
968557f75e5SDag-Erling Smørgrav 	options->queued_listen_addrs = NULL;
969557f75e5SDag-Erling Smørgrav 	options->num_queued_listens = 0;
970557f75e5SDag-Erling Smørgrav }
971557f75e5SDag-Erling Smørgrav 
9724f52dfbbSDag-Erling Smørgrav /*
973333ee039SDag-Erling Smørgrav  * The strategy for the Match blocks is that the config file is parsed twice.
974333ee039SDag-Erling Smørgrav  *
975333ee039SDag-Erling Smørgrav  * The first time is at startup.  activep is initialized to 1 and the
976333ee039SDag-Erling Smørgrav  * directives in the global context are processed and acted on.  Hitting a
977333ee039SDag-Erling Smørgrav  * Match directive unsets activep and the directives inside the block are
978333ee039SDag-Erling Smørgrav  * checked for syntax only.
979333ee039SDag-Erling Smørgrav  *
980333ee039SDag-Erling Smørgrav  * The second time is after a connection has been established but before
981333ee039SDag-Erling Smørgrav  * authentication.  activep is initialized to 2 and global config directives
982333ee039SDag-Erling Smørgrav  * are ignored since they have already been processed.  If the criteria in a
983333ee039SDag-Erling Smørgrav  * Match block is met, activep is set and the subsequent directives
984333ee039SDag-Erling Smørgrav  * processed and actioned until EOF or another Match block unsets it.  Any
985333ee039SDag-Erling Smørgrav  * options set are copied into the main server config.
986333ee039SDag-Erling Smørgrav  *
987333ee039SDag-Erling Smørgrav  * Potential additions/improvements:
988ca86bcf2SDag-Erling Smørgrav  *  - Add Match support for pre-kex directives, eg. Ciphers.
989333ee039SDag-Erling Smørgrav  *
990333ee039SDag-Erling Smørgrav  *  - Add a Tag directive (idea from David Leonard) ala pf, eg:
991333ee039SDag-Erling Smørgrav  *	Match Address 192.168.0.*
992333ee039SDag-Erling Smørgrav  *		Tag trusted
993333ee039SDag-Erling Smørgrav  *	Match Group wheel
994333ee039SDag-Erling Smørgrav  *		Tag trusted
995333ee039SDag-Erling Smørgrav  *	Match Tag trusted
996333ee039SDag-Erling Smørgrav  *		AllowTcpForwarding yes
997333ee039SDag-Erling Smørgrav  *		GatewayPorts clientspecified
998333ee039SDag-Erling Smørgrav  *		[...]
999333ee039SDag-Erling Smørgrav  *
1000333ee039SDag-Erling Smørgrav  *  - Add a PermittedChannelRequests directive
1001333ee039SDag-Erling Smørgrav  *	Match Group shell
1002333ee039SDag-Erling Smørgrav  *		PermittedChannelRequests session,forwarded-tcpip
1003333ee039SDag-Erling Smørgrav  */
1004333ee039SDag-Erling Smørgrav 
1005333ee039SDag-Erling Smørgrav static int
match_cfg_line_group(const char * grps,int line,const char * user)1006333ee039SDag-Erling Smørgrav match_cfg_line_group(const char *grps, int line, const char *user)
1007333ee039SDag-Erling Smørgrav {
1008333ee039SDag-Erling Smørgrav 	int result = 0;
1009333ee039SDag-Erling Smørgrav 	struct passwd *pw;
1010333ee039SDag-Erling Smørgrav 
1011333ee039SDag-Erling Smørgrav 	if (user == NULL)
1012333ee039SDag-Erling Smørgrav 		goto out;
1013333ee039SDag-Erling Smørgrav 
1014333ee039SDag-Erling Smørgrav 	if ((pw = getpwnam(user)) == NULL) {
1015333ee039SDag-Erling Smørgrav 		debug("Can't match group at line %d because user %.100s does "
1016333ee039SDag-Erling Smørgrav 		    "not exist", line, user);
1017333ee039SDag-Erling Smørgrav 	} else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
1018333ee039SDag-Erling Smørgrav 		debug("Can't Match group because user %.100s not in any group "
1019333ee039SDag-Erling Smørgrav 		    "at line %d", user, line);
1020d4af9e69SDag-Erling Smørgrav 	} else if (ga_match_pattern_list(grps) != 1) {
1021d4af9e69SDag-Erling Smørgrav 		debug("user %.100s does not match group list %.100s at line %d",
1022d4af9e69SDag-Erling Smørgrav 		    user, grps, line);
1023333ee039SDag-Erling Smørgrav 	} else {
1024d4af9e69SDag-Erling Smørgrav 		debug("user %.100s matched group list %.100s at line %d", user,
1025d4af9e69SDag-Erling Smørgrav 		    grps, line);
1026333ee039SDag-Erling Smørgrav 		result = 1;
1027333ee039SDag-Erling Smørgrav 	}
1028333ee039SDag-Erling Smørgrav out:
1029333ee039SDag-Erling Smørgrav 	ga_free();
1030333ee039SDag-Erling Smørgrav 	return result;
1031333ee039SDag-Erling Smørgrav }
1032333ee039SDag-Erling Smørgrav 
103347dd1d1bSDag-Erling Smørgrav static void
match_test_missing_fatal(const char * criteria,const char * attrib)103447dd1d1bSDag-Erling Smørgrav match_test_missing_fatal(const char *criteria, const char *attrib)
103547dd1d1bSDag-Erling Smørgrav {
103647dd1d1bSDag-Erling Smørgrav 	fatal("'Match %s' in configuration but '%s' not in connection "
103747dd1d1bSDag-Erling Smørgrav 	    "test specification.", criteria, attrib);
103847dd1d1bSDag-Erling Smørgrav }
103947dd1d1bSDag-Erling Smørgrav 
1040462c32cbSDag-Erling Smørgrav /*
10416888a9beSDag-Erling Smørgrav  * All of the attributes on a single Match line are ANDed together, so we need
1042f7167e0eSDag-Erling Smørgrav  * to check every attribute and set the result to zero if any attribute does
10436888a9beSDag-Erling Smørgrav  * not match.
1044462c32cbSDag-Erling Smørgrav  */
1045333ee039SDag-Erling Smørgrav static int
match_cfg_line(const char * full_line,int * acp,char *** avp,int line,struct connection_info * ci)10463d9fd9fcSEd Maste match_cfg_line(const char *full_line, int *acp, char ***avp,
10473d9fd9fcSEd Maste     int line, struct connection_info *ci)
1048333ee039SDag-Erling Smørgrav {
1049f7167e0eSDag-Erling Smørgrav 	int result = 1, attributes = 0, port;
1050*0ae642c7SEd Maste 	char *arg, *attrib = NULL, *oattrib;
1051333ee039SDag-Erling Smørgrav 
1052462c32cbSDag-Erling Smørgrav 	if (ci == NULL)
10533d9fd9fcSEd Maste 		debug3("checking syntax for 'Match %s'", full_line);
10543d9fd9fcSEd Maste 	else {
10553d9fd9fcSEd Maste 		debug3("checking match for '%s' user %s%s host %s addr %s "
10563d9fd9fcSEd Maste 		    "laddr %s lport %d", full_line,
10573d9fd9fcSEd Maste 		    ci->user ? ci->user : "(null)",
10583d9fd9fcSEd Maste 		    ci->user_invalid ? " (invalid)" : "",
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);
10623d9fd9fcSEd Maste 	}
1063333ee039SDag-Erling Smørgrav 
1064*0ae642c7SEd Maste 	while ((oattrib = argv_next(acp, avp)) != NULL) {
1065*0ae642c7SEd Maste 		attrib = xstrdup(oattrib);
106619261079SEd Maste 		/* Terminate on comment */
106719261079SEd Maste 		if (*attrib == '#') {
10683d9fd9fcSEd Maste 			argv_consume(acp); /* mark all arguments consumed */
106919261079SEd Maste 			break;
107019261079SEd Maste 		}
107119261079SEd Maste 		arg = NULL;
1072f7167e0eSDag-Erling Smørgrav 		attributes++;
107319261079SEd Maste 		/* Criterion "all" has no argument and must appear alone */
1074f7167e0eSDag-Erling Smørgrav 		if (strcasecmp(attrib, "all") == 0) {
10753d9fd9fcSEd Maste 			if (attributes > 1 ||
10763d9fd9fcSEd Maste 			    ((arg = argv_next(acp, avp)) != NULL &&
107719261079SEd Maste 			    *arg != '\0' && *arg != '#')) {
1078f7167e0eSDag-Erling Smørgrav 				error("'all' cannot be combined with other "
1079f7167e0eSDag-Erling Smørgrav 				    "Match attributes");
1080*0ae642c7SEd Maste 				result = -1;
1081*0ae642c7SEd Maste 				goto out;
1082f7167e0eSDag-Erling Smørgrav 			}
108319261079SEd Maste 			if (arg != NULL && *arg == '#')
10843d9fd9fcSEd Maste 				argv_consume(acp); /* consume remaining args */
1085*0ae642c7SEd Maste 			result = 1;
1086*0ae642c7SEd Maste 			goto out;
1087f7167e0eSDag-Erling Smørgrav 		}
10883d9fd9fcSEd Maste 		/* Criterion "invalid-user" also has no argument */
10893d9fd9fcSEd Maste 		if (strcasecmp(attrib, "invalid-user") == 0) {
1090*0ae642c7SEd Maste 			if (ci == NULL) {
1091*0ae642c7SEd Maste 				result = 0;
10923d9fd9fcSEd Maste 				continue;
1093*0ae642c7SEd Maste 			}
10943d9fd9fcSEd Maste 			if (ci->user_invalid == 0)
10953d9fd9fcSEd Maste 				result = 0;
10963d9fd9fcSEd Maste 			else
10973d9fd9fcSEd Maste 				debug("matched invalid-user at line %d", line);
10983d9fd9fcSEd Maste 			continue;
10993d9fd9fcSEd Maste 		}
1100*0ae642c7SEd Maste 
1101*0ae642c7SEd Maste 		/* Keep this list in sync with below */
1102*0ae642c7SEd Maste 		if (strprefix(attrib, "user=", 1) != NULL ||
1103*0ae642c7SEd Maste 		    strprefix(attrib, "group=", 1) != NULL ||
1104*0ae642c7SEd Maste 		    strprefix(attrib, "host=", 1) != NULL ||
1105*0ae642c7SEd Maste 		    strprefix(attrib, "address=", 1) != NULL ||
1106*0ae642c7SEd Maste 		    strprefix(attrib, "localaddress=", 1) != NULL ||
1107*0ae642c7SEd Maste 		    strprefix(attrib, "localport=", 1) != NULL ||
1108*0ae642c7SEd Maste 		    strprefix(attrib, "rdomain=", 1) != NULL) {
1109*0ae642c7SEd Maste 			arg = strchr(attrib, '=');
1110*0ae642c7SEd Maste 			*(arg++) = '\0';
1111*0ae642c7SEd Maste 		} else {
1112*0ae642c7SEd Maste 			arg = argv_next(acp, avp);
1113*0ae642c7SEd Maste 		}
1114*0ae642c7SEd Maste 
111519261079SEd Maste 		/* All other criteria require an argument */
1116*0ae642c7SEd Maste 		if (arg == NULL || *arg == '\0' || *arg == '#') {
1117333ee039SDag-Erling Smørgrav 			error("Missing Match criteria for %s", attrib);
1118*0ae642c7SEd Maste 			result = -1;
1119*0ae642c7SEd Maste 			goto out;
1120333ee039SDag-Erling Smørgrav 		}
1121333ee039SDag-Erling Smørgrav 		if (strcasecmp(attrib, "user") == 0) {
112219261079SEd Maste 			if (ci == NULL || (ci->test && ci->user == NULL)) {
1123333ee039SDag-Erling Smørgrav 				result = 0;
1124333ee039SDag-Erling Smørgrav 				continue;
1125333ee039SDag-Erling Smørgrav 			}
112647dd1d1bSDag-Erling Smørgrav 			if (ci->user == NULL)
112747dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("User", "user");
112819261079SEd Maste 			if (match_usergroup_pattern_list(ci->user, arg) != 1)
1129333ee039SDag-Erling Smørgrav 				result = 0;
1130333ee039SDag-Erling Smørgrav 			else
1131333ee039SDag-Erling Smørgrav 				debug("user %.100s matched 'User %.100s' at "
1132462c32cbSDag-Erling Smørgrav 				    "line %d", ci->user, arg, line);
1133333ee039SDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "group") == 0) {
113419261079SEd Maste 			if (ci == NULL || (ci->test && ci->user == NULL)) {
1135462c32cbSDag-Erling Smørgrav 				result = 0;
1136462c32cbSDag-Erling Smørgrav 				continue;
1137462c32cbSDag-Erling Smørgrav 			}
113847dd1d1bSDag-Erling Smørgrav 			if (ci->user == NULL)
113947dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("Group", "user");
1140462c32cbSDag-Erling Smørgrav 			switch (match_cfg_line_group(arg, line, ci->user)) {
1141333ee039SDag-Erling Smørgrav 			case -1:
1142*0ae642c7SEd Maste 				result = -1;
1143*0ae642c7SEd Maste 				goto out;
1144333ee039SDag-Erling Smørgrav 			case 0:
1145333ee039SDag-Erling Smørgrav 				result = 0;
1146333ee039SDag-Erling Smørgrav 			}
1147333ee039SDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "host") == 0) {
114819261079SEd Maste 			if (ci == NULL || (ci->test && ci->host == NULL)) {
1149333ee039SDag-Erling Smørgrav 				result = 0;
1150333ee039SDag-Erling Smørgrav 				continue;
1151333ee039SDag-Erling Smørgrav 			}
115247dd1d1bSDag-Erling Smørgrav 			if (ci->host == NULL)
115347dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("Host", "host");
1154557f75e5SDag-Erling Smørgrav 			if (match_hostname(ci->host, arg) != 1)
1155333ee039SDag-Erling Smørgrav 				result = 0;
1156333ee039SDag-Erling Smørgrav 			else
1157333ee039SDag-Erling Smørgrav 				debug("connection from %.100s matched 'Host "
1158462c32cbSDag-Erling Smørgrav 				    "%.100s' at line %d", ci->host, arg, line);
1159333ee039SDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "address") == 0) {
116019261079SEd Maste 			if (ci == NULL || (ci->test && ci->address == NULL)) {
116119261079SEd Maste 				if (addr_match_list(NULL, arg) != 0)
116219261079SEd Maste 					fatal("Invalid Match address argument "
116319261079SEd Maste 					    "'%s' at line %d", arg, line);
1164462c32cbSDag-Erling Smørgrav 				result = 0;
1165462c32cbSDag-Erling Smørgrav 				continue;
1166462c32cbSDag-Erling Smørgrav 			}
116747dd1d1bSDag-Erling Smørgrav 			if (ci->address == NULL)
116847dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("Address", "addr");
1169462c32cbSDag-Erling Smørgrav 			switch (addr_match_list(ci->address, arg)) {
1170d4af9e69SDag-Erling Smørgrav 			case 1:
1171333ee039SDag-Erling Smørgrav 				debug("connection from %.100s matched 'Address "
1172462c32cbSDag-Erling Smørgrav 				    "%.100s' at line %d", ci->address, arg, line);
1173d4af9e69SDag-Erling Smørgrav 				break;
1174d4af9e69SDag-Erling Smørgrav 			case 0:
1175d4af9e69SDag-Erling Smørgrav 			case -1:
1176d4af9e69SDag-Erling Smørgrav 				result = 0;
1177d4af9e69SDag-Erling Smørgrav 				break;
1178d4af9e69SDag-Erling Smørgrav 			case -2:
1179*0ae642c7SEd Maste 				result = -1;
1180*0ae642c7SEd Maste 				goto out;
1181d4af9e69SDag-Erling Smørgrav 			}
1182462c32cbSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "localaddress") == 0){
118319261079SEd Maste 			if (ci == NULL || (ci->test && ci->laddress == NULL)) {
118419261079SEd Maste 				if (addr_match_list(NULL, arg) != 0)
118519261079SEd Maste 					fatal("Invalid Match localaddress "
118619261079SEd Maste 					    "argument '%s' at line %d", arg,
118719261079SEd Maste 					    line);
1188462c32cbSDag-Erling Smørgrav 				result = 0;
1189462c32cbSDag-Erling Smørgrav 				continue;
1190462c32cbSDag-Erling Smørgrav 			}
119147dd1d1bSDag-Erling Smørgrav 			if (ci->laddress == NULL)
119247dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("LocalAddress",
119347dd1d1bSDag-Erling Smørgrav 				    "laddr");
1194462c32cbSDag-Erling Smørgrav 			switch (addr_match_list(ci->laddress, arg)) {
1195462c32cbSDag-Erling Smørgrav 			case 1:
1196462c32cbSDag-Erling Smørgrav 				debug("connection from %.100s matched "
1197462c32cbSDag-Erling Smørgrav 				    "'LocalAddress %.100s' at line %d",
1198462c32cbSDag-Erling Smørgrav 				    ci->laddress, arg, line);
1199462c32cbSDag-Erling Smørgrav 				break;
1200462c32cbSDag-Erling Smørgrav 			case 0:
1201462c32cbSDag-Erling Smørgrav 			case -1:
1202462c32cbSDag-Erling Smørgrav 				result = 0;
1203462c32cbSDag-Erling Smørgrav 				break;
1204462c32cbSDag-Erling Smørgrav 			case -2:
1205*0ae642c7SEd Maste 				result = -1;
1206*0ae642c7SEd Maste 				goto out;
1207462c32cbSDag-Erling Smørgrav 			}
1208462c32cbSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "localport") == 0) {
1209462c32cbSDag-Erling Smørgrav 			if ((port = a2port(arg)) == -1) {
1210462c32cbSDag-Erling Smørgrav 				error("Invalid LocalPort '%s' on Match line",
1211462c32cbSDag-Erling Smørgrav 				    arg);
1212*0ae642c7SEd Maste 				result = -1;
1213*0ae642c7SEd Maste 				goto out;
1214462c32cbSDag-Erling Smørgrav 			}
121519261079SEd Maste 			if (ci == NULL || (ci->test && ci->lport == -1)) {
1216462c32cbSDag-Erling Smørgrav 				result = 0;
1217462c32cbSDag-Erling Smørgrav 				continue;
1218462c32cbSDag-Erling Smørgrav 			}
121947dd1d1bSDag-Erling Smørgrav 			if (ci->lport == 0)
122047dd1d1bSDag-Erling Smørgrav 				match_test_missing_fatal("LocalPort", "lport");
1221462c32cbSDag-Erling Smørgrav 			/* TODO support port lists */
1222462c32cbSDag-Erling Smørgrav 			if (port == ci->lport)
1223462c32cbSDag-Erling Smørgrav 				debug("connection from %.100s matched "
1224462c32cbSDag-Erling Smørgrav 				    "'LocalPort %d' at line %d",
1225462c32cbSDag-Erling Smørgrav 				    ci->laddress, port, line);
1226462c32cbSDag-Erling Smørgrav 			else
1227462c32cbSDag-Erling Smørgrav 				result = 0;
122847dd1d1bSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "rdomain") == 0) {
122919261079SEd Maste 			if (ci == NULL || (ci->test && ci->rdomain == NULL)) {
123047dd1d1bSDag-Erling Smørgrav 				result = 0;
123147dd1d1bSDag-Erling Smørgrav 				continue;
123247dd1d1bSDag-Erling Smørgrav 			}
123319261079SEd Maste 			if (ci->rdomain == NULL)
123419261079SEd Maste 				match_test_missing_fatal("RDomain", "rdomain");
123547dd1d1bSDag-Erling Smørgrav 			if (match_pattern_list(ci->rdomain, arg, 0) != 1)
123647dd1d1bSDag-Erling Smørgrav 				result = 0;
123747dd1d1bSDag-Erling Smørgrav 			else
123847dd1d1bSDag-Erling Smørgrav 				debug("user %.100s matched 'RDomain %.100s' at "
123947dd1d1bSDag-Erling Smørgrav 				    "line %d", ci->rdomain, arg, line);
1240333ee039SDag-Erling Smørgrav 		} else {
1241*0ae642c7SEd Maste 			error("Unsupported Match attribute %s", oattrib);
1242*0ae642c7SEd Maste 			result = -1;
1243*0ae642c7SEd Maste 			goto out;
1244333ee039SDag-Erling Smørgrav 		}
1245*0ae642c7SEd Maste 		free(attrib);
1246*0ae642c7SEd Maste 		attrib = NULL;
1247333ee039SDag-Erling Smørgrav 	}
1248f7167e0eSDag-Erling Smørgrav 	if (attributes == 0) {
1249f7167e0eSDag-Erling Smørgrav 		error("One or more attributes required for Match");
1250f7167e0eSDag-Erling Smørgrav 		return -1;
1251f7167e0eSDag-Erling Smørgrav 	}
1252*0ae642c7SEd Maste  out:
1253*0ae642c7SEd Maste 	if (ci != NULL && result != -1)
1254333ee039SDag-Erling Smørgrav 		debug3("match %sfound", result ? "" : "not ");
1255*0ae642c7SEd Maste 	free(attrib);
1256333ee039SDag-Erling Smørgrav 	return result;
1257333ee039SDag-Erling Smørgrav }
1258333ee039SDag-Erling Smørgrav 
1259333ee039SDag-Erling Smørgrav #define WHITESPACE " \t\r\n"
1260333ee039SDag-Erling Smørgrav 
1261e146993eSDag-Erling Smørgrav /* Multistate option parsing */
1262e146993eSDag-Erling Smørgrav struct multistate {
1263e146993eSDag-Erling Smørgrav 	char *key;
1264e146993eSDag-Erling Smørgrav 	int value;
1265e146993eSDag-Erling Smørgrav };
126647dd1d1bSDag-Erling Smørgrav static const struct multistate multistate_flag[] = {
126747dd1d1bSDag-Erling Smørgrav 	{ "yes",			1 },
126847dd1d1bSDag-Erling Smørgrav 	{ "no",				0 },
126947dd1d1bSDag-Erling Smørgrav 	{ NULL, -1 }
127047dd1d1bSDag-Erling Smørgrav };
127119261079SEd Maste static const struct multistate multistate_ignore_rhosts[] = {
127219261079SEd Maste 	{ "yes",			IGNORE_RHOSTS_YES },
127319261079SEd Maste 	{ "no",				IGNORE_RHOSTS_NO },
127419261079SEd Maste 	{ "shosts-only",		IGNORE_RHOSTS_SHOSTS },
127519261079SEd Maste 	{ NULL, -1 }
127619261079SEd Maste };
1277e146993eSDag-Erling Smørgrav static const struct multistate multistate_addressfamily[] = {
1278e146993eSDag-Erling Smørgrav 	{ "inet",			AF_INET },
1279e146993eSDag-Erling Smørgrav 	{ "inet6",			AF_INET6 },
1280e146993eSDag-Erling Smørgrav 	{ "any",			AF_UNSPEC },
1281e146993eSDag-Erling Smørgrav 	{ NULL, -1 }
1282e146993eSDag-Erling Smørgrav };
1283e146993eSDag-Erling Smørgrav static const struct multistate multistate_permitrootlogin[] = {
1284e146993eSDag-Erling Smørgrav 	{ "without-password",		PERMIT_NO_PASSWD },
1285eccfee6eSDag-Erling Smørgrav 	{ "prohibit-password",		PERMIT_NO_PASSWD },
1286e146993eSDag-Erling Smørgrav 	{ "forced-commands-only",	PERMIT_FORCED_ONLY },
1287e146993eSDag-Erling Smørgrav 	{ "yes",			PERMIT_YES },
1288e146993eSDag-Erling Smørgrav 	{ "no",				PERMIT_NO },
1289e146993eSDag-Erling Smørgrav 	{ NULL, -1 }
1290e146993eSDag-Erling Smørgrav };
1291e146993eSDag-Erling Smørgrav static const struct multistate multistate_compression[] = {
129219261079SEd Maste #ifdef WITH_ZLIB
1293ca86bcf2SDag-Erling Smørgrav 	{ "yes",			COMP_DELAYED },
1294e146993eSDag-Erling Smørgrav 	{ "delayed",			COMP_DELAYED },
129519261079SEd Maste #endif
1296e146993eSDag-Erling Smørgrav 	{ "no",				COMP_NONE },
1297e146993eSDag-Erling Smørgrav 	{ NULL, -1 }
1298e146993eSDag-Erling Smørgrav };
1299e146993eSDag-Erling Smørgrav static const struct multistate multistate_gatewayports[] = {
1300e146993eSDag-Erling Smørgrav 	{ "clientspecified",		2 },
1301e146993eSDag-Erling Smørgrav 	{ "yes",			1 },
1302e146993eSDag-Erling Smørgrav 	{ "no",				0 },
1303e146993eSDag-Erling Smørgrav 	{ NULL, -1 }
1304e146993eSDag-Erling Smørgrav };
13056888a9beSDag-Erling Smørgrav static const struct multistate multistate_tcpfwd[] = {
13066888a9beSDag-Erling Smørgrav 	{ "yes",			FORWARD_ALLOW },
13076888a9beSDag-Erling Smørgrav 	{ "all",			FORWARD_ALLOW },
13086888a9beSDag-Erling Smørgrav 	{ "no",				FORWARD_DENY },
13096888a9beSDag-Erling Smørgrav 	{ "remote",			FORWARD_REMOTE },
13106888a9beSDag-Erling Smørgrav 	{ "local",			FORWARD_LOCAL },
13116888a9beSDag-Erling Smørgrav 	{ NULL, -1 }
13126888a9beSDag-Erling Smørgrav };
1313e146993eSDag-Erling Smørgrav 
131419261079SEd Maste static int
process_server_config_line_depth(ServerOptions * options,char * line,const char * filename,int linenum,int * activep,struct connection_info * connectinfo,int * inc_flags,int depth,struct include_list * includes)131519261079SEd Maste process_server_config_line_depth(ServerOptions *options, char *line,
1316462c32cbSDag-Erling Smørgrav     const char *filename, int linenum, int *activep,
131719261079SEd Maste     struct connection_info *connectinfo, int *inc_flags, int depth,
131819261079SEd Maste     struct include_list *includes)
1319511b41d2SMark Murray {
13201323ec57SEd Maste 	char *str, ***chararrayptr, **charptr, *arg, *arg2, *p, *keyword;
1321a91a2465SEd Maste 	int cmdline = 0, *intptr, value, value2, n, port, oactive, r;
1322a91a2465SEd Maste 	int ca_only = 0, found = 0;
1323d4af9e69SDag-Erling Smørgrav 	SyslogFacility *log_facility_ptr;
1324d4af9e69SDag-Erling Smørgrav 	LogLevel *log_level_ptr;
1325511b41d2SMark Murray 	ServerOpCodes opcode;
1326a91a2465SEd Maste 	u_int i, *uintptr, flags = 0;
1327333ee039SDag-Erling Smørgrav 	size_t len;
1328e4a9863fSDag-Erling Smørgrav 	long long val64;
1329e146993eSDag-Erling Smørgrav 	const struct multistate *multistate_ptr;
133047dd1d1bSDag-Erling Smørgrav 	const char *errstr;
133119261079SEd Maste 	struct include_item *item;
133219261079SEd Maste 	glob_t gbuf;
133319261079SEd Maste 	char **oav = NULL, **av;
133419261079SEd Maste 	int oac = 0, ac;
133519261079SEd Maste 	int ret = -1;
1336a91a2465SEd Maste 	char **strs = NULL; /* string array arguments; freed implicitly */
1337a91a2465SEd Maste 	u_int nstrs = 0;
1338511b41d2SMark Murray 
1339d93a896eSDag-Erling Smørgrav 	/* Strip trailing whitespace. Allow \f (form feed) at EOL only */
1340d93a896eSDag-Erling Smørgrav 	if ((len = strlen(line)) == 0)
1341d93a896eSDag-Erling Smørgrav 		return 0;
1342d93a896eSDag-Erling Smørgrav 	for (len--; len > 0; len--) {
1343d93a896eSDag-Erling Smørgrav 		if (strchr(WHITESPACE "\f", line[len]) == NULL)
1344d93a896eSDag-Erling Smørgrav 			break;
1345d93a896eSDag-Erling Smørgrav 		line[len] = '\0';
1346d93a896eSDag-Erling Smørgrav 	}
1347d93a896eSDag-Erling Smørgrav 
134819261079SEd Maste 	str = line;
134919261079SEd Maste 	if ((keyword = strdelim(&str)) == NULL)
1350333ee039SDag-Erling Smørgrav 		return 0;
1351c2d3a559SKris Kennaway 	/* Ignore leading whitespace */
135219261079SEd Maste 	if (*keyword == '\0')
135319261079SEd Maste 		keyword = strdelim(&str);
135419261079SEd Maste 	if (!keyword || !*keyword || *keyword == '#')
1355af12a3e7SDag-Erling Smørgrav 		return 0;
135619261079SEd Maste 	if (str == NULL || *str == '\0') {
135719261079SEd Maste 		error("%s line %d: no argument after keyword \"%s\"",
135819261079SEd Maste 		    filename, linenum, keyword);
135919261079SEd Maste 		return -1;
136019261079SEd Maste 	}
1361ca3176e7SBrian Feldman 	intptr = NULL;
1362ca3176e7SBrian Feldman 	charptr = NULL;
136319261079SEd Maste 	opcode = parse_token(keyword, filename, linenum, &flags);
136419261079SEd Maste 
136519261079SEd Maste 	if (argv_split(str, &oac, &oav, 1) != 0) {
136619261079SEd Maste 		error("%s line %d: invalid quotes", filename, linenum);
136719261079SEd Maste 		return -1;
136819261079SEd Maste 	}
136919261079SEd Maste 	ac = oac;
137019261079SEd Maste 	av = oav;
1371333ee039SDag-Erling Smørgrav 
1372333ee039SDag-Erling Smørgrav 	if (activep == NULL) { /* We are processing a command line directive */
1373333ee039SDag-Erling Smørgrav 		cmdline = 1;
1374333ee039SDag-Erling Smørgrav 		activep = &cmdline;
1375333ee039SDag-Erling Smørgrav 	}
137619261079SEd Maste 	if (*activep && opcode != sMatch && opcode != sInclude)
137719261079SEd Maste 		debug3("%s:%d setting %s %s", filename, linenum, keyword, str);
1378333ee039SDag-Erling Smørgrav 	if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
1379462c32cbSDag-Erling Smørgrav 		if (connectinfo == NULL) {
1380333ee039SDag-Erling Smørgrav 			fatal("%s line %d: Directive '%s' is not allowed "
138119261079SEd Maste 			    "within a Match block", filename, linenum, keyword);
1382333ee039SDag-Erling Smørgrav 		} else { /* this is a directive we have already processed */
138319261079SEd Maste 			ret = 0;
138419261079SEd Maste 			goto out;
1385333ee039SDag-Erling Smørgrav 		}
1386333ee039SDag-Erling Smørgrav 	}
1387333ee039SDag-Erling Smørgrav 
1388511b41d2SMark Murray 	switch (opcode) {
1389989dd127SDag-Erling Smørgrav 	/* Portable-specific options */
1390cf2b5f3bSDag-Erling Smørgrav 	case sUsePAM:
1391cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->use_pam;
1392989dd127SDag-Erling Smørgrav 		goto parse_flag;
13930fdf8faeSEd Maste 	case sPAMServiceName:
13940fdf8faeSEd Maste 		charptr = &options->pam_service_name;
13950fdf8faeSEd Maste 		arg = argv_next(&ac, &av);
13960fdf8faeSEd Maste 		if (!arg || *arg == '\0') {
13970fdf8faeSEd Maste 			fatal("%s line %d: missing argument.",
13980fdf8faeSEd Maste 			    filename, linenum);
13990fdf8faeSEd Maste 		}
14000fdf8faeSEd Maste 		if (*activep && *charptr == NULL)
14010fdf8faeSEd Maste 			*charptr = xstrdup(arg);
14020fdf8faeSEd Maste 		break;
1403989dd127SDag-Erling Smørgrav 
1404989dd127SDag-Erling Smørgrav 	/* Standard Options */
1405511b41d2SMark Murray 	case sBadOption:
140619261079SEd Maste 		goto out;
1407511b41d2SMark Murray 	case sPort:
1408511b41d2SMark Murray 		/* ignore ports from configfile if cmdline specifies ports */
140919261079SEd Maste 		if (options->ports_from_cmdline) {
141019261079SEd Maste 			argv_consume(&ac);
141119261079SEd Maste 			break;
141219261079SEd Maste 		}
1413511b41d2SMark Murray 		if (options->num_ports >= MAX_PORTS)
1414ca3176e7SBrian Feldman 			fatal("%s line %d: too many ports.",
1415511b41d2SMark Murray 			    filename, linenum);
141619261079SEd Maste 		arg = argv_next(&ac, &av);
1417c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1418ca3176e7SBrian Feldman 			fatal("%s line %d: missing port number.",
1419511b41d2SMark Murray 			    filename, linenum);
1420ca3176e7SBrian Feldman 		options->ports[options->num_ports++] = a2port(arg);
1421cce7d346SDag-Erling Smørgrav 		if (options->ports[options->num_ports-1] <= 0)
1422ca3176e7SBrian Feldman 			fatal("%s line %d: Badly formatted port number.",
1423ca3176e7SBrian Feldman 			    filename, linenum);
1424511b41d2SMark Murray 		break;
1425511b41d2SMark Murray 
1426511b41d2SMark Murray 	case sLoginGraceTime:
1427511b41d2SMark Murray 		intptr = &options->login_grace_time;
1428af12a3e7SDag-Erling Smørgrav  parse_time:
142919261079SEd Maste 		arg = argv_next(&ac, &av);
1430af12a3e7SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1431af12a3e7SDag-Erling Smørgrav 			fatal("%s line %d: missing time value.",
1432af12a3e7SDag-Erling Smørgrav 			    filename, linenum);
1433af12a3e7SDag-Erling Smørgrav 		if ((value = convtime(arg)) == -1)
1434af12a3e7SDag-Erling Smørgrav 			fatal("%s line %d: invalid time value.",
1435af12a3e7SDag-Erling Smørgrav 			    filename, linenum);
1436557f75e5SDag-Erling Smørgrav 		if (*activep && *intptr == -1)
1437af12a3e7SDag-Erling Smørgrav 			*intptr = value;
1438af12a3e7SDag-Erling Smørgrav 		break;
1439511b41d2SMark Murray 
1440511b41d2SMark Murray 	case sListenAddress:
144119261079SEd Maste 		arg = argv_next(&ac, &av);
1442aa49c926SDag-Erling Smørgrav 		if (arg == NULL || *arg == '\0')
1443aa49c926SDag-Erling Smørgrav 			fatal("%s line %d: missing address",
1444511b41d2SMark Murray 			    filename, linenum);
1445d4ecd108SDag-Erling Smørgrav 		/* check for bare IPv6 address: no "[]" and 2 or more ":" */
1446d4ecd108SDag-Erling Smørgrav 		if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL
1447d4ecd108SDag-Erling Smørgrav 		    && strchr(p+1, ':') != NULL) {
144847dd1d1bSDag-Erling Smørgrav 			port = 0;
144947dd1d1bSDag-Erling Smørgrav 			p = arg;
145047dd1d1bSDag-Erling Smørgrav 		} else {
145119261079SEd Maste 			arg2 = NULL;
14521323ec57SEd Maste 			p = hpdelim(&arg);
14531323ec57SEd Maste 			if (p == NULL)
1454aa49c926SDag-Erling Smørgrav 				fatal("%s line %d: bad address:port usage",
1455ca3176e7SBrian Feldman 				    filename, linenum);
1456aa49c926SDag-Erling Smørgrav 			p = cleanhostname(p);
1457aa49c926SDag-Erling Smørgrav 			if (arg == NULL)
1458aa49c926SDag-Erling Smørgrav 				port = 0;
1459cce7d346SDag-Erling Smørgrav 			else if ((port = a2port(arg)) <= 0)
146047dd1d1bSDag-Erling Smørgrav 				fatal("%s line %d: bad port number",
146147dd1d1bSDag-Erling Smørgrav 				    filename, linenum);
146247dd1d1bSDag-Erling Smørgrav 		}
146347dd1d1bSDag-Erling Smørgrav 		/* Optional routing table */
146447dd1d1bSDag-Erling Smørgrav 		arg2 = NULL;
146519261079SEd Maste 		if ((arg = argv_next(&ac, &av)) != NULL) {
146647dd1d1bSDag-Erling Smørgrav 			if (strcmp(arg, "rdomain") != 0 ||
146719261079SEd Maste 			    (arg2 = argv_next(&ac, &av)) == NULL)
146847dd1d1bSDag-Erling Smørgrav 				fatal("%s line %d: bad ListenAddress syntax",
146947dd1d1bSDag-Erling Smørgrav 				    filename, linenum);
147047dd1d1bSDag-Erling Smørgrav 			if (!valid_rdomain(arg2))
147147dd1d1bSDag-Erling Smørgrav 				fatal("%s line %d: bad routing domain",
147247dd1d1bSDag-Erling Smørgrav 				    filename, linenum);
147347dd1d1bSDag-Erling Smørgrav 		}
147447dd1d1bSDag-Erling Smørgrav 		queue_listen_addr(options, p, arg2, port);
1475aa49c926SDag-Erling Smørgrav 
1476aa49c926SDag-Erling Smørgrav 		break;
1477aa49c926SDag-Erling Smørgrav 
1478aa49c926SDag-Erling Smørgrav 	case sAddressFamily:
1479e146993eSDag-Erling Smørgrav 		intptr = &options->address_family;
1480e146993eSDag-Erling Smørgrav 		multistate_ptr = multistate_addressfamily;
1481e146993eSDag-Erling Smørgrav  parse_multistate:
148219261079SEd Maste 		arg = argv_next(&ac, &av);
1483d4ecd108SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1484e146993eSDag-Erling Smørgrav 			fatal("%s line %d: missing argument.",
1485d4ecd108SDag-Erling Smørgrav 			    filename, linenum);
1486e146993eSDag-Erling Smørgrav 		value = -1;
1487e146993eSDag-Erling Smørgrav 		for (i = 0; multistate_ptr[i].key != NULL; i++) {
1488e146993eSDag-Erling Smørgrav 			if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
1489e146993eSDag-Erling Smørgrav 				value = multistate_ptr[i].value;
1490e146993eSDag-Erling Smørgrav 				break;
1491e146993eSDag-Erling Smørgrav 			}
1492e146993eSDag-Erling Smørgrav 		}
1493e146993eSDag-Erling Smørgrav 		if (value == -1)
1494e146993eSDag-Erling Smørgrav 			fatal("%s line %d: unsupported option \"%s\".",
1495aa49c926SDag-Erling Smørgrav 			    filename, linenum, arg);
1496e146993eSDag-Erling Smørgrav 		if (*activep && *intptr == -1)
1497aa49c926SDag-Erling Smørgrav 			*intptr = value;
1498511b41d2SMark Murray 		break;
1499511b41d2SMark Murray 
1500511b41d2SMark Murray 	case sHostKeyFile:
150119261079SEd Maste 		arg = argv_next(&ac, &av);
1502ca3176e7SBrian Feldman 		if (!arg || *arg == '\0')
1503ca3176e7SBrian Feldman 			fatal("%s line %d: missing file name.",
1504e8aafc91SKris Kennaway 			    filename, linenum);
150519261079SEd Maste 		if (*activep) {
150619261079SEd Maste 			servconf_add_hostkey(filename, linenum,
150719261079SEd Maste 			    options, arg, 1);
150819261079SEd Maste 		}
1509e8aafc91SKris Kennaway 		break;
1510e8aafc91SKris Kennaway 
1511e4a9863fSDag-Erling Smørgrav 	case sHostKeyAgent:
1512e4a9863fSDag-Erling Smørgrav 		charptr = &options->host_key_agent;
151319261079SEd Maste 		arg = argv_next(&ac, &av);
1514e4a9863fSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1515e4a9863fSDag-Erling Smørgrav 			fatal("%s line %d: missing socket name.",
1516e4a9863fSDag-Erling Smørgrav 			    filename, linenum);
1517e4a9863fSDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
1518e4a9863fSDag-Erling Smørgrav 			*charptr = !strcmp(arg, SSH_AUTHSOCKET_ENV_NAME) ?
1519e4a9863fSDag-Erling Smørgrav 			    xstrdup(arg) : derelativise_path(arg);
1520e4a9863fSDag-Erling Smørgrav 		break;
1521e4a9863fSDag-Erling Smørgrav 
1522b15c8340SDag-Erling Smørgrav 	case sHostCertificate:
152319261079SEd Maste 		arg = argv_next(&ac, &av);
152447dd1d1bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
152547dd1d1bSDag-Erling Smørgrav 			fatal("%s line %d: missing file name.",
152647dd1d1bSDag-Erling Smørgrav 			    filename, linenum);
152747dd1d1bSDag-Erling Smørgrav 		if (*activep)
152847dd1d1bSDag-Erling Smørgrav 			servconf_add_hostcert(filename, linenum, options, arg);
152947dd1d1bSDag-Erling Smørgrav 		break;
1530b15c8340SDag-Erling Smørgrav 
1531e8aafc91SKris Kennaway 	case sPidFile:
1532e8aafc91SKris Kennaway 		charptr = &options->pid_file;
153347dd1d1bSDag-Erling Smørgrav  parse_filename:
153419261079SEd Maste 		arg = argv_next(&ac, &av);
153547dd1d1bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
153647dd1d1bSDag-Erling Smørgrav 			fatal("%s line %d: missing file name.",
153747dd1d1bSDag-Erling Smørgrav 			    filename, linenum);
153847dd1d1bSDag-Erling Smørgrav 		if (*activep && *charptr == NULL) {
153947dd1d1bSDag-Erling Smørgrav 			*charptr = derelativise_path(arg);
154047dd1d1bSDag-Erling Smørgrav 			/* increase optional counter */
154147dd1d1bSDag-Erling Smørgrav 			if (intptr != NULL)
154247dd1d1bSDag-Erling Smørgrav 				*intptr = *intptr + 1;
154347dd1d1bSDag-Erling Smørgrav 		}
154447dd1d1bSDag-Erling Smørgrav 		break;
1545511b41d2SMark Murray 
154619261079SEd Maste 	case sModuliFile:
154719261079SEd Maste 		charptr = &options->moduli_file;
154819261079SEd Maste 		goto parse_filename;
154919261079SEd Maste 
1550511b41d2SMark Murray 	case sPermitRootLogin:
1551511b41d2SMark Murray 		intptr = &options->permit_root_login;
1552e146993eSDag-Erling Smørgrav 		multistate_ptr = multistate_permitrootlogin;
1553e146993eSDag-Erling Smørgrav 		goto parse_multistate;
1554511b41d2SMark Murray 
1555511b41d2SMark Murray 	case sIgnoreRhosts:
1556511b41d2SMark Murray 		intptr = &options->ignore_rhosts;
155719261079SEd Maste 		multistate_ptr = multistate_ignore_rhosts;
155847dd1d1bSDag-Erling Smørgrav 		goto parse_multistate;
1559511b41d2SMark Murray 
1560511b41d2SMark Murray 	case sIgnoreUserKnownHosts:
1561511b41d2SMark Murray 		intptr = &options->ignore_user_known_hosts;
156219261079SEd Maste  parse_flag:
156319261079SEd Maste 		multistate_ptr = multistate_flag;
156419261079SEd Maste 		goto parse_multistate;
1565511b41d2SMark Murray 
1566ca3176e7SBrian Feldman 	case sHostbasedAuthentication:
1567ca3176e7SBrian Feldman 		intptr = &options->hostbased_authentication;
1568ca3176e7SBrian Feldman 		goto parse_flag;
1569ca3176e7SBrian Feldman 
1570ca3176e7SBrian Feldman 	case sHostbasedUsesNameFromPacketOnly:
1571ca3176e7SBrian Feldman 		intptr = &options->hostbased_uses_name_from_packet_only;
1572ca3176e7SBrian Feldman 		goto parse_flag;
1573ca3176e7SBrian Feldman 
157419261079SEd Maste 	case sHostbasedAcceptedAlgorithms:
157519261079SEd Maste 		charptr = &options->hostbased_accepted_algos;
1576535af610SEd Maste 		ca_only = 0;
157719261079SEd Maste  parse_pubkey_algos:
157819261079SEd Maste 		arg = argv_next(&ac, &av);
1579bc5531deSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1580bc5531deSDag-Erling Smørgrav 			fatal("%s line %d: Missing argument.",
1581bc5531deSDag-Erling Smørgrav 			    filename, linenum);
1582d93a896eSDag-Erling Smørgrav 		if (*arg != '-' &&
158319261079SEd Maste 		    !sshkey_names_valid2(*arg == '+' || *arg == '^' ?
1584535af610SEd Maste 		    arg + 1 : arg, 1, ca_only))
1585bc5531deSDag-Erling Smørgrav 			fatal("%s line %d: Bad key types '%s'.",
1586bc5531deSDag-Erling Smørgrav 			    filename, linenum, arg ? arg : "<NONE>");
1587bc5531deSDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
1588bc5531deSDag-Erling Smørgrav 			*charptr = xstrdup(arg);
1589bc5531deSDag-Erling Smørgrav 		break;
1590bc5531deSDag-Erling Smørgrav 
1591eccfee6eSDag-Erling Smørgrav 	case sHostKeyAlgorithms:
1592eccfee6eSDag-Erling Smørgrav 		charptr = &options->hostkeyalgorithms;
1593535af610SEd Maste 		ca_only = 0;
159419261079SEd Maste 		goto parse_pubkey_algos;
1595eccfee6eSDag-Erling Smørgrav 
15962f513db7SEd Maste 	case sCASignatureAlgorithms:
15972f513db7SEd Maste 		charptr = &options->ca_sign_algorithms;
1598535af610SEd Maste 		ca_only = 1;
159919261079SEd Maste 		goto parse_pubkey_algos;
16002f513db7SEd Maste 
1601ca3176e7SBrian Feldman 	case sPubkeyAuthentication:
1602ca3176e7SBrian Feldman 		intptr = &options->pubkey_authentication;
1603535af610SEd Maste 		ca_only = 0;
1604e8aafc91SKris Kennaway 		goto parse_flag;
1605cf2b5f3bSDag-Erling Smørgrav 
160619261079SEd Maste 	case sPubkeyAcceptedAlgorithms:
160719261079SEd Maste 		charptr = &options->pubkey_accepted_algos;
1608535af610SEd Maste 		ca_only = 0;
160919261079SEd Maste 		goto parse_pubkey_algos;
161019261079SEd Maste 
161119261079SEd Maste 	case sPubkeyAuthOptions:
161219261079SEd Maste 		intptr = &options->pubkey_auth_options;
161319261079SEd Maste 		value = 0;
161419261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
161519261079SEd Maste 			if (strcasecmp(arg, "none") == 0)
161619261079SEd Maste 				continue;
161719261079SEd Maste 			if (strcasecmp(arg, "touch-required") == 0)
161819261079SEd Maste 				value |= PUBKEYAUTH_TOUCH_REQUIRED;
161919261079SEd Maste 			else if (strcasecmp(arg, "verify-required") == 0)
162019261079SEd Maste 				value |= PUBKEYAUTH_VERIFY_REQUIRED;
162119261079SEd Maste 			else {
162219261079SEd Maste 				error("%s line %d: unsupported %s option %s",
162319261079SEd Maste 				    filename, linenum, keyword, arg);
162419261079SEd Maste 				goto out;
162519261079SEd Maste 			}
162619261079SEd Maste 		}
162719261079SEd Maste 		if (*activep && *intptr == -1)
162819261079SEd Maste 			*intptr = value;
162919261079SEd Maste 		break;
1630bc5531deSDag-Erling Smørgrav 
1631cb96ab36SAssar Westerlund 	case sKerberosAuthentication:
1632cb96ab36SAssar Westerlund 		intptr = &options->kerberos_authentication;
1633511b41d2SMark Murray 		goto parse_flag;
1634511b41d2SMark Murray 
1635af12a3e7SDag-Erling Smørgrav 	case sKerberosOrLocalPasswd:
1636af12a3e7SDag-Erling Smørgrav 		intptr = &options->kerberos_or_local_passwd;
1637511b41d2SMark Murray 		goto parse_flag;
1638511b41d2SMark Murray 
1639af12a3e7SDag-Erling Smørgrav 	case sKerberosTicketCleanup:
1640af12a3e7SDag-Erling Smørgrav 		intptr = &options->kerberos_ticket_cleanup;
1641511b41d2SMark Murray 		goto parse_flag;
1642cf2b5f3bSDag-Erling Smørgrav 
16431ec0d754SDag-Erling Smørgrav 	case sKerberosGetAFSToken:
16441ec0d754SDag-Erling Smørgrav 		intptr = &options->kerberos_get_afs_token;
16451ec0d754SDag-Erling Smørgrav 		goto parse_flag;
16461ec0d754SDag-Erling Smørgrav 
1647cf2b5f3bSDag-Erling Smørgrav 	case sGssAuthentication:
1648cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->gss_authentication;
1649fe5fd017SMark Murray 		goto parse_flag;
1650cf2b5f3bSDag-Erling Smørgrav 
1651cf2b5f3bSDag-Erling Smørgrav 	case sGssCleanupCreds:
1652cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->gss_cleanup_creds;
1653511b41d2SMark Murray 		goto parse_flag;
1654511b41d2SMark Murray 
1655557f75e5SDag-Erling Smørgrav 	case sGssStrictAcceptor:
1656557f75e5SDag-Erling Smørgrav 		intptr = &options->gss_strict_acceptor;
1657557f75e5SDag-Erling Smørgrav 		goto parse_flag;
1658557f75e5SDag-Erling Smørgrav 
1659511b41d2SMark Murray 	case sPasswordAuthentication:
1660511b41d2SMark Murray 		intptr = &options->password_authentication;
1661511b41d2SMark Murray 		goto parse_flag;
1662511b41d2SMark Murray 
166309958426SBrian Feldman 	case sKbdInteractiveAuthentication:
166409958426SBrian Feldman 		intptr = &options->kbd_interactive_authentication;
166509958426SBrian Feldman 		goto parse_flag;
166609958426SBrian Feldman 
1667511b41d2SMark Murray 	case sPrintMotd:
1668511b41d2SMark Murray 		intptr = &options->print_motd;
1669511b41d2SMark Murray 		goto parse_flag;
1670511b41d2SMark Murray 
1671ca3176e7SBrian Feldman 	case sPrintLastLog:
1672ca3176e7SBrian Feldman 		intptr = &options->print_lastlog;
1673ca3176e7SBrian Feldman 		goto parse_flag;
1674ca3176e7SBrian Feldman 
1675511b41d2SMark Murray 	case sX11Forwarding:
1676511b41d2SMark Murray 		intptr = &options->x11_forwarding;
1677511b41d2SMark Murray 		goto parse_flag;
1678511b41d2SMark Murray 
1679511b41d2SMark Murray 	case sX11DisplayOffset:
1680511b41d2SMark Murray 		intptr = &options->x11_display_offset;
1681ca86bcf2SDag-Erling Smørgrav  parse_int:
168219261079SEd Maste 		arg = argv_next(&ac, &av);
168347dd1d1bSDag-Erling Smørgrav 		if ((errstr = atoi_err(arg, &value)) != NULL)
168419261079SEd Maste 			fatal("%s line %d: %s integer value %s.",
168519261079SEd Maste 			    filename, linenum, keyword, errstr);
1686ca86bcf2SDag-Erling Smørgrav 		if (*activep && *intptr == -1)
1687ca86bcf2SDag-Erling Smørgrav 			*intptr = value;
1688ca86bcf2SDag-Erling Smørgrav 		break;
1689511b41d2SMark Murray 
1690af12a3e7SDag-Erling Smørgrav 	case sX11UseLocalhost:
1691af12a3e7SDag-Erling Smørgrav 		intptr = &options->x11_use_localhost;
1692af12a3e7SDag-Erling Smørgrav 		goto parse_flag;
1693af12a3e7SDag-Erling Smørgrav 
1694c2d3a559SKris Kennaway 	case sXAuthLocation:
1695c2d3a559SKris Kennaway 		charptr = &options->xauth_location;
1696c2d3a559SKris Kennaway 		goto parse_filename;
1697c2d3a559SKris Kennaway 
1698f7167e0eSDag-Erling Smørgrav 	case sPermitTTY:
1699f7167e0eSDag-Erling Smørgrav 		intptr = &options->permit_tty;
1700f7167e0eSDag-Erling Smørgrav 		goto parse_flag;
1701f7167e0eSDag-Erling Smørgrav 
1702a0ee8cc6SDag-Erling Smørgrav 	case sPermitUserRC:
1703a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->permit_user_rc;
1704a0ee8cc6SDag-Erling Smørgrav 		goto parse_flag;
1705a0ee8cc6SDag-Erling Smørgrav 
1706511b41d2SMark Murray 	case sStrictModes:
1707511b41d2SMark Murray 		intptr = &options->strict_modes;
1708511b41d2SMark Murray 		goto parse_flag;
1709511b41d2SMark Murray 
17101ec0d754SDag-Erling Smørgrav 	case sTCPKeepAlive:
17111ec0d754SDag-Erling Smørgrav 		intptr = &options->tcp_keep_alive;
1712511b41d2SMark Murray 		goto parse_flag;
1713511b41d2SMark Murray 
1714511b41d2SMark Murray 	case sEmptyPasswd:
1715511b41d2SMark Murray 		intptr = &options->permit_empty_passwd;
1716511b41d2SMark Murray 		goto parse_flag;
1717511b41d2SMark Murray 
1718f388f5efSDag-Erling Smørgrav 	case sPermitUserEnvironment:
1719f388f5efSDag-Erling Smørgrav 		intptr = &options->permit_user_env;
172019261079SEd Maste 		charptr = &options->permit_user_env_allowlist;
172119261079SEd Maste 		arg = argv_next(&ac, &av);
1722190cef3dSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
172319261079SEd Maste 			fatal("%s line %d: %s missing argument.",
172419261079SEd Maste 			    filename, linenum, keyword);
1725190cef3dSDag-Erling Smørgrav 		value = 0;
1726190cef3dSDag-Erling Smørgrav 		p = NULL;
1727190cef3dSDag-Erling Smørgrav 		if (strcmp(arg, "yes") == 0)
1728190cef3dSDag-Erling Smørgrav 			value = 1;
1729190cef3dSDag-Erling Smørgrav 		else if (strcmp(arg, "no") == 0)
1730190cef3dSDag-Erling Smørgrav 			value = 0;
1731190cef3dSDag-Erling Smørgrav 		else {
1732190cef3dSDag-Erling Smørgrav 			/* Pattern-list specified */
1733190cef3dSDag-Erling Smørgrav 			value = 1;
1734190cef3dSDag-Erling Smørgrav 			p = xstrdup(arg);
1735190cef3dSDag-Erling Smørgrav 		}
1736190cef3dSDag-Erling Smørgrav 		if (*activep && *intptr == -1) {
1737190cef3dSDag-Erling Smørgrav 			*intptr = value;
1738190cef3dSDag-Erling Smørgrav 			*charptr = p;
1739190cef3dSDag-Erling Smørgrav 			p = NULL;
1740190cef3dSDag-Erling Smørgrav 		}
1741190cef3dSDag-Erling Smørgrav 		free(p);
1742190cef3dSDag-Erling Smørgrav 		break;
1743f388f5efSDag-Erling Smørgrav 
174480628bacSDag-Erling Smørgrav 	case sCompression:
174580628bacSDag-Erling Smørgrav 		intptr = &options->compression;
1746e146993eSDag-Erling Smørgrav 		multistate_ptr = multistate_compression;
1747e146993eSDag-Erling Smørgrav 		goto parse_multistate;
174880628bacSDag-Erling Smørgrav 
1749e4a9863fSDag-Erling Smørgrav 	case sRekeyLimit:
175019261079SEd Maste 		arg = argv_next(&ac, &av);
1751e4a9863fSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
175219261079SEd Maste 			fatal("%s line %d: %s missing argument.",
175319261079SEd Maste 			    filename, linenum, keyword);
1754e4a9863fSDag-Erling Smørgrav 		if (strcmp(arg, "default") == 0) {
1755e4a9863fSDag-Erling Smørgrav 			val64 = 0;
1756e4a9863fSDag-Erling Smørgrav 		} else {
1757e4a9863fSDag-Erling Smørgrav 			if (scan_scaled(arg, &val64) == -1)
175819261079SEd Maste 				fatal("%.200s line %d: Bad %s number '%s': %s",
175919261079SEd Maste 				    filename, linenum, keyword,
176019261079SEd Maste 				    arg, strerror(errno));
1761e4a9863fSDag-Erling Smørgrav 			if (val64 != 0 && val64 < 16)
176219261079SEd Maste 				fatal("%.200s line %d: %s too small",
176319261079SEd Maste 				    filename, linenum, keyword);
1764e4a9863fSDag-Erling Smørgrav 		}
1765e4a9863fSDag-Erling Smørgrav 		if (*activep && options->rekey_limit == -1)
1766acc1a9efSDag-Erling Smørgrav 			options->rekey_limit = val64;
176719261079SEd Maste 		if (ac != 0) { /* optional rekey interval present */
176819261079SEd Maste 			if (strcmp(av[0], "none") == 0) {
176919261079SEd Maste 				(void)argv_next(&ac, &av);	/* discard */
1770e4a9863fSDag-Erling Smørgrav 				break;
1771e4a9863fSDag-Erling Smørgrav 			}
1772e4a9863fSDag-Erling Smørgrav 			intptr = &options->rekey_interval;
1773e4a9863fSDag-Erling Smørgrav 			goto parse_time;
1774e4a9863fSDag-Erling Smørgrav 		}
1775e4a9863fSDag-Erling Smørgrav 		break;
1776e4a9863fSDag-Erling Smørgrav 
1777e8aafc91SKris Kennaway 	case sGatewayPorts:
1778a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->fwd_opts.gateway_ports;
1779e146993eSDag-Erling Smørgrav 		multistate_ptr = multistate_gatewayports;
1780e146993eSDag-Erling Smørgrav 		goto parse_multistate;
1781e8aafc91SKris Kennaway 
1782cf2b5f3bSDag-Erling Smørgrav 	case sUseDNS:
1783cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->use_dns;
1784ca3176e7SBrian Feldman 		goto parse_flag;
1785ca3176e7SBrian Feldman 
1786511b41d2SMark Murray 	case sLogFacility:
1787d4af9e69SDag-Erling Smørgrav 		log_facility_ptr = &options->log_facility;
178819261079SEd Maste 		arg = argv_next(&ac, &av);
1789c2d3a559SKris Kennaway 		value = log_facility_number(arg);
1790af12a3e7SDag-Erling Smørgrav 		if (value == SYSLOG_FACILITY_NOT_SET)
1791ca3176e7SBrian Feldman 			fatal("%.200s line %d: unsupported log facility '%s'",
1792c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
1793d4af9e69SDag-Erling Smørgrav 		if (*log_facility_ptr == -1)
1794d4af9e69SDag-Erling Smørgrav 			*log_facility_ptr = (SyslogFacility) value;
1795511b41d2SMark Murray 		break;
1796511b41d2SMark Murray 
1797511b41d2SMark Murray 	case sLogLevel:
1798d4af9e69SDag-Erling Smørgrav 		log_level_ptr = &options->log_level;
179919261079SEd Maste 		arg = argv_next(&ac, &av);
1800c2d3a559SKris Kennaway 		value = log_level_number(arg);
1801af12a3e7SDag-Erling Smørgrav 		if (value == SYSLOG_LEVEL_NOT_SET)
1802ca3176e7SBrian Feldman 			fatal("%.200s line %d: unsupported log level '%s'",
1803c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
18044f52dfbbSDag-Erling Smørgrav 		if (*activep && *log_level_ptr == -1)
1805d4af9e69SDag-Erling Smørgrav 			*log_level_ptr = (LogLevel) value;
1806511b41d2SMark Murray 		break;
1807511b41d2SMark Murray 
180819261079SEd Maste 	case sLogVerbose:
180919261079SEd Maste 		found = options->num_log_verbose == 0;
181019261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
181119261079SEd Maste 			if (*arg == '\0') {
181219261079SEd Maste 				error("%s line %d: keyword %s empty argument",
181319261079SEd Maste 				    filename, linenum, keyword);
181419261079SEd Maste 				goto out;
181519261079SEd Maste 			}
181619261079SEd Maste 			/* Allow "none" only in first position */
181719261079SEd Maste 			if (strcasecmp(arg, "none") == 0) {
1818a91a2465SEd Maste 				if (nstrs > 0 || ac > 0) {
181919261079SEd Maste 					error("%s line %d: keyword %s \"none\" "
182019261079SEd Maste 					    "argument must appear alone.",
182119261079SEd Maste 					    filename, linenum, keyword);
182219261079SEd Maste 					goto out;
182319261079SEd Maste 				}
182419261079SEd Maste 			}
182519261079SEd Maste 			opt_array_append(filename, linenum, keyword,
1826a91a2465SEd Maste 			    &strs, &nstrs, arg);
1827a91a2465SEd Maste 		}
1828a91a2465SEd Maste 		if (nstrs == 0) {
1829a91a2465SEd Maste 			fatal("%s line %d: no %s specified",
1830a91a2465SEd Maste 			    filename, linenum, keyword);
1831a91a2465SEd Maste 		}
1832a91a2465SEd Maste 		if (found && *activep) {
1833a91a2465SEd Maste 			options->log_verbose = strs;
1834a91a2465SEd Maste 			options->num_log_verbose = nstrs;
1835a91a2465SEd Maste 			strs = NULL; /* transferred */
1836a91a2465SEd Maste 			nstrs = 0;
183719261079SEd Maste 		}
183819261079SEd Maste 		break;
183919261079SEd Maste 
184009958426SBrian Feldman 	case sAllowTcpForwarding:
184109958426SBrian Feldman 		intptr = &options->allow_tcp_forwarding;
18426888a9beSDag-Erling Smørgrav 		multistate_ptr = multistate_tcpfwd;
18436888a9beSDag-Erling Smørgrav 		goto parse_multistate;
184409958426SBrian Feldman 
1845a0ee8cc6SDag-Erling Smørgrav 	case sAllowStreamLocalForwarding:
1846a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->allow_streamlocal_forwarding;
1847a0ee8cc6SDag-Erling Smørgrav 		multistate_ptr = multistate_tcpfwd;
1848a0ee8cc6SDag-Erling Smørgrav 		goto parse_multistate;
1849a0ee8cc6SDag-Erling Smørgrav 
1850d4af9e69SDag-Erling Smørgrav 	case sAllowAgentForwarding:
1851d4af9e69SDag-Erling Smørgrav 		intptr = &options->allow_agent_forwarding;
1852d4af9e69SDag-Erling Smørgrav 		goto parse_flag;
1853d4af9e69SDag-Erling Smørgrav 
1854ca86bcf2SDag-Erling Smørgrav 	case sDisableForwarding:
1855ca86bcf2SDag-Erling Smørgrav 		intptr = &options->disable_forwarding;
1856ca86bcf2SDag-Erling Smørgrav 		goto parse_flag;
1857ca86bcf2SDag-Erling Smørgrav 
1858511b41d2SMark Murray 	case sAllowUsers:
185919261079SEd Maste 		chararrayptr = &options->allow_users;
186019261079SEd Maste 		uintptr = &options->num_allow_users;
186119261079SEd Maste  parse_allowdenyusers:
1862a91a2465SEd Maste 		/* XXX appends to list; doesn't respect first-match-wins */
186319261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
186419261079SEd Maste 			if (*arg == '\0' ||
186519261079SEd Maste 			    match_user(NULL, NULL, NULL, arg) == -1)
186619261079SEd Maste 				fatal("%s line %d: invalid %s pattern: \"%s\"",
186719261079SEd Maste 				    filename, linenum, keyword, arg);
1868a91a2465SEd Maste 			found = 1;
1869462c32cbSDag-Erling Smørgrav 			if (!*activep)
1870462c32cbSDag-Erling Smørgrav 				continue;
187119261079SEd Maste 			opt_array_append(filename, linenum, keyword,
187219261079SEd Maste 			    chararrayptr, uintptr, arg);
1873511b41d2SMark Murray 		}
1874a91a2465SEd Maste 		if (!found) {
1875a91a2465SEd Maste 			fatal("%s line %d: no %s specified",
1876a91a2465SEd Maste 			    filename, linenum, keyword);
1877a91a2465SEd Maste 		}
1878511b41d2SMark Murray 		break;
1879511b41d2SMark Murray 
1880511b41d2SMark Murray 	case sDenyUsers:
188119261079SEd Maste 		chararrayptr = &options->deny_users;
188219261079SEd Maste 		uintptr = &options->num_deny_users;
188319261079SEd Maste 		goto parse_allowdenyusers;
1884511b41d2SMark Murray 
1885511b41d2SMark Murray 	case sAllowGroups:
188619261079SEd Maste 		chararrayptr = &options->allow_groups;
188719261079SEd Maste 		uintptr = &options->num_allow_groups;
1888a91a2465SEd Maste 		/* XXX appends to list; doesn't respect first-match-wins */
188919261079SEd Maste  parse_allowdenygroups:
189019261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
189119261079SEd Maste 			if (*arg == '\0')
189219261079SEd Maste 				fatal("%s line %d: empty %s pattern",
189319261079SEd Maste 				    filename, linenum, keyword);
1894a91a2465SEd Maste 			found = 1;
1895462c32cbSDag-Erling Smørgrav 			if (!*activep)
1896462c32cbSDag-Erling Smørgrav 				continue;
189719261079SEd Maste 			opt_array_append(filename, linenum, keyword,
189819261079SEd Maste 			    chararrayptr, uintptr, arg);
1899511b41d2SMark Murray 		}
1900a91a2465SEd Maste 		if (!found) {
1901a91a2465SEd Maste 			fatal("%s line %d: no %s specified",
1902a91a2465SEd Maste 			    filename, linenum, keyword);
1903a91a2465SEd Maste 		}
1904511b41d2SMark Murray 		break;
1905511b41d2SMark Murray 
1906511b41d2SMark Murray 	case sDenyGroups:
190719261079SEd Maste 		chararrayptr = &options->deny_groups;
190819261079SEd Maste 		uintptr = &options->num_deny_groups;
190919261079SEd Maste 		goto parse_allowdenygroups;
1910511b41d2SMark Murray 
1911e8aafc91SKris Kennaway 	case sCiphers:
191219261079SEd Maste 		arg = argv_next(&ac, &av);
1913c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
191419261079SEd Maste 			fatal("%s line %d: %s missing argument.",
191519261079SEd Maste 			    filename, linenum, keyword);
191619261079SEd Maste 		if (*arg != '-' &&
191719261079SEd Maste 		    !ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg))
1918e8aafc91SKris Kennaway 			fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
1919c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
1920e8aafc91SKris Kennaway 		if (options->ciphers == NULL)
1921c2d3a559SKris Kennaway 			options->ciphers = xstrdup(arg);
1922e8aafc91SKris Kennaway 		break;
1923e8aafc91SKris Kennaway 
1924ca3176e7SBrian Feldman 	case sMacs:
192519261079SEd Maste 		arg = argv_next(&ac, &av);
1926ca3176e7SBrian Feldman 		if (!arg || *arg == '\0')
192719261079SEd Maste 			fatal("%s line %d: %s missing argument.",
192819261079SEd Maste 			    filename, linenum, keyword);
192919261079SEd Maste 		if (*arg != '-' &&
193019261079SEd Maste 		    !mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg))
1931ca3176e7SBrian Feldman 			fatal("%s line %d: Bad SSH2 mac spec '%s'.",
1932ca3176e7SBrian Feldman 			    filename, linenum, arg ? arg : "<NONE>");
1933ca3176e7SBrian Feldman 		if (options->macs == NULL)
1934ca3176e7SBrian Feldman 			options->macs = xstrdup(arg);
1935ca3176e7SBrian Feldman 		break;
1936ca3176e7SBrian Feldman 
19374a421b63SDag-Erling Smørgrav 	case sKexAlgorithms:
193819261079SEd Maste 		arg = argv_next(&ac, &av);
19394a421b63SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
194019261079SEd Maste 			fatal("%s line %d: %s missing argument.",
194119261079SEd Maste 			    filename, linenum, keyword);
1942d93a896eSDag-Erling Smørgrav 		if (*arg != '-' &&
194319261079SEd Maste 		    !kex_names_valid(*arg == '+' || *arg == '^' ?
194419261079SEd Maste 		    arg + 1 : arg))
19454a421b63SDag-Erling Smørgrav 			fatal("%s line %d: Bad SSH2 KexAlgorithms '%s'.",
19464a421b63SDag-Erling Smørgrav 			    filename, linenum, arg ? arg : "<NONE>");
19474a421b63SDag-Erling Smørgrav 		if (options->kex_algorithms == NULL)
19484a421b63SDag-Erling Smørgrav 			options->kex_algorithms = xstrdup(arg);
19494a421b63SDag-Erling Smørgrav 		break;
19504a421b63SDag-Erling Smørgrav 
1951c2d3a559SKris Kennaway 	case sSubsystem:
195219261079SEd Maste 		arg = argv_next(&ac, &av);
1953c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
195419261079SEd Maste 			fatal("%s line %d: %s missing argument.",
195519261079SEd Maste 			    filename, linenum, keyword);
1956333ee039SDag-Erling Smørgrav 		if (!*activep) {
1957edf85781SEd Maste 			argv_consume(&ac);
1958333ee039SDag-Erling Smørgrav 			break;
1959333ee039SDag-Erling Smørgrav 		}
1960edf85781SEd Maste 		found = 0;
1961edf85781SEd Maste 		for (i = 0; i < options->num_subsystems; i++) {
1962edf85781SEd Maste 			if (strcmp(arg, options->subsystem_name[i]) == 0) {
1963edf85781SEd Maste 				found = 1;
1964edf85781SEd Maste 				break;
1965edf85781SEd Maste 			}
1966edf85781SEd Maste 		}
1967edf85781SEd Maste 		if (found) {
1968edf85781SEd Maste 			debug("%s line %d: Subsystem '%s' already defined.",
1969edf85781SEd Maste 			    filename, linenum, arg);
1970edf85781SEd Maste 			argv_consume(&ac);
1971edf85781SEd Maste 			break;
1972edf85781SEd Maste 		}
1973edf85781SEd Maste 		options->subsystem_name = xrecallocarray(
1974edf85781SEd Maste 		    options->subsystem_name, options->num_subsystems,
1975edf85781SEd Maste 		    options->num_subsystems + 1,
1976edf85781SEd Maste 		    sizeof(*options->subsystem_name));
1977edf85781SEd Maste 		options->subsystem_command = xrecallocarray(
1978edf85781SEd Maste 		    options->subsystem_command, options->num_subsystems,
1979edf85781SEd Maste 		    options->num_subsystems + 1,
1980edf85781SEd Maste 		    sizeof(*options->subsystem_command));
1981edf85781SEd Maste 		options->subsystem_args = xrecallocarray(
1982edf85781SEd Maste 		    options->subsystem_args, options->num_subsystems,
1983edf85781SEd Maste 		    options->num_subsystems + 1,
1984edf85781SEd Maste 		    sizeof(*options->subsystem_args));
1985c2d3a559SKris Kennaway 		options->subsystem_name[options->num_subsystems] = xstrdup(arg);
198619261079SEd Maste 		arg = argv_next(&ac, &av);
1987edf85781SEd Maste 		if (!arg || *arg == '\0') {
1988c2d3a559SKris Kennaway 			fatal("%s line %d: Missing subsystem command.",
1989c2d3a559SKris Kennaway 			    filename, linenum);
1990333ee039SDag-Erling Smørgrav 		}
1991edf85781SEd Maste 		options->subsystem_command[options->num_subsystems] =
1992edf85781SEd Maste 		    xstrdup(arg);
1993edf85781SEd Maste 		/* Collect arguments (separate to executable) */
1994edf85781SEd Maste 		arg = argv_assemble(1, &arg); /* quote command correctly */
1995edf85781SEd Maste 		arg2 = argv_assemble(ac, av); /* rest of command */
1996edf85781SEd Maste 		xasprintf(&options->subsystem_args[options->num_subsystems],
1997a91a2465SEd Maste 		    "%s%s%s", arg, *arg2 == '\0' ? "" : " ", arg2);
1998edf85781SEd Maste 		free(arg2);
19993d9fd9fcSEd Maste 		free(arg);
2000edf85781SEd Maste 		argv_consume(&ac);
2001c2d3a559SKris Kennaway 		options->num_subsystems++;
2002c2d3a559SKris Kennaway 		break;
2003c2d3a559SKris Kennaway 
2004c2d3a559SKris Kennaway 	case sMaxStartups:
200519261079SEd Maste 		arg = argv_next(&ac, &av);
2006c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
200719261079SEd Maste 			fatal("%s line %d: %s missing argument.",
200819261079SEd Maste 			    filename, linenum, keyword);
2009af12a3e7SDag-Erling Smørgrav 		if ((n = sscanf(arg, "%d:%d:%d",
2010c2d3a559SKris Kennaway 		    &options->max_startups_begin,
2011c2d3a559SKris Kennaway 		    &options->max_startups_rate,
2012af12a3e7SDag-Erling Smørgrav 		    &options->max_startups)) == 3) {
2013c2d3a559SKris Kennaway 			if (options->max_startups_begin >
2014c2d3a559SKris Kennaway 			    options->max_startups ||
2015c2d3a559SKris Kennaway 			    options->max_startups_rate > 100 ||
2016c2d3a559SKris Kennaway 			    options->max_startups_rate < 1)
201719261079SEd Maste 				fatal("%s line %d: Invalid %s spec.",
201819261079SEd Maste 				    filename, linenum, keyword);
2019af12a3e7SDag-Erling Smørgrav 		} else if (n != 1)
202019261079SEd Maste 			fatal("%s line %d: Invalid %s spec.",
202119261079SEd Maste 			    filename, linenum, keyword);
2022af12a3e7SDag-Erling Smørgrav 		else
2023af12a3e7SDag-Erling Smørgrav 			options->max_startups = options->max_startups_begin;
2024f374ba41SEd Maste 		if (options->max_startups <= 0 ||
2025f374ba41SEd Maste 		    options->max_startups_begin <= 0)
2026f374ba41SEd Maste 			fatal("%s line %d: Invalid %s spec.",
2027f374ba41SEd Maste 			    filename, linenum, keyword);
2028933ca70fSBrian Feldman 		break;
2029933ca70fSBrian Feldman 
203019261079SEd Maste 	case sPerSourceNetBlockSize:
203119261079SEd Maste 		arg = argv_next(&ac, &av);
203219261079SEd Maste 		if (!arg || *arg == '\0')
203319261079SEd Maste 			fatal("%s line %d: %s missing argument.",
203419261079SEd Maste 			    filename, linenum, keyword);
203519261079SEd Maste 		switch (n = sscanf(arg, "%d:%d", &value, &value2)) {
203619261079SEd Maste 		case 2:
203719261079SEd Maste 			if (value2 < 0 || value2 > 128)
203819261079SEd Maste 				n = -1;
203919261079SEd Maste 			/* FALLTHROUGH */
204019261079SEd Maste 		case 1:
204119261079SEd Maste 			if (value < 0 || value > 32)
204219261079SEd Maste 				n = -1;
204319261079SEd Maste 		}
204419261079SEd Maste 		if (n != 1 && n != 2)
204519261079SEd Maste 			fatal("%s line %d: Invalid %s spec.",
204619261079SEd Maste 			    filename, linenum, keyword);
204719261079SEd Maste 		if (*activep) {
204819261079SEd Maste 			options->per_source_masklen_ipv4 = value;
204919261079SEd Maste 			options->per_source_masklen_ipv6 = value2;
205019261079SEd Maste 		}
205119261079SEd Maste 		break;
205219261079SEd Maste 
205319261079SEd Maste 	case sPerSourceMaxStartups:
205419261079SEd Maste 		arg = argv_next(&ac, &av);
205519261079SEd Maste 		if (!arg || *arg == '\0')
205619261079SEd Maste 			fatal("%s line %d: %s missing argument.",
205719261079SEd Maste 			    filename, linenum, keyword);
205819261079SEd Maste 		if (strcmp(arg, "none") == 0) { /* no limit */
205919261079SEd Maste 			value = INT_MAX;
206019261079SEd Maste 		} else {
206119261079SEd Maste 			if ((errstr = atoi_err(arg, &value)) != NULL)
206219261079SEd Maste 				fatal("%s line %d: %s integer value %s.",
206319261079SEd Maste 				    filename, linenum, keyword, errstr);
206419261079SEd Maste 		}
2065edf85781SEd Maste 		if (*activep && options->per_source_max_startups == -1)
206619261079SEd Maste 			options->per_source_max_startups = value;
206719261079SEd Maste 		break;
206819261079SEd Maste 
20690fdf8faeSEd Maste 	case sPerSourcePenaltyExemptList:
20700fdf8faeSEd Maste 		charptr = &options->per_source_penalty_exempt;
20710fdf8faeSEd Maste 		arg = argv_next(&ac, &av);
20720fdf8faeSEd Maste 		if (!arg || *arg == '\0')
20730fdf8faeSEd Maste 			fatal("%s line %d: missing argument.",
20740fdf8faeSEd Maste 			    filename, linenum);
20750fdf8faeSEd Maste 		if (addr_match_list(NULL, arg) != 0) {
20760fdf8faeSEd Maste 			fatal("%s line %d: keyword %s "
20770fdf8faeSEd Maste 			    "invalid address argument.",
20780fdf8faeSEd Maste 			    filename, linenum, keyword);
20790fdf8faeSEd Maste 		}
20800fdf8faeSEd Maste 		if (*activep && *charptr == NULL)
20810fdf8faeSEd Maste 			*charptr = xstrdup(arg);
20820fdf8faeSEd Maste 		break;
20830fdf8faeSEd Maste 
20840fdf8faeSEd Maste 	case sPerSourcePenalties:
20850fdf8faeSEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
20860fdf8faeSEd Maste 			found = 1;
20870fdf8faeSEd Maste 			value = -1;
20880fdf8faeSEd Maste 			value2 = 0;
20890fdf8faeSEd Maste 			p = NULL;
20900fdf8faeSEd Maste 			/* Allow no/yes only in first position */
20910fdf8faeSEd Maste 			if (strcasecmp(arg, "no") == 0 ||
20920fdf8faeSEd Maste 			    (value2 = (strcasecmp(arg, "yes") == 0))) {
20930fdf8faeSEd Maste 				if (ac > 0) {
20940fdf8faeSEd Maste 					fatal("%s line %d: keyword %s \"%s\" "
20950fdf8faeSEd Maste 					    "argument must appear alone.",
20960fdf8faeSEd Maste 					    filename, linenum, keyword, arg);
20970fdf8faeSEd Maste 				}
20980fdf8faeSEd Maste 				if (*activep &&
20990fdf8faeSEd Maste 				    options->per_source_penalty.enabled == -1)
21000fdf8faeSEd Maste 					options->per_source_penalty.enabled = value2;
21010fdf8faeSEd Maste 				continue;
21020fdf8faeSEd Maste 			} else if (strncmp(arg, "crash:", 6) == 0) {
21030fdf8faeSEd Maste 				p = arg + 6;
21040fdf8faeSEd Maste 				intptr = &options->per_source_penalty.penalty_crash;
21050fdf8faeSEd Maste 			} else if (strncmp(arg, "authfail:", 9) == 0) {
21060fdf8faeSEd Maste 				p = arg + 9;
21070fdf8faeSEd Maste 				intptr = &options->per_source_penalty.penalty_authfail;
21080fdf8faeSEd Maste 			} else if (strncmp(arg, "noauth:", 7) == 0) {
21090fdf8faeSEd Maste 				p = arg + 7;
21100fdf8faeSEd Maste 				intptr = &options->per_source_penalty.penalty_noauth;
21110fdf8faeSEd Maste 			} else if (strncmp(arg, "grace-exceeded:", 15) == 0) {
21120fdf8faeSEd Maste 				p = arg + 15;
21130fdf8faeSEd Maste 				intptr = &options->per_source_penalty.penalty_grace;
21143d9fd9fcSEd Maste 			} else if (strncmp(arg, "refuseconnection:", 17) == 0) {
21153d9fd9fcSEd Maste 				p = arg + 17;
21163d9fd9fcSEd Maste 				intptr = &options->per_source_penalty.penalty_refuseconnection;
21170fdf8faeSEd Maste 			} else if (strncmp(arg, "max:", 4) == 0) {
21180fdf8faeSEd Maste 				p = arg + 4;
21190fdf8faeSEd Maste 				intptr = &options->per_source_penalty.penalty_max;
21200fdf8faeSEd Maste 			} else if (strncmp(arg, "min:", 4) == 0) {
21210fdf8faeSEd Maste 				p = arg + 4;
21220fdf8faeSEd Maste 				intptr = &options->per_source_penalty.penalty_min;
21230fdf8faeSEd Maste 			} else if (strncmp(arg, "max-sources4:", 13) == 0) {
21240fdf8faeSEd Maste 				intptr = &options->per_source_penalty.max_sources4;
21250fdf8faeSEd Maste 				if ((errstr = atoi_err(arg+13, &value)) != NULL)
21260fdf8faeSEd Maste 					fatal("%s line %d: %s value %s.",
21270fdf8faeSEd Maste 					    filename, linenum, keyword, errstr);
21280fdf8faeSEd Maste 			} else if (strncmp(arg, "max-sources6:", 13) == 0) {
21290fdf8faeSEd Maste 				intptr = &options->per_source_penalty.max_sources6;
21300fdf8faeSEd Maste 				if ((errstr = atoi_err(arg+13, &value)) != NULL)
21310fdf8faeSEd Maste 					fatal("%s line %d: %s value %s.",
21320fdf8faeSEd Maste 					    filename, linenum, keyword, errstr);
21330fdf8faeSEd Maste 			} else if (strcmp(arg, "overflow:deny-all") == 0) {
21340fdf8faeSEd Maste 				intptr = &options->per_source_penalty.overflow_mode;
21350fdf8faeSEd Maste 				value = PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL;
21360fdf8faeSEd Maste 			} else if (strcmp(arg, "overflow:permissive") == 0) {
21370fdf8faeSEd Maste 				intptr = &options->per_source_penalty.overflow_mode;
21380fdf8faeSEd Maste 				value = PER_SOURCE_PENALTY_OVERFLOW_PERMISSIVE;
21390fdf8faeSEd Maste 			} else if (strcmp(arg, "overflow6:deny-all") == 0) {
21400fdf8faeSEd Maste 				intptr = &options->per_source_penalty.overflow_mode6;
21410fdf8faeSEd Maste 				value = PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL;
21420fdf8faeSEd Maste 			} else if (strcmp(arg, "overflow6:permissive") == 0) {
21430fdf8faeSEd Maste 				intptr = &options->per_source_penalty.overflow_mode6;
21440fdf8faeSEd Maste 				value = PER_SOURCE_PENALTY_OVERFLOW_PERMISSIVE;
21450fdf8faeSEd Maste 			} else {
21460fdf8faeSEd Maste 				fatal("%s line %d: unsupported %s keyword %s",
21470fdf8faeSEd Maste 				    filename, linenum, keyword, arg);
21480fdf8faeSEd Maste 			}
21490fdf8faeSEd Maste 			/* If no value was parsed above, assume it's a time */
21500fdf8faeSEd Maste 			if (value == -1 && (value = convtime(p)) == -1) {
21510fdf8faeSEd Maste 				fatal("%s line %d: invalid %s time value.",
21520fdf8faeSEd Maste 				    filename, linenum, keyword);
21530fdf8faeSEd Maste 			}
21540fdf8faeSEd Maste 			if (*activep && *intptr == -1) {
21550fdf8faeSEd Maste 				*intptr = value;
21560fdf8faeSEd Maste 				/* any option implicitly enables penalties */
21570fdf8faeSEd Maste 				options->per_source_penalty.enabled = 1;
21580fdf8faeSEd Maste 			}
21590fdf8faeSEd Maste 		}
21600fdf8faeSEd Maste 		if (!found) {
21610fdf8faeSEd Maste 			fatal("%s line %d: no %s specified",
21620fdf8faeSEd Maste 			    filename, linenum, keyword);
21630fdf8faeSEd Maste 		}
21640fdf8faeSEd Maste 		break;
21650fdf8faeSEd Maste 
216621e764dfSDag-Erling Smørgrav 	case sMaxAuthTries:
216721e764dfSDag-Erling Smørgrav 		intptr = &options->max_authtries;
216821e764dfSDag-Erling Smørgrav 		goto parse_int;
216921e764dfSDag-Erling Smørgrav 
2170d4af9e69SDag-Erling Smørgrav 	case sMaxSessions:
2171d4af9e69SDag-Erling Smørgrav 		intptr = &options->max_sessions;
2172d4af9e69SDag-Erling Smørgrav 		goto parse_int;
2173d4af9e69SDag-Erling Smørgrav 
2174ca3176e7SBrian Feldman 	case sBanner:
2175ca3176e7SBrian Feldman 		charptr = &options->banner;
2176ca3176e7SBrian Feldman 		goto parse_filename;
2177d4af9e69SDag-Erling Smørgrav 
2178af12a3e7SDag-Erling Smørgrav 	/*
2179af12a3e7SDag-Erling Smørgrav 	 * These options can contain %X options expanded at
2180af12a3e7SDag-Erling Smørgrav 	 * connect time, so that you can specify paths like:
2181af12a3e7SDag-Erling Smørgrav 	 *
2182af12a3e7SDag-Erling Smørgrav 	 * AuthorizedKeysFile	/etc/ssh_keys/%u
2183af12a3e7SDag-Erling Smørgrav 	 */
2184af12a3e7SDag-Erling Smørgrav 	case sAuthorizedKeysFile:
2185a91a2465SEd Maste 		found = options->num_authkeys_files == 0;
218619261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
218719261079SEd Maste 			if (*arg == '\0') {
218819261079SEd Maste 				error("%s line %d: keyword %s empty argument",
218919261079SEd Maste 				    filename, linenum, keyword);
219019261079SEd Maste 				goto out;
219119261079SEd Maste 			}
219219261079SEd Maste 			arg2 = tilde_expand_filename(arg, getuid());
219319261079SEd Maste 			opt_array_append(filename, linenum, keyword,
2194a91a2465SEd Maste 			    &strs, &nstrs, arg2);
219519261079SEd Maste 			free(arg2);
2196e146993eSDag-Erling Smørgrav 		}
2197a91a2465SEd Maste 		if (nstrs == 0) {
2198a91a2465SEd Maste 			fatal("%s line %d: no %s specified",
2199a91a2465SEd Maste 			    filename, linenum, keyword);
2200a91a2465SEd Maste 		}
2201a91a2465SEd Maste 		if (found && *activep) {
2202a91a2465SEd Maste 			options->authorized_keys_files = strs;
2203a91a2465SEd Maste 			options->num_authkeys_files = nstrs;
2204a91a2465SEd Maste 			strs = NULL; /* transferred */
2205a91a2465SEd Maste 			nstrs = 0;
2206a91a2465SEd Maste 		}
220719261079SEd Maste 		break;
2208e146993eSDag-Erling Smørgrav 
2209e2f6069cSDag-Erling Smørgrav 	case sAuthorizedPrincipalsFile:
2210e2f6069cSDag-Erling Smørgrav 		charptr = &options->authorized_principals_file;
221119261079SEd Maste 		arg = argv_next(&ac, &av);
22128ad9b54aSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
221319261079SEd Maste 			fatal("%s line %d: %s missing argument.",
221419261079SEd Maste 			    filename, linenum, keyword);
22158ad9b54aSDag-Erling Smørgrav 		if (*activep && *charptr == NULL) {
22168ad9b54aSDag-Erling Smørgrav 			*charptr = tilde_expand_filename(arg, getuid());
22178ad9b54aSDag-Erling Smørgrav 			/* increase optional counter */
22188ad9b54aSDag-Erling Smørgrav 			if (intptr != NULL)
22198ad9b54aSDag-Erling Smørgrav 				*intptr = *intptr + 1;
22208ad9b54aSDag-Erling Smørgrav 		}
22218ad9b54aSDag-Erling Smørgrav 		break;
2222af12a3e7SDag-Erling Smørgrav 
2223ca3176e7SBrian Feldman 	case sClientAliveInterval:
2224ca3176e7SBrian Feldman 		intptr = &options->client_alive_interval;
2225af12a3e7SDag-Erling Smørgrav 		goto parse_time;
2226af12a3e7SDag-Erling Smørgrav 
2227ca3176e7SBrian Feldman 	case sClientAliveCountMax:
2228ca3176e7SBrian Feldman 		intptr = &options->client_alive_count_max;
2229ca3176e7SBrian Feldman 		goto parse_int;
2230af12a3e7SDag-Erling Smørgrav 
223121e764dfSDag-Erling Smørgrav 	case sAcceptEnv:
2232a91a2465SEd Maste 		/* XXX appends to list; doesn't respect first-match-wins */
223319261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
223419261079SEd Maste 			if (*arg == '\0' || strchr(arg, '=') != NULL)
223521e764dfSDag-Erling Smørgrav 				fatal("%s line %d: Invalid environment name.",
223621e764dfSDag-Erling Smørgrav 				    filename, linenum);
2237a91a2465SEd Maste 			found = 1;
2238333ee039SDag-Erling Smørgrav 			if (!*activep)
2239462c32cbSDag-Erling Smørgrav 				continue;
224019261079SEd Maste 			opt_array_append(filename, linenum, keyword,
224147dd1d1bSDag-Erling Smørgrav 			    &options->accept_env, &options->num_accept_env,
224247dd1d1bSDag-Erling Smørgrav 			    arg);
224321e764dfSDag-Erling Smørgrav 		}
2244a91a2465SEd Maste 		if (!found) {
2245a91a2465SEd Maste 			fatal("%s line %d: no %s specified",
2246a91a2465SEd Maste 			    filename, linenum, keyword);
2247a91a2465SEd Maste 		}
224821e764dfSDag-Erling Smørgrav 		break;
224921e764dfSDag-Erling Smørgrav 
2250190cef3dSDag-Erling Smørgrav 	case sSetEnv:
2251a91a2465SEd Maste 		found = options->num_setenv == 0;
225219261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
225319261079SEd Maste 			if (*arg == '\0' || strchr(arg, '=') == NULL)
2254190cef3dSDag-Erling Smørgrav 				fatal("%s line %d: Invalid environment.",
2255190cef3dSDag-Erling Smørgrav 				    filename, linenum);
2256a91a2465SEd Maste 			if (lookup_setenv_in_list(arg, strs, nstrs) != NULL) {
225738a52bd3SEd Maste 				debug2("%s line %d: ignoring duplicate env "
225838a52bd3SEd Maste 				    "name \"%.64s\"", filename, linenum, arg);
225938a52bd3SEd Maste 				continue;
226038a52bd3SEd Maste 			}
226119261079SEd Maste 			opt_array_append(filename, linenum, keyword,
2262a91a2465SEd Maste 			    &strs, &nstrs, arg);
2263a91a2465SEd Maste 		}
2264a91a2465SEd Maste 		if (nstrs == 0) {
2265a91a2465SEd Maste 			fatal("%s line %d: no %s specified",
2266a91a2465SEd Maste 			    filename, linenum, keyword);
2267a91a2465SEd Maste 		}
2268a91a2465SEd Maste 		if (found && *activep) {
2269a91a2465SEd Maste 			options->setenv = strs;
2270a91a2465SEd Maste 			options->num_setenv = nstrs;
2271a91a2465SEd Maste 			strs = NULL; /* transferred */
2272a91a2465SEd Maste 			nstrs = 0;
2273190cef3dSDag-Erling Smørgrav 		}
2274190cef3dSDag-Erling Smørgrav 		break;
2275190cef3dSDag-Erling Smørgrav 
2276b74df5b2SDag-Erling Smørgrav 	case sPermitTunnel:
2277b74df5b2SDag-Erling Smørgrav 		intptr = &options->permit_tun;
227819261079SEd Maste 		arg = argv_next(&ac, &av);
2279b74df5b2SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
228019261079SEd Maste 			fatal("%s line %d: %s missing argument.",
228119261079SEd Maste 			    filename, linenum, keyword);
2282d4af9e69SDag-Erling Smørgrav 		value = -1;
2283d4af9e69SDag-Erling Smørgrav 		for (i = 0; tunmode_desc[i].val != -1; i++)
2284d4af9e69SDag-Erling Smørgrav 			if (strcmp(tunmode_desc[i].text, arg) == 0) {
2285d4af9e69SDag-Erling Smørgrav 				value = tunmode_desc[i].val;
2286d4af9e69SDag-Erling Smørgrav 				break;
2287d4af9e69SDag-Erling Smørgrav 			}
2288d4af9e69SDag-Erling Smørgrav 		if (value == -1)
228919261079SEd Maste 			fatal("%s line %d: bad %s argument %s",
229019261079SEd Maste 			    filename, linenum, keyword, arg);
2291557f75e5SDag-Erling Smørgrav 		if (*activep && *intptr == -1)
2292b74df5b2SDag-Erling Smørgrav 			*intptr = value;
2293b74df5b2SDag-Erling Smørgrav 		break;
2294b74df5b2SDag-Erling Smørgrav 
229519261079SEd Maste 	case sInclude:
229619261079SEd Maste 		if (cmdline) {
229719261079SEd Maste 			fatal("Include directive not supported as a "
229819261079SEd Maste 			    "command-line option");
229919261079SEd Maste 		}
230019261079SEd Maste 		value = 0;
230119261079SEd Maste 		while ((arg2 = argv_next(&ac, &av)) != NULL) {
230219261079SEd Maste 			if (*arg2 == '\0') {
230319261079SEd Maste 				error("%s line %d: keyword %s empty argument",
230419261079SEd Maste 				    filename, linenum, keyword);
230519261079SEd Maste 				goto out;
230619261079SEd Maste 			}
230719261079SEd Maste 			value++;
230819261079SEd Maste 			found = 0;
230919261079SEd Maste 			if (*arg2 != '/' && *arg2 != '~') {
231019261079SEd Maste 				xasprintf(&arg, "%s/%s", SSHDIR, arg2);
231119261079SEd Maste 			} else
231219261079SEd Maste 				arg = xstrdup(arg2);
231319261079SEd Maste 
231419261079SEd Maste 			/*
231519261079SEd Maste 			 * Don't let included files clobber the containing
231619261079SEd Maste 			 * file's Match state.
231719261079SEd Maste 			 */
231819261079SEd Maste 			oactive = *activep;
231919261079SEd Maste 
232019261079SEd Maste 			/* consult cache of include files */
232119261079SEd Maste 			TAILQ_FOREACH(item, includes, entry) {
232219261079SEd Maste 				if (strcmp(item->selector, arg) != 0)
232319261079SEd Maste 					continue;
232419261079SEd Maste 				if (item->filename != NULL) {
232519261079SEd Maste 					parse_server_config_depth(options,
232619261079SEd Maste 					    item->filename, item->contents,
232719261079SEd Maste 					    includes, connectinfo,
232819261079SEd Maste 					    (*inc_flags & SSHCFG_MATCH_ONLY
232919261079SEd Maste 					        ? SSHCFG_MATCH_ONLY : (oactive
233019261079SEd Maste 					            ? 0 : SSHCFG_NEVERMATCH)),
233119261079SEd Maste 					    activep, depth + 1);
233219261079SEd Maste 				}
233319261079SEd Maste 				found = 1;
233419261079SEd Maste 				*activep = oactive;
233519261079SEd Maste 			}
233619261079SEd Maste 			if (found != 0) {
233719261079SEd Maste 				free(arg);
233819261079SEd Maste 				continue;
233919261079SEd Maste 			}
234019261079SEd Maste 
234119261079SEd Maste 			/* requested glob was not in cache */
234219261079SEd Maste 			debug2("%s line %d: new include %s",
234319261079SEd Maste 			    filename, linenum, arg);
234419261079SEd Maste 			if ((r = glob(arg, 0, NULL, &gbuf)) != 0) {
234519261079SEd Maste 				if (r != GLOB_NOMATCH) {
234619261079SEd Maste 					fatal("%s line %d: include \"%s\" glob "
234719261079SEd Maste 					    "failed", filename, linenum, arg);
234819261079SEd Maste 				}
234919261079SEd Maste 				/*
235019261079SEd Maste 				 * If no entry matched then record a
235119261079SEd Maste 				 * placeholder to skip later glob calls.
235219261079SEd Maste 				 */
235319261079SEd Maste 				debug2("%s line %d: no match for %s",
235419261079SEd Maste 				    filename, linenum, arg);
235519261079SEd Maste 				item = xcalloc(1, sizeof(*item));
235619261079SEd Maste 				item->selector = strdup(arg);
235719261079SEd Maste 				TAILQ_INSERT_TAIL(includes,
235819261079SEd Maste 				    item, entry);
235919261079SEd Maste 			}
236019261079SEd Maste 			if (gbuf.gl_pathc > INT_MAX)
236119261079SEd Maste 				fatal_f("too many glob results");
236219261079SEd Maste 			for (n = 0; n < (int)gbuf.gl_pathc; n++) {
236319261079SEd Maste 				debug2("%s line %d: including %s",
236419261079SEd Maste 				    filename, linenum, gbuf.gl_pathv[n]);
236519261079SEd Maste 				item = xcalloc(1, sizeof(*item));
236619261079SEd Maste 				item->selector = strdup(arg);
236719261079SEd Maste 				item->filename = strdup(gbuf.gl_pathv[n]);
236819261079SEd Maste 				if ((item->contents = sshbuf_new()) == NULL)
236919261079SEd Maste 					fatal_f("sshbuf_new failed");
237019261079SEd Maste 				load_server_config(item->filename,
237119261079SEd Maste 				    item->contents);
237219261079SEd Maste 				parse_server_config_depth(options,
237319261079SEd Maste 				    item->filename, item->contents,
237419261079SEd Maste 				    includes, connectinfo,
237519261079SEd Maste 				    (*inc_flags & SSHCFG_MATCH_ONLY
237619261079SEd Maste 				        ? SSHCFG_MATCH_ONLY : (oactive
237719261079SEd Maste 				            ? 0 : SSHCFG_NEVERMATCH)),
237819261079SEd Maste 				    activep, depth + 1);
237919261079SEd Maste 				*activep = oactive;
238019261079SEd Maste 				TAILQ_INSERT_TAIL(includes, item, entry);
238119261079SEd Maste 			}
238219261079SEd Maste 			globfree(&gbuf);
238319261079SEd Maste 			free(arg);
238419261079SEd Maste 		}
238519261079SEd Maste 		if (value == 0) {
238619261079SEd Maste 			fatal("%s line %d: %s missing filename argument",
238719261079SEd Maste 			    filename, linenum, keyword);
238819261079SEd Maste 		}
238919261079SEd Maste 		break;
239019261079SEd Maste 
2391333ee039SDag-Erling Smørgrav 	case sMatch:
2392333ee039SDag-Erling Smørgrav 		if (cmdline)
2393333ee039SDag-Erling Smørgrav 			fatal("Match directive not supported as a command-line "
2394333ee039SDag-Erling Smørgrav 			    "option");
23953d9fd9fcSEd Maste 		value = match_cfg_line(str, &ac, &av, linenum,
239619261079SEd Maste 		    (*inc_flags & SSHCFG_NEVERMATCH ? NULL : connectinfo));
2397333ee039SDag-Erling Smørgrav 		if (value < 0)
2398333ee039SDag-Erling Smørgrav 			fatal("%s line %d: Bad Match condition", filename,
2399333ee039SDag-Erling Smørgrav 			    linenum);
240019261079SEd Maste 		*activep = (*inc_flags & SSHCFG_NEVERMATCH) ? 0 : value;
240119261079SEd Maste 		/*
240219261079SEd Maste 		 * The MATCH_ONLY flag is applicable only until the first
240319261079SEd Maste 		 * match block.
240419261079SEd Maste 		 */
240519261079SEd Maste 		*inc_flags &= ~SSHCFG_MATCH_ONLY;
2406333ee039SDag-Erling Smørgrav 		break;
2407333ee039SDag-Erling Smørgrav 
2408190cef3dSDag-Erling Smørgrav 	case sPermitListen:
2409333ee039SDag-Erling Smørgrav 	case sPermitOpen:
2410190cef3dSDag-Erling Smørgrav 		if (opcode == sPermitListen) {
2411190cef3dSDag-Erling Smørgrav 			uintptr = &options->num_permitted_listens;
2412190cef3dSDag-Erling Smørgrav 			chararrayptr = &options->permitted_listens;
2413190cef3dSDag-Erling Smørgrav 		} else {
2414190cef3dSDag-Erling Smørgrav 			uintptr = &options->num_permitted_opens;
2415190cef3dSDag-Erling Smørgrav 			chararrayptr = &options->permitted_opens;
2416190cef3dSDag-Erling Smørgrav 		}
2417a91a2465SEd Maste 		found = *uintptr == 0;
2418a91a2465SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
2419a91a2465SEd Maste 			if (strcmp(arg, "any") == 0 ||
2420a91a2465SEd Maste 			    strcmp(arg, "none") == 0) {
2421a91a2465SEd Maste 				if (nstrs != 0) {
2422a91a2465SEd Maste 					fatal("%s line %d: %s must appear "
2423a91a2465SEd Maste 					    "alone on a %s line.",
2424a91a2465SEd Maste 					    filename, linenum, arg, keyword);
2425462c32cbSDag-Erling Smørgrav 				}
2426a91a2465SEd Maste 				opt_array_append(filename, linenum, keyword,
2427a91a2465SEd Maste 				    &strs, &nstrs, arg);
2428a91a2465SEd Maste 				continue;
2429462c32cbSDag-Erling Smørgrav 			}
2430a91a2465SEd Maste 
2431190cef3dSDag-Erling Smørgrav 			if (opcode == sPermitListen &&
2432190cef3dSDag-Erling Smørgrav 			    strchr(arg, ':') == NULL) {
2433190cef3dSDag-Erling Smørgrav 				/*
2434190cef3dSDag-Erling Smørgrav 				 * Allow bare port number for PermitListen
2435190cef3dSDag-Erling Smørgrav 				 * to indicate a wildcard listen host.
2436190cef3dSDag-Erling Smørgrav 				 */
2437190cef3dSDag-Erling Smørgrav 				xasprintf(&arg2, "*:%s", arg);
2438190cef3dSDag-Erling Smørgrav 			} else {
24394f52dfbbSDag-Erling Smørgrav 				arg2 = xstrdup(arg);
24401323ec57SEd Maste 				p = hpdelim(&arg);
24411323ec57SEd Maste 				if (p == NULL) {
244219261079SEd Maste 					fatal("%s line %d: %s missing host",
244319261079SEd Maste 					    filename, linenum, keyword);
2444190cef3dSDag-Erling Smørgrav 				}
2445333ee039SDag-Erling Smørgrav 				p = cleanhostname(p);
2446190cef3dSDag-Erling Smørgrav 			}
2447190cef3dSDag-Erling Smørgrav 			if (arg == NULL ||
2448190cef3dSDag-Erling Smørgrav 			    ((port = permitopen_port(arg)) < 0)) {
244919261079SEd Maste 				fatal("%s line %d: %s bad port number",
245019261079SEd Maste 				    filename, linenum, keyword);
2451190cef3dSDag-Erling Smørgrav 			}
245219261079SEd Maste 			opt_array_append(filename, linenum, keyword,
2453a91a2465SEd Maste 			    &strs, &nstrs, arg2);
24544f52dfbbSDag-Erling Smørgrav 			free(arg2);
2455333ee039SDag-Erling Smørgrav 		}
2456a91a2465SEd Maste 		if (nstrs == 0) {
2457a91a2465SEd Maste 			fatal("%s line %d: %s missing argument.",
2458a91a2465SEd Maste 			    filename, linenum, keyword);
2459a91a2465SEd Maste 		}
2460a91a2465SEd Maste 		if (found && *activep) {
2461a91a2465SEd Maste 			*chararrayptr = strs;
2462a91a2465SEd Maste 			*uintptr = nstrs;
2463a91a2465SEd Maste 			strs = NULL; /* transferred */
2464a91a2465SEd Maste 			nstrs = 0;
2465a91a2465SEd Maste 		}
2466333ee039SDag-Erling Smørgrav 		break;
2467333ee039SDag-Erling Smørgrav 
2468333ee039SDag-Erling Smørgrav 	case sForceCommand:
246919261079SEd Maste 		if (str == NULL || *str == '\0')
247019261079SEd Maste 			fatal("%s line %d: %s missing argument.",
247119261079SEd Maste 			    filename, linenum, keyword);
247219261079SEd Maste 		len = strspn(str, WHITESPACE);
2473333ee039SDag-Erling Smørgrav 		if (*activep && options->adm_forced_command == NULL)
247419261079SEd Maste 			options->adm_forced_command = xstrdup(str + len);
247519261079SEd Maste 		argv_consume(&ac);
247619261079SEd Maste 		break;
2477333ee039SDag-Erling Smørgrav 
2478d4af9e69SDag-Erling Smørgrav 	case sChrootDirectory:
2479d4af9e69SDag-Erling Smørgrav 		charptr = &options->chroot_directory;
2480d4af9e69SDag-Erling Smørgrav 
248119261079SEd Maste 		arg = argv_next(&ac, &av);
2482d4af9e69SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
248319261079SEd Maste 			fatal("%s line %d: %s missing argument.",
248419261079SEd Maste 			    filename, linenum, keyword);
2485d4af9e69SDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
2486d4af9e69SDag-Erling Smørgrav 			*charptr = xstrdup(arg);
2487d4af9e69SDag-Erling Smørgrav 		break;
2488d4af9e69SDag-Erling Smørgrav 
2489b15c8340SDag-Erling Smørgrav 	case sTrustedUserCAKeys:
2490b15c8340SDag-Erling Smørgrav 		charptr = &options->trusted_user_ca_keys;
2491b15c8340SDag-Erling Smørgrav 		goto parse_filename;
2492b15c8340SDag-Erling Smørgrav 
2493b15c8340SDag-Erling Smørgrav 	case sRevokedKeys:
2494b15c8340SDag-Erling Smørgrav 		charptr = &options->revoked_keys_file;
2495b15c8340SDag-Erling Smørgrav 		goto parse_filename;
2496b15c8340SDag-Erling Smørgrav 
249719261079SEd Maste 	case sSecurityKeyProvider:
249819261079SEd Maste 		charptr = &options->sk_provider;
249919261079SEd Maste 		arg = argv_next(&ac, &av);
250019261079SEd Maste 		if (!arg || *arg == '\0')
250119261079SEd Maste 			fatal("%s line %d: %s missing argument.",
250219261079SEd Maste 			    filename, linenum, keyword);
250319261079SEd Maste 		if (*activep && *charptr == NULL) {
250419261079SEd Maste 			*charptr = strcasecmp(arg, "internal") == 0 ?
250519261079SEd Maste 			    xstrdup(arg) : derelativise_path(arg);
250619261079SEd Maste 			/* increase optional counter */
250719261079SEd Maste 			if (intptr != NULL)
250819261079SEd Maste 				*intptr = *intptr + 1;
250919261079SEd Maste 		}
251019261079SEd Maste 		break;
251119261079SEd Maste 
25124a421b63SDag-Erling Smørgrav 	case sIPQoS:
251319261079SEd Maste 		arg = argv_next(&ac, &av);
251419261079SEd Maste 		if (!arg || *arg == '\0')
251519261079SEd Maste 			fatal("%s line %d: %s missing argument.",
251619261079SEd Maste 			    filename, linenum, keyword);
25174a421b63SDag-Erling Smørgrav 		if ((value = parse_ipqos(arg)) == -1)
251819261079SEd Maste 			fatal("%s line %d: Bad %s value: %s",
251919261079SEd Maste 			    filename, linenum, keyword, arg);
252019261079SEd Maste 		arg = argv_next(&ac, &av);
25214a421b63SDag-Erling Smørgrav 		if (arg == NULL)
25224a421b63SDag-Erling Smørgrav 			value2 = value;
25234a421b63SDag-Erling Smørgrav 		else if ((value2 = parse_ipqos(arg)) == -1)
252419261079SEd Maste 			fatal("%s line %d: Bad %s value: %s",
252519261079SEd Maste 			    filename, linenum, keyword, arg);
25264a421b63SDag-Erling Smørgrav 		if (*activep) {
25274a421b63SDag-Erling Smørgrav 			options->ip_qos_interactive = value;
25284a421b63SDag-Erling Smørgrav 			options->ip_qos_bulk = value2;
25294a421b63SDag-Erling Smørgrav 		}
25304a421b63SDag-Erling Smørgrav 		break;
25314a421b63SDag-Erling Smørgrav 
2532db58a8e4SDag-Erling Smørgrav 	case sVersionAddendum:
253319261079SEd Maste 		if (str == NULL || *str == '\0')
253419261079SEd Maste 			fatal("%s line %d: %s missing argument.",
253519261079SEd Maste 			    filename, linenum, keyword);
253619261079SEd Maste 		len = strspn(str, WHITESPACE);
253719261079SEd Maste 		if (strchr(str + len, '\r') != NULL) {
253819261079SEd Maste 			fatal("%.200s line %d: Invalid %s argument",
253919261079SEd Maste 			    filename, linenum, keyword);
2540462c32cbSDag-Erling Smørgrav 		}
254119261079SEd Maste 		if ((arg = strchr(line, '#')) != NULL) {
254219261079SEd Maste 			*arg = '\0';
254319261079SEd Maste 			rtrim(line);
254419261079SEd Maste 		}
254519261079SEd Maste 		if (*activep && options->version_addendum == NULL) {
254619261079SEd Maste 			if (strcasecmp(str + len, "none") == 0)
254719261079SEd Maste 				options->version_addendum = xstrdup("");
254819261079SEd Maste 			else
254919261079SEd Maste 				options->version_addendum = xstrdup(str + len);
255019261079SEd Maste 		}
255119261079SEd Maste 		argv_consume(&ac);
255219261079SEd Maste 		break;
2553db58a8e4SDag-Erling Smørgrav 
25546888a9beSDag-Erling Smørgrav 	case sAuthorizedKeysCommand:
255519261079SEd Maste 		charptr = &options->authorized_keys_command;
255619261079SEd Maste  parse_command:
255719261079SEd Maste 		len = strspn(str, WHITESPACE);
255819261079SEd Maste 		if (str[len] != '/' && strcasecmp(str + len, "none") != 0) {
255919261079SEd Maste 			fatal("%.200s line %d: %s must be an absolute path",
256019261079SEd Maste 			    filename, linenum, keyword);
25616888a9beSDag-Erling Smørgrav 		}
2562535af610SEd Maste 		if (*activep && *charptr == NULL)
256319261079SEd Maste 			*charptr = xstrdup(str + len);
256419261079SEd Maste 		argv_consume(&ac);
256519261079SEd Maste 		break;
25666888a9beSDag-Erling Smørgrav 
25676888a9beSDag-Erling Smørgrav 	case sAuthorizedKeysCommandUser:
25686888a9beSDag-Erling Smørgrav 		charptr = &options->authorized_keys_command_user;
256919261079SEd Maste  parse_localuser:
257019261079SEd Maste 		arg = argv_next(&ac, &av);
257119261079SEd Maste 		if (!arg || *arg == '\0') {
257219261079SEd Maste 			fatal("%s line %d: missing %s argument.",
257319261079SEd Maste 			    filename, linenum, keyword);
257419261079SEd Maste 		}
25756888a9beSDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
25766888a9beSDag-Erling Smørgrav 			*charptr = xstrdup(arg);
25776888a9beSDag-Erling Smørgrav 		break;
25786888a9beSDag-Erling Smørgrav 
2579557f75e5SDag-Erling Smørgrav 	case sAuthorizedPrincipalsCommand:
258019261079SEd Maste 		charptr = &options->authorized_principals_command;
258119261079SEd Maste 		goto parse_command;
2582557f75e5SDag-Erling Smørgrav 
2583557f75e5SDag-Erling Smørgrav 	case sAuthorizedPrincipalsCommandUser:
2584557f75e5SDag-Erling Smørgrav 		charptr = &options->authorized_principals_command_user;
258519261079SEd Maste 		goto parse_localuser;
2586557f75e5SDag-Erling Smørgrav 
25876888a9beSDag-Erling Smørgrav 	case sAuthenticationMethods:
258819261079SEd Maste 		found = options->num_auth_methods == 0;
2589076ad2f8SDag-Erling Smørgrav 		value = 0; /* seen "any" pseudo-method */
259019261079SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
2591076ad2f8SDag-Erling Smørgrav 			if (strcmp(arg, "any") == 0) {
2592a91a2465SEd Maste 				if (nstrs > 0) {
259319261079SEd Maste 					fatal("%s line %d: \"any\" must "
259419261079SEd Maste 					    "appear alone in %s",
259519261079SEd Maste 					    filename, linenum, keyword);
2596076ad2f8SDag-Erling Smørgrav 				}
2597076ad2f8SDag-Erling Smørgrav 				value = 1;
2598076ad2f8SDag-Erling Smørgrav 			} else if (value) {
2599076ad2f8SDag-Erling Smørgrav 				fatal("%s line %d: \"any\" must appear "
260019261079SEd Maste 				    "alone in %s", filename, linenum, keyword);
2601076ad2f8SDag-Erling Smørgrav 			} else if (auth2_methods_valid(arg, 0) != 0) {
260219261079SEd Maste 				fatal("%s line %d: invalid %s method list.",
260319261079SEd Maste 				    filename, linenum, keyword);
2604076ad2f8SDag-Erling Smørgrav 			}
260519261079SEd Maste 			opt_array_append(filename, linenum, keyword,
2606a91a2465SEd Maste 			    &strs, &nstrs, arg);
26076888a9beSDag-Erling Smørgrav 		}
2608a91a2465SEd Maste 		if (nstrs == 0) {
260919261079SEd Maste 			fatal("%s line %d: no %s specified",
261019261079SEd Maste 			    filename, linenum, keyword);
2611076ad2f8SDag-Erling Smørgrav 		}
2612a91a2465SEd Maste 		if (found && *activep) {
2613a91a2465SEd Maste 			options->auth_methods = strs;
2614a91a2465SEd Maste 			options->num_auth_methods = nstrs;
2615a91a2465SEd Maste 			strs = NULL; /* transferred */
2616a91a2465SEd Maste 			nstrs = 0;
2617a91a2465SEd Maste 		}
261819261079SEd Maste 		break;
26196888a9beSDag-Erling Smørgrav 
2620a0ee8cc6SDag-Erling Smørgrav 	case sStreamLocalBindMask:
262119261079SEd Maste 		arg = argv_next(&ac, &av);
2622a0ee8cc6SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
262319261079SEd Maste 			fatal("%s line %d: %s missing argument.",
262419261079SEd Maste 			    filename, linenum, keyword);
2625a0ee8cc6SDag-Erling Smørgrav 		/* Parse mode in octal format */
2626a0ee8cc6SDag-Erling Smørgrav 		value = strtol(arg, &p, 8);
2627a0ee8cc6SDag-Erling Smørgrav 		if (arg == p || value < 0 || value > 0777)
262819261079SEd Maste 			fatal("%s line %d: Invalid %s.",
262919261079SEd Maste 			    filename, linenum, keyword);
2630557f75e5SDag-Erling Smørgrav 		if (*activep)
2631a0ee8cc6SDag-Erling Smørgrav 			options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
2632a0ee8cc6SDag-Erling Smørgrav 		break;
2633a0ee8cc6SDag-Erling Smørgrav 
2634a0ee8cc6SDag-Erling Smørgrav 	case sStreamLocalBindUnlink:
2635a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->fwd_opts.streamlocal_bind_unlink;
2636a0ee8cc6SDag-Erling Smørgrav 		goto parse_flag;
2637a0ee8cc6SDag-Erling Smørgrav 
2638bc5531deSDag-Erling Smørgrav 	case sFingerprintHash:
263919261079SEd Maste 		arg = argv_next(&ac, &av);
2640bc5531deSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
264119261079SEd Maste 			fatal("%s line %d: %s missing argument.",
264219261079SEd Maste 			    filename, linenum, keyword);
2643bc5531deSDag-Erling Smørgrav 		if ((value = ssh_digest_alg_by_name(arg)) == -1)
264419261079SEd Maste 			fatal("%.200s line %d: Invalid %s algorithm \"%s\".",
264519261079SEd Maste 			    filename, linenum, keyword, arg);
2646bc5531deSDag-Erling Smørgrav 		if (*activep)
2647bc5531deSDag-Erling Smørgrav 			options->fingerprint_hash = value;
2648bc5531deSDag-Erling Smørgrav 		break;
2649bc5531deSDag-Erling Smørgrav 
26504f52dfbbSDag-Erling Smørgrav 	case sExposeAuthInfo:
26514f52dfbbSDag-Erling Smørgrav 		intptr = &options->expose_userauth_info;
26524f52dfbbSDag-Erling Smørgrav 		goto parse_flag;
26534f52dfbbSDag-Erling Smørgrav 
265447dd1d1bSDag-Erling Smørgrav 	case sRDomain:
265519261079SEd Maste #if !defined(__OpenBSD__) && !defined(HAVE_SYS_SET_PROCESS_RDOMAIN)
265619261079SEd Maste 		fatal("%s line %d: setting RDomain not supported on this "
265719261079SEd Maste 		    "platform.", filename, linenum);
265819261079SEd Maste #endif
265947dd1d1bSDag-Erling Smørgrav 		charptr = &options->routing_domain;
266019261079SEd Maste 		arg = argv_next(&ac, &av);
266147dd1d1bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
266219261079SEd Maste 			fatal("%s line %d: %s missing argument.",
266319261079SEd Maste 			    filename, linenum, keyword);
266447dd1d1bSDag-Erling Smørgrav 		if (strcasecmp(arg, "none") != 0 && strcmp(arg, "%D") != 0 &&
266547dd1d1bSDag-Erling Smørgrav 		    !valid_rdomain(arg))
266619261079SEd Maste 			fatal("%s line %d: invalid routing domain",
266747dd1d1bSDag-Erling Smørgrav 			    filename, linenum);
266847dd1d1bSDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
266947dd1d1bSDag-Erling Smørgrav 			*charptr = xstrdup(arg);
267047dd1d1bSDag-Erling Smørgrav 		break;
267147dd1d1bSDag-Erling Smørgrav 
267238a52bd3SEd Maste 	case sRequiredRSASize:
267338a52bd3SEd Maste 		intptr = &options->required_rsa_size;
267438a52bd3SEd Maste 		goto parse_int;
267538a52bd3SEd Maste 
2676f374ba41SEd Maste 	case sChannelTimeout:
2677a91a2465SEd Maste 		found = options->num_channel_timeouts == 0;
2678f374ba41SEd Maste 		while ((arg = argv_next(&ac, &av)) != NULL) {
2679f374ba41SEd Maste 			/* Allow "none" only in first position */
2680f374ba41SEd Maste 			if (strcasecmp(arg, "none") == 0) {
2681a91a2465SEd Maste 				if (nstrs > 0 || ac > 0) {
2682f374ba41SEd Maste 					error("%s line %d: keyword %s \"none\" "
2683f374ba41SEd Maste 					    "argument must appear alone.",
2684f374ba41SEd Maste 					    filename, linenum, keyword);
2685f374ba41SEd Maste 					goto out;
2686f374ba41SEd Maste 				}
2687069ac184SEd Maste 			} else if (parse_pattern_interval(arg,
2688069ac184SEd Maste 			    NULL, NULL) != 0) {
2689f374ba41SEd Maste 				fatal("%s line %d: invalid channel timeout %s",
2690f374ba41SEd Maste 				    filename, linenum, arg);
2691f374ba41SEd Maste 			}
2692f374ba41SEd Maste 			opt_array_append(filename, linenum, keyword,
2693a91a2465SEd Maste 			    &strs, &nstrs, arg);
2694a91a2465SEd Maste 		}
2695a91a2465SEd Maste 		if (nstrs == 0) {
2696a91a2465SEd Maste 			fatal("%s line %d: no %s specified",
2697a91a2465SEd Maste 			    filename, linenum, keyword);
2698a91a2465SEd Maste 		}
2699a91a2465SEd Maste 		if (found && *activep) {
2700a91a2465SEd Maste 			options->channel_timeouts = strs;
2701a91a2465SEd Maste 			options->num_channel_timeouts = nstrs;
2702a91a2465SEd Maste 			strs = NULL; /* transferred */
2703a91a2465SEd Maste 			nstrs = 0;
2704f374ba41SEd Maste 		}
2705f374ba41SEd Maste 		break;
2706f374ba41SEd Maste 
2707f374ba41SEd Maste 	case sUnusedConnectionTimeout:
2708f374ba41SEd Maste 		intptr = &options->unused_connection_timeout;
2709f374ba41SEd Maste 		/* peek at first arg for "none" so we can reuse parse_time */
2710f374ba41SEd Maste 		if (av[0] != NULL && strcasecmp(av[0], "none") == 0) {
2711f374ba41SEd Maste 			(void)argv_next(&ac, &av); /* consume arg */
2712f374ba41SEd Maste 			if (*activep)
2713f374ba41SEd Maste 				*intptr = 0;
2714f374ba41SEd Maste 			break;
2715f374ba41SEd Maste 		}
2716f374ba41SEd Maste 		goto parse_time;
2717f374ba41SEd Maste 
27180fdf8faeSEd Maste 	case sSshdSessionPath:
27190fdf8faeSEd Maste 		charptr = &options->sshd_session_path;
27200fdf8faeSEd Maste 		goto parse_filename;
27210fdf8faeSEd Maste 
27223d9fd9fcSEd Maste 	case sRefuseConnection:
27233d9fd9fcSEd Maste 		intptr = &options->refuse_connection;
27243d9fd9fcSEd Maste 		multistate_ptr = multistate_flag;
27253d9fd9fcSEd Maste 		goto parse_multistate;
27263d9fd9fcSEd Maste 
2727b2af61ecSKurt Lidl 	case sUseBlacklist:
2728b2af61ecSKurt Lidl 		intptr = &options->use_blacklist;
2729b2af61ecSKurt Lidl 		goto parse_flag;
2730b2af61ecSKurt Lidl 
2731af12a3e7SDag-Erling Smørgrav 	case sDeprecated:
2732ca86bcf2SDag-Erling Smørgrav 	case sIgnore:
2733cf2b5f3bSDag-Erling Smørgrav 	case sUnsupported:
2734ca86bcf2SDag-Erling Smørgrav 		do_log2(opcode == sIgnore ?
2735ca86bcf2SDag-Erling Smørgrav 		    SYSLOG_LEVEL_DEBUG2 : SYSLOG_LEVEL_INFO,
2736ca86bcf2SDag-Erling Smørgrav 		    "%s line %d: %s option %s", filename, linenum,
273719261079SEd Maste 		    opcode == sUnsupported ? "Unsupported" : "Deprecated",
273819261079SEd Maste 		    keyword);
273919261079SEd Maste 		argv_consume(&ac);
2740af12a3e7SDag-Erling Smørgrav 		break;
2741af12a3e7SDag-Erling Smørgrav 
274242f71286SMark Murray 	default:
2743af12a3e7SDag-Erling Smørgrav 		fatal("%s line %d: Missing handler for opcode %s (%d)",
274419261079SEd Maste 		    filename, linenum, keyword, opcode);
2745511b41d2SMark Murray 	}
274619261079SEd Maste 	/* Check that there is no garbage at end of line. */
274719261079SEd Maste 	if (ac > 0) {
274819261079SEd Maste 		error("%.200s line %d: keyword %s extra arguments "
274919261079SEd Maste 		    "at end of line", filename, linenum, keyword);
275019261079SEd Maste 		goto out;
2751af12a3e7SDag-Erling Smørgrav 	}
2752af12a3e7SDag-Erling Smørgrav 
275319261079SEd Maste 	/* success */
275419261079SEd Maste 	ret = 0;
275519261079SEd Maste  out:
2756a91a2465SEd Maste 	opt_array_free2(strs, NULL, nstrs);
275719261079SEd Maste 	argv_free(oav, oac);
275819261079SEd Maste 	return ret;
275919261079SEd Maste }
276019261079SEd Maste 
276119261079SEd Maste int
process_server_config_line(ServerOptions * options,char * line,const char * filename,int linenum,int * activep,struct connection_info * connectinfo,struct include_list * includes)276219261079SEd Maste process_server_config_line(ServerOptions *options, char *line,
276319261079SEd Maste     const char *filename, int linenum, int *activep,
276419261079SEd Maste     struct connection_info *connectinfo, struct include_list *includes)
276519261079SEd Maste {
276619261079SEd Maste 	int inc_flags = 0;
276719261079SEd Maste 
276819261079SEd Maste 	return process_server_config_line_depth(options, line, filename,
276919261079SEd Maste 	    linenum, activep, connectinfo, &inc_flags, 0, includes);
277019261079SEd Maste }
277119261079SEd Maste 
277219261079SEd Maste 
2773af12a3e7SDag-Erling Smørgrav /* Reads the server configuration file. */
2774af12a3e7SDag-Erling Smørgrav 
2775af12a3e7SDag-Erling Smørgrav void
load_server_config(const char * filename,struct sshbuf * conf)2776190cef3dSDag-Erling Smørgrav load_server_config(const char *filename, struct sshbuf *conf)
2777af12a3e7SDag-Erling Smørgrav {
277819261079SEd Maste 	struct stat st;
2779190cef3dSDag-Erling Smørgrav 	char *line = NULL, *cp;
2780190cef3dSDag-Erling Smørgrav 	size_t linesize = 0;
2781a82e551fSDag-Erling Smørgrav 	FILE *f;
2782f374ba41SEd Maste 	int r;
2783af12a3e7SDag-Erling Smørgrav 
278419261079SEd Maste 	debug2_f("filename %s", filename);
278521e764dfSDag-Erling Smørgrav 	if ((f = fopen(filename, "r")) == NULL) {
2786af12a3e7SDag-Erling Smørgrav 		perror(filename);
2787af12a3e7SDag-Erling Smørgrav 		exit(1);
2788af12a3e7SDag-Erling Smørgrav 	}
2789190cef3dSDag-Erling Smørgrav 	sshbuf_reset(conf);
279019261079SEd Maste 	/* grow buffer, so realloc is avoided for large config files */
279119261079SEd Maste 	if (fstat(fileno(f), &st) == 0 && st.st_size > 0 &&
279219261079SEd Maste 	    (r = sshbuf_allocate(conf, st.st_size)) != 0)
279319261079SEd Maste 		fatal_fr(r, "allocate");
2794190cef3dSDag-Erling Smørgrav 	while (getline(&line, &linesize, f) != -1) {
279521e764dfSDag-Erling Smørgrav 		/*
279619261079SEd Maste 		 * Strip whitespace
279721e764dfSDag-Erling Smørgrav 		 * NB - preserve newlines, they are needed to reproduce
279821e764dfSDag-Erling Smørgrav 		 * line numbers later for error messages
279921e764dfSDag-Erling Smørgrav 		 */
280021e764dfSDag-Erling Smørgrav 		cp = line + strspn(line, " \t\r");
2801190cef3dSDag-Erling Smørgrav 		if ((r = sshbuf_put(conf, cp, strlen(cp))) != 0)
280219261079SEd Maste 			fatal_fr(r, "sshbuf_put");
280321e764dfSDag-Erling Smørgrav 	}
2804190cef3dSDag-Erling Smørgrav 	free(line);
2805190cef3dSDag-Erling Smørgrav 	if ((r = sshbuf_put_u8(conf, 0)) != 0)
280619261079SEd Maste 		fatal_fr(r, "sshbuf_put_u8");
280721e764dfSDag-Erling Smørgrav 	fclose(f);
280819261079SEd Maste 	debug2_f("done config len = %zu", sshbuf_len(conf));
280921e764dfSDag-Erling Smørgrav }
281021e764dfSDag-Erling Smørgrav 
281121e764dfSDag-Erling Smørgrav void
parse_server_match_config(ServerOptions * options,struct include_list * includes,struct connection_info * connectinfo)2812462c32cbSDag-Erling Smørgrav parse_server_match_config(ServerOptions *options,
281319261079SEd Maste    struct include_list *includes, struct connection_info *connectinfo)
281421e764dfSDag-Erling Smørgrav {
2815333ee039SDag-Erling Smørgrav 	ServerOptions mo;
2816333ee039SDag-Erling Smørgrav 
2817333ee039SDag-Erling Smørgrav 	initialize_server_options(&mo);
281819261079SEd Maste 	parse_server_config(&mo, "reprocess config", cfg, includes,
281987c1498dSEd Maste 	    connectinfo, 0);
2820d4af9e69SDag-Erling Smørgrav 	copy_set_server_options(options, &mo, 0);
2821333ee039SDag-Erling Smørgrav }
2822333ee039SDag-Erling Smørgrav 
parse_server_match_testspec(struct connection_info * ci,char * spec)2823462c32cbSDag-Erling Smørgrav int parse_server_match_testspec(struct connection_info *ci, char *spec)
2824462c32cbSDag-Erling Smørgrav {
2825462c32cbSDag-Erling Smørgrav 	char *p;
2826462c32cbSDag-Erling Smørgrav 
2827462c32cbSDag-Erling Smørgrav 	while ((p = strsep(&spec, ",")) && *p != '\0') {
2828462c32cbSDag-Erling Smørgrav 		if (strncmp(p, "addr=", 5) == 0) {
2829462c32cbSDag-Erling Smørgrav 			ci->address = xstrdup(p + 5);
2830462c32cbSDag-Erling Smørgrav 		} else if (strncmp(p, "host=", 5) == 0) {
2831462c32cbSDag-Erling Smørgrav 			ci->host = xstrdup(p + 5);
2832462c32cbSDag-Erling Smørgrav 		} else if (strncmp(p, "user=", 5) == 0) {
2833462c32cbSDag-Erling Smørgrav 			ci->user = xstrdup(p + 5);
2834462c32cbSDag-Erling Smørgrav 		} else if (strncmp(p, "laddr=", 6) == 0) {
2835462c32cbSDag-Erling Smørgrav 			ci->laddress = xstrdup(p + 6);
283647dd1d1bSDag-Erling Smørgrav 		} else if (strncmp(p, "rdomain=", 8) == 0) {
283747dd1d1bSDag-Erling Smørgrav 			ci->rdomain = xstrdup(p + 8);
2838462c32cbSDag-Erling Smørgrav 		} else if (strncmp(p, "lport=", 6) == 0) {
2839462c32cbSDag-Erling Smørgrav 			ci->lport = a2port(p + 6);
2840462c32cbSDag-Erling Smørgrav 			if (ci->lport == -1) {
2841462c32cbSDag-Erling Smørgrav 				fprintf(stderr, "Invalid port '%s' in test mode"
2842462c32cbSDag-Erling Smørgrav 				    " specification %s\n", p+6, p);
2843462c32cbSDag-Erling Smørgrav 				return -1;
2844462c32cbSDag-Erling Smørgrav 			}
28453d9fd9fcSEd Maste 		} else if (strcmp(p, "invalid-user") == 0) {
28463d9fd9fcSEd Maste 			ci->user_invalid = 1;
2847462c32cbSDag-Erling Smørgrav 		} else {
2848462c32cbSDag-Erling Smørgrav 			fprintf(stderr, "Invalid test mode specification %s\n",
2849462c32cbSDag-Erling Smørgrav 			    p);
2850462c32cbSDag-Erling Smørgrav 			return -1;
2851462c32cbSDag-Erling Smørgrav 		}
2852462c32cbSDag-Erling Smørgrav 	}
2853462c32cbSDag-Erling Smørgrav 	return 0;
2854462c32cbSDag-Erling Smørgrav }
2855462c32cbSDag-Erling Smørgrav 
2856edf85781SEd Maste void
servconf_merge_subsystems(ServerOptions * dst,ServerOptions * src)2857edf85781SEd Maste servconf_merge_subsystems(ServerOptions *dst, ServerOptions *src)
2858edf85781SEd Maste {
2859edf85781SEd Maste 	u_int i, j, found;
2860edf85781SEd Maste 
2861edf85781SEd Maste 	for (i = 0; i < src->num_subsystems; i++) {
2862edf85781SEd Maste 		found = 0;
2863edf85781SEd Maste 		for (j = 0; j < dst->num_subsystems; j++) {
2864edf85781SEd Maste 			if (strcmp(src->subsystem_name[i],
2865edf85781SEd Maste 			    dst->subsystem_name[j]) == 0) {
2866edf85781SEd Maste 				found = 1;
2867edf85781SEd Maste 				break;
2868edf85781SEd Maste 			}
2869edf85781SEd Maste 		}
2870edf85781SEd Maste 		if (found) {
2871edf85781SEd Maste 			debug_f("override \"%s\"", dst->subsystem_name[j]);
2872edf85781SEd Maste 			free(dst->subsystem_command[j]);
2873edf85781SEd Maste 			free(dst->subsystem_args[j]);
2874edf85781SEd Maste 			dst->subsystem_command[j] =
2875edf85781SEd Maste 			    xstrdup(src->subsystem_command[i]);
2876edf85781SEd Maste 			dst->subsystem_args[j] =
2877edf85781SEd Maste 			    xstrdup(src->subsystem_args[i]);
2878edf85781SEd Maste 			continue;
2879edf85781SEd Maste 		}
2880edf85781SEd Maste 		debug_f("add \"%s\"", src->subsystem_name[i]);
2881edf85781SEd Maste 		dst->subsystem_name = xrecallocarray(
2882edf85781SEd Maste 		    dst->subsystem_name, dst->num_subsystems,
2883edf85781SEd Maste 		    dst->num_subsystems + 1, sizeof(*dst->subsystem_name));
2884edf85781SEd Maste 		dst->subsystem_command = xrecallocarray(
2885edf85781SEd Maste 		    dst->subsystem_command, dst->num_subsystems,
2886edf85781SEd Maste 		    dst->num_subsystems + 1, sizeof(*dst->subsystem_command));
2887edf85781SEd Maste 		dst->subsystem_args = xrecallocarray(
2888edf85781SEd Maste 		    dst->subsystem_args, dst->num_subsystems,
2889edf85781SEd Maste 		    dst->num_subsystems + 1, sizeof(*dst->subsystem_args));
2890edf85781SEd Maste 		j = dst->num_subsystems++;
2891edf85781SEd Maste 		dst->subsystem_name[j] = xstrdup(src->subsystem_name[i]);
2892edf85781SEd Maste 		dst->subsystem_command[j] = xstrdup(src->subsystem_command[i]);
2893edf85781SEd Maste 		dst->subsystem_args[j] = xstrdup(src->subsystem_args[i]);
2894edf85781SEd Maste 	}
2895edf85781SEd Maste }
2896edf85781SEd Maste 
2897462c32cbSDag-Erling Smørgrav /*
2898d4af9e69SDag-Erling Smørgrav  * Copy any supported values that are set.
2899d4af9e69SDag-Erling Smørgrav  *
29007aee6ffeSDag-Erling Smørgrav  * If the preauth flag is set, we do not bother copying the string or
2901d4af9e69SDag-Erling Smørgrav  * array values that are not used pre-authentication, because any that we
2902190cef3dSDag-Erling Smørgrav  * do use must be explicitly sent in mm_getpwnamallow().
2903d4af9e69SDag-Erling Smørgrav  */
2904333ee039SDag-Erling Smørgrav void
copy_set_server_options(ServerOptions * dst,ServerOptions * src,int preauth)2905d4af9e69SDag-Erling Smørgrav copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
2906333ee039SDag-Erling Smørgrav {
2907f7167e0eSDag-Erling Smørgrav #define M_CP_INTOPT(n) do {\
2908f7167e0eSDag-Erling Smørgrav 	if (src->n != -1) \
2909f7167e0eSDag-Erling Smørgrav 		dst->n = src->n; \
2910f7167e0eSDag-Erling Smørgrav } while (0)
2911f7167e0eSDag-Erling Smørgrav 
2912d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(password_authentication);
2913d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(gss_authentication);
2914d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(pubkey_authentication);
291519261079SEd Maste 	M_CP_INTOPT(pubkey_auth_options);
2916d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(kerberos_authentication);
2917d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(hostbased_authentication);
2918e2f6069cSDag-Erling Smørgrav 	M_CP_INTOPT(hostbased_uses_name_from_packet_only);
2919d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(kbd_interactive_authentication);
2920d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(permit_root_login);
2921cce7d346SDag-Erling Smørgrav 	M_CP_INTOPT(permit_empty_passwd);
292219261079SEd Maste 	M_CP_INTOPT(ignore_rhosts);
2923d4af9e69SDag-Erling Smørgrav 
2924d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(allow_tcp_forwarding);
2925a0ee8cc6SDag-Erling Smørgrav 	M_CP_INTOPT(allow_streamlocal_forwarding);
2926d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(allow_agent_forwarding);
2927ca86bcf2SDag-Erling Smørgrav 	M_CP_INTOPT(disable_forwarding);
29284f52dfbbSDag-Erling Smørgrav 	M_CP_INTOPT(expose_userauth_info);
2929e2f6069cSDag-Erling Smørgrav 	M_CP_INTOPT(permit_tun);
2930a0ee8cc6SDag-Erling Smørgrav 	M_CP_INTOPT(fwd_opts.gateway_ports);
2931076ad2f8SDag-Erling Smørgrav 	M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink);
2932d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(x11_display_offset);
2933d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(x11_forwarding);
2934d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(x11_use_localhost);
2935f7167e0eSDag-Erling Smørgrav 	M_CP_INTOPT(permit_tty);
2936a0ee8cc6SDag-Erling Smørgrav 	M_CP_INTOPT(permit_user_rc);
2937d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(max_sessions);
2938d4af9e69SDag-Erling Smørgrav 	M_CP_INTOPT(max_authtries);
2939ca86bcf2SDag-Erling Smørgrav 	M_CP_INTOPT(client_alive_count_max);
2940ca86bcf2SDag-Erling Smørgrav 	M_CP_INTOPT(client_alive_interval);
29414a421b63SDag-Erling Smørgrav 	M_CP_INTOPT(ip_qos_interactive);
29424a421b63SDag-Erling Smørgrav 	M_CP_INTOPT(ip_qos_bulk);
2943e4a9863fSDag-Erling Smørgrav 	M_CP_INTOPT(rekey_limit);
2944e4a9863fSDag-Erling Smørgrav 	M_CP_INTOPT(rekey_interval);
29454f52dfbbSDag-Erling Smørgrav 	M_CP_INTOPT(log_level);
294638a52bd3SEd Maste 	M_CP_INTOPT(required_rsa_size);
2947f374ba41SEd Maste 	M_CP_INTOPT(unused_connection_timeout);
29483d9fd9fcSEd Maste 	M_CP_INTOPT(refuse_connection);
2949d4af9e69SDag-Erling Smørgrav 
2950076ad2f8SDag-Erling Smørgrav 	/*
2951076ad2f8SDag-Erling Smørgrav 	 * The bind_mask is a mode_t that may be unsigned, so we can't use
2952076ad2f8SDag-Erling Smørgrav 	 * M_CP_INTOPT - it does a signed comparison that causes compiler
2953076ad2f8SDag-Erling Smørgrav 	 * warnings.
2954076ad2f8SDag-Erling Smørgrav 	 */
2955076ad2f8SDag-Erling Smørgrav 	if (src->fwd_opts.streamlocal_bind_mask != (mode_t)-1) {
2956076ad2f8SDag-Erling Smørgrav 		dst->fwd_opts.streamlocal_bind_mask =
2957076ad2f8SDag-Erling Smørgrav 		    src->fwd_opts.streamlocal_bind_mask;
2958076ad2f8SDag-Erling Smørgrav 	}
2959076ad2f8SDag-Erling Smørgrav 
2960f7167e0eSDag-Erling Smørgrav 	/* M_CP_STROPT and M_CP_STRARRAYOPT should not appear before here */
2961f7167e0eSDag-Erling Smørgrav #define M_CP_STROPT(n) do {\
2962f7167e0eSDag-Erling Smørgrav 	if (src->n != NULL && dst->n != src->n) { \
2963f7167e0eSDag-Erling Smørgrav 		free(dst->n); \
2964f7167e0eSDag-Erling Smørgrav 		dst->n = src->n; \
2965f7167e0eSDag-Erling Smørgrav 	} \
2966f7167e0eSDag-Erling Smørgrav } while(0)
296747dd1d1bSDag-Erling Smørgrav #define M_CP_STRARRAYOPT(s, num_s) do {\
296847dd1d1bSDag-Erling Smørgrav 	u_int i; \
296947dd1d1bSDag-Erling Smørgrav 	if (src->num_s != 0) { \
297047dd1d1bSDag-Erling Smørgrav 		for (i = 0; i < dst->num_s; i++) \
297147dd1d1bSDag-Erling Smørgrav 			free(dst->s[i]); \
297247dd1d1bSDag-Erling Smørgrav 		free(dst->s); \
297347dd1d1bSDag-Erling Smørgrav 		dst->s = xcalloc(src->num_s, sizeof(*dst->s)); \
297447dd1d1bSDag-Erling Smørgrav 		for (i = 0; i < src->num_s; i++) \
297547dd1d1bSDag-Erling Smørgrav 			dst->s[i] = xstrdup(src->s[i]); \
297647dd1d1bSDag-Erling Smørgrav 		dst->num_s = src->num_s; \
29774f52dfbbSDag-Erling Smørgrav 	} \
29784f52dfbbSDag-Erling Smørgrav } while(0)
2979f7167e0eSDag-Erling Smørgrav 
2980e146993eSDag-Erling Smørgrav 	/* See comment in servconf.h */
2981e146993eSDag-Erling Smørgrav 	COPY_MATCH_STRING_OPTS();
2982e146993eSDag-Erling Smørgrav 
2983acc1a9efSDag-Erling Smørgrav 	/* Arguments that accept '+...' need to be expanded */
2984acc1a9efSDag-Erling Smørgrav 	assemble_algorithms(dst);
2985acc1a9efSDag-Erling Smørgrav 
2986e146993eSDag-Erling Smørgrav 	/*
2987e146993eSDag-Erling Smørgrav 	 * The only things that should be below this point are string options
2988e146993eSDag-Erling Smørgrav 	 * which are only used after authentication.
2989e146993eSDag-Erling Smørgrav 	 */
2990d4af9e69SDag-Erling Smørgrav 	if (preauth)
2991d4af9e69SDag-Erling Smørgrav 		return;
2992e146993eSDag-Erling Smørgrav 
2993acc1a9efSDag-Erling Smørgrav 	/* These options may be "none" to clear a global setting */
2994d4af9e69SDag-Erling Smørgrav 	M_CP_STROPT(adm_forced_command);
2995acc1a9efSDag-Erling Smørgrav 	if (option_clear_or_none(dst->adm_forced_command)) {
2996acc1a9efSDag-Erling Smørgrav 		free(dst->adm_forced_command);
2997acc1a9efSDag-Erling Smørgrav 		dst->adm_forced_command = NULL;
2998acc1a9efSDag-Erling Smørgrav 	}
2999d4af9e69SDag-Erling Smørgrav 	M_CP_STROPT(chroot_directory);
3000acc1a9efSDag-Erling Smørgrav 	if (option_clear_or_none(dst->chroot_directory)) {
3001acc1a9efSDag-Erling Smørgrav 		free(dst->chroot_directory);
3002acc1a9efSDag-Erling Smørgrav 		dst->chroot_directory = NULL;
3003acc1a9efSDag-Erling Smørgrav 	}
3004edf85781SEd Maste 
3005edf85781SEd Maste 	/* Subsystems require merging. */
3006edf85781SEd Maste 	servconf_merge_subsystems(dst, src);
3007333ee039SDag-Erling Smørgrav }
3008d4af9e69SDag-Erling Smørgrav 
3009d4af9e69SDag-Erling Smørgrav #undef M_CP_INTOPT
3010d4af9e69SDag-Erling Smørgrav #undef M_CP_STROPT
3011e146993eSDag-Erling Smørgrav #undef M_CP_STRARRAYOPT
3012333ee039SDag-Erling Smørgrav 
301319261079SEd Maste #define SERVCONF_MAX_DEPTH	16
301419261079SEd Maste static void
parse_server_config_depth(ServerOptions * options,const char * filename,struct sshbuf * conf,struct include_list * includes,struct connection_info * connectinfo,int flags,int * activep,int depth)301519261079SEd Maste parse_server_config_depth(ServerOptions *options, const char *filename,
301619261079SEd Maste     struct sshbuf *conf, struct include_list *includes,
301719261079SEd Maste     struct connection_info *connectinfo, int flags, int *activep, int depth)
3018333ee039SDag-Erling Smørgrav {
301919261079SEd Maste 	int linenum, bad_options = 0;
302021e764dfSDag-Erling Smørgrav 	char *cp, *obuf, *cbuf;
302121e764dfSDag-Erling Smørgrav 
302219261079SEd Maste 	if (depth < 0 || depth > SERVCONF_MAX_DEPTH)
302319261079SEd Maste 		fatal("Too many recursive configuration includes");
302419261079SEd Maste 
302519261079SEd Maste 	debug2_f("config %s len %zu%s", filename, sshbuf_len(conf),
302619261079SEd Maste 	    (flags & SSHCFG_NEVERMATCH ? " [checking syntax only]" : ""));
302721e764dfSDag-Erling Smørgrav 
3028076ad2f8SDag-Erling Smørgrav 	if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL)
302919261079SEd Maste 		fatal_f("sshbuf_dup_string failed");
303021e764dfSDag-Erling Smørgrav 	linenum = 1;
303121e764dfSDag-Erling Smørgrav 	while ((cp = strsep(&cbuf, "\n")) != NULL) {
303219261079SEd Maste 		if (process_server_config_line_depth(options, cp,
303319261079SEd Maste 		    filename, linenum++, activep, connectinfo, &flags,
303419261079SEd Maste 		    depth, includes) != 0)
3035af12a3e7SDag-Erling Smørgrav 			bad_options++;
3036511b41d2SMark Murray 	}
3037e4a9863fSDag-Erling Smørgrav 	free(obuf);
3038ca3176e7SBrian Feldman 	if (bad_options > 0)
3039af12a3e7SDag-Erling Smørgrav 		fatal("%s: terminating, %d bad configuration options",
3040511b41d2SMark Murray 		    filename, bad_options);
304119261079SEd Maste }
304219261079SEd Maste 
304319261079SEd Maste void
parse_server_config(ServerOptions * options,const char * filename,struct sshbuf * conf,struct include_list * includes,struct connection_info * connectinfo,int reexec)304419261079SEd Maste parse_server_config(ServerOptions *options, const char *filename,
304519261079SEd Maste     struct sshbuf *conf, struct include_list *includes,
304687c1498dSEd Maste     struct connection_info *connectinfo, int reexec)
304719261079SEd Maste {
304819261079SEd Maste 	int active = connectinfo ? 0 : 1;
304919261079SEd Maste 	parse_server_config_depth(options, filename, conf, includes,
305019261079SEd Maste 	    connectinfo, (connectinfo ? SSHCFG_MATCH_ONLY : 0), &active, 0);
305187c1498dSEd Maste 	if (!reexec)
3052557f75e5SDag-Erling Smørgrav 		process_queued_listen_addrs(options);
3053511b41d2SMark Murray }
3054d4af9e69SDag-Erling Smørgrav 
3055d4af9e69SDag-Erling Smørgrav static const char *
fmt_multistate_int(int val,const struct multistate * m)3056e146993eSDag-Erling Smørgrav fmt_multistate_int(int val, const struct multistate *m)
3057d4af9e69SDag-Erling Smørgrav {
3058e146993eSDag-Erling Smørgrav 	u_int i;
3059e146993eSDag-Erling Smørgrav 
3060e146993eSDag-Erling Smørgrav 	for (i = 0; m[i].key != NULL; i++) {
3061e146993eSDag-Erling Smørgrav 		if (m[i].value == val)
3062e146993eSDag-Erling Smørgrav 			return m[i].key;
3063e146993eSDag-Erling Smørgrav 	}
3064d4af9e69SDag-Erling Smørgrav 	return "UNKNOWN";
3065d4af9e69SDag-Erling Smørgrav }
3066e146993eSDag-Erling Smørgrav 
3067e146993eSDag-Erling Smørgrav static const char *
fmt_intarg(ServerOpCodes code,int val)3068e146993eSDag-Erling Smørgrav fmt_intarg(ServerOpCodes code, int val)
3069e146993eSDag-Erling Smørgrav {
3070e146993eSDag-Erling Smørgrav 	if (val == -1)
3071e146993eSDag-Erling Smørgrav 		return "unset";
3072e146993eSDag-Erling Smørgrav 	switch (code) {
3073e146993eSDag-Erling Smørgrav 	case sAddressFamily:
3074e146993eSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_addressfamily);
3075e146993eSDag-Erling Smørgrav 	case sPermitRootLogin:
3076e146993eSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_permitrootlogin);
3077e146993eSDag-Erling Smørgrav 	case sGatewayPorts:
3078e146993eSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_gatewayports);
3079e146993eSDag-Erling Smørgrav 	case sCompression:
3080e146993eSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_compression);
30816888a9beSDag-Erling Smørgrav 	case sAllowTcpForwarding:
30826888a9beSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_tcpfwd);
3083a0ee8cc6SDag-Erling Smørgrav 	case sAllowStreamLocalForwarding:
3084a0ee8cc6SDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_tcpfwd);
308519261079SEd Maste 	case sIgnoreRhosts:
308619261079SEd Maste 		return fmt_multistate_int(val, multistate_ignore_rhosts);
3087bc5531deSDag-Erling Smørgrav 	case sFingerprintHash:
3088bc5531deSDag-Erling Smørgrav 		return ssh_digest_alg_name(val);
3089e146993eSDag-Erling Smørgrav 	default:
3090d4af9e69SDag-Erling Smørgrav 		switch (val) {
3091d4af9e69SDag-Erling Smørgrav 		case 0:
3092d4af9e69SDag-Erling Smørgrav 			return "no";
3093d4af9e69SDag-Erling Smørgrav 		case 1:
3094d4af9e69SDag-Erling Smørgrav 			return "yes";
3095e146993eSDag-Erling Smørgrav 		default:
3096d4af9e69SDag-Erling Smørgrav 			return "UNKNOWN";
3097d4af9e69SDag-Erling Smørgrav 		}
3098e146993eSDag-Erling Smørgrav 	}
3099e146993eSDag-Erling Smørgrav }
3100d4af9e69SDag-Erling Smørgrav 
3101d4af9e69SDag-Erling Smørgrav static void
dump_cfg_int(ServerOpCodes code,int val)3102d4af9e69SDag-Erling Smørgrav dump_cfg_int(ServerOpCodes code, int val)
3103d4af9e69SDag-Erling Smørgrav {
3104f374ba41SEd Maste 	if (code == sUnusedConnectionTimeout && val == 0) {
3105f374ba41SEd Maste 		printf("%s none\n", lookup_opcode_name(code));
3106f374ba41SEd Maste 		return;
3107f374ba41SEd Maste 	}
3108d4af9e69SDag-Erling Smørgrav 	printf("%s %d\n", lookup_opcode_name(code), val);
3109d4af9e69SDag-Erling Smørgrav }
3110d4af9e69SDag-Erling Smørgrav 
3111d4af9e69SDag-Erling Smørgrav static void
dump_cfg_oct(ServerOpCodes code,int val)3112557f75e5SDag-Erling Smørgrav dump_cfg_oct(ServerOpCodes code, int val)
3113557f75e5SDag-Erling Smørgrav {
3114557f75e5SDag-Erling Smørgrav 	printf("%s 0%o\n", lookup_opcode_name(code), val);
3115557f75e5SDag-Erling Smørgrav }
3116557f75e5SDag-Erling Smørgrav 
3117557f75e5SDag-Erling Smørgrav static void
dump_cfg_fmtint(ServerOpCodes code,int val)3118d4af9e69SDag-Erling Smørgrav dump_cfg_fmtint(ServerOpCodes code, int val)
3119d4af9e69SDag-Erling Smørgrav {
3120d4af9e69SDag-Erling Smørgrav 	printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
3121d4af9e69SDag-Erling Smørgrav }
3122d4af9e69SDag-Erling Smørgrav 
3123d4af9e69SDag-Erling Smørgrav static void
dump_cfg_string(ServerOpCodes code,const char * val)3124d4af9e69SDag-Erling Smørgrav dump_cfg_string(ServerOpCodes code, const char *val)
3125d4af9e69SDag-Erling Smørgrav {
3126bc5531deSDag-Erling Smørgrav 	printf("%s %s\n", lookup_opcode_name(code),
3127bc5531deSDag-Erling Smørgrav 	    val == NULL ? "none" : val);
3128d4af9e69SDag-Erling Smørgrav }
3129d4af9e69SDag-Erling Smørgrav 
3130d4af9e69SDag-Erling Smørgrav static void
dump_cfg_strarray(ServerOpCodes code,u_int count,char ** vals)3131d4af9e69SDag-Erling Smørgrav dump_cfg_strarray(ServerOpCodes code, u_int count, char **vals)
3132d4af9e69SDag-Erling Smørgrav {
3133d4af9e69SDag-Erling Smørgrav 	u_int i;
3134d4af9e69SDag-Erling Smørgrav 
3135d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < count; i++)
3136d4af9e69SDag-Erling Smørgrav 		printf("%s %s\n", lookup_opcode_name(code), vals[i]);
3137d4af9e69SDag-Erling Smørgrav }
3138d4af9e69SDag-Erling Smørgrav 
3139e146993eSDag-Erling Smørgrav static void
dump_cfg_strarray_oneline(ServerOpCodes code,u_int count,char ** vals)3140e146993eSDag-Erling Smørgrav dump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals)
3141e146993eSDag-Erling Smørgrav {
3142e146993eSDag-Erling Smørgrav 	u_int i;
3143e146993eSDag-Erling Smørgrav 
31444d3fc8b0SEd Maste 	switch (code) {
31454d3fc8b0SEd Maste 	case sAuthenticationMethods:
31464d3fc8b0SEd Maste 	case sChannelTimeout:
31474d3fc8b0SEd Maste 		break;
31484d3fc8b0SEd Maste 	default:
31494d3fc8b0SEd Maste 		if (count <= 0)
3150557f75e5SDag-Erling Smørgrav 			return;
31514d3fc8b0SEd Maste 		break;
31524d3fc8b0SEd Maste 	}
31534d3fc8b0SEd Maste 
3154e146993eSDag-Erling Smørgrav 	printf("%s", lookup_opcode_name(code));
3155e146993eSDag-Erling Smørgrav 	for (i = 0; i < count; i++)
3156e146993eSDag-Erling Smørgrav 		printf(" %s",  vals[i]);
3157076ad2f8SDag-Erling Smørgrav 	if (code == sAuthenticationMethods && count == 0)
3158076ad2f8SDag-Erling Smørgrav 		printf(" any");
3159f374ba41SEd Maste 	else if (code == sChannelTimeout && count == 0)
3160f374ba41SEd Maste 		printf(" none");
3161e146993eSDag-Erling Smørgrav 	printf("\n");
3162e146993eSDag-Erling Smørgrav }
3163e146993eSDag-Erling Smørgrav 
316447dd1d1bSDag-Erling Smørgrav static char *
format_listen_addrs(struct listenaddr * la)316547dd1d1bSDag-Erling Smørgrav format_listen_addrs(struct listenaddr *la)
3166d4af9e69SDag-Erling Smørgrav {
316747dd1d1bSDag-Erling Smørgrav 	int r;
3168d4af9e69SDag-Erling Smørgrav 	struct addrinfo *ai;
316947dd1d1bSDag-Erling Smørgrav 	char addr[NI_MAXHOST], port[NI_MAXSERV];
3170557f75e5SDag-Erling Smørgrav 	char *laddr1 = xstrdup(""), *laddr2 = NULL;
3171d4af9e69SDag-Erling Smørgrav 
3172557f75e5SDag-Erling Smørgrav 	/*
3173557f75e5SDag-Erling Smørgrav 	 * ListenAddress must be after Port.  add_one_listen_addr pushes
3174557f75e5SDag-Erling Smørgrav 	 * addresses onto a stack, so to maintain ordering we need to
3175557f75e5SDag-Erling Smørgrav 	 * print these in reverse order.
3176557f75e5SDag-Erling Smørgrav 	 */
317747dd1d1bSDag-Erling Smørgrav 	for (ai = la->addrs; ai; ai = ai->ai_next) {
317847dd1d1bSDag-Erling Smørgrav 		if ((r = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
3179d4af9e69SDag-Erling Smørgrav 		    sizeof(addr), port, sizeof(port),
3180d4af9e69SDag-Erling Smørgrav 		    NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
318147dd1d1bSDag-Erling Smørgrav 			error("getnameinfo: %.100s", ssh_gai_strerror(r));
318247dd1d1bSDag-Erling Smørgrav 			continue;
318347dd1d1bSDag-Erling Smørgrav 		}
3184557f75e5SDag-Erling Smørgrav 		laddr2 = laddr1;
318547dd1d1bSDag-Erling Smørgrav 		if (ai->ai_family == AF_INET6) {
318647dd1d1bSDag-Erling Smørgrav 			xasprintf(&laddr1, "listenaddress [%s]:%s%s%s\n%s",
318747dd1d1bSDag-Erling Smørgrav 			    addr, port,
318847dd1d1bSDag-Erling Smørgrav 			    la->rdomain == NULL ? "" : " rdomain ",
318947dd1d1bSDag-Erling Smørgrav 			    la->rdomain == NULL ? "" : la->rdomain,
319047dd1d1bSDag-Erling Smørgrav 			    laddr2);
319147dd1d1bSDag-Erling Smørgrav 		} else {
319247dd1d1bSDag-Erling Smørgrav 			xasprintf(&laddr1, "listenaddress %s:%s%s%s\n%s",
319347dd1d1bSDag-Erling Smørgrav 			    addr, port,
319447dd1d1bSDag-Erling Smørgrav 			    la->rdomain == NULL ? "" : " rdomain ",
319547dd1d1bSDag-Erling Smørgrav 			    la->rdomain == NULL ? "" : la->rdomain,
319647dd1d1bSDag-Erling Smørgrav 			    laddr2);
319747dd1d1bSDag-Erling Smørgrav 		}
3198557f75e5SDag-Erling Smørgrav 		free(laddr2);
3199d4af9e69SDag-Erling Smørgrav 	}
320047dd1d1bSDag-Erling Smørgrav 	return laddr1;
3201d4af9e69SDag-Erling Smørgrav }
320247dd1d1bSDag-Erling Smørgrav 
320347dd1d1bSDag-Erling Smørgrav void
dump_config(ServerOptions * o)320447dd1d1bSDag-Erling Smørgrav dump_config(ServerOptions *o)
320547dd1d1bSDag-Erling Smørgrav {
320647dd1d1bSDag-Erling Smørgrav 	char *s;
320747dd1d1bSDag-Erling Smørgrav 	u_int i;
320847dd1d1bSDag-Erling Smørgrav 
320947dd1d1bSDag-Erling Smørgrav 	/* these are usually at the top of the config */
321047dd1d1bSDag-Erling Smørgrav 	for (i = 0; i < o->num_ports; i++)
321147dd1d1bSDag-Erling Smørgrav 		printf("port %d\n", o->ports[i]);
321247dd1d1bSDag-Erling Smørgrav 	dump_cfg_fmtint(sAddressFamily, o->address_family);
321347dd1d1bSDag-Erling Smørgrav 
321447dd1d1bSDag-Erling Smørgrav 	for (i = 0; i < o->num_listen_addrs; i++) {
321547dd1d1bSDag-Erling Smørgrav 		s = format_listen_addrs(&o->listen_addrs[i]);
321647dd1d1bSDag-Erling Smørgrav 		printf("%s", s);
321747dd1d1bSDag-Erling Smørgrav 		free(s);
321847dd1d1bSDag-Erling Smørgrav 	}
3219d4af9e69SDag-Erling Smørgrav 
3220d4af9e69SDag-Erling Smørgrav 	/* integer arguments */
3221cce7d346SDag-Erling Smørgrav #ifdef USE_PAM
3222557f75e5SDag-Erling Smørgrav 	dump_cfg_fmtint(sUsePAM, o->use_pam);
32230fdf8faeSEd Maste 	dump_cfg_string(sPAMServiceName, o->pam_service_name);
3224cce7d346SDag-Erling Smørgrav #endif
3225d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sLoginGraceTime, o->login_grace_time);
3226d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sX11DisplayOffset, o->x11_display_offset);
3227d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sMaxAuthTries, o->max_authtries);
3228cce7d346SDag-Erling Smørgrav 	dump_cfg_int(sMaxSessions, o->max_sessions);
3229d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
3230d4af9e69SDag-Erling Smørgrav 	dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
323138a52bd3SEd Maste 	dump_cfg_int(sRequiredRSASize, o->required_rsa_size);
3232557f75e5SDag-Erling Smørgrav 	dump_cfg_oct(sStreamLocalBindMask, o->fwd_opts.streamlocal_bind_mask);
3233f374ba41SEd Maste 	dump_cfg_int(sUnusedConnectionTimeout, o->unused_connection_timeout);
3234d4af9e69SDag-Erling Smørgrav 
3235d4af9e69SDag-Erling Smørgrav 	/* formatted integer arguments */
3236d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login);
3237d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sIgnoreRhosts, o->ignore_rhosts);
3238d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sIgnoreUserKnownHosts, o->ignore_user_known_hosts);
3239d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sHostbasedAuthentication, o->hostbased_authentication);
3240d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sHostbasedUsesNameFromPacketOnly,
3241d4af9e69SDag-Erling Smørgrav 	    o->hostbased_uses_name_from_packet_only);
3242d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPubkeyAuthentication, o->pubkey_authentication);
3243cce7d346SDag-Erling Smørgrav #ifdef KRB5
3244d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKerberosAuthentication, o->kerberos_authentication);
3245d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKerberosOrLocalPasswd, o->kerberos_or_local_passwd);
3246d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKerberosTicketCleanup, o->kerberos_ticket_cleanup);
3247cce7d346SDag-Erling Smørgrav # ifdef USE_AFS
3248d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
3249cce7d346SDag-Erling Smørgrav # endif
3250cce7d346SDag-Erling Smørgrav #endif
3251cce7d346SDag-Erling Smørgrav #ifdef GSSAPI
3252d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
3253d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
3254cce7d346SDag-Erling Smørgrav #endif
3255d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
3256d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sKbdInteractiveAuthentication,
3257d4af9e69SDag-Erling Smørgrav 	    o->kbd_interactive_authentication);
3258d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPrintMotd, o->print_motd);
3259acc1a9efSDag-Erling Smørgrav #ifndef DISABLE_LASTLOG
3260d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sPrintLastLog, o->print_lastlog);
3261acc1a9efSDag-Erling Smørgrav #endif
3262d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding);
3263d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost);
3264f7167e0eSDag-Erling Smørgrav 	dump_cfg_fmtint(sPermitTTY, o->permit_tty);
3265a0ee8cc6SDag-Erling Smørgrav 	dump_cfg_fmtint(sPermitUserRC, o->permit_user_rc);
3266d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sStrictModes, o->strict_modes);
3267d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive);
3268d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd);
3269d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sCompression, o->compression);
3270a0ee8cc6SDag-Erling Smørgrav 	dump_cfg_fmtint(sGatewayPorts, o->fwd_opts.gateway_ports);
3271d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sUseDNS, o->use_dns);
3272d4af9e69SDag-Erling Smørgrav 	dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
3273557f75e5SDag-Erling Smørgrav 	dump_cfg_fmtint(sAllowAgentForwarding, o->allow_agent_forwarding);
3274ca86bcf2SDag-Erling Smørgrav 	dump_cfg_fmtint(sDisableForwarding, o->disable_forwarding);
3275a0ee8cc6SDag-Erling Smørgrav 	dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding);
3276076ad2f8SDag-Erling Smørgrav 	dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
3277bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash);
32784f52dfbbSDag-Erling Smørgrav 	dump_cfg_fmtint(sExposeAuthInfo, o->expose_userauth_info);
32793d9fd9fcSEd Maste 	dump_cfg_fmtint(sRefuseConnection, o->refuse_connection);
3280b2af61ecSKurt Lidl 	dump_cfg_fmtint(sUseBlacklist, o->use_blacklist);
3281d4af9e69SDag-Erling Smørgrav 
3282d4af9e69SDag-Erling Smørgrav 	/* string arguments */
3283d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sPidFile, o->pid_file);
328419261079SEd Maste 	dump_cfg_string(sModuliFile, o->moduli_file);
3285d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sXAuthLocation, o->xauth_location);
328619261079SEd Maste 	dump_cfg_string(sCiphers, o->ciphers);
328719261079SEd Maste 	dump_cfg_string(sMacs, o->macs);
3288d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sBanner, o->banner);
3289d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sForceCommand, o->adm_forced_command);
3290b15c8340SDag-Erling Smørgrav 	dump_cfg_string(sChrootDirectory, o->chroot_directory);
3291b15c8340SDag-Erling Smørgrav 	dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys);
3292b15c8340SDag-Erling Smørgrav 	dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
329319261079SEd Maste 	dump_cfg_string(sSecurityKeyProvider, o->sk_provider);
3294e2f6069cSDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedPrincipalsFile,
3295e2f6069cSDag-Erling Smørgrav 	    o->authorized_principals_file);
3296557f75e5SDag-Erling Smørgrav 	dump_cfg_string(sVersionAddendum, *o->version_addendum == '\0'
3297557f75e5SDag-Erling Smørgrav 	    ? "none" : o->version_addendum);
32986888a9beSDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command);
32996888a9beSDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedKeysCommandUser, o->authorized_keys_command_user);
3300557f75e5SDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedPrincipalsCommand, o->authorized_principals_command);
3301557f75e5SDag-Erling Smørgrav 	dump_cfg_string(sAuthorizedPrincipalsCommandUser, o->authorized_principals_command_user);
3302e4a9863fSDag-Erling Smørgrav 	dump_cfg_string(sHostKeyAgent, o->host_key_agent);
330319261079SEd Maste 	dump_cfg_string(sKexAlgorithms, o->kex_algorithms);
330419261079SEd Maste 	dump_cfg_string(sCASignatureAlgorithms, o->ca_sign_algorithms);
330519261079SEd Maste 	dump_cfg_string(sHostbasedAcceptedAlgorithms, o->hostbased_accepted_algos);
330619261079SEd Maste 	dump_cfg_string(sHostKeyAlgorithms, o->hostkeyalgorithms);
330719261079SEd Maste 	dump_cfg_string(sPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos);
330819261079SEd Maste #if defined(__OpenBSD__) || defined(HAVE_SYS_SET_PROCESS_RDOMAIN)
330947dd1d1bSDag-Erling Smørgrav 	dump_cfg_string(sRDomain, o->routing_domain);
331019261079SEd Maste #endif
33110fdf8faeSEd Maste 	dump_cfg_string(sSshdSessionPath, o->sshd_session_path);
33120fdf8faeSEd Maste 	dump_cfg_string(sPerSourcePenaltyExemptList, o->per_source_penalty_exempt);
3313d4af9e69SDag-Erling Smørgrav 
3314d4af9e69SDag-Erling Smørgrav 	/* string arguments requiring a lookup */
3315d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sLogLevel, log_level_name(o->log_level));
3316d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sLogFacility, log_facility_name(o->log_facility));
3317d4af9e69SDag-Erling Smørgrav 
3318d4af9e69SDag-Erling Smørgrav 	/* string array arguments */
3319e146993eSDag-Erling Smørgrav 	dump_cfg_strarray_oneline(sAuthorizedKeysFile, o->num_authkeys_files,
3320e146993eSDag-Erling Smørgrav 	    o->authorized_keys_files);
3321d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sHostKeyFile, o->num_host_key_files,
3322d4af9e69SDag-Erling Smørgrav 	    o->host_key_files);
3323557f75e5SDag-Erling Smørgrav 	dump_cfg_strarray(sHostCertificate, o->num_host_cert_files,
3324b15c8340SDag-Erling Smørgrav 	    o->host_cert_files);
3325d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users);
3326d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users);
3327d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups);
3328d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sDenyGroups, o->num_deny_groups, o->deny_groups);
3329d4af9e69SDag-Erling Smørgrav 	dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env);
3330190cef3dSDag-Erling Smørgrav 	dump_cfg_strarray(sSetEnv, o->num_setenv, o->setenv);
33316888a9beSDag-Erling Smørgrav 	dump_cfg_strarray_oneline(sAuthenticationMethods,
33326888a9beSDag-Erling Smørgrav 	    o->num_auth_methods, o->auth_methods);
333319261079SEd Maste 	dump_cfg_strarray_oneline(sLogVerbose,
333419261079SEd Maste 	    o->num_log_verbose, o->log_verbose);
3335f374ba41SEd Maste 	dump_cfg_strarray_oneline(sChannelTimeout,
3336f374ba41SEd Maste 	    o->num_channel_timeouts, o->channel_timeouts);
3337d4af9e69SDag-Erling Smørgrav 
3338d4af9e69SDag-Erling Smørgrav 	/* other arguments */
3339d4af9e69SDag-Erling Smørgrav 	for (i = 0; i < o->num_subsystems; i++)
3340d4af9e69SDag-Erling Smørgrav 		printf("subsystem %s %s\n", o->subsystem_name[i],
3341d4af9e69SDag-Erling Smørgrav 		    o->subsystem_args[i]);
3342d4af9e69SDag-Erling Smørgrav 
3343d4af9e69SDag-Erling Smørgrav 	printf("maxstartups %d:%d:%d\n", o->max_startups_begin,
3344d4af9e69SDag-Erling Smørgrav 	    o->max_startups_rate, o->max_startups);
334519261079SEd Maste 	printf("persourcemaxstartups ");
334619261079SEd Maste 	if (o->per_source_max_startups == INT_MAX)
334719261079SEd Maste 		printf("none\n");
334819261079SEd Maste 	else
334919261079SEd Maste 		printf("%d\n", o->per_source_max_startups);
335019261079SEd Maste 	printf("persourcenetblocksize %d:%d\n", o->per_source_masklen_ipv4,
335119261079SEd Maste 	    o->per_source_masklen_ipv6);
3352d4af9e69SDag-Erling Smørgrav 
335347dd1d1bSDag-Erling Smørgrav 	s = NULL;
335447dd1d1bSDag-Erling Smørgrav 	for (i = 0; tunmode_desc[i].val != -1; i++) {
3355d4af9e69SDag-Erling Smørgrav 		if (tunmode_desc[i].val == o->permit_tun) {
3356d4af9e69SDag-Erling Smørgrav 			s = tunmode_desc[i].text;
3357d4af9e69SDag-Erling Smørgrav 			break;
3358d4af9e69SDag-Erling Smørgrav 		}
335947dd1d1bSDag-Erling Smørgrav 	}
3360d4af9e69SDag-Erling Smørgrav 	dump_cfg_string(sPermitTunnel, s);
3361d4af9e69SDag-Erling Smørgrav 
3362e146993eSDag-Erling Smørgrav 	printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
3363e146993eSDag-Erling Smørgrav 	printf("%s\n", iptos2str(o->ip_qos_bulk));
33644a421b63SDag-Erling Smørgrav 
3365acc1a9efSDag-Erling Smørgrav 	printf("rekeylimit %llu %d\n", (unsigned long long)o->rekey_limit,
3366e4a9863fSDag-Erling Smørgrav 	    o->rekey_interval);
3367e4a9863fSDag-Erling Smørgrav 
33684f52dfbbSDag-Erling Smørgrav 	printf("permitopen");
33694f52dfbbSDag-Erling Smørgrav 	if (o->num_permitted_opens == 0)
33704f52dfbbSDag-Erling Smørgrav 		printf(" any");
33714f52dfbbSDag-Erling Smørgrav 	else {
33724f52dfbbSDag-Erling Smørgrav 		for (i = 0; i < o->num_permitted_opens; i++)
33734f52dfbbSDag-Erling Smørgrav 			printf(" %s", o->permitted_opens[i]);
33744f52dfbbSDag-Erling Smørgrav 	}
33754f52dfbbSDag-Erling Smørgrav 	printf("\n");
3376190cef3dSDag-Erling Smørgrav 	printf("permitlisten");
3377190cef3dSDag-Erling Smørgrav 	if (o->num_permitted_listens == 0)
3378190cef3dSDag-Erling Smørgrav 		printf(" any");
3379190cef3dSDag-Erling Smørgrav 	else {
3380190cef3dSDag-Erling Smørgrav 		for (i = 0; i < o->num_permitted_listens; i++)
3381190cef3dSDag-Erling Smørgrav 			printf(" %s", o->permitted_listens[i]);
3382190cef3dSDag-Erling Smørgrav 	}
3383190cef3dSDag-Erling Smørgrav 	printf("\n");
3384190cef3dSDag-Erling Smørgrav 
338519261079SEd Maste 	if (o->permit_user_env_allowlist == NULL) {
3386190cef3dSDag-Erling Smørgrav 		dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
3387190cef3dSDag-Erling Smørgrav 	} else {
3388190cef3dSDag-Erling Smørgrav 		printf("permituserenvironment %s\n",
338919261079SEd Maste 		    o->permit_user_env_allowlist);
3390190cef3dSDag-Erling Smørgrav 	}
3391190cef3dSDag-Erling Smørgrav 
339219261079SEd Maste 	printf("pubkeyauthoptions");
339319261079SEd Maste 	if (o->pubkey_auth_options == 0)
339419261079SEd Maste 		printf(" none");
339519261079SEd Maste 	if (o->pubkey_auth_options & PUBKEYAUTH_TOUCH_REQUIRED)
339619261079SEd Maste 		printf(" touch-required");
339719261079SEd Maste 	if (o->pubkey_auth_options & PUBKEYAUTH_VERIFY_REQUIRED)
339819261079SEd Maste 		printf(" verify-required");
339919261079SEd Maste 	printf("\n");
34000fdf8faeSEd Maste 
34010fdf8faeSEd Maste 	if (o->per_source_penalty.enabled) {
34020fdf8faeSEd Maste 		printf("persourcepenalties crash:%d authfail:%d noauth:%d "
34033d9fd9fcSEd Maste 		    "grace-exceeded:%d refuseconnection:%d max:%d min:%d "
34043d9fd9fcSEd Maste 		    "max-sources4:%d max-sources6:%d "
34053d9fd9fcSEd Maste 		    "overflow:%s overflow6:%s\n",
34060fdf8faeSEd Maste 		    o->per_source_penalty.penalty_crash,
34070fdf8faeSEd Maste 		    o->per_source_penalty.penalty_authfail,
34080fdf8faeSEd Maste 		    o->per_source_penalty.penalty_noauth,
34090fdf8faeSEd Maste 		    o->per_source_penalty.penalty_grace,
34103d9fd9fcSEd Maste 		    o->per_source_penalty.penalty_refuseconnection,
34110fdf8faeSEd Maste 		    o->per_source_penalty.penalty_max,
34120fdf8faeSEd Maste 		    o->per_source_penalty.penalty_min,
34130fdf8faeSEd Maste 		    o->per_source_penalty.max_sources4,
34140fdf8faeSEd Maste 		    o->per_source_penalty.max_sources6,
34150fdf8faeSEd Maste 		    o->per_source_penalty.overflow_mode ==
34160fdf8faeSEd Maste 		    PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL ?
34170fdf8faeSEd Maste 		    "deny-all" : "permissive",
34180fdf8faeSEd Maste 		    o->per_source_penalty.overflow_mode6 ==
34190fdf8faeSEd Maste 		    PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL ?
34200fdf8faeSEd Maste 		    "deny-all" : "permissive");
34210fdf8faeSEd Maste 	} else
34220fdf8faeSEd Maste 		printf("persourcepenalties no\n");
3423d4af9e69SDag-Erling Smørgrav }
3424