xref: /freebsd/crypto/openssh/servconf.c (revision 2574974648c68c738aec3ff96644d888d7913a37)
1 /* $OpenBSD: servconf.c,v 1.446 2026/04/02 07:38:14 djm Exp $ */
2 /*
3  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4  *                    All rights reserved
5  *
6  * As far as I am concerned, the code I have written for this software
7  * can be used freely for any purpose.  Any derived versions of this
8  * software must be clearly marked as such, and if the derived work is
9  * incompatible with the protocol description in the RFC file, it must be
10  * called by a name other than "ssh" or "Secure Shell".
11  */
12 
13 #include "includes.h"
14 
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <sys/queue.h>
18 #include <sys/stat.h>
19 #ifdef __OpenBSD__
20 #include <sys/sysctl.h>
21 #endif
22 
23 #include <netinet/in.h>
24 #include <netinet/ip.h>
25 #ifdef HAVE_NET_ROUTE_H
26 #include <net/route.h>
27 #endif
28 
29 #include <ctype.h>
30 #include <glob.h>
31 #include <netdb.h>
32 #include <pwd.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <signal.h>
37 #include <unistd.h>
38 #include <limits.h>
39 #include <stdarg.h>
40 #include <errno.h>
41 #include <util.h>
42 
43 #include "xmalloc.h"
44 #include "ssh.h"
45 #include "log.h"
46 #include "sshbuf.h"
47 #include "misc.h"
48 #include "servconf.h"
49 #include "pathnames.h"
50 #include "cipher.h"
51 #include "sshkey.h"
52 #include "kex.h"
53 #include "mac.h"
54 #include "match.h"
55 #include "channels.h"
56 #include "groupaccess.h"
57 #include "canohost.h"
58 #include "packet.h"
59 #include "ssherr.h"
60 #include "hostfile.h"
61 #include "auth.h"
62 #include "myproposal.h"
63 #include "digest.h"
64 #include "version.h"
65 
66 #if !defined(SSHD_PAM_SERVICE)
67 # define SSHD_PAM_SERVICE		"sshd"
68 #endif
69 
70 static void add_listen_addr(ServerOptions *, const char *,
71     const char *, int);
72 static void add_one_listen_addr(ServerOptions *, const char *,
73     const char *, int);
74 static void parse_server_config_depth(ServerOptions *options,
75     const char *filename, struct sshbuf *conf, struct include_list *includes,
76     struct connection_info *connectinfo, int flags, int *activep, int depth);
77 
78 extern struct sshbuf *cfg;
79 
80 /* Initializes the server options to their default values. */
81 
82 void
initialize_server_options(ServerOptions * options)83 initialize_server_options(ServerOptions *options)
84 {
85 	memset(options, 0, sizeof(*options));
86 
87 	/* Portable-specific options */
88 	options->use_pam = -1;
89 	options->pam_service_name = NULL;
90 
91 	/* Standard Options */
92 	options->num_ports = 0;
93 	options->ports_from_cmdline = 0;
94 	options->queued_listen_addrs = NULL;
95 	options->num_queued_listens = 0;
96 	options->listen_addrs = NULL;
97 	options->num_listen_addrs = 0;
98 	options->address_family = -1;
99 	options->routing_domain = NULL;
100 	options->num_host_key_files = 0;
101 	options->num_host_cert_files = 0;
102 	options->host_key_agent = NULL;
103 	options->pid_file = NULL;
104 	options->login_grace_time = -1;
105 	options->permit_root_login = PERMIT_NOT_SET;
106 	options->ignore_rhosts = -1;
107 	options->ignore_user_known_hosts = -1;
108 	options->print_motd = -1;
109 	options->print_lastlog = -1;
110 	options->x11_forwarding = -1;
111 	options->x11_display_offset = -1;
112 	options->x11_use_localhost = -1;
113 	options->permit_tty = -1;
114 	options->permit_user_rc = -1;
115 	options->xauth_location = NULL;
116 	options->strict_modes = -1;
117 	options->tcp_keep_alive = -1;
118 	options->log_facility = SYSLOG_FACILITY_NOT_SET;
119 	options->log_level = SYSLOG_LEVEL_NOT_SET;
120 	options->num_log_verbose = 0;
121 	options->log_verbose = NULL;
122 	options->hostbased_authentication = -1;
123 	options->hostbased_uses_name_from_packet_only = -1;
124 	options->hostbased_accepted_algos = NULL;
125 	options->hostkeyalgorithms = NULL;
126 	options->pubkey_authentication = -1;
127 	options->pubkey_auth_options = -1;
128 	options->pubkey_accepted_algos = NULL;
129 	options->kerberos_authentication = -1;
130 	options->kerberos_or_local_passwd = -1;
131 	options->kerberos_ticket_cleanup = -1;
132 	options->kerberos_get_afs_token = -1;
133 	options->gss_authentication=-1;
134 	options->gss_cleanup_creds = -1;
135 	options->gss_deleg_creds = -1;
136 	options->gss_strict_acceptor = -1;
137 	options->password_authentication = -1;
138 	options->kbd_interactive_authentication = -1;
139 	options->permit_empty_passwd = -1;
140 	options->permit_user_env = -1;
141 	options->permit_user_env_allowlist = NULL;
142 	options->compression = -1;
143 	options->rekey_limit = -1;
144 	options->rekey_interval = -1;
145 	options->allow_tcp_forwarding = -1;
146 	options->allow_streamlocal_forwarding = -1;
147 	options->allow_agent_forwarding = -1;
148 	options->num_allow_users = 0;
149 	options->num_deny_users = 0;
150 	options->num_allow_groups = 0;
151 	options->num_deny_groups = 0;
152 	options->ciphers = NULL;
153 	options->macs = NULL;
154 	options->kex_algorithms = NULL;
155 	options->ca_sign_algorithms = NULL;
156 	options->fwd_opts.gateway_ports = -1;
157 	options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
158 	options->fwd_opts.streamlocal_bind_unlink = -1;
159 	options->num_subsystems = 0;
160 	options->max_startups_begin = -1;
161 	options->max_startups_rate = -1;
162 	options->max_startups = -1;
163 	options->per_source_max_startups = -1;
164 	options->per_source_masklen_ipv4 = -1;
165 	options->per_source_masklen_ipv6 = -1;
166 	options->per_source_penalty_exempt = NULL;
167 	options->per_source_penalty.enabled = -1;
168 	options->per_source_penalty.max_sources4 = -1;
169 	options->per_source_penalty.max_sources6 = -1;
170 	options->per_source_penalty.overflow_mode = -1;
171 	options->per_source_penalty.overflow_mode6 = -1;
172 	options->per_source_penalty.penalty_crash = -1.0;
173 	options->per_source_penalty.penalty_authfail = -1.0;
174 	options->per_source_penalty.penalty_invaliduser = -1.0;
175 	options->per_source_penalty.penalty_noauth = -1.0;
176 	options->per_source_penalty.penalty_grace = -1.0;
177 	options->per_source_penalty.penalty_refuseconnection = -1.0;
178 	options->per_source_penalty.penalty_max = -1.0;
179 	options->per_source_penalty.penalty_min = -1.0;
180 	options->max_authtries = -1;
181 	options->max_sessions = -1;
182 	options->banner = NULL;
183 	options->use_dns = -1;
184 	options->client_alive_interval = -1;
185 	options->client_alive_count_max = -1;
186 	options->num_authkeys_files = 0;
187 	options->num_accept_env = 0;
188 	options->num_setenv = 0;
189 	options->permit_tun = -1;
190 	options->permitted_opens = NULL;
191 	options->permitted_listens = NULL;
192 	options->adm_forced_command = NULL;
193 	options->chroot_directory = NULL;
194 	options->authorized_keys_command = NULL;
195 	options->authorized_keys_command_user = NULL;
196 	options->revoked_keys_files = NULL;
197 	options->num_revoked_keys_files = 0;
198 	options->sk_provider = NULL;
199 	options->trusted_user_ca_keys = NULL;
200 	options->authorized_principals_file = NULL;
201 	options->authorized_principals_command = NULL;
202 	options->authorized_principals_command_user = NULL;
203 	options->ip_qos_interactive = -1;
204 	options->ip_qos_bulk = -1;
205 	options->version_addendum = NULL;
206 	options->fingerprint_hash = -1;
207 	options->disable_forwarding = -1;
208 	options->expose_userauth_info = -1;
209 	options->required_rsa_size = -1;
210 	options->channel_timeouts = NULL;
211 	options->num_channel_timeouts = 0;
212 	options->unused_connection_timeout = -1;
213 	options->sshd_session_path = NULL;
214 	options->sshd_auth_path = NULL;
215 	options->refuse_connection = -1;
216 	options->use_blocklist = -1;
217 }
218 
219 /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
220 static int
option_clear_or_none(const char * o)221 option_clear_or_none(const char *o)
222 {
223 	return o == NULL || strcasecmp(o, "none") == 0;
224 }
225 
226 static void
assemble_algorithms(ServerOptions * o)227 assemble_algorithms(ServerOptions *o)
228 {
229 	char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
230 	char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig;
231 	int r;
232 
233 	all_cipher = cipher_alg_list(',', 0);
234 	all_mac = mac_alg_list(',');
235 	all_kex = kex_alg_list(',');
236 	all_key = sshkey_alg_list(0, 0, 1, ',');
237 	all_sig = sshkey_alg_list(0, 1, 1, ',');
238 	/* remove unsupported algos from default lists */
239 	def_cipher = match_filter_allowlist(KEX_SERVER_ENCRYPT, all_cipher);
240 	def_mac = match_filter_allowlist(KEX_SERVER_MAC, all_mac);
241 	def_kex = match_filter_allowlist(KEX_SERVER_KEX, all_kex);
242 	def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
243 	def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig);
244 #define ASSEMBLE(what, defaults, all) \
245 	do { \
246 		if ((r = kex_assemble_names(&o->what, defaults, all)) != 0) \
247 			fatal_fr(r, "%s", #what); \
248 	} while (0)
249 	ASSEMBLE(ciphers, def_cipher, all_cipher);
250 	ASSEMBLE(macs, def_mac, all_mac);
251 	ASSEMBLE(kex_algorithms, def_kex, all_kex);
252 	ASSEMBLE(hostkeyalgorithms, def_key, all_key);
253 	ASSEMBLE(hostbased_accepted_algos, def_key, all_key);
254 	ASSEMBLE(pubkey_accepted_algos, def_key, all_key);
255 	ASSEMBLE(ca_sign_algorithms, def_sig, all_sig);
256 #undef ASSEMBLE
257 	free(all_cipher);
258 	free(all_mac);
259 	free(all_kex);
260 	free(all_key);
261 	free(all_sig);
262 	free(def_cipher);
263 	free(def_mac);
264 	free(def_kex);
265 	free(def_key);
266 	free(def_sig);
267 }
268 
269 static const char *defaultkey = "[default]";
270 
271 void
servconf_add_hostkey(const char * file,const int line,ServerOptions * options,const char * path,int userprovided)272 servconf_add_hostkey(const char *file, const int line,
273     ServerOptions *options, const char *path, int userprovided)
274 {
275 	char *apath = derelativise_path(path);
276 
277 	if (file == defaultkey && access(path, R_OK) != 0)
278 		return;
279 	opt_array_append2(file, line, "HostKey",
280 	    &options->host_key_files, &options->host_key_file_userprovided,
281 	    &options->num_host_key_files, apath, userprovided);
282 	free(apath);
283 }
284 
285 void
servconf_add_hostcert(const char * file,const int line,ServerOptions * options,const char * path)286 servconf_add_hostcert(const char *file, const int line,
287     ServerOptions *options, const char *path)
288 {
289 	char *apath = derelativise_path(path);
290 
291 	opt_array_append(file, line, "HostCertificate",
292 	    &options->host_cert_files, &options->num_host_cert_files, apath);
293 	free(apath);
294 }
295 
296 void
fill_default_server_options(ServerOptions * options)297 fill_default_server_options(ServerOptions *options)
298 {
299 	u_int i;
300 
301 	/* Portable-specific options */
302 	if (options->use_pam == -1)
303 		options->use_pam = 1;
304 	if (options->pam_service_name == NULL)
305 		options->pam_service_name = xstrdup(SSHD_PAM_SERVICE);
306 
307 	/* Standard Options */
308 	if (options->num_host_key_files == 0) {
309 		/* fill default hostkeys for protocols */
310 		servconf_add_hostkey(defaultkey, 0, options,
311 		    _PATH_HOST_RSA_KEY_FILE, 0);
312 #ifdef OPENSSL_HAS_ECC
313 		servconf_add_hostkey(defaultkey, 0, options,
314 		    _PATH_HOST_ECDSA_KEY_FILE, 0);
315 #endif
316 		servconf_add_hostkey(defaultkey, 0, options,
317 		    _PATH_HOST_ED25519_KEY_FILE, 0);
318 	}
319 	if (options->num_host_key_files == 0)
320 		fatal("No host key files found");
321 	/* No certificates by default */
322 	if (options->num_ports == 0)
323 		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
324 	if (options->address_family == -1)
325 		options->address_family = AF_UNSPEC;
326 	if (options->listen_addrs == NULL)
327 		add_listen_addr(options, NULL, NULL, 0);
328 	if (options->pid_file == NULL)
329 		options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE);
330 	if (options->moduli_file == NULL)
331 		options->moduli_file = xstrdup(_PATH_DH_MODULI);
332 	if (options->login_grace_time == -1)
333 		options->login_grace_time = 120;
334 	if (options->permit_root_login == PERMIT_NOT_SET)
335 		options->permit_root_login = PERMIT_NO;
336 	if (options->ignore_rhosts == -1)
337 		options->ignore_rhosts = 1;
338 	if (options->ignore_user_known_hosts == -1)
339 		options->ignore_user_known_hosts = 0;
340 	if (options->print_motd == -1)
341 		options->print_motd = 1;
342 	if (options->print_lastlog == -1)
343 		options->print_lastlog = 1;
344 	if (options->x11_forwarding == -1)
345 		options->x11_forwarding = 0;
346 	if (options->x11_display_offset == -1)
347 		options->x11_display_offset = 10;
348 	if (options->x11_use_localhost == -1)
349 		options->x11_use_localhost = 1;
350 	if (options->xauth_location == NULL)
351 		options->xauth_location = xstrdup(_PATH_XAUTH);
352 	if (options->permit_tty == -1)
353 		options->permit_tty = 1;
354 	if (options->permit_user_rc == -1)
355 		options->permit_user_rc = 1;
356 	if (options->strict_modes == -1)
357 		options->strict_modes = 1;
358 	if (options->tcp_keep_alive == -1)
359 		options->tcp_keep_alive = 1;
360 	if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
361 		options->log_facility = SYSLOG_FACILITY_AUTH;
362 	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
363 		options->log_level = SYSLOG_LEVEL_INFO;
364 	if (options->hostbased_authentication == -1)
365 		options->hostbased_authentication = 0;
366 	if (options->hostbased_uses_name_from_packet_only == -1)
367 		options->hostbased_uses_name_from_packet_only = 0;
368 	if (options->pubkey_authentication == -1)
369 		options->pubkey_authentication = 1;
370 	if (options->pubkey_auth_options == -1)
371 		options->pubkey_auth_options = 0;
372 	if (options->kerberos_authentication == -1)
373 		options->kerberos_authentication = 0;
374 	if (options->kerberos_or_local_passwd == -1)
375 		options->kerberos_or_local_passwd = 1;
376 	if (options->kerberos_ticket_cleanup == -1)
377 		options->kerberos_ticket_cleanup = 1;
378 	if (options->kerberos_get_afs_token == -1)
379 		options->kerberos_get_afs_token = 0;
380 	if (options->gss_authentication == -1)
381 		options->gss_authentication = 0;
382 	if (options->gss_cleanup_creds == -1)
383 		options->gss_cleanup_creds = 1;
384 	if (options->gss_deleg_creds == -1)
385 		options->gss_deleg_creds = 1;
386 	if (options->gss_strict_acceptor == -1)
387 		options->gss_strict_acceptor = 1;
388 	if (options->password_authentication == -1)
389 		options->password_authentication = 0;
390 	if (options->kbd_interactive_authentication == -1)
391 		options->kbd_interactive_authentication = 1;
392 	if (options->permit_empty_passwd == -1)
393 		options->permit_empty_passwd = 0;
394 	if (options->permit_user_env == -1) {
395 		options->permit_user_env = 0;
396 		options->permit_user_env_allowlist = NULL;
397 	}
398 	if (options->compression == -1)
399 #ifdef WITH_ZLIB
400 		options->compression = COMP_DELAYED;
401 #else
402 		options->compression = COMP_NONE;
403 #endif
404 
405 	if (options->rekey_limit == -1)
406 		options->rekey_limit = 0;
407 	if (options->rekey_interval == -1)
408 		options->rekey_interval = 0;
409 	if (options->allow_tcp_forwarding == -1)
410 		options->allow_tcp_forwarding = FORWARD_ALLOW;
411 	if (options->allow_streamlocal_forwarding == -1)
412 		options->allow_streamlocal_forwarding = FORWARD_ALLOW;
413 	if (options->allow_agent_forwarding == -1)
414 		options->allow_agent_forwarding = 1;
415 	if (options->fwd_opts.gateway_ports == -1)
416 		options->fwd_opts.gateway_ports = 0;
417 	if (options->max_startups == -1)
418 		options->max_startups = 100;
419 	if (options->max_startups_rate == -1)
420 		options->max_startups_rate = 30;		/* 30% */
421 	if (options->max_startups_begin == -1)
422 		options->max_startups_begin = 10;
423 	if (options->per_source_max_startups == -1)
424 		options->per_source_max_startups = INT_MAX;
425 	if (options->per_source_masklen_ipv4 == -1)
426 		options->per_source_masklen_ipv4 = 32;
427 	if (options->per_source_masklen_ipv6 == -1)
428 		options->per_source_masklen_ipv6 = 128;
429 	if (options->per_source_penalty.enabled == -1)
430 		options->per_source_penalty.enabled = 1;
431 	if (options->per_source_penalty.max_sources4 == -1)
432 		options->per_source_penalty.max_sources4 = 65536;
433 	if (options->per_source_penalty.max_sources6 == -1)
434 		options->per_source_penalty.max_sources6 = 65536;
435 	if (options->per_source_penalty.overflow_mode == -1)
436 		options->per_source_penalty.overflow_mode = PER_SOURCE_PENALTY_OVERFLOW_PERMISSIVE;
437 	if (options->per_source_penalty.overflow_mode6 == -1)
438 		options->per_source_penalty.overflow_mode6 = options->per_source_penalty.overflow_mode;
439 	if (options->per_source_penalty.penalty_crash < 0.0)
440 		options->per_source_penalty.penalty_crash = 90.0;
441 	if (options->per_source_penalty.penalty_grace < 0.0)
442 		options->per_source_penalty.penalty_grace = 10.0;
443 	if (options->per_source_penalty.penalty_authfail < 0.0)
444 		options->per_source_penalty.penalty_authfail = 5.0;
445 	if (options->per_source_penalty.penalty_invaliduser < 0.0)
446 		options->per_source_penalty.penalty_invaliduser = 5.0;
447 	if (options->per_source_penalty.penalty_noauth < 0.0)
448 		options->per_source_penalty.penalty_noauth = 1.0;
449 	if (options->per_source_penalty.penalty_refuseconnection < 0.0)
450 		options->per_source_penalty.penalty_refuseconnection = 10.0;
451 	if (options->per_source_penalty.penalty_min < 0.0)
452 		options->per_source_penalty.penalty_min = 15.0;
453 	if (options->per_source_penalty.penalty_max < 0.0)
454 		options->per_source_penalty.penalty_max = 600.0;
455 	if (options->max_authtries == -1)
456 		options->max_authtries = DEFAULT_AUTH_FAIL_MAX;
457 	if (options->max_sessions == -1)
458 		options->max_sessions = DEFAULT_SESSIONS_MAX;
459 	if (options->use_dns == -1)
460 		options->use_dns = 1;
461 	if (options->client_alive_interval == -1)
462 		options->client_alive_interval = 0;
463 	if (options->client_alive_count_max == -1)
464 		options->client_alive_count_max = 3;
465 	if (options->num_authkeys_files == 0) {
466 		opt_array_append(defaultkey, 0, "AuthorizedKeysFiles",
467 		    &options->authorized_keys_files,
468 		    &options->num_authkeys_files,
469 		    _PATH_SSH_USER_PERMITTED_KEYS);
470 		opt_array_append(defaultkey, 0, "AuthorizedKeysFiles",
471 		    &options->authorized_keys_files,
472 		    &options->num_authkeys_files,
473 		    _PATH_SSH_USER_PERMITTED_KEYS2);
474 	}
475 	if (options->permit_tun == -1)
476 		options->permit_tun = SSH_TUNMODE_NO;
477 	if (options->ip_qos_interactive == -1)
478 		options->ip_qos_interactive = IPTOS_DSCP_EF;
479 	if (options->ip_qos_bulk == -1)
480 		options->ip_qos_bulk = IPTOS_DSCP_CS0;
481 	if (options->version_addendum == NULL)
482 		options->version_addendum = xstrdup(SSH_VERSION_FREEBSD);
483 	if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
484 		options->fwd_opts.streamlocal_bind_mask = 0177;
485 	if (options->fwd_opts.streamlocal_bind_unlink == -1)
486 		options->fwd_opts.streamlocal_bind_unlink = 0;
487 	if (options->fingerprint_hash == -1)
488 		options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
489 	if (options->disable_forwarding == -1)
490 		options->disable_forwarding = 0;
491 	if (options->expose_userauth_info == -1)
492 		options->expose_userauth_info = 0;
493 	if (options->sk_provider == NULL)
494 		options->sk_provider = xstrdup("internal");
495 	if (options->required_rsa_size == -1)
496 		options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
497 	if (options->unused_connection_timeout == -1)
498 		options->unused_connection_timeout = 0;
499 	if (options->sshd_session_path == NULL)
500 		options->sshd_session_path = xstrdup(_PATH_SSHD_SESSION);
501 	if (options->sshd_auth_path == NULL)
502 		options->sshd_auth_path = xstrdup(_PATH_SSHD_AUTH);
503 	if (options->refuse_connection == -1)
504 		options->refuse_connection = 0;
505 	if (options->use_blocklist == -1)
506 		options->use_blocklist = 0;
507 
508 	assemble_algorithms(options);
509 
510 #define CLEAR_ON_NONE(v) \
511 	do { \
512 		if (option_clear_or_none(v)) { \
513 			free(v); \
514 			v = NULL; \
515 		} \
516 	} while(0)
517 #define CLEAR_ON_NONE_ARRAY(v, nv, none) \
518 	do { \
519 		if (options->nv == 1 && \
520 		    strcasecmp(options->v[0], none) == 0) { \
521 			free(options->v[0]); \
522 			free(options->v); \
523 			options->v = NULL; \
524 			options->nv = 0; \
525 		} \
526 	} while (0)
527 	CLEAR_ON_NONE(options->pid_file);
528 	CLEAR_ON_NONE(options->xauth_location);
529 	CLEAR_ON_NONE(options->banner);
530 	CLEAR_ON_NONE(options->trusted_user_ca_keys);
531 	CLEAR_ON_NONE(options->sk_provider);
532 	CLEAR_ON_NONE(options->authorized_principals_file);
533 	CLEAR_ON_NONE(options->adm_forced_command);
534 	CLEAR_ON_NONE(options->chroot_directory);
535 	CLEAR_ON_NONE(options->routing_domain);
536 	CLEAR_ON_NONE(options->host_key_agent);
537 	CLEAR_ON_NONE(options->per_source_penalty_exempt);
538 
539 	for (i = 0; i < options->num_host_key_files; i++)
540 		CLEAR_ON_NONE(options->host_key_files[i]);
541 	for (i = 0; i < options->num_host_cert_files; i++)
542 		CLEAR_ON_NONE(options->host_cert_files[i]);
543 
544 	CLEAR_ON_NONE_ARRAY(channel_timeouts, num_channel_timeouts, "none");
545 	CLEAR_ON_NONE_ARRAY(auth_methods, num_auth_methods, "any");
546 	CLEAR_ON_NONE_ARRAY(revoked_keys_files, num_revoked_keys_files, "none");
547 	CLEAR_ON_NONE_ARRAY(authorized_keys_files, num_authkeys_files, "none");
548 #undef CLEAR_ON_NONE
549 #undef CLEAR_ON_NONE_ARRAY
550 }
551 
552 /* Keyword tokens. */
553 typedef enum {
554 	sBadOption,		/* == unknown option */
555 	/* Portable-specific options */
556 	sUsePAM, sPAMServiceName,
557 	/* Standard Options */
558 	sPort, sHostKeyFile, sLoginGraceTime,
559 	sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose,
560 	sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
561 	sKerberosGetAFSToken, sPasswordAuthentication,
562 	sKbdInteractiveAuthentication, sListenAddress, sAddressFamily,
563 	sPrintMotd, sPrintLastLog, sIgnoreRhosts,
564 	sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
565 	sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive,
566 	sPermitUserEnvironment, sAllowTcpForwarding, sCompression,
567 	sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
568 	sIgnoreUserKnownHosts, sCiphers, sMacs, sPidFile, sModuliFile,
569 	sGatewayPorts, sPubkeyAuthentication, sPubkeyAcceptedAlgorithms,
570 	sXAuthLocation, sSubsystem, sMaxStartups, sMaxAuthTries, sMaxSessions,
571 	sBanner, sUseDNS, sHostbasedAuthentication,
572 	sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedAlgorithms,
573 	sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize,
574 	sPerSourcePenalties, sPerSourcePenaltyExemptList,
575 	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
576 	sGssAuthentication, sGssCleanupCreds, sGssDelegateCreds, sGssStrictAcceptor,
577 	sAcceptEnv, sSetEnv, sPermitTunnel,
578 	sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory,
579 	sUsePrivilegeSeparation, sAllowAgentForwarding,
580 	sHostCertificate, sInclude,
581 	sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
582 	sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser,
583 	sKexAlgorithms, sCASignatureAlgorithms, sIPQoS, sVersionAddendum,
584 	sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
585 	sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
586 	sStreamLocalBindMask, sStreamLocalBindUnlink,
587 	sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
588 	sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider,
589 	sRequiredRSASize, sChannelTimeout, sUnusedConnectionTimeout,
590 	sSshdSessionPath, sSshdAuthPath, sRefuseConnection,
591 	sUseBlocklist,
592 	sDeprecated, sIgnore, sUnsupported
593 } ServerOpCodes;
594 
595 #define SSHCFG_GLOBAL		0x01	/* allowed in main section of config */
596 #define SSHCFG_MATCH		0x02	/* allowed inside a Match section */
597 #define SSHCFG_ALL		(SSHCFG_GLOBAL|SSHCFG_MATCH)
598 #define SSHCFG_NEVERMATCH	0x04  /* Match never matches; internal only */
599 #define SSHCFG_MATCH_ONLY	0x08  /* Match only in conditional blocks; internal only */
600 
601 /* Textual representation of the tokens. */
602 static struct {
603 	const char *name;
604 	ServerOpCodes opcode;
605 	u_int flags;
606 } keywords[] = {
607 	/* Portable-specific options */
608 #ifdef USE_PAM
609 	{ "usepam", sUsePAM, SSHCFG_GLOBAL },
610 	{ "pamservicename", sPAMServiceName, SSHCFG_ALL },
611 #else
612 	{ "usepam", sUnsupported, SSHCFG_GLOBAL },
613 	{ "pamservicename", sUnsupported, SSHCFG_ALL },
614 #endif
615 	{ "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
616 	/* Standard Options */
617 	{ "port", sPort, SSHCFG_GLOBAL },
618 	{ "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
619 	{ "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL },		/* alias */
620 	{ "hostkeyagent", sHostKeyAgent, SSHCFG_GLOBAL },
621 	{ "pidfile", sPidFile, SSHCFG_GLOBAL },
622 	{ "modulifile", sModuliFile, SSHCFG_GLOBAL },
623 	{ "serverkeybits", sDeprecated, SSHCFG_GLOBAL },
624 	{ "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL },
625 	{ "keyregenerationinterval", sDeprecated, SSHCFG_GLOBAL },
626 	{ "permitrootlogin", sPermitRootLogin, SSHCFG_ALL },
627 	{ "syslogfacility", sLogFacility, SSHCFG_GLOBAL },
628 	{ "loglevel", sLogLevel, SSHCFG_ALL },
629 	{ "logverbose", sLogVerbose, SSHCFG_ALL },
630 	{ "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL },
631 	{ "rhostsrsaauthentication", sDeprecated, SSHCFG_ALL },
632 	{ "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL },
633 	{ "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_ALL },
634 	{ "hostbasedacceptedalgorithms", sHostbasedAcceptedAlgorithms, SSHCFG_ALL },
635 	{ "hostbasedacceptedkeytypes", sHostbasedAcceptedAlgorithms, SSHCFG_ALL }, /* obsolete */
636 	{ "hostkeyalgorithms", sHostKeyAlgorithms, SSHCFG_GLOBAL },
637 	{ "rsaauthentication", sDeprecated, SSHCFG_ALL },
638 	{ "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL },
639 	{ "pubkeyacceptedalgorithms", sPubkeyAcceptedAlgorithms, SSHCFG_ALL },
640 	{ "pubkeyacceptedkeytypes", sPubkeyAcceptedAlgorithms, SSHCFG_ALL }, /* obsolete */
641 	{ "pubkeyauthoptions", sPubkeyAuthOptions, SSHCFG_ALL },
642 	{ "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */
643 #ifdef KRB5
644 	{ "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL },
645 	{ "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL },
646 	{ "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL },
647 #ifdef USE_AFS
648 	{ "kerberosgetafstoken", sKerberosGetAFSToken, SSHCFG_GLOBAL },
649 #else
650 	{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
651 #endif
652 #else
653 	{ "kerberosauthentication", sUnsupported, SSHCFG_ALL },
654 	{ "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
655 	{ "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
656 	{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
657 #endif
658 	{ "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
659 	{ "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
660 #ifdef GSSAPI
661 	{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
662 	{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
663 	{ "gssapidelegatecredentials", sGssDelegateCreds, SSHCFG_GLOBAL },
664 	{ "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
665 #else
666 	{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
667 	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
668 	{ "gssapidelegatecredentials", sUnsupported, SSHCFG_GLOBAL },
669 	{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
670 #endif
671 	{ "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
672 	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
673 	{ "challengeresponseauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */
674 	{ "skeyauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */
675 	{ "checkmail", sDeprecated, SSHCFG_GLOBAL },
676 	{ "listenaddress", sListenAddress, SSHCFG_GLOBAL },
677 	{ "addressfamily", sAddressFamily, SSHCFG_GLOBAL },
678 	{ "printmotd", sPrintMotd, SSHCFG_GLOBAL },
679 #ifdef DISABLE_LASTLOG
680 	{ "printlastlog", sUnsupported, SSHCFG_GLOBAL },
681 #else
682 	{ "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
683 #endif
684 	{ "ignorerhosts", sIgnoreRhosts, SSHCFG_ALL },
685 	{ "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
686 	{ "x11forwarding", sX11Forwarding, SSHCFG_ALL },
687 	{ "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
688 	{ "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
689 	{ "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
690 	{ "strictmodes", sStrictModes, SSHCFG_GLOBAL },
691 	{ "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL },
692 	{ "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
693 	{ "uselogin", sDeprecated, SSHCFG_GLOBAL },
694 	{ "compression", sCompression, SSHCFG_GLOBAL },
695 	{ "rekeylimit", sRekeyLimit, SSHCFG_ALL },
696 	{ "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
697 	{ "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL },	/* obsolete alias */
698 	{ "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
699 	{ "allowagentforwarding", sAllowAgentForwarding, SSHCFG_ALL },
700 	{ "allowusers", sAllowUsers, SSHCFG_ALL },
701 	{ "denyusers", sDenyUsers, SSHCFG_ALL },
702 	{ "allowgroups", sAllowGroups, SSHCFG_ALL },
703 	{ "denygroups", sDenyGroups, SSHCFG_ALL },
704 	{ "ciphers", sCiphers, SSHCFG_GLOBAL },
705 	{ "macs", sMacs, SSHCFG_GLOBAL },
706 	{ "protocol", sIgnore, SSHCFG_GLOBAL },
707 	{ "gatewayports", sGatewayPorts, SSHCFG_ALL },
708 	{ "subsystem", sSubsystem, SSHCFG_ALL },
709 	{ "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
710 	{ "persourcemaxstartups", sPerSourceMaxStartups, SSHCFG_GLOBAL },
711 	{ "persourcenetblocksize", sPerSourceNetBlockSize, SSHCFG_GLOBAL },
712 	{ "persourcepenalties", sPerSourcePenalties, SSHCFG_GLOBAL },
713 	{ "persourcepenaltyexemptlist", sPerSourcePenaltyExemptList, SSHCFG_GLOBAL },
714 	{ "maxauthtries", sMaxAuthTries, SSHCFG_ALL },
715 	{ "maxsessions", sMaxSessions, SSHCFG_ALL },
716 	{ "banner", sBanner, SSHCFG_ALL },
717 	{ "usedns", sUseDNS, SSHCFG_GLOBAL },
718 	{ "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
719 	{ "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL },
720 	{ "clientaliveinterval", sClientAliveInterval, SSHCFG_ALL },
721 	{ "clientalivecountmax", sClientAliveCountMax, SSHCFG_ALL },
722 	{ "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_ALL },
723 	{ "authorizedkeysfile2", sDeprecated, SSHCFG_ALL },
724 	{ "useprivilegeseparation", sDeprecated, SSHCFG_GLOBAL},
725 	{ "acceptenv", sAcceptEnv, SSHCFG_ALL },
726 	{ "setenv", sSetEnv, SSHCFG_ALL },
727 	{ "permittunnel", sPermitTunnel, SSHCFG_ALL },
728 	{ "permittty", sPermitTTY, SSHCFG_ALL },
729 	{ "permituserrc", sPermitUserRC, SSHCFG_ALL },
730 	{ "match", sMatch, SSHCFG_ALL },
731 	{ "permitopen", sPermitOpen, SSHCFG_ALL },
732 	{ "permitlisten", sPermitListen, SSHCFG_ALL },
733 	{ "forcecommand", sForceCommand, SSHCFG_ALL },
734 	{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
735 	{ "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
736 	{ "revokedkeys", sRevokedKeys, SSHCFG_ALL },
737 	{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
738 	{ "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
739 	{ "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
740 	{ "include", sInclude, SSHCFG_ALL },
741 	{ "ipqos", sIPQoS, SSHCFG_ALL },
742 	{ "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
743 	{ "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
744 	{ "authorizedprincipalscommand", sAuthorizedPrincipalsCommand, SSHCFG_ALL },
745 	{ "authorizedprincipalscommanduser", sAuthorizedPrincipalsCommandUser, SSHCFG_ALL },
746 	{ "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL },
747 	{ "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL },
748 	{ "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_ALL },
749 	{ "streamlocalbindunlink", sStreamLocalBindUnlink, SSHCFG_ALL },
750 	{ "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL },
751 	{ "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL },
752 	{ "disableforwarding", sDisableForwarding, SSHCFG_ALL },
753 	{ "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL },
754 	{ "rdomain", sRDomain, SSHCFG_ALL },
755 	{ "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL },
756 	{ "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL },
757 	{ "requiredrsasize", sRequiredRSASize, SSHCFG_ALL },
758 	{ "channeltimeout", sChannelTimeout, SSHCFG_ALL },
759 	{ "unusedconnectiontimeout", sUnusedConnectionTimeout, SSHCFG_ALL },
760 	{ "sshdsessionpath", sSshdSessionPath, SSHCFG_GLOBAL },
761 	{ "sshdauthpath", sSshdAuthPath, SSHCFG_GLOBAL },
762 	{ "refuseconnection", sRefuseConnection, SSHCFG_ALL },
763 	{ "useblocklist", sUseBlocklist, SSHCFG_GLOBAL },
764 	{ "useblacklist", sUseBlocklist, SSHCFG_GLOBAL }, /* alias */
765 
766 	{ NULL, sBadOption, 0 }
767 };
768 
769 static struct {
770 	int val;
771 	char *text;
772 } tunmode_desc[] = {
773 	{ SSH_TUNMODE_NO, "no" },
774 	{ SSH_TUNMODE_POINTOPOINT, "point-to-point" },
775 	{ SSH_TUNMODE_ETHERNET, "ethernet" },
776 	{ SSH_TUNMODE_YES, "yes" },
777 	{ -1, NULL }
778 };
779 
780 /* Returns an opcode name from its number */
781 
782 static const char *
lookup_opcode_name(ServerOpCodes code)783 lookup_opcode_name(ServerOpCodes code)
784 {
785 	u_int i;
786 
787 	for (i = 0; keywords[i].name != NULL; i++)
788 		if (keywords[i].opcode == code)
789 			return(keywords[i].name);
790 	return "UNKNOWN";
791 }
792 
793 
794 /*
795  * Returns the number of the token pointed to by cp or sBadOption.
796  */
797 
798 static ServerOpCodes
parse_token(const char * cp,const char * filename,int linenum,u_int * flags)799 parse_token(const char *cp, const char *filename,
800 	    int linenum, u_int *flags)
801 {
802 	u_int i;
803 
804 	for (i = 0; keywords[i].name; i++)
805 		if (strcasecmp(cp, keywords[i].name) == 0) {
806 			*flags = keywords[i].flags;
807 			return keywords[i].opcode;
808 		}
809 
810 	error("%s: line %d: Bad configuration option: %s",
811 	    filename, linenum, cp);
812 	return sBadOption;
813 }
814 
815 char *
derelativise_path(const char * path)816 derelativise_path(const char *path)
817 {
818 	char *expanded, *ret, cwd[PATH_MAX];
819 
820 	if (strcasecmp(path, "none") == 0)
821 		return xstrdup("none");
822 	expanded = tilde_expand_filename(path, getuid());
823 	if (path_absolute(expanded))
824 		return expanded;
825 	if (getcwd(cwd, sizeof(cwd)) == NULL)
826 		fatal_f("getcwd: %s", strerror(errno));
827 	xasprintf(&ret, "%s/%s", cwd, expanded);
828 	free(expanded);
829 	return ret;
830 }
831 
832 static void
add_listen_addr(ServerOptions * options,const char * addr,const char * rdomain,int port)833 add_listen_addr(ServerOptions *options, const char *addr,
834     const char *rdomain, int port)
835 {
836 	u_int i;
837 
838 	if (port > 0)
839 		add_one_listen_addr(options, addr, rdomain, port);
840 	else {
841 		for (i = 0; i < options->num_ports; i++) {
842 			add_one_listen_addr(options, addr, rdomain,
843 			    options->ports[i]);
844 		}
845 	}
846 }
847 
848 static void
add_one_listen_addr(ServerOptions * options,const char * addr,const char * rdomain,int port)849 add_one_listen_addr(ServerOptions *options, const char *addr,
850     const char *rdomain, int port)
851 {
852 	struct addrinfo hints, *ai, *aitop;
853 	char strport[NI_MAXSERV];
854 	int gaierr;
855 	u_int i;
856 
857 	/* Find listen_addrs entry for this rdomain */
858 	for (i = 0; i < options->num_listen_addrs; i++) {
859 		if (rdomain == NULL && options->listen_addrs[i].rdomain == NULL)
860 			break;
861 		if (rdomain == NULL || options->listen_addrs[i].rdomain == NULL)
862 			continue;
863 		if (strcmp(rdomain, options->listen_addrs[i].rdomain) == 0)
864 			break;
865 	}
866 	if (i >= options->num_listen_addrs) {
867 		/* No entry for this rdomain; allocate one */
868 		if (i >= INT_MAX)
869 			fatal_f("too many listen addresses");
870 		options->listen_addrs = xrecallocarray(options->listen_addrs,
871 		    options->num_listen_addrs, options->num_listen_addrs + 1,
872 		    sizeof(*options->listen_addrs));
873 		i = options->num_listen_addrs++;
874 		if (rdomain != NULL)
875 			options->listen_addrs[i].rdomain = xstrdup(rdomain);
876 	}
877 	/* options->listen_addrs[i] points to the addresses for this rdomain */
878 
879 	memset(&hints, 0, sizeof(hints));
880 	hints.ai_family = options->address_family;
881 	hints.ai_socktype = SOCK_STREAM;
882 	hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
883 	snprintf(strport, sizeof strport, "%d", port);
884 	if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
885 		fatal("bad addr or host: %s (%s)",
886 		    addr ? addr : "<NULL>",
887 		    ssh_gai_strerror(gaierr));
888 	for (ai = aitop; ai->ai_next; ai = ai->ai_next)
889 		;
890 	ai->ai_next = options->listen_addrs[i].addrs;
891 	options->listen_addrs[i].addrs = aitop;
892 }
893 
894 /* Returns nonzero if the routing domain name is valid */
895 static int
valid_rdomain(const char * name)896 valid_rdomain(const char *name)
897 {
898 #if defined(HAVE_SYS_VALID_RDOMAIN)
899 	return sys_valid_rdomain(name);
900 #elif defined(__OpenBSD__)
901 	const char *errstr;
902 	long long num;
903 	struct rt_tableinfo info;
904 	int mib[6];
905 	size_t miblen = sizeof(mib);
906 
907 	if (name == NULL)
908 		return 1;
909 
910 	num = strtonum(name, 0, 255, &errstr);
911 	if (errstr != NULL)
912 		return 0;
913 
914 	/* Check whether the table actually exists */
915 	memset(mib, 0, sizeof(mib));
916 	mib[0] = CTL_NET;
917 	mib[1] = PF_ROUTE;
918 	mib[4] = NET_RT_TABLE;
919 	mib[5] = (int)num;
920 	if (sysctl(mib, 6, &info, &miblen, NULL, 0) == -1)
921 		return 0;
922 
923 	return 1;
924 #else /* defined(__OpenBSD__) */
925 	error("Routing domains are not supported on this platform");
926 	return 0;
927 #endif
928 }
929 
930 /*
931  * Queue a ListenAddress to be processed once we have all of the Ports
932  * and AddressFamily options.
933  */
934 static void
queue_listen_addr(ServerOptions * options,const char * addr,const char * rdomain,int port)935 queue_listen_addr(ServerOptions *options, const char *addr,
936     const char *rdomain, int port)
937 {
938 	struct queued_listenaddr *qla;
939 
940 	options->queued_listen_addrs = xrecallocarray(
941 	    options->queued_listen_addrs,
942 	    options->num_queued_listens, options->num_queued_listens + 1,
943 	    sizeof(*options->queued_listen_addrs));
944 	qla = &options->queued_listen_addrs[options->num_queued_listens++];
945 	qla->addr = xstrdup(addr);
946 	qla->port = port;
947 	qla->rdomain = rdomain == NULL ? NULL : xstrdup(rdomain);
948 }
949 
950 /*
951  * Process queued (text) ListenAddress entries.
952  */
953 static void
process_queued_listen_addrs(ServerOptions * options)954 process_queued_listen_addrs(ServerOptions *options)
955 {
956 	u_int i;
957 	struct queued_listenaddr *qla;
958 
959 	if (options->num_ports == 0)
960 		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
961 	if (options->address_family == -1)
962 		options->address_family = AF_UNSPEC;
963 
964 	for (i = 0; i < options->num_queued_listens; i++) {
965 		qla = &options->queued_listen_addrs[i];
966 		add_listen_addr(options, qla->addr, qla->rdomain, qla->port);
967 		free(qla->addr);
968 		free(qla->rdomain);
969 	}
970 	free(options->queued_listen_addrs);
971 	options->queued_listen_addrs = NULL;
972 	options->num_queued_listens = 0;
973 }
974 
975 /*
976  * The strategy for the Match blocks is that the config file is parsed twice.
977  *
978  * The first time is at startup.  activep is initialized to 1 and the
979  * directives in the global context are processed and acted on.  Hitting a
980  * Match directive unsets activep and the directives inside the block are
981  * checked for syntax only.
982  *
983  * The second time is after a connection has been established but before
984  * authentication.  activep is initialized to 2 and global config directives
985  * are ignored since they have already been processed.  If the criteria in a
986  * Match block is met, activep is set and the subsequent directives
987  * processed and actioned until EOF or another Match block unsets it.  Any
988  * options set are copied into the main server config.
989  *
990  * Potential additions/improvements:
991  *  - Add Match support for pre-kex directives, eg. Ciphers.
992  *
993  *  - Add a Tag directive (idea from David Leonard) ala pf, eg:
994  *	Match Address 192.168.0.*
995  *		Tag trusted
996  *	Match Group wheel
997  *		Tag trusted
998  *	Match Tag trusted
999  *		AllowTcpForwarding yes
1000  *		GatewayPorts clientspecified
1001  *		[...]
1002  *
1003  *  - Add a PermittedChannelRequests directive
1004  *	Match Group shell
1005  *		PermittedChannelRequests session,forwarded-tcpip
1006  */
1007 
1008 static int
match_cfg_line_group(const char * grps,int line,const char * user)1009 match_cfg_line_group(const char *grps, int line, const char *user)
1010 {
1011 	int result = 0;
1012 	struct passwd *pw;
1013 
1014 	if (user == NULL)
1015 		goto out;
1016 
1017 	if ((pw = getpwnam(user)) == NULL) {
1018 		debug("Can't match group at line %d because user %.100s does "
1019 		    "not exist", line, user);
1020 	} else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
1021 		debug("Can't Match group because user %.100s not in any group "
1022 		    "at line %d", user, line);
1023 	} else if (ga_match_pattern_list(grps) != 1) {
1024 		debug("user %.100s does not match group list %.100s at line %d",
1025 		    user, grps, line);
1026 	} else {
1027 		debug("user %.100s matched group list %.100s at line %d", user,
1028 		    grps, line);
1029 		result = 1;
1030 	}
1031 out:
1032 	ga_free();
1033 	return result;
1034 }
1035 
1036 static void
match_test_missing_fatal(const char * criteria,const char * attrib)1037 match_test_missing_fatal(const char *criteria, const char *attrib)
1038 {
1039 	fatal("'Match %s' in configuration but '%s' not in connection "
1040 	    "test specification.", criteria, attrib);
1041 }
1042 
1043 /*
1044  * All of the attributes on a single Match line are ANDed together, so we need
1045  * to check every attribute and set the result to zero if any attribute does
1046  * not match.
1047  */
1048 static int
match_cfg_line(const char * full_line,int * acp,char *** avp,int line,struct connection_info * ci)1049 match_cfg_line(const char *full_line, int *acp, char ***avp,
1050     int line, struct connection_info *ci)
1051 {
1052 	int result = 1, attributes = 0, port;
1053 	char *arg, *attrib = NULL, *oattrib;
1054 
1055 	if (ci == NULL) {
1056 		debug3("checking syntax for 'Match %s' on line %d",
1057 		    full_line, line);
1058 	} else {
1059 		debug3("checking match for '%s' user %s%s host %s addr %s "
1060 		    "laddr %s lport %d on line %d", full_line,
1061 		    ci->user ? ci->user : "(null)",
1062 		    ci->user_invalid ? " (invalid)" : "",
1063 		    ci->host ? ci->host : "(null)",
1064 		    ci->address ? ci->address : "(null)",
1065 		    ci->laddress ? ci->laddress : "(null)", ci->lport, line);
1066 	}
1067 
1068 	while ((oattrib = argv_next(acp, avp)) != NULL) {
1069 		/* Terminate on comment */
1070 		if (*oattrib == '#') {
1071 			argv_consume(acp); /* mark all arguments consumed */
1072 			break;
1073 		}
1074 		attrib = xstrdup(oattrib);
1075 		arg = NULL;
1076 		attributes++;
1077 		/* Criterion "all" has no argument and must appear alone */
1078 		if (strcasecmp(attrib, "all") == 0) {
1079 			if (attributes > 1 ||
1080 			    ((arg = argv_next(acp, avp)) != NULL &&
1081 			    *arg != '\0' && *arg != '#')) {
1082 				error("'all' cannot be combined with other "
1083 				    "Match attributes");
1084 				result = -1;
1085 				goto out;
1086 			}
1087 			if (arg != NULL && *arg == '#')
1088 				argv_consume(acp); /* consume remaining args */
1089 			result = 1;
1090 			goto out;
1091 		}
1092 		/* Criterion "invalid-user" also has no argument */
1093 		if (strcasecmp(attrib, "invalid-user") == 0) {
1094 			if (ci == NULL) {
1095 				result = 0;
1096 				goto next;
1097 			}
1098 			if (ci->user_invalid == 0)
1099 				result = 0;
1100 			else
1101 				debug("matched invalid-user at line %d", line);
1102 			goto next;
1103 		}
1104 
1105 		/* Keep this list in sync with below */
1106 		if (strprefix(attrib, "user=", 1) != NULL ||
1107 		    strprefix(attrib, "group=", 1) != NULL ||
1108 		    strprefix(attrib, "host=", 1) != NULL ||
1109 		    strprefix(attrib, "address=", 1) != NULL ||
1110 		    strprefix(attrib, "localaddress=", 1) != NULL ||
1111 		    strprefix(attrib, "localport=", 1) != NULL ||
1112 		    strprefix(attrib, "rdomain=", 1) != NULL ||
1113 		    strprefix(attrib, "version=", 1) != NULL) {
1114 			arg = strchr(attrib, '=');
1115 			*(arg++) = '\0';
1116 		} else {
1117 			arg = argv_next(acp, avp);
1118 		}
1119 
1120 		/* All other criteria require an argument */
1121 		if (arg == NULL || *arg == '\0' || *arg == '#') {
1122 			error("Missing Match criteria for %s", attrib);
1123 			result = -1;
1124 			goto out;
1125 		}
1126 		if (strcasecmp(attrib, "user") == 0) {
1127 			if (ci == NULL || (ci->test && ci->user == NULL)) {
1128 				result = 0;
1129 				goto next;
1130 			}
1131 			if (ci->user == NULL)
1132 				match_test_missing_fatal("User", "user");
1133 			if (match_usergroup_pattern_list(ci->user, arg) != 1)
1134 				result = 0;
1135 			else
1136 				debug("user %.100s matched 'User %.100s' at "
1137 				    "line %d", ci->user, arg, line);
1138 		} else if (strcasecmp(attrib, "group") == 0) {
1139 			if (ci == NULL || (ci->test && ci->user == NULL)) {
1140 				result = 0;
1141 				goto next;
1142 			}
1143 			if (ci->user == NULL)
1144 				match_test_missing_fatal("Group", "user");
1145 			switch (match_cfg_line_group(arg, line, ci->user)) {
1146 			case -1:
1147 				result = -1;
1148 				goto out;
1149 			case 0:
1150 				result = 0;
1151 			}
1152 		} else if (strcasecmp(attrib, "host") == 0) {
1153 			if (ci == NULL || (ci->test && ci->host == NULL)) {
1154 				result = 0;
1155 				goto next;
1156 			}
1157 			if (ci->host == NULL)
1158 				match_test_missing_fatal("Host", "host");
1159 			if (match_hostname(ci->host, arg) != 1)
1160 				result = 0;
1161 			else
1162 				debug("connection from %.100s matched 'Host "
1163 				    "%.100s' at line %d", ci->host, arg, line);
1164 		} else if (strcasecmp(attrib, "address") == 0) {
1165 			if (ci == NULL || (ci->test && ci->address == NULL)) {
1166 				if (addr_match_list(NULL, arg) != 0)
1167 					fatal("Invalid Match address argument "
1168 					    "'%s' at line %d", arg, line);
1169 				result = 0;
1170 				goto next;
1171 			}
1172 			if (ci->address == NULL)
1173 				match_test_missing_fatal("Address", "addr");
1174 			switch (addr_match_list(ci->address, arg)) {
1175 			case 1:
1176 				debug("connection from %.100s matched 'Address "
1177 				    "%.100s' at line %d", ci->address, arg, line);
1178 				break;
1179 			case 0:
1180 			case -1:
1181 				result = 0;
1182 				break;
1183 			case -2:
1184 				result = -1;
1185 				goto out;
1186 			}
1187 		} else if (strcasecmp(attrib, "localaddress") == 0){
1188 			if (ci == NULL || (ci->test && ci->laddress == NULL)) {
1189 				if (addr_match_list(NULL, arg) != 0)
1190 					fatal("Invalid Match localaddress "
1191 					    "argument '%s' at line %d", arg,
1192 					    line);
1193 				result = 0;
1194 				goto next;
1195 			}
1196 			if (ci->laddress == NULL)
1197 				match_test_missing_fatal("LocalAddress",
1198 				    "laddr");
1199 			switch (addr_match_list(ci->laddress, arg)) {
1200 			case 1:
1201 				debug("connection from %.100s matched "
1202 				    "'LocalAddress %.100s' at line %d",
1203 				    ci->laddress, arg, line);
1204 				break;
1205 			case 0:
1206 			case -1:
1207 				result = 0;
1208 				break;
1209 			case -2:
1210 				result = -1;
1211 				goto out;
1212 			}
1213 		} else if (strcasecmp(attrib, "localport") == 0) {
1214 			if ((port = a2port(arg)) == -1) {
1215 				error("Invalid LocalPort '%s' on Match line",
1216 				    arg);
1217 				result = -1;
1218 				goto out;
1219 			}
1220 			if (ci == NULL || (ci->test && ci->lport == -1)) {
1221 				result = 0;
1222 				goto next;
1223 			}
1224 			if (ci->lport == 0)
1225 				match_test_missing_fatal("LocalPort", "lport");
1226 			/* TODO support port lists */
1227 			if (port == ci->lport)
1228 				debug("connection from %.100s matched "
1229 				    "'LocalPort %d' at line %d",
1230 				    ci->laddress, port, line);
1231 			else
1232 				result = 0;
1233 		} else if (strcasecmp(attrib, "rdomain") == 0) {
1234 			if (ci == NULL || (ci->test && ci->rdomain == NULL)) {
1235 				result = 0;
1236 				goto next;
1237 			}
1238 			if (ci->rdomain == NULL)
1239 				match_test_missing_fatal("RDomain", "rdomain");
1240 			if (match_pattern_list(ci->rdomain, arg, 0) != 1)
1241 				result = 0;
1242 			else
1243 				debug("connection RDomain %.100s matched "
1244 				    "'RDomain %.100s' at line %d",
1245 				    ci->rdomain, arg, line);
1246 		} else if (strcasecmp(attrib, "version") == 0) {
1247 			if (match_pattern_list(SSH_RELEASE, arg, 0) != 1)
1248 				result = 0;
1249 			else
1250 				debug("version %.100s matched "
1251 				    "'version %.100s' at line %d",
1252 				    SSH_RELEASE, arg, line);
1253 		} else {
1254 			error("Unsupported Match attribute %s", oattrib);
1255 			result = -1;
1256 			goto out;
1257 		}
1258  next:
1259 		free(attrib);
1260 		attrib = NULL;
1261 	}
1262 	if (attributes == 0) {
1263 		error("One or more attributes required for Match");
1264 		return -1;
1265 	}
1266  out:
1267 	if (ci != NULL && result != -1)
1268 		debug3("match %sfound on line %d", result ? "" : "not ", line);
1269 	free(attrib);
1270 	return result;
1271 }
1272 
1273 #define WHITESPACE " \t\r\n"
1274 
1275 /* Multistate option parsing */
1276 struct multistate {
1277 	char *key;
1278 	int value;
1279 };
1280 static const struct multistate multistate_flag[] = {
1281 	{ "yes",			1 },
1282 	{ "no",				0 },
1283 	{ NULL, -1 }
1284 };
1285 static const struct multistate multistate_ignore_rhosts[] = {
1286 	{ "yes",			IGNORE_RHOSTS_YES },
1287 	{ "no",				IGNORE_RHOSTS_NO },
1288 	{ "shosts-only",		IGNORE_RHOSTS_SHOSTS },
1289 	{ NULL, -1 }
1290 };
1291 static const struct multistate multistate_addressfamily[] = {
1292 	{ "inet",			AF_INET },
1293 	{ "inet6",			AF_INET6 },
1294 	{ "any",			AF_UNSPEC },
1295 	{ NULL, -1 }
1296 };
1297 static const struct multistate multistate_permitrootlogin[] = {
1298 	{ "prohibit-password",		PERMIT_NO_PASSWD },
1299 	{ "without-password",		PERMIT_NO_PASSWD },
1300 	{ "forced-commands-only",	PERMIT_FORCED_ONLY },
1301 	{ "yes",			PERMIT_YES },
1302 	{ "no",				PERMIT_NO },
1303 	{ NULL, -1 }
1304 };
1305 static const struct multistate multistate_compression[] = {
1306 #ifdef WITH_ZLIB
1307 	{ "yes",			COMP_DELAYED },
1308 	{ "delayed",			COMP_DELAYED },
1309 #endif
1310 	{ "no",				COMP_NONE },
1311 	{ NULL, -1 }
1312 };
1313 static const struct multistate multistate_gatewayports[] = {
1314 	{ "clientspecified",		2 },
1315 	{ "yes",			1 },
1316 	{ "no",				0 },
1317 	{ NULL, -1 }
1318 };
1319 static const struct multistate multistate_tcpfwd[] = {
1320 	{ "yes",			FORWARD_ALLOW },
1321 	{ "all",			FORWARD_ALLOW },
1322 	{ "no",				FORWARD_DENY },
1323 	{ "remote",			FORWARD_REMOTE },
1324 	{ "local",			FORWARD_LOCAL },
1325 	{ NULL, -1 }
1326 };
1327 
1328 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)1329 process_server_config_line_depth(ServerOptions *options, char *line,
1330     const char *filename, int linenum, int *activep,
1331     struct connection_info *connectinfo, int *inc_flags, int depth,
1332     struct include_list *includes)
1333 {
1334 	char *str, ***chararrayptr, **charptr, *arg, *arg2, *p, *keyword;
1335 	int cmdline = 0, *intptr, value, value2, value3, n, port, oactive, r;
1336 	double dvalue, *doubleptr = NULL;
1337 	int ca_only = 0, found = 0;
1338 	SyslogFacility *log_facility_ptr;
1339 	LogLevel *log_level_ptr;
1340 	ServerOpCodes opcode;
1341 	u_int i, *uintptr, flags = 0;
1342 	size_t len;
1343 	long long val64;
1344 	const struct multistate *multistate_ptr;
1345 	const char *errstr;
1346 	struct include_item *item;
1347 	glob_t gbuf;
1348 	char **oav = NULL, **av;
1349 	int oac = 0, ac;
1350 	int ret = -1;
1351 	char **strs = NULL; /* string array arguments; freed implicitly */
1352 	u_int nstrs = 0;
1353 
1354 	/* Strip trailing whitespace. Allow \f (form feed) at EOL only */
1355 	if ((len = strlen(line)) == 0)
1356 		return 0;
1357 	for (len--; len > 0; len--) {
1358 		if (strchr(WHITESPACE "\f", line[len]) == NULL)
1359 			break;
1360 		line[len] = '\0';
1361 	}
1362 
1363 	str = line;
1364 	if ((keyword = strdelim(&str)) == NULL)
1365 		return 0;
1366 	/* Ignore leading whitespace */
1367 	if (*keyword == '\0')
1368 		keyword = strdelim(&str);
1369 	if (!keyword || !*keyword || *keyword == '#')
1370 		return 0;
1371 	if (str == NULL || *str == '\0') {
1372 		error("%s line %d: no argument after keyword \"%s\"",
1373 		    filename, linenum, keyword);
1374 		return -1;
1375 	}
1376 	intptr = NULL;
1377 	charptr = NULL;
1378 	opcode = parse_token(keyword, filename, linenum, &flags);
1379 
1380 	if (argv_split(str, &oac, &oav, 1) != 0) {
1381 		error("%s line %d: invalid quotes", filename, linenum);
1382 		return -1;
1383 	}
1384 	ac = oac;
1385 	av = oav;
1386 
1387 	if (activep == NULL) { /* We are processing a command line directive */
1388 		cmdline = 1;
1389 		activep = &cmdline;
1390 	}
1391 	if (*activep && opcode != sMatch && opcode != sInclude)
1392 		debug3("%s:%d setting %s %s", filename, linenum, keyword, str);
1393 	if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
1394 		if (connectinfo == NULL) {
1395 			fatal("%s line %d: Directive '%s' is not allowed "
1396 			    "within a Match block", filename, linenum, keyword);
1397 		} else { /* this is a directive we have already processed */
1398 			ret = 0;
1399 			goto out;
1400 		}
1401 	}
1402 
1403 	switch (opcode) {
1404 	/* Portable-specific options */
1405 	case sUsePAM:
1406 		intptr = &options->use_pam;
1407 		goto parse_flag;
1408 	case sPAMServiceName:
1409 		charptr = &options->pam_service_name;
1410 		arg = argv_next(&ac, &av);
1411 		if (!arg || *arg == '\0') {
1412 			fatal("%s line %d: missing argument.",
1413 			    filename, linenum);
1414 		}
1415 		if (*activep && *charptr == NULL)
1416 			*charptr = xstrdup(arg);
1417 		break;
1418 
1419 	/* Standard Options */
1420 	case sBadOption:
1421 		goto out;
1422 	case sPort:
1423 		/* ignore ports from configfile if cmdline specifies ports */
1424 		if (options->ports_from_cmdline) {
1425 			argv_consume(&ac);
1426 			break;
1427 		}
1428 		if (options->num_ports >= MAX_PORTS)
1429 			fatal("%s line %d: too many ports.",
1430 			    filename, linenum);
1431 		arg = argv_next(&ac, &av);
1432 		if (!arg || *arg == '\0')
1433 			fatal("%s line %d: missing port number.",
1434 			    filename, linenum);
1435 		options->ports[options->num_ports++] = a2port(arg);
1436 		if (options->ports[options->num_ports-1] <= 0)
1437 			fatal("%s line %d: Badly formatted port number.",
1438 			    filename, linenum);
1439 		break;
1440 
1441 	case sLoginGraceTime:
1442 		intptr = &options->login_grace_time;
1443  parse_time:
1444 		arg = argv_next(&ac, &av);
1445 		if (!arg || *arg == '\0')
1446 			fatal("%s line %d: missing time value.",
1447 			    filename, linenum);
1448 		if ((value = convtime(arg)) == -1)
1449 			fatal("%s line %d: invalid time value.",
1450 			    filename, linenum);
1451 		if (*activep && *intptr == -1)
1452 			*intptr = value;
1453 		break;
1454 
1455 	case sListenAddress:
1456 		arg = argv_next(&ac, &av);
1457 		if (arg == NULL || *arg == '\0')
1458 			fatal("%s line %d: missing address",
1459 			    filename, linenum);
1460 		/* check for bare IPv6 address: no "[]" and 2 or more ":" */
1461 		if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL
1462 		    && strchr(p+1, ':') != NULL) {
1463 			port = 0;
1464 			p = arg;
1465 		} else {
1466 			arg2 = NULL;
1467 			p = hpdelim(&arg);
1468 			if (p == NULL)
1469 				fatal("%s line %d: bad address:port usage",
1470 				    filename, linenum);
1471 			p = cleanhostname(p);
1472 			if (arg == NULL)
1473 				port = 0;
1474 			else if ((port = a2port(arg)) <= 0)
1475 				fatal("%s line %d: bad port number",
1476 				    filename, linenum);
1477 		}
1478 		/* Optional routing table */
1479 		arg2 = NULL;
1480 		if ((arg = argv_next(&ac, &av)) != NULL) {
1481 			if (strcmp(arg, "rdomain") != 0 ||
1482 			    (arg2 = argv_next(&ac, &av)) == NULL)
1483 				fatal("%s line %d: bad ListenAddress syntax",
1484 				    filename, linenum);
1485 			if (!valid_rdomain(arg2))
1486 				fatal("%s line %d: bad routing domain",
1487 				    filename, linenum);
1488 		}
1489 		queue_listen_addr(options, p, arg2, port);
1490 
1491 		break;
1492 
1493 	case sAddressFamily:
1494 		intptr = &options->address_family;
1495 		multistate_ptr = multistate_addressfamily;
1496  parse_multistate:
1497 		arg = argv_next(&ac, &av);
1498 		if (!arg || *arg == '\0')
1499 			fatal("%s line %d: missing argument.",
1500 			    filename, linenum);
1501 		value = -1;
1502 		for (i = 0; multistate_ptr[i].key != NULL; i++) {
1503 			if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
1504 				value = multistate_ptr[i].value;
1505 				break;
1506 			}
1507 		}
1508 		if (value == -1)
1509 			fatal("%s line %d: unsupported option \"%s\".",
1510 			    filename, linenum, arg);
1511 		if (*activep && *intptr == -1)
1512 			*intptr = value;
1513 		break;
1514 
1515 	case sHostKeyFile:
1516 		arg = argv_next(&ac, &av);
1517 		if (!arg || *arg == '\0')
1518 			fatal("%s line %d: missing file name.",
1519 			    filename, linenum);
1520 		if (*activep) {
1521 			servconf_add_hostkey(filename, linenum,
1522 			    options, arg, 1);
1523 		}
1524 		break;
1525 
1526 	case sHostKeyAgent:
1527 		charptr = &options->host_key_agent;
1528 		arg = argv_next(&ac, &av);
1529 		if (!arg || *arg == '\0')
1530 			fatal("%s line %d: missing socket name.",
1531 			    filename, linenum);
1532 		if (*activep && *charptr == NULL)
1533 			*charptr = !strcmp(arg, SSH_AUTHSOCKET_ENV_NAME) ?
1534 			    xstrdup(arg) : derelativise_path(arg);
1535 		break;
1536 
1537 	case sHostCertificate:
1538 		arg = argv_next(&ac, &av);
1539 		if (!arg || *arg == '\0')
1540 			fatal("%s line %d: missing file name.",
1541 			    filename, linenum);
1542 		if (*activep)
1543 			servconf_add_hostcert(filename, linenum, options, arg);
1544 		break;
1545 
1546 	case sPidFile:
1547 		charptr = &options->pid_file;
1548  parse_filename:
1549 		arg = argv_next(&ac, &av);
1550 		if (!arg || *arg == '\0')
1551 			fatal("%s line %d: missing file name.",
1552 			    filename, linenum);
1553 		if (*activep && *charptr == NULL) {
1554 			*charptr = derelativise_path(arg);
1555 			/* increase optional counter */
1556 			if (intptr != NULL)
1557 				*intptr = *intptr + 1;
1558 		}
1559 		break;
1560 
1561 	case sModuliFile:
1562 		charptr = &options->moduli_file;
1563 		goto parse_filename;
1564 
1565 	case sPermitRootLogin:
1566 		intptr = &options->permit_root_login;
1567 		multistate_ptr = multistate_permitrootlogin;
1568 		goto parse_multistate;
1569 
1570 	case sIgnoreRhosts:
1571 		intptr = &options->ignore_rhosts;
1572 		multistate_ptr = multistate_ignore_rhosts;
1573 		goto parse_multistate;
1574 
1575 	case sIgnoreUserKnownHosts:
1576 		intptr = &options->ignore_user_known_hosts;
1577  parse_flag:
1578 		multistate_ptr = multistate_flag;
1579 		goto parse_multistate;
1580 
1581 	case sHostbasedAuthentication:
1582 		intptr = &options->hostbased_authentication;
1583 		goto parse_flag;
1584 
1585 	case sHostbasedUsesNameFromPacketOnly:
1586 		intptr = &options->hostbased_uses_name_from_packet_only;
1587 		goto parse_flag;
1588 
1589 	case sHostbasedAcceptedAlgorithms:
1590 		charptr = &options->hostbased_accepted_algos;
1591 		ca_only = 0;
1592  parse_pubkey_algos:
1593 		arg = argv_next(&ac, &av);
1594 		if (!arg || *arg == '\0')
1595 			fatal("%s line %d: Missing argument.",
1596 			    filename, linenum);
1597 		if (*arg != '-' &&
1598 		    !sshkey_names_valid2(*arg == '+' || *arg == '^' ?
1599 		    arg + 1 : arg, 1, ca_only))
1600 			fatal("%s line %d: Bad key types '%s'.",
1601 			    filename, linenum, arg ? arg : "<NONE>");
1602 		if (*activep && *charptr == NULL)
1603 			*charptr = xstrdup(arg);
1604 		break;
1605 
1606 	case sHostKeyAlgorithms:
1607 		charptr = &options->hostkeyalgorithms;
1608 		ca_only = 0;
1609 		goto parse_pubkey_algos;
1610 
1611 	case sCASignatureAlgorithms:
1612 		charptr = &options->ca_sign_algorithms;
1613 		ca_only = 1;
1614 		goto parse_pubkey_algos;
1615 
1616 	case sPubkeyAuthentication:
1617 		intptr = &options->pubkey_authentication;
1618 		ca_only = 0;
1619 		goto parse_flag;
1620 
1621 	case sPubkeyAcceptedAlgorithms:
1622 		charptr = &options->pubkey_accepted_algos;
1623 		ca_only = 0;
1624 		goto parse_pubkey_algos;
1625 
1626 	case sPubkeyAuthOptions:
1627 		intptr = &options->pubkey_auth_options;
1628 		value = 0;
1629 		while ((arg = argv_next(&ac, &av)) != NULL) {
1630 			if (strcasecmp(arg, "none") == 0)
1631 				continue;
1632 			if (strcasecmp(arg, "touch-required") == 0)
1633 				value |= PUBKEYAUTH_TOUCH_REQUIRED;
1634 			else if (strcasecmp(arg, "verify-required") == 0)
1635 				value |= PUBKEYAUTH_VERIFY_REQUIRED;
1636 			else {
1637 				error("%s line %d: unsupported %s option %s",
1638 				    filename, linenum, keyword, arg);
1639 				goto out;
1640 			}
1641 		}
1642 		if (*activep && *intptr == -1)
1643 			*intptr = value;
1644 		break;
1645 
1646 	case sKerberosAuthentication:
1647 		intptr = &options->kerberos_authentication;
1648 		goto parse_flag;
1649 
1650 	case sKerberosOrLocalPasswd:
1651 		intptr = &options->kerberos_or_local_passwd;
1652 		goto parse_flag;
1653 
1654 	case sKerberosTicketCleanup:
1655 		intptr = &options->kerberos_ticket_cleanup;
1656 		goto parse_flag;
1657 
1658 	case sKerberosGetAFSToken:
1659 		intptr = &options->kerberos_get_afs_token;
1660 		goto parse_flag;
1661 
1662 	case sGssAuthentication:
1663 		intptr = &options->gss_authentication;
1664 		goto parse_flag;
1665 
1666 	case sGssCleanupCreds:
1667 		intptr = &options->gss_cleanup_creds;
1668 		goto parse_flag;
1669 
1670 	case sGssDelegateCreds:
1671 		intptr = &options->gss_deleg_creds;
1672 		goto parse_flag;
1673 
1674 	case sGssStrictAcceptor:
1675 		intptr = &options->gss_strict_acceptor;
1676 		goto parse_flag;
1677 
1678 	case sPasswordAuthentication:
1679 		intptr = &options->password_authentication;
1680 		goto parse_flag;
1681 
1682 	case sKbdInteractiveAuthentication:
1683 		intptr = &options->kbd_interactive_authentication;
1684 		goto parse_flag;
1685 
1686 	case sPrintMotd:
1687 		intptr = &options->print_motd;
1688 		goto parse_flag;
1689 
1690 	case sPrintLastLog:
1691 		intptr = &options->print_lastlog;
1692 		goto parse_flag;
1693 
1694 	case sX11Forwarding:
1695 		intptr = &options->x11_forwarding;
1696 		goto parse_flag;
1697 
1698 	case sX11DisplayOffset:
1699 		intptr = &options->x11_display_offset;
1700  parse_int:
1701 		arg = argv_next(&ac, &av);
1702 		if ((errstr = atoi_err(arg, &value)) != NULL)
1703 			fatal("%s line %d: %s integer value %s.",
1704 			    filename, linenum, keyword, errstr);
1705 		if (*activep && *intptr == -1)
1706 			*intptr = value;
1707 		break;
1708 
1709 	case sX11UseLocalhost:
1710 		intptr = &options->x11_use_localhost;
1711 		goto parse_flag;
1712 
1713 	case sXAuthLocation:
1714 		charptr = &options->xauth_location;
1715 		goto parse_filename;
1716 
1717 	case sPermitTTY:
1718 		intptr = &options->permit_tty;
1719 		goto parse_flag;
1720 
1721 	case sPermitUserRC:
1722 		intptr = &options->permit_user_rc;
1723 		goto parse_flag;
1724 
1725 	case sStrictModes:
1726 		intptr = &options->strict_modes;
1727 		goto parse_flag;
1728 
1729 	case sTCPKeepAlive:
1730 		intptr = &options->tcp_keep_alive;
1731 		goto parse_flag;
1732 
1733 	case sEmptyPasswd:
1734 		intptr = &options->permit_empty_passwd;
1735 		goto parse_flag;
1736 
1737 	case sPermitUserEnvironment:
1738 		intptr = &options->permit_user_env;
1739 		charptr = &options->permit_user_env_allowlist;
1740 		arg = argv_next(&ac, &av);
1741 		if (!arg || *arg == '\0')
1742 			fatal("%s line %d: %s missing argument.",
1743 			    filename, linenum, keyword);
1744 		value = 0;
1745 		p = NULL;
1746 		if (strcmp(arg, "yes") == 0)
1747 			value = 1;
1748 		else if (strcmp(arg, "no") == 0)
1749 			value = 0;
1750 		else {
1751 			/* Pattern-list specified */
1752 			value = 1;
1753 			p = xstrdup(arg);
1754 		}
1755 		if (*activep && *intptr == -1) {
1756 			*intptr = value;
1757 			*charptr = p;
1758 			p = NULL;
1759 		}
1760 		free(p);
1761 		break;
1762 
1763 	case sCompression:
1764 		intptr = &options->compression;
1765 		multistate_ptr = multistate_compression;
1766 		goto parse_multistate;
1767 
1768 	case sRekeyLimit:
1769 		arg = argv_next(&ac, &av);
1770 		if (!arg || *arg == '\0')
1771 			fatal("%s line %d: %s missing argument.",
1772 			    filename, linenum, keyword);
1773 		if (strcmp(arg, "default") == 0) {
1774 			val64 = 0;
1775 		} else {
1776 			if (scan_scaled(arg, &val64) == -1)
1777 				fatal("%.200s line %d: Bad %s number '%s': %s",
1778 				    filename, linenum, keyword,
1779 				    arg, strerror(errno));
1780 			if (val64 != 0 && val64 < 16)
1781 				fatal("%.200s line %d: %s too small",
1782 				    filename, linenum, keyword);
1783 		}
1784 		if (*activep && options->rekey_limit == -1)
1785 			options->rekey_limit = val64;
1786 		if (ac != 0) { /* optional rekey interval present */
1787 			if (strcmp(av[0], "none") == 0) {
1788 				(void)argv_next(&ac, &av);	/* discard */
1789 				break;
1790 			}
1791 			intptr = &options->rekey_interval;
1792 			goto parse_time;
1793 		}
1794 		break;
1795 
1796 	case sGatewayPorts:
1797 		intptr = &options->fwd_opts.gateway_ports;
1798 		multistate_ptr = multistate_gatewayports;
1799 		goto parse_multistate;
1800 
1801 	case sUseDNS:
1802 		intptr = &options->use_dns;
1803 		goto parse_flag;
1804 
1805 	case sLogFacility:
1806 		log_facility_ptr = &options->log_facility;
1807 		arg = argv_next(&ac, &av);
1808 		value = log_facility_number(arg);
1809 		if (value == SYSLOG_FACILITY_NOT_SET)
1810 			fatal("%.200s line %d: unsupported log facility '%s'",
1811 			    filename, linenum, arg ? arg : "<NONE>");
1812 		if (*log_facility_ptr == -1)
1813 			*log_facility_ptr = (SyslogFacility) value;
1814 		break;
1815 
1816 	case sLogLevel:
1817 		log_level_ptr = &options->log_level;
1818 		arg = argv_next(&ac, &av);
1819 		value = log_level_number(arg);
1820 		if (value == SYSLOG_LEVEL_NOT_SET)
1821 			fatal("%.200s line %d: unsupported log level '%s'",
1822 			    filename, linenum, arg ? arg : "<NONE>");
1823 		if (*activep && *log_level_ptr == -1)
1824 			*log_level_ptr = (LogLevel) value;
1825 		break;
1826 
1827 	case sLogVerbose:
1828 		found = options->num_log_verbose == 0;
1829 		while ((arg = argv_next(&ac, &av)) != NULL) {
1830 			if (*arg == '\0') {
1831 				error("%s line %d: keyword %s empty argument",
1832 				    filename, linenum, keyword);
1833 				goto out;
1834 			}
1835 			/* Allow "none" only in first position */
1836 			if (strcasecmp(arg, "none") == 0) {
1837 				if (nstrs > 0 || ac > 0) {
1838 					error("%s line %d: keyword %s \"none\" "
1839 					    "argument must appear alone.",
1840 					    filename, linenum, keyword);
1841 					goto out;
1842 				}
1843 			}
1844 			opt_array_append(filename, linenum, keyword,
1845 			    &strs, &nstrs, arg);
1846 		}
1847 		if (nstrs == 0) {
1848 			fatal("%s line %d: no %s specified",
1849 			    filename, linenum, keyword);
1850 		}
1851 		if (found && *activep) {
1852 			options->log_verbose = strs;
1853 			options->num_log_verbose = nstrs;
1854 			strs = NULL; /* transferred */
1855 			nstrs = 0;
1856 		}
1857 		break;
1858 
1859 	case sAllowTcpForwarding:
1860 		intptr = &options->allow_tcp_forwarding;
1861 		multistate_ptr = multistate_tcpfwd;
1862 		goto parse_multistate;
1863 
1864 	case sAllowStreamLocalForwarding:
1865 		intptr = &options->allow_streamlocal_forwarding;
1866 		multistate_ptr = multistate_tcpfwd;
1867 		goto parse_multistate;
1868 
1869 	case sAllowAgentForwarding:
1870 		intptr = &options->allow_agent_forwarding;
1871 		goto parse_flag;
1872 
1873 	case sDisableForwarding:
1874 		intptr = &options->disable_forwarding;
1875 		goto parse_flag;
1876 
1877 	case sAllowUsers:
1878 		chararrayptr = &options->allow_users;
1879 		uintptr = &options->num_allow_users;
1880  parse_allowdenyusers:
1881 		/* XXX appends to list; doesn't respect first-match-wins */
1882 		while ((arg = argv_next(&ac, &av)) != NULL) {
1883 			if (*arg == '\0' ||
1884 			    match_user(NULL, NULL, NULL, arg) == -1)
1885 				fatal("%s line %d: invalid %s pattern: \"%s\"",
1886 				    filename, linenum, keyword, arg);
1887 			found = 1;
1888 			if (!*activep)
1889 				continue;
1890 			opt_array_append(filename, linenum, keyword,
1891 			    chararrayptr, uintptr, arg);
1892 		}
1893 		if (!found) {
1894 			fatal("%s line %d: no %s specified",
1895 			    filename, linenum, keyword);
1896 		}
1897 		break;
1898 
1899 	case sDenyUsers:
1900 		chararrayptr = &options->deny_users;
1901 		uintptr = &options->num_deny_users;
1902 		goto parse_allowdenyusers;
1903 
1904 	case sAllowGroups:
1905 		chararrayptr = &options->allow_groups;
1906 		uintptr = &options->num_allow_groups;
1907 		/* XXX appends to list; doesn't respect first-match-wins */
1908  parse_allowdenygroups:
1909 		while ((arg = argv_next(&ac, &av)) != NULL) {
1910 			if (*arg == '\0')
1911 				fatal("%s line %d: empty %s pattern",
1912 				    filename, linenum, keyword);
1913 			found = 1;
1914 			if (!*activep)
1915 				continue;
1916 			opt_array_append(filename, linenum, keyword,
1917 			    chararrayptr, uintptr, arg);
1918 		}
1919 		if (!found) {
1920 			fatal("%s line %d: no %s specified",
1921 			    filename, linenum, keyword);
1922 		}
1923 		break;
1924 
1925 	case sDenyGroups:
1926 		chararrayptr = &options->deny_groups;
1927 		uintptr = &options->num_deny_groups;
1928 		goto parse_allowdenygroups;
1929 
1930 	case sCiphers:
1931 		arg = argv_next(&ac, &av);
1932 		if (!arg || *arg == '\0')
1933 			fatal("%s line %d: %s missing argument.",
1934 			    filename, linenum, keyword);
1935 		if (*arg != '-' &&
1936 		    !ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg))
1937 			fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
1938 			    filename, linenum, arg ? arg : "<NONE>");
1939 		if (options->ciphers == NULL)
1940 			options->ciphers = xstrdup(arg);
1941 		break;
1942 
1943 	case sMacs:
1944 		arg = argv_next(&ac, &av);
1945 		if (!arg || *arg == '\0')
1946 			fatal("%s line %d: %s missing argument.",
1947 			    filename, linenum, keyword);
1948 		if (*arg != '-' &&
1949 		    !mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg))
1950 			fatal("%s line %d: Bad SSH2 mac spec '%s'.",
1951 			    filename, linenum, arg ? arg : "<NONE>");
1952 		if (options->macs == NULL)
1953 			options->macs = xstrdup(arg);
1954 		break;
1955 
1956 	case sKexAlgorithms:
1957 		arg = argv_next(&ac, &av);
1958 		if (!arg || *arg == '\0')
1959 			fatal("%s line %d: %s missing argument.",
1960 			    filename, linenum, keyword);
1961 		if (*arg != '-' &&
1962 		    !kex_names_valid(*arg == '+' || *arg == '^' ?
1963 		    arg + 1 : arg))
1964 			fatal("%s line %d: Bad SSH2 KexAlgorithms '%s'.",
1965 			    filename, linenum, arg ? arg : "<NONE>");
1966 		if (options->kex_algorithms == NULL)
1967 			options->kex_algorithms = xstrdup(arg);
1968 		break;
1969 
1970 	case sSubsystem:
1971 		if ((arg = argv_next(&ac, &av)) == NULL || *arg == '\0' ||
1972 		   ((arg2 = argv_next(&ac, &av)) == NULL || *arg2 == '\0'))
1973 			fatal("%s line %d: %s missing argument.",
1974 			    filename, linenum, keyword);
1975 		if (!*activep) {
1976 			argv_consume(&ac);
1977 			break;
1978 		}
1979 		found = 0;
1980 		for (i = 0; i < options->num_subsystems; i++) {
1981 			if (strcmp(arg, options->subsystem_name[i]) == 0) {
1982 				found = 1;
1983 				break;
1984 			}
1985 		}
1986 		if (found) {
1987 			debug("%s line %d: Subsystem '%s' already defined.",
1988 			    filename, linenum, arg);
1989 			argv_consume(&ac);
1990 			break;
1991 		}
1992 		options->subsystem_name = xrecallocarray(
1993 		    options->subsystem_name, options->num_subsystems,
1994 		    options->num_subsystems + 1,
1995 		    sizeof(*options->subsystem_name));
1996 		options->subsystem_command = xrecallocarray(
1997 		    options->subsystem_command, options->num_subsystems,
1998 		    options->num_subsystems + 1,
1999 		    sizeof(*options->subsystem_command));
2000 		options->subsystem_args = xrecallocarray(
2001 		    options->subsystem_args, options->num_subsystems,
2002 		    options->num_subsystems + 1,
2003 		    sizeof(*options->subsystem_args));
2004 		options->subsystem_name[options->num_subsystems] = xstrdup(arg);
2005 		options->subsystem_command[options->num_subsystems] =
2006 		    xstrdup(arg2);
2007 		/* Collect arguments (separate to executable) */
2008 		arg = argv_assemble(1, &arg2); /* quote command correctly */
2009 		arg2 = argv_assemble(ac, av); /* rest of command */
2010 		xasprintf(&options->subsystem_args[options->num_subsystems],
2011 		    "%s%s%s", arg, *arg2 == '\0' ? "" : " ", arg2);
2012 		free(arg2);
2013 		free(arg);
2014 		argv_consume(&ac);
2015 		options->num_subsystems++;
2016 		break;
2017 
2018 	case sMaxStartups:
2019 		arg = argv_next(&ac, &av);
2020 		if (!arg || *arg == '\0')
2021 			fatal("%s line %d: %s missing argument.",
2022 			    filename, linenum, keyword);
2023 		/* begin:rate:max */
2024 		if ((n = sscanf(arg, "%d:%d:%d",
2025 		    &value, &value2, &value3)) == 3) {
2026 			if (value > value3 || value2 > 100 || value2 < 1)
2027 				fatal("%s line %d: Invalid %s spec.",
2028 				    filename, linenum, keyword);
2029 		} else if (n == 1) {
2030 			value3 = value;
2031 			value2 = -1;
2032 		} else {
2033 			fatal("%s line %d: Invalid %s spec.",
2034 			    filename, linenum, keyword);
2035 		}
2036 		if (value <= 0 || value3 <= 0)
2037 			fatal("%s line %d: Invalid %s spec.",
2038 			    filename, linenum, keyword);
2039 		if (*activep && options->max_startups == -1) {
2040 			options->max_startups_begin = value;
2041 			options->max_startups_rate = value2;
2042 			options->max_startups = value3;
2043 		}
2044 		break;
2045 
2046 	case sPerSourceNetBlockSize:
2047 		arg = argv_next(&ac, &av);
2048 		if (!arg || *arg == '\0')
2049 			fatal("%s line %d: %s missing argument.",
2050 			    filename, linenum, keyword);
2051 		switch (n = sscanf(arg, "%d:%d", &value, &value2)) {
2052 		case 2:
2053 			if (value2 < 0 || value2 > 128)
2054 				n = -1;
2055 			/* FALLTHROUGH */
2056 		case 1:
2057 			if (value < 0 || value > 32)
2058 				n = -1;
2059 		}
2060 		if (n != 1 && n != 2)
2061 			fatal("%s line %d: Invalid %s spec.",
2062 			    filename, linenum, keyword);
2063 		if (*activep && options->per_source_masklen_ipv4 == -1) {
2064 			options->per_source_masklen_ipv4 = value;
2065 			if (n == 2)
2066 				options->per_source_masklen_ipv6 = value2;
2067 		}
2068 		break;
2069 
2070 	case sPerSourceMaxStartups:
2071 		arg = argv_next(&ac, &av);
2072 		if (!arg || *arg == '\0')
2073 			fatal("%s line %d: %s missing argument.",
2074 			    filename, linenum, keyword);
2075 		if (strcmp(arg, "none") == 0) { /* no limit */
2076 			value = INT_MAX;
2077 		} else {
2078 			if ((errstr = atoi_err(arg, &value)) != NULL)
2079 				fatal("%s line %d: %s integer value %s.",
2080 				    filename, linenum, keyword, errstr);
2081 		}
2082 		if (*activep && options->per_source_max_startups == -1)
2083 			options->per_source_max_startups = value;
2084 		break;
2085 
2086 	case sPerSourcePenaltyExemptList:
2087 		charptr = &options->per_source_penalty_exempt;
2088 		arg = argv_next(&ac, &av);
2089 		if (!arg || *arg == '\0')
2090 			fatal("%s line %d: missing argument.",
2091 			    filename, linenum);
2092 		if (addr_match_list(NULL, arg) != 0) {
2093 			fatal("%s line %d: keyword %s "
2094 			    "invalid address argument.",
2095 			    filename, linenum, keyword);
2096 		}
2097 		if (*activep && *charptr == NULL)
2098 			*charptr = xstrdup(arg);
2099 		break;
2100 
2101 	case sPerSourcePenalties:
2102 		while ((arg = argv_next(&ac, &av)) != NULL) {
2103 			const char *q = NULL;
2104 
2105 			found = 1;
2106 			intptr = NULL;
2107 			doubleptr = NULL;
2108 			value = -1;
2109 			value2 = 0;
2110 			/* Allow no/yes only in first position */
2111 			if (strcasecmp(arg, "no") == 0 ||
2112 			    (value2 = (strcasecmp(arg, "yes") == 0))) {
2113 				if (ac > 0) {
2114 					fatal("%s line %d: keyword %s \"%s\" "
2115 					    "argument must appear alone.",
2116 					    filename, linenum, keyword, arg);
2117 				}
2118 				if (*activep &&
2119 				    options->per_source_penalty.enabled == -1)
2120 					options->per_source_penalty.enabled = value2;
2121 				continue;
2122 			} else if ((q = strprefix(arg, "crash:", 0)) != NULL) {
2123 				doubleptr = &options->per_source_penalty.penalty_crash;
2124 			} else if ((q = strprefix(arg, "authfail:", 0)) != NULL) {
2125 				doubleptr = &options->per_source_penalty.penalty_authfail;
2126 			} else if ((q = strprefix(arg, "invaliduser:", 0)) != NULL) {
2127 				doubleptr = &options->per_source_penalty.penalty_invaliduser;
2128 			} else if ((q = strprefix(arg, "noauth:", 0)) != NULL) {
2129 				doubleptr = &options->per_source_penalty.penalty_noauth;
2130 			} else if ((q = strprefix(arg, "grace-exceeded:", 0)) != NULL) {
2131 				doubleptr = &options->per_source_penalty.penalty_grace;
2132 			} else if ((q = strprefix(arg, "refuseconnection:", 0)) != NULL) {
2133 				doubleptr = &options->per_source_penalty.penalty_refuseconnection;
2134 			} else if ((q = strprefix(arg, "max:", 0)) != NULL) {
2135 				doubleptr = &options->per_source_penalty.penalty_max;
2136 			} else if ((q = strprefix(arg, "min:", 0)) != NULL) {
2137 				doubleptr = &options->per_source_penalty.penalty_min;
2138 			} else if ((q = strprefix(arg, "max-sources4:", 0)) != NULL) {
2139 				intptr = &options->per_source_penalty.max_sources4;
2140 				if ((errstr = atoi_err(q, &value)) != NULL)
2141 					fatal("%s line %d: %s value %s.",
2142 					    filename, linenum, keyword, errstr);
2143 			} else if ((q = strprefix(arg, "max-sources6:", 0)) != NULL) {
2144 				intptr = &options->per_source_penalty.max_sources6;
2145 				if ((errstr = atoi_err(q, &value)) != NULL)
2146 					fatal("%s line %d: %s value %s.",
2147 					    filename, linenum, keyword, errstr);
2148 			} else if (strcmp(arg, "overflow:deny-all") == 0) {
2149 				intptr = &options->per_source_penalty.overflow_mode;
2150 				value = PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL;
2151 			} else if (strcmp(arg, "overflow:permissive") == 0) {
2152 				intptr = &options->per_source_penalty.overflow_mode;
2153 				value = PER_SOURCE_PENALTY_OVERFLOW_PERMISSIVE;
2154 			} else if (strcmp(arg, "overflow6:deny-all") == 0) {
2155 				intptr = &options->per_source_penalty.overflow_mode6;
2156 				value = PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL;
2157 			} else if (strcmp(arg, "overflow6:permissive") == 0) {
2158 				intptr = &options->per_source_penalty.overflow_mode6;
2159 				value = PER_SOURCE_PENALTY_OVERFLOW_PERMISSIVE;
2160 			} else {
2161 				fatal("%s line %d: unsupported %s keyword %s",
2162 				    filename, linenum, keyword, arg);
2163 			}
2164 
2165 			if (doubleptr != NULL) {
2166 				if ((dvalue = convtime_double(q)) < 0) {
2167 					fatal("%s line %d: invalid %s time value.",
2168 					    filename, linenum, keyword);
2169 				}
2170 				if (*activep && *doubleptr < 0.0) {
2171 					*doubleptr = dvalue;
2172 					options->per_source_penalty.enabled = 1;
2173 				}
2174 			} else if (intptr != NULL) {
2175 				if (*activep && *intptr == -1) {
2176 					*intptr = value;
2177 					options->per_source_penalty.enabled = 1;
2178 				}
2179 			} else {
2180 				fatal_f("%s line %d: internal error",
2181 				    filename, linenum);
2182 			}
2183 		}
2184 		if (!found) {
2185 			fatal("%s line %d: no %s specified",
2186 			    filename, linenum, keyword);
2187 		}
2188 		break;
2189 
2190 	case sMaxAuthTries:
2191 		intptr = &options->max_authtries;
2192 		goto parse_int;
2193 
2194 	case sMaxSessions:
2195 		intptr = &options->max_sessions;
2196 		goto parse_int;
2197 
2198 	case sBanner:
2199 		charptr = &options->banner;
2200 		goto parse_filename;
2201 
2202 	/*
2203 	 * These options can contain %X options expanded at
2204 	 * connect time, so that you can specify paths like:
2205 	 *
2206 	 * AuthorizedKeysFile	/etc/ssh_keys/%u
2207 	 */
2208 	case sAuthorizedKeysFile:
2209 		uintptr = &options->num_authkeys_files;
2210 		chararrayptr = &options->authorized_keys_files;
2211  parse_filenames:
2212 		found = *uintptr == 0;
2213 		while ((arg = argv_next(&ac, &av)) != NULL) {
2214 			if (*arg == '\0') {
2215 				error("%s line %d: keyword %s empty argument",
2216 				    filename, linenum, keyword);
2217 				goto out;
2218 			}
2219 			/* Allow "none" only in first position */
2220 			if (strcasecmp(arg, "none") == 0) {
2221 				if (nstrs > 0 || ac > 0) {
2222 					error("%s line %d: keyword %s \"none\" "
2223 					    "argument must appear alone.",
2224 					    filename, linenum, keyword);
2225 					goto out;
2226 				}
2227 			}
2228 			arg2 = tilde_expand_filename(arg, getuid());
2229 			opt_array_append(filename, linenum, keyword,
2230 			    &strs, &nstrs, arg2);
2231 			free(arg2);
2232 		}
2233 		if (nstrs == 0) {
2234 			fatal("%s line %d: no %s specified",
2235 			    filename, linenum, keyword);
2236 		}
2237 		if (found && *activep) {
2238 			*chararrayptr = strs;
2239 			*uintptr = nstrs;
2240 			strs = NULL; /* transferred */
2241 			nstrs = 0;
2242 		}
2243 		break;
2244 
2245 	case sAuthorizedPrincipalsFile:
2246 		charptr = &options->authorized_principals_file;
2247 		arg = argv_next(&ac, &av);
2248 		if (!arg || *arg == '\0')
2249 			fatal("%s line %d: %s missing argument.",
2250 			    filename, linenum, keyword);
2251 		if (*activep && *charptr == NULL) {
2252 			*charptr = tilde_expand_filename(arg, getuid());
2253 			/* increase optional counter */
2254 			if (intptr != NULL)
2255 				*intptr = *intptr + 1;
2256 		}
2257 		break;
2258 
2259 	case sClientAliveInterval:
2260 		intptr = &options->client_alive_interval;
2261 		goto parse_time;
2262 
2263 	case sClientAliveCountMax:
2264 		intptr = &options->client_alive_count_max;
2265 		goto parse_int;
2266 
2267 	case sAcceptEnv:
2268 		/* XXX appends to list; doesn't respect first-match-wins */
2269 		while ((arg = argv_next(&ac, &av)) != NULL) {
2270 			if (*arg == '\0' || strchr(arg, '=') != NULL)
2271 				fatal("%s line %d: Invalid environment name.",
2272 				    filename, linenum);
2273 			found = 1;
2274 			if (!*activep)
2275 				continue;
2276 			opt_array_append(filename, linenum, keyword,
2277 			    &options->accept_env, &options->num_accept_env,
2278 			    arg);
2279 		}
2280 		if (!found) {
2281 			fatal("%s line %d: no %s specified",
2282 			    filename, linenum, keyword);
2283 		}
2284 		break;
2285 
2286 	case sSetEnv:
2287 		found = options->num_setenv == 0;
2288 		while ((arg = argv_next(&ac, &av)) != NULL) {
2289 			if (*arg == '\0' || strchr(arg, '=') == NULL)
2290 				fatal("%s line %d: Invalid environment.",
2291 				    filename, linenum);
2292 			if (lookup_setenv_in_list(arg, strs, nstrs) != NULL) {
2293 				debug2("%s line %d: ignoring duplicate env "
2294 				    "name \"%.64s\"", filename, linenum, arg);
2295 				continue;
2296 			}
2297 			opt_array_append(filename, linenum, keyword,
2298 			    &strs, &nstrs, arg);
2299 		}
2300 		if (nstrs == 0) {
2301 			fatal("%s line %d: no %s specified",
2302 			    filename, linenum, keyword);
2303 		}
2304 		if (found && *activep) {
2305 			options->setenv = strs;
2306 			options->num_setenv = nstrs;
2307 			strs = NULL; /* transferred */
2308 			nstrs = 0;
2309 		}
2310 		break;
2311 
2312 	case sPermitTunnel:
2313 		intptr = &options->permit_tun;
2314 		arg = argv_next(&ac, &av);
2315 		if (!arg || *arg == '\0')
2316 			fatal("%s line %d: %s missing argument.",
2317 			    filename, linenum, keyword);
2318 		value = -1;
2319 		for (i = 0; tunmode_desc[i].val != -1; i++)
2320 			if (strcmp(tunmode_desc[i].text, arg) == 0) {
2321 				value = tunmode_desc[i].val;
2322 				break;
2323 			}
2324 		if (value == -1)
2325 			fatal("%s line %d: bad %s argument %s",
2326 			    filename, linenum, keyword, arg);
2327 		if (*activep && *intptr == -1)
2328 			*intptr = value;
2329 		break;
2330 
2331 	case sInclude:
2332 		if (cmdline) {
2333 			fatal("Include directive not supported as a "
2334 			    "command-line option");
2335 		}
2336 		value = 0;
2337 		while ((arg2 = argv_next(&ac, &av)) != NULL) {
2338 			if (*arg2 == '\0') {
2339 				error("%s line %d: keyword %s empty argument",
2340 				    filename, linenum, keyword);
2341 				goto out;
2342 			}
2343 			value++;
2344 			found = 0;
2345 			if (*arg2 != '/' && *arg2 != '~') {
2346 				xasprintf(&arg, "%s/%s", SSHDIR, arg2);
2347 			} else
2348 				arg = xstrdup(arg2);
2349 
2350 			/*
2351 			 * Don't let included files clobber the containing
2352 			 * file's Match state.
2353 			 */
2354 			oactive = *activep;
2355 
2356 			/* consult cache of include files */
2357 			TAILQ_FOREACH(item, includes, entry) {
2358 				if (strcmp(item->selector, arg) != 0)
2359 					continue;
2360 				if (item->filename != NULL) {
2361 					parse_server_config_depth(options,
2362 					    item->filename, item->contents,
2363 					    includes, connectinfo,
2364 					    (*inc_flags & SSHCFG_MATCH_ONLY
2365 					        ? SSHCFG_MATCH_ONLY : (oactive
2366 					            ? 0 : SSHCFG_NEVERMATCH)),
2367 					    activep, depth + 1);
2368 				}
2369 				found = 1;
2370 				*activep = oactive;
2371 			}
2372 			if (found != 0) {
2373 				free(arg);
2374 				continue;
2375 			}
2376 
2377 			/* requested glob was not in cache */
2378 			debug2("%s line %d: new include %s",
2379 			    filename, linenum, arg);
2380 			if ((r = glob(arg, 0, NULL, &gbuf)) != 0) {
2381 				if (r != GLOB_NOMATCH) {
2382 					fatal("%s line %d: include \"%s\" glob "
2383 					    "failed", filename, linenum, arg);
2384 				}
2385 				/*
2386 				 * If no entry matched then record a
2387 				 * placeholder to skip later glob calls.
2388 				 */
2389 				debug2("%s line %d: no match for %s",
2390 				    filename, linenum, arg);
2391 				item = xcalloc(1, sizeof(*item));
2392 				item->selector = strdup(arg);
2393 				TAILQ_INSERT_TAIL(includes,
2394 				    item, entry);
2395 			}
2396 			if (gbuf.gl_pathc > INT_MAX)
2397 				fatal_f("too many glob results");
2398 			for (n = 0; n < (int)gbuf.gl_pathc; n++) {
2399 				debug2("%s line %d: including %s",
2400 				    filename, linenum, gbuf.gl_pathv[n]);
2401 				item = xcalloc(1, sizeof(*item));
2402 				item->selector = strdup(arg);
2403 				item->filename = strdup(gbuf.gl_pathv[n]);
2404 				if ((item->contents = sshbuf_new()) == NULL)
2405 					fatal_f("sshbuf_new failed");
2406 				load_server_config(item->filename,
2407 				    item->contents);
2408 				parse_server_config_depth(options,
2409 				    item->filename, item->contents,
2410 				    includes, connectinfo,
2411 				    (*inc_flags & SSHCFG_MATCH_ONLY
2412 				        ? SSHCFG_MATCH_ONLY : (oactive
2413 				            ? 0 : SSHCFG_NEVERMATCH)),
2414 				    activep, depth + 1);
2415 				*activep = oactive;
2416 				TAILQ_INSERT_TAIL(includes, item, entry);
2417 			}
2418 			globfree(&gbuf);
2419 			free(arg);
2420 		}
2421 		if (value == 0) {
2422 			fatal("%s line %d: %s missing filename argument",
2423 			    filename, linenum, keyword);
2424 		}
2425 		break;
2426 
2427 	case sMatch:
2428 		if (cmdline)
2429 			fatal("Match directive not supported as a command-line "
2430 			    "option");
2431 		value = match_cfg_line(str, &ac, &av, linenum,
2432 		    (*inc_flags & SSHCFG_NEVERMATCH ? NULL : connectinfo));
2433 		if (value < 0)
2434 			fatal("%s line %d: Bad Match condition", filename,
2435 			    linenum);
2436 		*activep = (*inc_flags & SSHCFG_NEVERMATCH) ? 0 : value;
2437 		/*
2438 		 * The MATCH_ONLY flag is applicable only until the first
2439 		 * match block.
2440 		 */
2441 		*inc_flags &= ~SSHCFG_MATCH_ONLY;
2442 		break;
2443 
2444 	case sPermitListen:
2445 	case sPermitOpen:
2446 		if (opcode == sPermitListen) {
2447 			uintptr = &options->num_permitted_listens;
2448 			chararrayptr = &options->permitted_listens;
2449 		} else {
2450 			uintptr = &options->num_permitted_opens;
2451 			chararrayptr = &options->permitted_opens;
2452 		}
2453 		found = *uintptr == 0;
2454 		while ((arg = argv_next(&ac, &av)) != NULL) {
2455 			if (strcmp(arg, "any") == 0 ||
2456 			    strcmp(arg, "none") == 0) {
2457 				if (nstrs != 0) {
2458 					fatal("%s line %d: %s must appear "
2459 					    "alone on a %s line.",
2460 					    filename, linenum, arg, keyword);
2461 				}
2462 				opt_array_append(filename, linenum, keyword,
2463 				    &strs, &nstrs, arg);
2464 				continue;
2465 			}
2466 
2467 			if (opcode == sPermitListen &&
2468 			    strchr(arg, ':') == NULL) {
2469 				/*
2470 				 * Allow bare port number for PermitListen
2471 				 * to indicate a wildcard listen host.
2472 				 */
2473 				xasprintf(&arg2, "*:%s", arg);
2474 			} else {
2475 				arg2 = xstrdup(arg);
2476 				p = hpdelim(&arg);
2477 				if (p == NULL) {
2478 					fatal("%s line %d: %s missing host",
2479 					    filename, linenum, keyword);
2480 				}
2481 				p = cleanhostname(p);
2482 			}
2483 			if (arg == NULL ||
2484 			    ((port = permitopen_port(arg)) < 0)) {
2485 				fatal("%s line %d: %s bad port number",
2486 				    filename, linenum, keyword);
2487 			}
2488 			opt_array_append(filename, linenum, keyword,
2489 			    &strs, &nstrs, arg2);
2490 			free(arg2);
2491 		}
2492 		if (nstrs == 0) {
2493 			fatal("%s line %d: %s missing argument.",
2494 			    filename, linenum, keyword);
2495 		}
2496 		if (found && *activep) {
2497 			*chararrayptr = strs;
2498 			*uintptr = nstrs;
2499 			strs = NULL; /* transferred */
2500 			nstrs = 0;
2501 		}
2502 		break;
2503 
2504 	case sForceCommand:
2505 		if (str == NULL || *str == '\0')
2506 			fatal("%s line %d: %s missing argument.",
2507 			    filename, linenum, keyword);
2508 		len = strspn(str, WHITESPACE);
2509 		if (*activep && options->adm_forced_command == NULL)
2510 			options->adm_forced_command = xstrdup(str + len);
2511 		argv_consume(&ac);
2512 		break;
2513 
2514 	case sChrootDirectory:
2515 		charptr = &options->chroot_directory;
2516 
2517 		arg = argv_next(&ac, &av);
2518 		if (!arg || *arg == '\0')
2519 			fatal("%s line %d: %s missing argument.",
2520 			    filename, linenum, keyword);
2521 		if (*activep && *charptr == NULL)
2522 			*charptr = xstrdup(arg);
2523 		break;
2524 
2525 	case sTrustedUserCAKeys:
2526 		charptr = &options->trusted_user_ca_keys;
2527 		goto parse_filename;
2528 
2529 	case sRevokedKeys:
2530 		uintptr = &options->num_revoked_keys_files;
2531 		chararrayptr = &options->revoked_keys_files;
2532 		goto parse_filenames;
2533 
2534 	case sSecurityKeyProvider:
2535 		charptr = &options->sk_provider;
2536 		arg = argv_next(&ac, &av);
2537 		if (!arg || *arg == '\0')
2538 			fatal("%s line %d: %s missing argument.",
2539 			    filename, linenum, keyword);
2540 		if (*activep && *charptr == NULL) {
2541 			*charptr = strcasecmp(arg, "internal") == 0 ?
2542 			    xstrdup(arg) : derelativise_path(arg);
2543 			/* increase optional counter */
2544 			if (intptr != NULL)
2545 				*intptr = *intptr + 1;
2546 		}
2547 		break;
2548 
2549 	case sIPQoS:
2550 		arg = argv_next(&ac, &av);
2551 		if (!arg || *arg == '\0')
2552 			fatal("%s line %d: %s missing argument.",
2553 			    filename, linenum, keyword);
2554 		if ((value = parse_ipqos(arg)) == -1)
2555 			fatal("%s line %d: Bad %s value: %s",
2556 			    filename, linenum, keyword, arg);
2557 		if (value == INT_MIN) {
2558 			debug("%s line %d: Deprecated IPQoS value \"%s\" "
2559 			    "ignored - using system default instead. Consider"
2560 			    " using DSCP values.", filename, linenum, arg);
2561 			value = INT_MAX;
2562 		}
2563 		arg = argv_next(&ac, &av);
2564 		if (arg == NULL)
2565 			value2 = value;
2566 		else if ((value2 = parse_ipqos(arg)) == -1)
2567 			fatal("%s line %d: Bad %s value: %s",
2568 			    filename, linenum, keyword, arg);
2569 		if (value2 == INT_MIN) {
2570 			debug("%s line %d: Deprecated IPQoS value \"%s\" "
2571 			    "ignored - using system default instead. Consider"
2572 			    " using DSCP values.", filename, linenum, arg);
2573 			value2 = INT_MAX;
2574 		}
2575 		if (*activep && options->ip_qos_interactive == -1) {
2576 			options->ip_qos_interactive = value;
2577 			options->ip_qos_bulk = value2;
2578 		}
2579 		break;
2580 
2581 	case sVersionAddendum:
2582 		if (str == NULL || *str == '\0')
2583 			fatal("%s line %d: %s missing argument.",
2584 			    filename, linenum, keyword);
2585 		len = strspn(str, WHITESPACE);
2586 		if (strchr(str + len, '\r') != NULL) {
2587 			fatal("%.200s line %d: Invalid %s argument",
2588 			    filename, linenum, keyword);
2589 		}
2590 		if ((arg = strchr(line, '#')) != NULL) {
2591 			*arg = '\0';
2592 			rtrim(line);
2593 		}
2594 		if (*activep && options->version_addendum == NULL) {
2595 			if (strcasecmp(str + len, "none") == 0)
2596 				options->version_addendum = xstrdup("");
2597 			else
2598 				options->version_addendum = xstrdup(str + len);
2599 		}
2600 		argv_consume(&ac);
2601 		break;
2602 
2603 	case sAuthorizedKeysCommand:
2604 		charptr = &options->authorized_keys_command;
2605  parse_command:
2606 		len = strspn(str, WHITESPACE);
2607 		if (str[len] != '/' && strcasecmp(str + len, "none") != 0) {
2608 			fatal("%.200s line %d: %s must be an absolute path",
2609 			    filename, linenum, keyword);
2610 		}
2611 		if (*activep && *charptr == NULL)
2612 			*charptr = xstrdup(str + len);
2613 		argv_consume(&ac);
2614 		break;
2615 
2616 	case sAuthorizedKeysCommandUser:
2617 		charptr = &options->authorized_keys_command_user;
2618  parse_localuser:
2619 		arg = argv_next(&ac, &av);
2620 		if (!arg || *arg == '\0') {
2621 			fatal("%s line %d: missing %s argument.",
2622 			    filename, linenum, keyword);
2623 		}
2624 		if (*activep && *charptr == NULL)
2625 			*charptr = xstrdup(arg);
2626 		break;
2627 
2628 	case sAuthorizedPrincipalsCommand:
2629 		charptr = &options->authorized_principals_command;
2630 		goto parse_command;
2631 
2632 	case sAuthorizedPrincipalsCommandUser:
2633 		charptr = &options->authorized_principals_command_user;
2634 		goto parse_localuser;
2635 
2636 	case sAuthenticationMethods:
2637 		found = options->num_auth_methods == 0;
2638 		value = 0; /* seen "any" pseudo-method */
2639 		while ((arg = argv_next(&ac, &av)) != NULL) {
2640 			if (strcmp(arg, "any") == 0) {
2641 				if (nstrs > 0) {
2642 					fatal("%s line %d: \"any\" must "
2643 					    "appear alone in %s",
2644 					    filename, linenum, keyword);
2645 				}
2646 				value = 1;
2647 			} else if (value) {
2648 				fatal("%s line %d: \"any\" must appear "
2649 				    "alone in %s", filename, linenum, keyword);
2650 			} else if (auth2_methods_valid(arg, 0) != 0) {
2651 				fatal("%s line %d: invalid %s method list.",
2652 				    filename, linenum, keyword);
2653 			}
2654 			opt_array_append(filename, linenum, keyword,
2655 			    &strs, &nstrs, arg);
2656 		}
2657 		if (nstrs == 0) {
2658 			fatal("%s line %d: no %s specified",
2659 			    filename, linenum, keyword);
2660 		}
2661 		if (found && *activep) {
2662 			options->auth_methods = strs;
2663 			options->num_auth_methods = nstrs;
2664 			strs = NULL; /* transferred */
2665 			nstrs = 0;
2666 		}
2667 		break;
2668 
2669 	case sStreamLocalBindMask:
2670 		arg = argv_next(&ac, &av);
2671 		if (!arg || *arg == '\0')
2672 			fatal("%s line %d: %s missing argument.",
2673 			    filename, linenum, keyword);
2674 		/* Parse mode in octal format */
2675 		value = strtol(arg, &p, 8);
2676 		if (arg == p || value < 0 || value > 0777)
2677 			fatal("%s line %d: Invalid %s.",
2678 			    filename, linenum, keyword);
2679 		if (*activep)
2680 			options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
2681 		break;
2682 
2683 	case sStreamLocalBindUnlink:
2684 		intptr = &options->fwd_opts.streamlocal_bind_unlink;
2685 		goto parse_flag;
2686 
2687 	case sFingerprintHash:
2688 		arg = argv_next(&ac, &av);
2689 		if (!arg || *arg == '\0')
2690 			fatal("%s line %d: %s missing argument.",
2691 			    filename, linenum, keyword);
2692 		if ((value = ssh_digest_alg_by_name(arg)) == -1)
2693 			fatal("%.200s line %d: Invalid %s algorithm \"%s\".",
2694 			    filename, linenum, keyword, arg);
2695 		if (*activep)
2696 			options->fingerprint_hash = value;
2697 		break;
2698 
2699 	case sExposeAuthInfo:
2700 		intptr = &options->expose_userauth_info;
2701 		goto parse_flag;
2702 
2703 	case sRDomain:
2704 #if !defined(__OpenBSD__) && !defined(HAVE_SYS_SET_PROCESS_RDOMAIN)
2705 		fatal("%s line %d: setting RDomain not supported on this "
2706 		    "platform.", filename, linenum);
2707 #endif
2708 		charptr = &options->routing_domain;
2709 		arg = argv_next(&ac, &av);
2710 		if (!arg || *arg == '\0')
2711 			fatal("%s line %d: %s missing argument.",
2712 			    filename, linenum, keyword);
2713 		if (strcasecmp(arg, "none") != 0 && strcmp(arg, "%D") != 0 &&
2714 		    !valid_rdomain(arg))
2715 			fatal("%s line %d: invalid routing domain",
2716 			    filename, linenum);
2717 		if (*activep && *charptr == NULL)
2718 			*charptr = xstrdup(arg);
2719 		break;
2720 
2721 	case sRequiredRSASize:
2722 		intptr = &options->required_rsa_size;
2723 		goto parse_int;
2724 
2725 	case sChannelTimeout:
2726 		found = options->num_channel_timeouts == 0;
2727 		while ((arg = argv_next(&ac, &av)) != NULL) {
2728 			/* Allow "none" only in first position */
2729 			if (strcasecmp(arg, "none") == 0) {
2730 				if (nstrs > 0 || ac > 0) {
2731 					error("%s line %d: keyword %s \"none\" "
2732 					    "argument must appear alone.",
2733 					    filename, linenum, keyword);
2734 					goto out;
2735 				}
2736 			} else if (parse_pattern_interval(arg,
2737 			    NULL, NULL) != 0) {
2738 				fatal("%s line %d: invalid channel timeout %s",
2739 				    filename, linenum, arg);
2740 			}
2741 			opt_array_append(filename, linenum, keyword,
2742 			    &strs, &nstrs, arg);
2743 		}
2744 		if (nstrs == 0) {
2745 			fatal("%s line %d: no %s specified",
2746 			    filename, linenum, keyword);
2747 		}
2748 		if (found && *activep) {
2749 			options->channel_timeouts = strs;
2750 			options->num_channel_timeouts = nstrs;
2751 			strs = NULL; /* transferred */
2752 			nstrs = 0;
2753 		}
2754 		break;
2755 
2756 	case sUnusedConnectionTimeout:
2757 		intptr = &options->unused_connection_timeout;
2758 		/* peek at first arg for "none" so we can reuse parse_time */
2759 		if (av[0] != NULL && strcasecmp(av[0], "none") == 0) {
2760 			(void)argv_next(&ac, &av); /* consume arg */
2761 			if (*activep)
2762 				*intptr = 0;
2763 			break;
2764 		}
2765 		goto parse_time;
2766 
2767 	case sSshdSessionPath:
2768 		charptr = &options->sshd_session_path;
2769 		goto parse_filename;
2770 
2771 	case sSshdAuthPath:
2772 		charptr = &options->sshd_auth_path;
2773 		goto parse_filename;
2774 
2775 	case sRefuseConnection:
2776 		intptr = &options->refuse_connection;
2777 		multistate_ptr = multistate_flag;
2778 		goto parse_multistate;
2779 
2780 	case sUseBlocklist:
2781 		intptr = &options->use_blocklist;
2782 		goto parse_flag;
2783 
2784 	case sDeprecated:
2785 	case sIgnore:
2786 	case sUnsupported:
2787 		do_log2(opcode == sIgnore ?
2788 		    SYSLOG_LEVEL_DEBUG2 : SYSLOG_LEVEL_INFO,
2789 		    "%s line %d: %s option %s", filename, linenum,
2790 		    opcode == sUnsupported ? "Unsupported" : "Deprecated",
2791 		    keyword);
2792 		argv_consume(&ac);
2793 		break;
2794 
2795 	default:
2796 		fatal("%s line %d: Missing handler for opcode %s (%d)",
2797 		    filename, linenum, keyword, opcode);
2798 	}
2799 	/* Check that there is no garbage at end of line. */
2800 	if (ac > 0) {
2801 		error("%.200s line %d: keyword %s extra arguments "
2802 		    "at end of line", filename, linenum, keyword);
2803 		goto out;
2804 	}
2805 
2806 	/* success */
2807 	ret = 0;
2808  out:
2809 	opt_array_free2(strs, NULL, nstrs);
2810 	argv_free(oav, oac);
2811 	return ret;
2812 }
2813 
2814 int
process_server_config_line(ServerOptions * options,char * line,const char * filename,int linenum,int * activep,struct connection_info * connectinfo,struct include_list * includes)2815 process_server_config_line(ServerOptions *options, char *line,
2816     const char *filename, int linenum, int *activep,
2817     struct connection_info *connectinfo, struct include_list *includes)
2818 {
2819 	int inc_flags = 0;
2820 
2821 	return process_server_config_line_depth(options, line, filename,
2822 	    linenum, activep, connectinfo, &inc_flags, 0, includes);
2823 }
2824 
2825 
2826 /* Reads the server configuration file. */
2827 
2828 void
load_server_config(const char * filename,struct sshbuf * conf)2829 load_server_config(const char *filename, struct sshbuf *conf)
2830 {
2831 	struct stat st;
2832 	char *line = NULL, *cp;
2833 	size_t linesize = 0;
2834 	FILE *f;
2835 	int r;
2836 
2837 	debug2_f("filename %s", filename);
2838 	if ((f = fopen(filename, "r")) == NULL) {
2839 		perror(filename);
2840 		exit(1);
2841 	}
2842 	sshbuf_reset(conf);
2843 	/* grow buffer, so realloc is avoided for large config files */
2844 	if (fstat(fileno(f), &st) == 0 && st.st_size > 0 &&
2845 	    (r = sshbuf_allocate(conf, st.st_size)) != 0)
2846 		fatal_fr(r, "allocate");
2847 	while (getline(&line, &linesize, f) != -1) {
2848 		/*
2849 		 * Strip whitespace
2850 		 * NB - preserve newlines, they are needed to reproduce
2851 		 * line numbers later for error messages
2852 		 */
2853 		cp = line + strspn(line, " \t\r");
2854 		if ((r = sshbuf_put(conf, cp, strlen(cp))) != 0)
2855 			fatal_fr(r, "sshbuf_put");
2856 	}
2857 	free(line);
2858 	if ((r = sshbuf_put_u8(conf, 0)) != 0)
2859 		fatal_fr(r, "sshbuf_put_u8");
2860 	fclose(f);
2861 	debug2_f("done config len = %zu", sshbuf_len(conf));
2862 }
2863 
2864 void
parse_server_match_config(ServerOptions * options,struct include_list * includes,struct connection_info * connectinfo)2865 parse_server_match_config(ServerOptions *options,
2866    struct include_list *includes, struct connection_info *connectinfo)
2867 {
2868 	ServerOptions mo;
2869 
2870 	initialize_server_options(&mo);
2871 	parse_server_config(&mo, "reprocess config", cfg, includes,
2872 	    connectinfo, 0);
2873 	copy_set_server_options(options, &mo, 0);
2874 }
2875 
2876 int
parse_server_match_testspec(struct connection_info * ci,char * spec)2877 parse_server_match_testspec(struct connection_info *ci, char *spec)
2878 {
2879 	char *p;
2880 	const char *val;
2881 
2882 	while ((p = strsep(&spec, ",")) && *p != '\0') {
2883 		if ((val = strprefix(p, "addr=", 0)) != NULL) {
2884 			ci->address = xstrdup(val);
2885 		} else if ((val = strprefix(p, "host=", 0)) != NULL) {
2886 			ci->host = xstrdup(val);
2887 		} else if ((val = strprefix(p, "user=", 0)) != NULL) {
2888 			ci->user = xstrdup(val);
2889 		} else if ((val = strprefix(p, "laddr=", 0)) != NULL) {
2890 			ci->laddress = xstrdup(val);
2891 		} else if ((val = strprefix(p, "rdomain=", 0)) != NULL) {
2892 			ci->rdomain = xstrdup(val);
2893 		} else if ((val = strprefix(p, "lport=", 0)) != NULL) {
2894 			ci->lport = a2port(val);
2895 			if (ci->lport == -1) {
2896 				fprintf(stderr, "Invalid port '%s' in test mode"
2897 				    " specification %s\n", p+6, p);
2898 				return -1;
2899 			}
2900 		} else if (strcmp(p, "invalid-user") == 0) {
2901 			ci->user_invalid = 1;
2902 		} else {
2903 			fprintf(stderr, "Invalid test mode specification %s\n",
2904 			    p);
2905 			return -1;
2906 		}
2907 	}
2908 	return 0;
2909 }
2910 
2911 void
servconf_merge_subsystems(ServerOptions * dst,ServerOptions * src)2912 servconf_merge_subsystems(ServerOptions *dst, ServerOptions *src)
2913 {
2914 	u_int i, j, found;
2915 
2916 	for (i = 0; i < src->num_subsystems; i++) {
2917 		found = 0;
2918 		for (j = 0; j < dst->num_subsystems; j++) {
2919 			if (strcmp(src->subsystem_name[i],
2920 			    dst->subsystem_name[j]) == 0) {
2921 				found = 1;
2922 				break;
2923 			}
2924 		}
2925 		if (found) {
2926 			debug_f("override \"%s\"", dst->subsystem_name[j]);
2927 			free(dst->subsystem_command[j]);
2928 			free(dst->subsystem_args[j]);
2929 			dst->subsystem_command[j] =
2930 			    xstrdup(src->subsystem_command[i]);
2931 			dst->subsystem_args[j] =
2932 			    xstrdup(src->subsystem_args[i]);
2933 			continue;
2934 		}
2935 		debug_f("add \"%s\"", src->subsystem_name[i]);
2936 		dst->subsystem_name = xrecallocarray(
2937 		    dst->subsystem_name, dst->num_subsystems,
2938 		    dst->num_subsystems + 1, sizeof(*dst->subsystem_name));
2939 		dst->subsystem_command = xrecallocarray(
2940 		    dst->subsystem_command, dst->num_subsystems,
2941 		    dst->num_subsystems + 1, sizeof(*dst->subsystem_command));
2942 		dst->subsystem_args = xrecallocarray(
2943 		    dst->subsystem_args, dst->num_subsystems,
2944 		    dst->num_subsystems + 1, sizeof(*dst->subsystem_args));
2945 		j = dst->num_subsystems++;
2946 		dst->subsystem_name[j] = xstrdup(src->subsystem_name[i]);
2947 		dst->subsystem_command[j] = xstrdup(src->subsystem_command[i]);
2948 		dst->subsystem_args[j] = xstrdup(src->subsystem_args[i]);
2949 	}
2950 }
2951 
2952 /*
2953  * Copy any supported values that are set.
2954  *
2955  * If the preauth flag is set, we do not bother copying the string or
2956  * array values that are not used pre-authentication, because any that we
2957  * do use must be explicitly sent in mm_getpwnamallow().
2958  */
2959 void
copy_set_server_options(ServerOptions * dst,ServerOptions * src,int preauth)2960 copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
2961 {
2962 #define M_CP_INTOPT(n) do {\
2963 	if (src->n != -1) \
2964 		dst->n = src->n; \
2965 } while (0)
2966 
2967 	M_CP_INTOPT(password_authentication);
2968 	M_CP_INTOPT(gss_authentication);
2969 	M_CP_INTOPT(pubkey_authentication);
2970 	M_CP_INTOPT(pubkey_auth_options);
2971 	M_CP_INTOPT(kerberos_authentication);
2972 	M_CP_INTOPT(hostbased_authentication);
2973 	M_CP_INTOPT(hostbased_uses_name_from_packet_only);
2974 	M_CP_INTOPT(kbd_interactive_authentication);
2975 	M_CP_INTOPT(permit_root_login);
2976 	M_CP_INTOPT(permit_empty_passwd);
2977 	M_CP_INTOPT(ignore_rhosts);
2978 
2979 	M_CP_INTOPT(allow_tcp_forwarding);
2980 	M_CP_INTOPT(allow_streamlocal_forwarding);
2981 	M_CP_INTOPT(allow_agent_forwarding);
2982 	M_CP_INTOPT(disable_forwarding);
2983 	M_CP_INTOPT(expose_userauth_info);
2984 	M_CP_INTOPT(permit_tun);
2985 	M_CP_INTOPT(fwd_opts.gateway_ports);
2986 	M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink);
2987 	M_CP_INTOPT(x11_display_offset);
2988 	M_CP_INTOPT(x11_forwarding);
2989 	M_CP_INTOPT(x11_use_localhost);
2990 	M_CP_INTOPT(permit_tty);
2991 	M_CP_INTOPT(permit_user_rc);
2992 	M_CP_INTOPT(max_sessions);
2993 	M_CP_INTOPT(max_authtries);
2994 	M_CP_INTOPT(client_alive_count_max);
2995 	M_CP_INTOPT(client_alive_interval);
2996 	M_CP_INTOPT(ip_qos_interactive);
2997 	M_CP_INTOPT(ip_qos_bulk);
2998 	M_CP_INTOPT(rekey_limit);
2999 	M_CP_INTOPT(rekey_interval);
3000 	M_CP_INTOPT(log_level);
3001 	M_CP_INTOPT(required_rsa_size);
3002 	M_CP_INTOPT(unused_connection_timeout);
3003 	M_CP_INTOPT(refuse_connection);
3004 
3005 	/*
3006 	 * The bind_mask is a mode_t that may be unsigned, so we can't use
3007 	 * M_CP_INTOPT - it does a signed comparison that causes compiler
3008 	 * warnings.
3009 	 */
3010 	if (src->fwd_opts.streamlocal_bind_mask != (mode_t)-1) {
3011 		dst->fwd_opts.streamlocal_bind_mask =
3012 		    src->fwd_opts.streamlocal_bind_mask;
3013 	}
3014 
3015 	/* M_CP_STROPT and M_CP_STRARRAYOPT should not appear before here */
3016 #define M_CP_STROPT(n) do {\
3017 	if (src->n != NULL && dst->n != src->n) { \
3018 		free(dst->n); \
3019 		dst->n = xstrdup(src->n); \
3020 	} \
3021 } while(0)
3022 #define M_CP_STRARRAYOPT(s, num_s, clobber) do {\
3023 	u_int i; \
3024 	if (src->num_s != 0) { \
3025 		for (i = 0; i < dst->num_s; i++) \
3026 			free(dst->s[i]); \
3027 		free(dst->s); \
3028 		dst->s = xcalloc(src->num_s, sizeof(*dst->s)); \
3029 		for (i = 0; i < src->num_s; i++) \
3030 			dst->s[i] = xstrdup(src->s[i]); \
3031 		if (clobber) \
3032 			dst->num_s = src->num_s; \
3033 	} \
3034 } while(0)
3035 
3036 	/* See comment in servconf.h */
3037 	COPY_MATCH_STRING_OPTS();
3038 
3039 	/* Arguments that accept '+...' need to be expanded */
3040 	assemble_algorithms(dst);
3041 
3042 	/*
3043 	 * The only things that should be below this point are string options
3044 	 * which are only used after authentication.
3045 	 */
3046 	if (preauth)
3047 		return;
3048 
3049 	/* These options may be "none" to clear a global setting */
3050 	M_CP_STROPT(adm_forced_command);
3051 	if (option_clear_or_none(dst->adm_forced_command)) {
3052 		free(dst->adm_forced_command);
3053 		dst->adm_forced_command = NULL;
3054 	}
3055 	M_CP_STROPT(chroot_directory);
3056 	if (option_clear_or_none(dst->chroot_directory)) {
3057 		free(dst->chroot_directory);
3058 		dst->chroot_directory = NULL;
3059 	}
3060 
3061 	/* Subsystems require merging. */
3062 	servconf_merge_subsystems(dst, src);
3063 }
3064 
3065 #undef M_CP_INTOPT
3066 #undef M_CP_STROPT
3067 #undef M_CP_STRARRAYOPT
3068 
3069 #define SERVCONF_MAX_DEPTH	16
3070 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)3071 parse_server_config_depth(ServerOptions *options, const char *filename,
3072     struct sshbuf *conf, struct include_list *includes,
3073     struct connection_info *connectinfo, int flags, int *activep, int depth)
3074 {
3075 	int linenum, bad_options = 0;
3076 	char *cp, *obuf, *cbuf;
3077 
3078 	if (depth < 0 || depth > SERVCONF_MAX_DEPTH)
3079 		fatal("Too many recursive configuration includes");
3080 
3081 	debug2_f("config %s len %zu%s", filename, sshbuf_len(conf),
3082 	    (flags & SSHCFG_NEVERMATCH ? " [checking syntax only]" : ""));
3083 
3084 	if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL)
3085 		fatal_f("sshbuf_dup_string failed");
3086 	linenum = 1;
3087 	while ((cp = strsep(&cbuf, "\n")) != NULL) {
3088 		if (process_server_config_line_depth(options, cp,
3089 		    filename, linenum++, activep, connectinfo, &flags,
3090 		    depth, includes) != 0)
3091 			bad_options++;
3092 	}
3093 	free(obuf);
3094 	if (bad_options > 0)
3095 		fatal("%s: terminating, %d bad configuration options",
3096 		    filename, bad_options);
3097 }
3098 
3099 void
parse_server_config(ServerOptions * options,const char * filename,struct sshbuf * conf,struct include_list * includes,struct connection_info * connectinfo,int reexec)3100 parse_server_config(ServerOptions *options, const char *filename,
3101     struct sshbuf *conf, struct include_list *includes,
3102     struct connection_info *connectinfo, int reexec)
3103 {
3104 	int active = connectinfo ? 0 : 1;
3105 	parse_server_config_depth(options, filename, conf, includes,
3106 	    connectinfo, (connectinfo ? SSHCFG_MATCH_ONLY : 0), &active, 0);
3107 	if (!reexec)
3108 		process_queued_listen_addrs(options);
3109 }
3110 
3111 static const char *
fmt_multistate_int(int val,const struct multistate * m)3112 fmt_multistate_int(int val, const struct multistate *m)
3113 {
3114 	u_int i;
3115 
3116 	for (i = 0; m[i].key != NULL; i++) {
3117 		if (m[i].value == val)
3118 			return m[i].key;
3119 	}
3120 	return "UNKNOWN";
3121 }
3122 
3123 static const char *
fmt_intarg(ServerOpCodes code,int val)3124 fmt_intarg(ServerOpCodes code, int val)
3125 {
3126 	if (val == -1)
3127 		return "unset";
3128 	switch (code) {
3129 	case sAddressFamily:
3130 		return fmt_multistate_int(val, multistate_addressfamily);
3131 	case sPermitRootLogin:
3132 		return fmt_multistate_int(val, multistate_permitrootlogin);
3133 	case sGatewayPorts:
3134 		return fmt_multistate_int(val, multistate_gatewayports);
3135 	case sCompression:
3136 		return fmt_multistate_int(val, multistate_compression);
3137 	case sAllowTcpForwarding:
3138 		return fmt_multistate_int(val, multistate_tcpfwd);
3139 	case sAllowStreamLocalForwarding:
3140 		return fmt_multistate_int(val, multistate_tcpfwd);
3141 	case sIgnoreRhosts:
3142 		return fmt_multistate_int(val, multistate_ignore_rhosts);
3143 	case sFingerprintHash:
3144 		return ssh_digest_alg_name(val);
3145 	default:
3146 		switch (val) {
3147 		case 0:
3148 			return "no";
3149 		case 1:
3150 			return "yes";
3151 		default:
3152 			return "UNKNOWN";
3153 		}
3154 	}
3155 }
3156 
3157 static void
dump_cfg_int(ServerOpCodes code,int val)3158 dump_cfg_int(ServerOpCodes code, int val)
3159 {
3160 	if (code == sUnusedConnectionTimeout && val == 0) {
3161 		printf("%s none\n", lookup_opcode_name(code));
3162 		return;
3163 	}
3164 	printf("%s %d\n", lookup_opcode_name(code), val);
3165 }
3166 
3167 static void
dump_cfg_oct(ServerOpCodes code,int val)3168 dump_cfg_oct(ServerOpCodes code, int val)
3169 {
3170 	printf("%s 0%o\n", lookup_opcode_name(code), val);
3171 }
3172 
3173 static void
dump_cfg_fmtint(ServerOpCodes code,int val)3174 dump_cfg_fmtint(ServerOpCodes code, int val)
3175 {
3176 	printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
3177 }
3178 
3179 static void
dump_cfg_string(ServerOpCodes code,const char * val)3180 dump_cfg_string(ServerOpCodes code, const char *val)
3181 {
3182 	printf("%s %s\n", lookup_opcode_name(code),
3183 	    val == NULL ? "none" : val);
3184 }
3185 
3186 static void
dump_cfg_strarray(ServerOpCodes code,u_int count,char ** vals)3187 dump_cfg_strarray(ServerOpCodes code, u_int count, char **vals)
3188 {
3189 	u_int i;
3190 
3191 	for (i = 0; i < count; i++)
3192 		printf("%s %s\n", lookup_opcode_name(code), vals[i]);
3193 }
3194 
3195 static void
dump_cfg_strarray_oneline(ServerOpCodes code,u_int count,char ** vals)3196 dump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals)
3197 {
3198 	u_int i;
3199 
3200 	switch (code) {
3201 	case sAuthenticationMethods:
3202 	case sChannelTimeout:
3203 		break;
3204 	default:
3205 		if (count <= 0)
3206 			return;
3207 		break;
3208 	}
3209 
3210 	printf("%s", lookup_opcode_name(code));
3211 	for (i = 0; i < count; i++)
3212 		printf(" %s",  vals[i]);
3213 	if (code == sAuthenticationMethods && count == 0)
3214 		printf(" any");
3215 	else if (code == sChannelTimeout && count == 0)
3216 		printf(" none");
3217 	printf("\n");
3218 }
3219 
3220 static char *
format_listen_addrs(struct listenaddr * la)3221 format_listen_addrs(struct listenaddr *la)
3222 {
3223 	int r;
3224 	struct addrinfo *ai;
3225 	char addr[NI_MAXHOST], port[NI_MAXSERV];
3226 	char *laddr1 = xstrdup(""), *laddr2 = NULL;
3227 
3228 	/*
3229 	 * ListenAddress must be after Port.  add_one_listen_addr pushes
3230 	 * addresses onto a stack, so to maintain ordering we need to
3231 	 * print these in reverse order.
3232 	 */
3233 	for (ai = la->addrs; ai; ai = ai->ai_next) {
3234 		if ((r = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
3235 		    sizeof(addr), port, sizeof(port),
3236 		    NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
3237 			error("getnameinfo: %.100s", ssh_gai_strerror(r));
3238 			continue;
3239 		}
3240 		laddr2 = laddr1;
3241 		if (ai->ai_family == AF_INET6) {
3242 			xasprintf(&laddr1, "listenaddress [%s]:%s%s%s\n%s",
3243 			    addr, port,
3244 			    la->rdomain == NULL ? "" : " rdomain ",
3245 			    la->rdomain == NULL ? "" : la->rdomain,
3246 			    laddr2);
3247 		} else {
3248 			xasprintf(&laddr1, "listenaddress %s:%s%s%s\n%s",
3249 			    addr, port,
3250 			    la->rdomain == NULL ? "" : " rdomain ",
3251 			    la->rdomain == NULL ? "" : la->rdomain,
3252 			    laddr2);
3253 		}
3254 		free(laddr2);
3255 	}
3256 	return laddr1;
3257 }
3258 
3259 void
dump_config(ServerOptions * o)3260 dump_config(ServerOptions *o)
3261 {
3262 	char *s;
3263 	u_int i;
3264 
3265 	/* these are usually at the top of the config */
3266 	for (i = 0; i < o->num_ports; i++)
3267 		printf("port %d\n", o->ports[i]);
3268 	dump_cfg_fmtint(sAddressFamily, o->address_family);
3269 
3270 	for (i = 0; i < o->num_listen_addrs; i++) {
3271 		s = format_listen_addrs(&o->listen_addrs[i]);
3272 		printf("%s", s);
3273 		free(s);
3274 	}
3275 
3276 	/* integer arguments */
3277 #ifdef USE_PAM
3278 	dump_cfg_fmtint(sUsePAM, o->use_pam);
3279 	dump_cfg_string(sPAMServiceName, o->pam_service_name);
3280 #endif
3281 	dump_cfg_int(sLoginGraceTime, o->login_grace_time);
3282 	dump_cfg_int(sX11DisplayOffset, o->x11_display_offset);
3283 	dump_cfg_int(sMaxAuthTries, o->max_authtries);
3284 	dump_cfg_int(sMaxSessions, o->max_sessions);
3285 	dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
3286 	dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
3287 	dump_cfg_int(sRequiredRSASize, o->required_rsa_size);
3288 	dump_cfg_oct(sStreamLocalBindMask, o->fwd_opts.streamlocal_bind_mask);
3289 	dump_cfg_int(sUnusedConnectionTimeout, o->unused_connection_timeout);
3290 
3291 	/* formatted integer arguments */
3292 	dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login);
3293 	dump_cfg_fmtint(sIgnoreRhosts, o->ignore_rhosts);
3294 	dump_cfg_fmtint(sIgnoreUserKnownHosts, o->ignore_user_known_hosts);
3295 	dump_cfg_fmtint(sHostbasedAuthentication, o->hostbased_authentication);
3296 	dump_cfg_fmtint(sHostbasedUsesNameFromPacketOnly,
3297 	    o->hostbased_uses_name_from_packet_only);
3298 	dump_cfg_fmtint(sPubkeyAuthentication, o->pubkey_authentication);
3299 #ifdef KRB5
3300 	dump_cfg_fmtint(sKerberosAuthentication, o->kerberos_authentication);
3301 	dump_cfg_fmtint(sKerberosOrLocalPasswd, o->kerberos_or_local_passwd);
3302 	dump_cfg_fmtint(sKerberosTicketCleanup, o->kerberos_ticket_cleanup);
3303 # ifdef USE_AFS
3304 	dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
3305 # endif
3306 #endif
3307 #ifdef GSSAPI
3308 	dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
3309 	dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
3310 	dump_cfg_fmtint(sGssDelegateCreds, o->gss_deleg_creds);
3311 	dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor);
3312 #endif
3313 	dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
3314 	dump_cfg_fmtint(sKbdInteractiveAuthentication,
3315 	    o->kbd_interactive_authentication);
3316 	dump_cfg_fmtint(sPrintMotd, o->print_motd);
3317 #ifndef DISABLE_LASTLOG
3318 	dump_cfg_fmtint(sPrintLastLog, o->print_lastlog);
3319 #endif
3320 	dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding);
3321 	dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost);
3322 	dump_cfg_fmtint(sPermitTTY, o->permit_tty);
3323 	dump_cfg_fmtint(sPermitUserRC, o->permit_user_rc);
3324 	dump_cfg_fmtint(sStrictModes, o->strict_modes);
3325 	dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive);
3326 	dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd);
3327 	dump_cfg_fmtint(sCompression, o->compression);
3328 	dump_cfg_fmtint(sGatewayPorts, o->fwd_opts.gateway_ports);
3329 	dump_cfg_fmtint(sUseDNS, o->use_dns);
3330 	dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
3331 	dump_cfg_fmtint(sAllowAgentForwarding, o->allow_agent_forwarding);
3332 	dump_cfg_fmtint(sDisableForwarding, o->disable_forwarding);
3333 	dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding);
3334 	dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
3335 	dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash);
3336 	dump_cfg_fmtint(sExposeAuthInfo, o->expose_userauth_info);
3337 	dump_cfg_fmtint(sRefuseConnection, o->refuse_connection);
3338 	dump_cfg_fmtint(sUseBlocklist, o->use_blocklist);
3339 
3340 	/* string arguments */
3341 	dump_cfg_string(sPidFile, o->pid_file);
3342 	dump_cfg_string(sModuliFile, o->moduli_file);
3343 	dump_cfg_string(sXAuthLocation, o->xauth_location);
3344 	dump_cfg_string(sCiphers, o->ciphers);
3345 	dump_cfg_string(sMacs, o->macs);
3346 	dump_cfg_string(sBanner, o->banner);
3347 	dump_cfg_string(sForceCommand, o->adm_forced_command);
3348 	dump_cfg_string(sChrootDirectory, o->chroot_directory);
3349 	dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys);
3350 	dump_cfg_string(sSecurityKeyProvider, o->sk_provider);
3351 	dump_cfg_string(sAuthorizedPrincipalsFile,
3352 	    o->authorized_principals_file);
3353 	dump_cfg_string(sVersionAddendum, *o->version_addendum == '\0'
3354 	    ? "none" : o->version_addendum);
3355 	dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command);
3356 	dump_cfg_string(sAuthorizedKeysCommandUser, o->authorized_keys_command_user);
3357 	dump_cfg_string(sAuthorizedPrincipalsCommand, o->authorized_principals_command);
3358 	dump_cfg_string(sAuthorizedPrincipalsCommandUser, o->authorized_principals_command_user);
3359 	dump_cfg_string(sHostKeyAgent, o->host_key_agent);
3360 	dump_cfg_string(sKexAlgorithms, o->kex_algorithms);
3361 	dump_cfg_string(sCASignatureAlgorithms, o->ca_sign_algorithms);
3362 	dump_cfg_string(sHostbasedAcceptedAlgorithms, o->hostbased_accepted_algos);
3363 	dump_cfg_string(sHostKeyAlgorithms, o->hostkeyalgorithms);
3364 	dump_cfg_string(sPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos);
3365 #if defined(__OpenBSD__) || defined(HAVE_SYS_SET_PROCESS_RDOMAIN)
3366 	dump_cfg_string(sRDomain, o->routing_domain);
3367 #endif
3368 	dump_cfg_string(sSshdSessionPath, o->sshd_session_path);
3369 	dump_cfg_string(sSshdAuthPath, o->sshd_auth_path);
3370 	dump_cfg_string(sPerSourcePenaltyExemptList, o->per_source_penalty_exempt);
3371 
3372 	/* string arguments requiring a lookup */
3373 	dump_cfg_string(sLogLevel, log_level_name(o->log_level));
3374 	dump_cfg_string(sLogFacility, log_facility_name(o->log_facility));
3375 
3376 	/* string array arguments */
3377 	dump_cfg_strarray_oneline(sAuthorizedKeysFile, o->num_authkeys_files,
3378 	    o->authorized_keys_files);
3379 	dump_cfg_strarray_oneline(sRevokedKeys, o->num_revoked_keys_files,
3380 	    o->revoked_keys_files);
3381 	dump_cfg_strarray(sHostKeyFile, o->num_host_key_files,
3382 	    o->host_key_files);
3383 	dump_cfg_strarray(sHostCertificate, o->num_host_cert_files,
3384 	    o->host_cert_files);
3385 	dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users);
3386 	dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users);
3387 	dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups);
3388 	dump_cfg_strarray(sDenyGroups, o->num_deny_groups, o->deny_groups);
3389 	dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env);
3390 	dump_cfg_strarray(sSetEnv, o->num_setenv, o->setenv);
3391 	dump_cfg_strarray_oneline(sAuthenticationMethods,
3392 	    o->num_auth_methods, o->auth_methods);
3393 	dump_cfg_strarray_oneline(sLogVerbose,
3394 	    o->num_log_verbose, o->log_verbose);
3395 	dump_cfg_strarray_oneline(sChannelTimeout,
3396 	    o->num_channel_timeouts, o->channel_timeouts);
3397 
3398 	/* other arguments */
3399 	for (i = 0; i < o->num_subsystems; i++)
3400 		printf("subsystem %s %s\n", o->subsystem_name[i],
3401 		    o->subsystem_args[i]);
3402 
3403 	printf("maxstartups %d:%d:%d\n", o->max_startups_begin,
3404 	    o->max_startups_rate, o->max_startups);
3405 	printf("persourcemaxstartups ");
3406 	if (o->per_source_max_startups == INT_MAX)
3407 		printf("none\n");
3408 	else
3409 		printf("%d\n", o->per_source_max_startups);
3410 	printf("persourcenetblocksize %d:%d\n", o->per_source_masklen_ipv4,
3411 	    o->per_source_masklen_ipv6);
3412 
3413 	s = NULL;
3414 	for (i = 0; tunmode_desc[i].val != -1; i++) {
3415 		if (tunmode_desc[i].val == o->permit_tun) {
3416 			s = tunmode_desc[i].text;
3417 			break;
3418 		}
3419 	}
3420 	dump_cfg_string(sPermitTunnel, s);
3421 
3422 	printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
3423 	printf("%s\n", iptos2str(o->ip_qos_bulk));
3424 
3425 	printf("rekeylimit %llu %d\n", (unsigned long long)o->rekey_limit,
3426 	    o->rekey_interval);
3427 
3428 	printf("permitopen");
3429 	if (o->num_permitted_opens == 0)
3430 		printf(" any");
3431 	else {
3432 		for (i = 0; i < o->num_permitted_opens; i++)
3433 			printf(" %s", o->permitted_opens[i]);
3434 	}
3435 	printf("\n");
3436 	printf("permitlisten");
3437 	if (o->num_permitted_listens == 0)
3438 		printf(" any");
3439 	else {
3440 		for (i = 0; i < o->num_permitted_listens; i++)
3441 			printf(" %s", o->permitted_listens[i]);
3442 	}
3443 	printf("\n");
3444 
3445 	if (o->permit_user_env_allowlist == NULL) {
3446 		dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
3447 	} else {
3448 		printf("permituserenvironment %s\n",
3449 		    o->permit_user_env_allowlist);
3450 	}
3451 
3452 	printf("pubkeyauthoptions");
3453 	if (o->pubkey_auth_options == 0)
3454 		printf(" none");
3455 	if (o->pubkey_auth_options & PUBKEYAUTH_TOUCH_REQUIRED)
3456 		printf(" touch-required");
3457 	if (o->pubkey_auth_options & PUBKEYAUTH_VERIFY_REQUIRED)
3458 		printf(" verify-required");
3459 	printf("\n");
3460 
3461 	if (o->per_source_penalty.enabled) {
3462 		printf("persourcepenalties crash:%f authfail:%f noauth:%f "
3463 		    "invaliduser:%f "
3464 		    "grace-exceeded:%f refuseconnection:%f max:%f min:%f "
3465 		    "max-sources4:%d max-sources6:%d "
3466 		    "overflow:%s overflow6:%s\n",
3467 		    o->per_source_penalty.penalty_crash,
3468 		    o->per_source_penalty.penalty_authfail,
3469 		    o->per_source_penalty.penalty_noauth,
3470 		    o->per_source_penalty.penalty_invaliduser,
3471 		    o->per_source_penalty.penalty_grace,
3472 		    o->per_source_penalty.penalty_refuseconnection,
3473 		    o->per_source_penalty.penalty_max,
3474 		    o->per_source_penalty.penalty_min,
3475 		    o->per_source_penalty.max_sources4,
3476 		    o->per_source_penalty.max_sources6,
3477 		    o->per_source_penalty.overflow_mode ==
3478 		    PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL ?
3479 		    "deny-all" : "permissive",
3480 		    o->per_source_penalty.overflow_mode6 ==
3481 		    PER_SOURCE_PENALTY_OVERFLOW_DENY_ALL ?
3482 		    "deny-all" : "permissive");
3483 	} else
3484 		printf("persourcepenalties no\n");
3485 }
3486