1240075Sdes
2323124Sdes/* $OpenBSD: servconf.c,v 1.292 2016/06/23 05:17:51 djm Exp $ */
357429Smarkm/*
457429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
557429Smarkm *                    All rights reserved
660576Skris *
765674Skris * As far as I am concerned, the code I have written for this software
865674Skris * can be used freely for any purpose.  Any derived versions of this
965674Skris * software must be clearly marked as such, and if the derived work is
1065674Skris * incompatible with the protocol description in the RFC file, it must be
1165674Skris * called by a name other than "ssh" or "Secure Shell".
1257429Smarkm */
1357429Smarkm
1457429Smarkm#include "includes.h"
15162856Sdes__RCSID("$FreeBSD: stable/10/crypto/openssh/servconf.c 323124 2017-09-01 22:52:18Z des $");
1657429Smarkm
17162856Sdes#include <sys/types.h>
18162856Sdes#include <sys/socket.h>
19162856Sdes
20221420Sdes#include <netinet/in.h>
21221420Sdes#include <netinet/in_systm.h>
22221420Sdes#include <netinet/ip.h>
23221420Sdes
24255767Sdes#include <ctype.h>
25162856Sdes#include <netdb.h>
26162856Sdes#include <pwd.h>
27162856Sdes#include <stdio.h>
28162856Sdes#include <stdlib.h>
29162856Sdes#include <string.h>
30162856Sdes#include <signal.h>
31162856Sdes#include <unistd.h>
32295367Sdes#include <limits.h>
33162856Sdes#include <stdarg.h>
34181111Sdes#include <errno.h>
35255767Sdes#ifdef HAVE_UTIL_H
36255767Sdes#include <util.h>
37255767Sdes#endif
38162856Sdes
39181111Sdes#include "openbsd-compat/sys-queue.h"
40162856Sdes#include "xmalloc.h"
4157429Smarkm#include "ssh.h"
4276262Sgreen#include "log.h"
43162856Sdes#include "buffer.h"
44295367Sdes#include "misc.h"
4557429Smarkm#include "servconf.h"
4660576Skris#include "compat.h"
4776262Sgreen#include "pathnames.h"
4876262Sgreen#include "cipher.h"
49162856Sdes#include "key.h"
5076262Sgreen#include "kex.h"
5176262Sgreen#include "mac.h"
52162856Sdes#include "match.h"
53162856Sdes#include "channels.h"
54162856Sdes#include "groupaccess.h"
55240075Sdes#include "canohost.h"
56240075Sdes#include "packet.h"
57248619Sdes#include "hostfile.h"
58248619Sdes#include "auth.h"
59295367Sdes#include "myproposal.h"
60295367Sdes#include "digest.h"
61204917Sdes#include "version.h"
6257429Smarkm
63192595Sdesstatic void add_listen_addr(ServerOptions *, char *, int);
64192595Sdesstatic void add_one_listen_addr(ServerOptions *, char *, int);
6557429Smarkm
6698684Sdes/* Use of privilege separation or not */
6798684Sdesextern int use_privsep;
68162856Sdesextern Buffer cfg;
6976262Sgreen
7057429Smarkm/* Initializes the server options to their default values. */
7157429Smarkm
7260576Skrisvoid
7357429Smarkminitialize_server_options(ServerOptions *options)
7457429Smarkm{
7557429Smarkm	memset(options, 0, sizeof(*options));
7698941Sdes
7798941Sdes	/* Portable-specific options */
78124211Sdes	options->use_pam = -1;
7998941Sdes
8098941Sdes	/* Standard Options */
8157429Smarkm	options->num_ports = 0;
8257429Smarkm	options->ports_from_cmdline = 0;
83295367Sdes	options->queued_listen_addrs = NULL;
84295367Sdes	options->num_queued_listens = 0;
8557429Smarkm	options->listen_addrs = NULL;
86147005Sdes	options->address_family = -1;
8776262Sgreen	options->num_host_key_files = 0;
88204917Sdes	options->num_host_cert_files = 0;
89255767Sdes	options->host_key_agent = NULL;
9060576Skris	options->pid_file = NULL;
9157429Smarkm	options->server_key_bits = -1;
9257429Smarkm	options->login_grace_time = -1;
9357429Smarkm	options->key_regeneration_time = -1;
9476262Sgreen	options->permit_root_login = PERMIT_NOT_SET;
9557429Smarkm	options->ignore_rhosts = -1;
9657429Smarkm	options->ignore_user_known_hosts = -1;
9757429Smarkm	options->print_motd = -1;
9876262Sgreen	options->print_lastlog = -1;
9957429Smarkm	options->x11_forwarding = -1;
10057429Smarkm	options->x11_display_offset = -1;
10192559Sdes	options->x11_use_localhost = -1;
102262566Sdes	options->permit_tty = -1;
103295367Sdes	options->permit_user_rc = -1;
10465674Skris	options->xauth_location = NULL;
10557429Smarkm	options->strict_modes = -1;
106126277Sdes	options->tcp_keep_alive = -1;
10792559Sdes	options->log_facility = SYSLOG_FACILITY_NOT_SET;
10892559Sdes	options->log_level = SYSLOG_LEVEL_NOT_SET;
10957429Smarkm	options->rhosts_rsa_authentication = -1;
11076262Sgreen	options->hostbased_authentication = -1;
11176262Sgreen	options->hostbased_uses_name_from_packet_only = -1;
112295367Sdes	options->hostbased_key_types = NULL;
113295367Sdes	options->hostkeyalgorithms = NULL;
11457429Smarkm	options->rsa_authentication = -1;
11576262Sgreen	options->pubkey_authentication = -1;
116295367Sdes	options->pubkey_key_types = NULL;
11773400Sassar	options->kerberos_authentication = -1;
11892559Sdes	options->kerberos_or_local_passwd = -1;
11992559Sdes	options->kerberos_ticket_cleanup = -1;
120126277Sdes	options->kerberos_get_afs_token = -1;
121124211Sdes	options->gss_authentication=-1;
122124211Sdes	options->gss_cleanup_creds = -1;
123295367Sdes	options->gss_strict_acceptor = -1;
12457429Smarkm	options->password_authentication = -1;
12569591Sgreen	options->kbd_interactive_authentication = -1;
12692559Sdes	options->challenge_response_authentication = -1;
12757429Smarkm	options->permit_empty_passwd = -1;
128106130Sdes	options->permit_user_env = -1;
12957429Smarkm	options->use_login = -1;
13098684Sdes	options->compression = -1;
131255767Sdes	options->rekey_limit = -1;
132255767Sdes	options->rekey_interval = -1;
13369591Sgreen	options->allow_tcp_forwarding = -1;
134295367Sdes	options->allow_streamlocal_forwarding = -1;
135181111Sdes	options->allow_agent_forwarding = -1;
13657429Smarkm	options->num_allow_users = 0;
13757429Smarkm	options->num_deny_users = 0;
13857429Smarkm	options->num_allow_groups = 0;
13957429Smarkm	options->num_deny_groups = 0;
14060576Skris	options->ciphers = NULL;
14176262Sgreen	options->macs = NULL;
142221420Sdes	options->kex_algorithms = NULL;
14360576Skris	options->protocol = SSH_PROTO_UNKNOWN;
144295367Sdes	options->fwd_opts.gateway_ports = -1;
145295367Sdes	options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
146295367Sdes	options->fwd_opts.streamlocal_bind_unlink = -1;
14765674Skris	options->num_subsystems = 0;
14865674Skris	options->max_startups_begin = -1;
14965674Skris	options->max_startups_rate = -1;
15065674Skris	options->max_startups = -1;
151137019Sdes	options->max_authtries = -1;
152181111Sdes	options->max_sessions = -1;
15376262Sgreen	options->banner = NULL;
154124211Sdes	options->use_dns = -1;
15576262Sgreen	options->client_alive_interval = -1;
15676262Sgreen	options->client_alive_count_max = -1;
157226046Sdes	options->num_authkeys_files = 0;
158137019Sdes	options->num_accept_env = 0;
159157019Sdes	options->permit_tun = -1;
160162856Sdes	options->num_permitted_opens = -1;
161162856Sdes	options->adm_forced_command = NULL;
162181111Sdes	options->chroot_directory = NULL;
163248619Sdes	options->authorized_keys_command = NULL;
164248619Sdes	options->authorized_keys_command_user = NULL;
165204917Sdes	options->revoked_keys_file = NULL;
166204917Sdes	options->trusted_user_ca_keys = NULL;
167215116Sdes	options->authorized_principals_file = NULL;
168295367Sdes	options->authorized_principals_command = NULL;
169295367Sdes	options->authorized_principals_command_user = NULL;
170221420Sdes	options->ip_qos_interactive = -1;
171221420Sdes	options->ip_qos_bulk = -1;
172240075Sdes	options->version_addendum = NULL;
173295367Sdes	options->fingerprint_hash = -1;
17457429Smarkm}
17557429Smarkm
176295367Sdes/* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
177295367Sdesstatic int
178295367Sdesoption_clear_or_none(const char *o)
179295367Sdes{
180295367Sdes	return o == NULL || strcasecmp(o, "none") == 0;
181295367Sdes}
182295367Sdes
183296781Sdesstatic void
184296781Sdesassemble_algorithms(ServerOptions *o)
185296781Sdes{
186296781Sdes	if (kex_assemble_names(KEX_SERVER_ENCRYPT, &o->ciphers) != 0 ||
187296781Sdes	    kex_assemble_names(KEX_SERVER_MAC, &o->macs) != 0 ||
188296781Sdes	    kex_assemble_names(KEX_SERVER_KEX, &o->kex_algorithms) != 0 ||
189296781Sdes	    kex_assemble_names(KEX_DEFAULT_PK_ALG,
190296781Sdes	    &o->hostkeyalgorithms) != 0 ||
191296781Sdes	    kex_assemble_names(KEX_DEFAULT_PK_ALG,
192296781Sdes	    &o->hostbased_key_types) != 0 ||
193296781Sdes	    kex_assemble_names(KEX_DEFAULT_PK_ALG, &o->pubkey_key_types) != 0)
194296781Sdes		fatal("kex_assemble_names failed");
195296781Sdes}
196296781Sdes
19760576Skrisvoid
19857429Smarkmfill_default_server_options(ServerOptions *options)
19957429Smarkm{
200295367Sdes	int i;
201295367Sdes
20298941Sdes	/* Portable-specific options */
203124211Sdes	if (options->use_pam == -1)
204124279Sdes		options->use_pam = 1;
20598941Sdes
20698941Sdes	/* Standard Options */
20776262Sgreen	if (options->protocol == SSH_PROTO_UNKNOWN)
208126271Sdes		options->protocol = SSH_PROTO_2;
209295367Sdes	if (options->protocol & SSH_PROTO_1)
210295367Sdes		error("WARNING: SSH protocol version 1 enabled");
21176262Sgreen	if (options->num_host_key_files == 0) {
21276262Sgreen		/* fill default hostkeys for protocols */
21376262Sgreen		if (options->protocol & SSH_PROTO_1)
21492559Sdes			options->host_key_files[options->num_host_key_files++] =
21592559Sdes			    _PATH_HOST_KEY_FILE;
21692559Sdes		if (options->protocol & SSH_PROTO_2) {
21792559Sdes			options->host_key_files[options->num_host_key_files++] =
218231584Sed			    _PATH_HOST_RSA_KEY_FILE;
219181111Sdes			options->host_key_files[options->num_host_key_files++] =
22092559Sdes			    _PATH_HOST_DSA_KEY_FILE;
221221420Sdes#ifdef OPENSSL_HAS_ECC
222221420Sdes			options->host_key_files[options->num_host_key_files++] =
223221420Sdes			    _PATH_HOST_ECDSA_KEY_FILE;
224221420Sdes#endif
225262566Sdes			options->host_key_files[options->num_host_key_files++] =
226262566Sdes			    _PATH_HOST_ED25519_KEY_FILE;
22792559Sdes		}
22876262Sgreen	}
229204917Sdes	/* No certificates by default */
23057429Smarkm	if (options->num_ports == 0)
23157429Smarkm		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
232295367Sdes	if (options->address_family == -1)
233295367Sdes		options->address_family = AF_UNSPEC;
23457429Smarkm	if (options->listen_addrs == NULL)
23576262Sgreen		add_listen_addr(options, NULL, 0);
23660576Skris	if (options->pid_file == NULL)
237295367Sdes		options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE);
23857429Smarkm	if (options->server_key_bits == -1)
239181111Sdes		options->server_key_bits = 1024;
24057429Smarkm	if (options->login_grace_time == -1)
24199048Sdes		options->login_grace_time = 120;
24257429Smarkm	if (options->key_regeneration_time == -1)
24357429Smarkm		options->key_regeneration_time = 3600;
24476262Sgreen	if (options->permit_root_login == PERMIT_NOT_SET)
24599048Sdes		options->permit_root_login = PERMIT_NO;
24657429Smarkm	if (options->ignore_rhosts == -1)
24757565Smarkm		options->ignore_rhosts = 1;
24857429Smarkm	if (options->ignore_user_known_hosts == -1)
24957429Smarkm		options->ignore_user_known_hosts = 0;
25057429Smarkm	if (options->print_motd == -1)
25157429Smarkm		options->print_motd = 1;
25276262Sgreen	if (options->print_lastlog == -1)
25376262Sgreen		options->print_lastlog = 1;
25457429Smarkm	if (options->x11_forwarding == -1)
25599048Sdes		options->x11_forwarding = 1;
25657429Smarkm	if (options->x11_display_offset == -1)
25757565Smarkm		options->x11_display_offset = 10;
25892559Sdes	if (options->x11_use_localhost == -1)
25992559Sdes		options->x11_use_localhost = 1;
26065674Skris	if (options->xauth_location == NULL)
261295367Sdes		options->xauth_location = xstrdup(_PATH_XAUTH);
262262566Sdes	if (options->permit_tty == -1)
263262566Sdes		options->permit_tty = 1;
264295367Sdes	if (options->permit_user_rc == -1)
265295367Sdes		options->permit_user_rc = 1;
26657429Smarkm	if (options->strict_modes == -1)
26757429Smarkm		options->strict_modes = 1;
268126277Sdes	if (options->tcp_keep_alive == -1)
269126277Sdes		options->tcp_keep_alive = 1;
27092559Sdes	if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
27157429Smarkm		options->log_facility = SYSLOG_FACILITY_AUTH;
27292559Sdes	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
27357429Smarkm		options->log_level = SYSLOG_LEVEL_INFO;
27457429Smarkm	if (options->rhosts_rsa_authentication == -1)
27557565Smarkm		options->rhosts_rsa_authentication = 0;
27676262Sgreen	if (options->hostbased_authentication == -1)
27776262Sgreen		options->hostbased_authentication = 0;
27876262Sgreen	if (options->hostbased_uses_name_from_packet_only == -1)
27976262Sgreen		options->hostbased_uses_name_from_packet_only = 0;
28057429Smarkm	if (options->rsa_authentication == -1)
28157429Smarkm		options->rsa_authentication = 1;
28276262Sgreen	if (options->pubkey_authentication == -1)
28376262Sgreen		options->pubkey_authentication = 1;
28499048Sdes	if (options->kerberos_authentication == -1)
285124211Sdes		options->kerberos_authentication = 0;
28692559Sdes	if (options->kerberos_or_local_passwd == -1)
28792559Sdes		options->kerberos_or_local_passwd = 1;
28892559Sdes	if (options->kerberos_ticket_cleanup == -1)
28992559Sdes		options->kerberos_ticket_cleanup = 1;
290126277Sdes	if (options->kerberos_get_afs_token == -1)
291126277Sdes		options->kerberos_get_afs_token = 0;
292124211Sdes	if (options->gss_authentication == -1)
293124211Sdes		options->gss_authentication = 0;
294124211Sdes	if (options->gss_cleanup_creds == -1)
295124211Sdes		options->gss_cleanup_creds = 1;
296295367Sdes	if (options->gss_strict_acceptor == -1)
297295367Sdes		options->gss_strict_acceptor = 0;
29857429Smarkm	if (options->password_authentication == -1)
299126009Sdes		options->password_authentication = 0;
30069591Sgreen	if (options->kbd_interactive_authentication == -1)
30169591Sgreen		options->kbd_interactive_authentication = 0;
30292559Sdes	if (options->challenge_response_authentication == -1)
30395456Sdes		options->challenge_response_authentication = 1;
30457429Smarkm	if (options->permit_empty_passwd == -1)
30557565Smarkm		options->permit_empty_passwd = 0;
306106130Sdes	if (options->permit_user_env == -1)
307106130Sdes		options->permit_user_env = 0;
30857429Smarkm	if (options->use_login == -1)
30957429Smarkm		options->use_login = 0;
31098684Sdes	if (options->compression == -1)
311149753Sdes		options->compression = COMP_DELAYED;
312255767Sdes	if (options->rekey_limit == -1)
313255767Sdes		options->rekey_limit = 0;
314255767Sdes	if (options->rekey_interval == -1)
315255767Sdes		options->rekey_interval = 0;
31669591Sgreen	if (options->allow_tcp_forwarding == -1)
317248619Sdes		options->allow_tcp_forwarding = FORWARD_ALLOW;
318295367Sdes	if (options->allow_streamlocal_forwarding == -1)
319295367Sdes		options->allow_streamlocal_forwarding = FORWARD_ALLOW;
320181111Sdes	if (options->allow_agent_forwarding == -1)
321181111Sdes		options->allow_agent_forwarding = 1;
322295367Sdes	if (options->fwd_opts.gateway_ports == -1)
323295367Sdes		options->fwd_opts.gateway_ports = 0;
32465674Skris	if (options->max_startups == -1)
325248619Sdes		options->max_startups = 100;
32665674Skris	if (options->max_startups_rate == -1)
327248619Sdes		options->max_startups_rate = 30;		/* 30% */
32865674Skris	if (options->max_startups_begin == -1)
329248619Sdes		options->max_startups_begin = 10;
330137019Sdes	if (options->max_authtries == -1)
331137019Sdes		options->max_authtries = DEFAULT_AUTH_FAIL_MAX;
332181111Sdes	if (options->max_sessions == -1)
333181111Sdes		options->max_sessions = DEFAULT_SESSIONS_MAX;
334124211Sdes	if (options->use_dns == -1)
335124211Sdes		options->use_dns = 1;
33676262Sgreen	if (options->client_alive_interval == -1)
33792559Sdes		options->client_alive_interval = 0;
33876262Sgreen	if (options->client_alive_count_max == -1)
33976262Sgreen		options->client_alive_count_max = 3;
340226046Sdes	if (options->num_authkeys_files == 0) {
341226046Sdes		options->authorized_keys_files[options->num_authkeys_files++] =
342226046Sdes		    xstrdup(_PATH_SSH_USER_PERMITTED_KEYS);
343226046Sdes		options->authorized_keys_files[options->num_authkeys_files++] =
344226046Sdes		    xstrdup(_PATH_SSH_USER_PERMITTED_KEYS2);
34592559Sdes	}
346157019Sdes	if (options->permit_tun == -1)
347157019Sdes		options->permit_tun = SSH_TUNMODE_NO;
348221420Sdes	if (options->ip_qos_interactive == -1)
349221420Sdes		options->ip_qos_interactive = IPTOS_LOWDELAY;
350221420Sdes	if (options->ip_qos_bulk == -1)
351221420Sdes		options->ip_qos_bulk = IPTOS_THROUGHPUT;
352240075Sdes	if (options->version_addendum == NULL)
353240075Sdes		options->version_addendum = xstrdup(SSH_VERSION_FREEBSD);
354295367Sdes	if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
355295367Sdes		options->fwd_opts.streamlocal_bind_mask = 0177;
356295367Sdes	if (options->fwd_opts.streamlocal_bind_unlink == -1)
357295367Sdes		options->fwd_opts.streamlocal_bind_unlink = 0;
358295367Sdes	if (options->fingerprint_hash == -1)
359295367Sdes		options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
360295367Sdes
361296781Sdes	assemble_algorithms(options);
362295367Sdes
363296781Sdes	/* Turn privilege separation and sandboxing on by default */
364240075Sdes	if (use_privsep == -1)
365262566Sdes		use_privsep = PRIVSEP_ON;
366240075Sdes
367295367Sdes#define CLEAR_ON_NONE(v) \
368295367Sdes	do { \
369295367Sdes		if (option_clear_or_none(v)) { \
370295367Sdes			free(v); \
371295367Sdes			v = NULL; \
372295367Sdes		} \
373295367Sdes	} while(0)
374295367Sdes	CLEAR_ON_NONE(options->pid_file);
375295367Sdes	CLEAR_ON_NONE(options->xauth_location);
376295367Sdes	CLEAR_ON_NONE(options->banner);
377295367Sdes	CLEAR_ON_NONE(options->trusted_user_ca_keys);
378295367Sdes	CLEAR_ON_NONE(options->revoked_keys_file);
379295367Sdes	CLEAR_ON_NONE(options->authorized_principals_file);
380296781Sdes	CLEAR_ON_NONE(options->adm_forced_command);
381296781Sdes	CLEAR_ON_NONE(options->chroot_directory);
382295367Sdes	for (i = 0; i < options->num_host_key_files; i++)
383295367Sdes		CLEAR_ON_NONE(options->host_key_files[i]);
384295367Sdes	for (i = 0; i < options->num_host_cert_files; i++)
385295367Sdes		CLEAR_ON_NONE(options->host_cert_files[i]);
386295367Sdes#undef CLEAR_ON_NONE
387295367Sdes
388323124Sdes	/* Similar handling for AuthenticationMethods=any */
389323124Sdes	if (options->num_auth_methods == 1 &&
390323124Sdes	    strcmp(options->auth_methods[0], "any") == 0) {
391323124Sdes		free(options->auth_methods[0]);
392323124Sdes		options->auth_methods[0] = NULL;
393323124Sdes		options->num_auth_methods = 0;
394323124Sdes	}
395323124Sdes
396240075Sdes#ifndef HAVE_MMAP
397240075Sdes	if (use_privsep && options->compression == 1) {
398240075Sdes		error("This platform does not support both privilege "
399240075Sdes		    "separation and compression");
400240075Sdes		error("Compression disabled");
401240075Sdes		options->compression = 0;
402240075Sdes	}
403240075Sdes#endif
404240075Sdes
40557429Smarkm}
40657429Smarkm
40757429Smarkm/* Keyword tokens. */
40857429Smarkmtypedef enum {
40957429Smarkm	sBadOption,		/* == unknown option */
41098941Sdes	/* Portable-specific options */
411124211Sdes	sUsePAM,
41298941Sdes	/* Standard Options */
413295367Sdes	sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime,
414295367Sdes	sKeyRegenerationTime, sPermitRootLogin, sLogFacility, sLogLevel,
415124211Sdes	sRhostsRSAAuthentication, sRSAAuthentication,
41692559Sdes	sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
417126277Sdes	sKerberosGetAFSToken,
418124211Sdes	sKerberosTgtPassing, sChallengeResponseAuthentication,
419147005Sdes	sPasswordAuthentication, sKbdInteractiveAuthentication,
420147005Sdes	sListenAddress, sAddressFamily,
42176262Sgreen	sPrintMotd, sPrintLastLog, sIgnoreRhosts,
42292559Sdes	sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
423262566Sdes	sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive,
424106130Sdes	sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression,
425255767Sdes	sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
42676262Sgreen	sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
427295367Sdes	sGatewayPorts, sPubkeyAuthentication, sPubkeyAcceptedKeyTypes,
428295367Sdes	sXAuthLocation, sSubsystem, sMaxStartups, sMaxAuthTries, sMaxSessions,
429124211Sdes	sBanner, sUseDNS, sHostbasedAuthentication,
430295367Sdes	sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedKeyTypes,
431295367Sdes	sHostKeyAlgorithms,
432295367Sdes	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
433295367Sdes	sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
434295367Sdes	sAcceptEnv, sPermitTunnel,
435181111Sdes	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
436181111Sdes	sUsePrivilegeSeparation, sAllowAgentForwarding,
437264377Sdes	sHostCertificate,
438215116Sdes	sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
439295367Sdes	sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser,
440240075Sdes	sKexAlgorithms, sIPQoS, sVersionAddendum,
441248619Sdes	sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
442295367Sdes	sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
443295367Sdes	sStreamLocalBindMask, sStreamLocalBindUnlink,
444295367Sdes	sAllowStreamLocalForwarding, sFingerprintHash,
445124211Sdes	sDeprecated, sUnsupported
44657429Smarkm} ServerOpCodes;
44757429Smarkm
448162856Sdes#define SSHCFG_GLOBAL	0x01	/* allowed in main section of sshd_config */
449162856Sdes#define SSHCFG_MATCH	0x02	/* allowed inside a Match section */
450162856Sdes#define SSHCFG_ALL	(SSHCFG_GLOBAL|SSHCFG_MATCH)
451162856Sdes
45257429Smarkm/* Textual representation of the tokens. */
45357429Smarkmstatic struct {
45457429Smarkm	const char *name;
45557429Smarkm	ServerOpCodes opcode;
456162856Sdes	u_int flags;
45757429Smarkm} keywords[] = {
45898941Sdes	/* Portable-specific options */
459124211Sdes#ifdef USE_PAM
460162856Sdes	{ "usepam", sUsePAM, SSHCFG_GLOBAL },
461124211Sdes#else
462162856Sdes	{ "usepam", sUnsupported, SSHCFG_GLOBAL },
46399048Sdes#endif
464162856Sdes	{ "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
46598941Sdes	/* Standard Options */
466162856Sdes	{ "port", sPort, SSHCFG_GLOBAL },
467162856Sdes	{ "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
468162856Sdes	{ "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL },		/* alias */
469255767Sdes	{ "hostkeyagent", sHostKeyAgent, SSHCFG_GLOBAL },
470162856Sdes	{ "pidfile", sPidFile, SSHCFG_GLOBAL },
471162856Sdes	{ "serverkeybits", sServerKeyBits, SSHCFG_GLOBAL },
472162856Sdes	{ "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL },
473162856Sdes	{ "keyregenerationinterval", sKeyRegenerationTime, SSHCFG_GLOBAL },
474181111Sdes	{ "permitrootlogin", sPermitRootLogin, SSHCFG_ALL },
475162856Sdes	{ "syslogfacility", sLogFacility, SSHCFG_GLOBAL },
476162856Sdes	{ "loglevel", sLogLevel, SSHCFG_GLOBAL },
477162856Sdes	{ "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL },
478181111Sdes	{ "rhostsrsaauthentication", sRhostsRSAAuthentication, SSHCFG_ALL },
479181111Sdes	{ "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL },
480215116Sdes	{ "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_ALL },
481295367Sdes	{ "hostbasedacceptedkeytypes", sHostbasedAcceptedKeyTypes, SSHCFG_ALL },
482295367Sdes	{ "hostkeyalgorithms", sHostKeyAlgorithms, SSHCFG_GLOBAL },
483181111Sdes	{ "rsaauthentication", sRSAAuthentication, SSHCFG_ALL },
484181111Sdes	{ "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL },
485295367Sdes	{ "pubkeyacceptedkeytypes", sPubkeyAcceptedKeyTypes, SSHCFG_ALL },
486197679Sdes	{ "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */
487124211Sdes#ifdef KRB5
488181111Sdes	{ "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL },
489162856Sdes	{ "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL },
490162856Sdes	{ "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL },
491126277Sdes#ifdef USE_AFS
492162856Sdes	{ "kerberosgetafstoken", sKerberosGetAFSToken, SSHCFG_GLOBAL },
493124211Sdes#else
494162856Sdes	{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
495126277Sdes#endif
496126277Sdes#else
497181111Sdes	{ "kerberosauthentication", sUnsupported, SSHCFG_ALL },
498162856Sdes	{ "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
499162856Sdes	{ "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
500162856Sdes	{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
50173400Sassar#endif
502162856Sdes	{ "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
503162856Sdes	{ "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
504124211Sdes#ifdef GSSAPI
505181111Sdes	{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
506162856Sdes	{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
507295367Sdes	{ "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
508124211Sdes#else
509181111Sdes	{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
510162856Sdes	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
511295367Sdes	{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
51257429Smarkm#endif
513181111Sdes	{ "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
514181111Sdes	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
515162856Sdes	{ "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
516162856Sdes	{ "skeyauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, /* alias */
517162856Sdes	{ "checkmail", sDeprecated, SSHCFG_GLOBAL },
518162856Sdes	{ "listenaddress", sListenAddress, SSHCFG_GLOBAL },
519162856Sdes	{ "addressfamily", sAddressFamily, SSHCFG_GLOBAL },
520162856Sdes	{ "printmotd", sPrintMotd, SSHCFG_GLOBAL },
521296781Sdes#ifdef DISABLE_LASTLOG
522296781Sdes	{ "printlastlog", sUnsupported, SSHCFG_GLOBAL },
523296781Sdes#else
524162856Sdes	{ "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
525296781Sdes#endif
526162856Sdes	{ "ignorerhosts", sIgnoreRhosts, SSHCFG_GLOBAL },
527162856Sdes	{ "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
528162856Sdes	{ "x11forwarding", sX11Forwarding, SSHCFG_ALL },
529162856Sdes	{ "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
530162856Sdes	{ "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
531162856Sdes	{ "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
532162856Sdes	{ "strictmodes", sStrictModes, SSHCFG_GLOBAL },
533192595Sdes	{ "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL },
534162856Sdes	{ "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
535162856Sdes	{ "uselogin", sUseLogin, SSHCFG_GLOBAL },
536162856Sdes	{ "compression", sCompression, SSHCFG_GLOBAL },
537255767Sdes	{ "rekeylimit", sRekeyLimit, SSHCFG_ALL },
538162856Sdes	{ "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
539162856Sdes	{ "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL },	/* obsolete alias */
540162856Sdes	{ "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
541181111Sdes	{ "allowagentforwarding", sAllowAgentForwarding, SSHCFG_ALL },
542240075Sdes	{ "allowusers", sAllowUsers, SSHCFG_ALL },
543240075Sdes	{ "denyusers", sDenyUsers, SSHCFG_ALL },
544240075Sdes	{ "allowgroups", sAllowGroups, SSHCFG_ALL },
545240075Sdes	{ "denygroups", sDenyGroups, SSHCFG_ALL },
546162856Sdes	{ "ciphers", sCiphers, SSHCFG_GLOBAL },
547162856Sdes	{ "macs", sMacs, SSHCFG_GLOBAL },
548162856Sdes	{ "protocol", sProtocol, SSHCFG_GLOBAL },
549162856Sdes	{ "gatewayports", sGatewayPorts, SSHCFG_ALL },
550162856Sdes	{ "subsystem", sSubsystem, SSHCFG_GLOBAL },
551162856Sdes	{ "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
552181111Sdes	{ "maxauthtries", sMaxAuthTries, SSHCFG_ALL },
553181111Sdes	{ "maxsessions", sMaxSessions, SSHCFG_ALL },
554181111Sdes	{ "banner", sBanner, SSHCFG_ALL },
555162856Sdes	{ "usedns", sUseDNS, SSHCFG_GLOBAL },
556162856Sdes	{ "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
557162856Sdes	{ "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL },
558162856Sdes	{ "clientaliveinterval", sClientAliveInterval, SSHCFG_GLOBAL },
559162856Sdes	{ "clientalivecountmax", sClientAliveCountMax, SSHCFG_GLOBAL },
560215116Sdes	{ "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_ALL },
561226046Sdes	{ "authorizedkeysfile2", sDeprecated, SSHCFG_ALL },
562197679Sdes	{ "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL},
563240075Sdes	{ "acceptenv", sAcceptEnv, SSHCFG_ALL },
564215116Sdes	{ "permittunnel", sPermitTunnel, SSHCFG_ALL },
565262566Sdes	{ "permittty", sPermitTTY, SSHCFG_ALL },
566295367Sdes	{ "permituserrc", sPermitUserRC, SSHCFG_ALL },
567197679Sdes	{ "match", sMatch, SSHCFG_ALL },
568162856Sdes	{ "permitopen", sPermitOpen, SSHCFG_ALL },
569162856Sdes	{ "forcecommand", sForceCommand, SSHCFG_ALL },
570181111Sdes	{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
571204917Sdes	{ "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
572204917Sdes	{ "revokedkeys", sRevokedKeys, SSHCFG_ALL },
573204917Sdes	{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
574215116Sdes	{ "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
575221420Sdes	{ "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
576221420Sdes	{ "ipqos", sIPQoS, SSHCFG_ALL },
577248619Sdes	{ "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
578248619Sdes	{ "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
579295367Sdes	{ "authorizedprincipalscommand", sAuthorizedPrincipalsCommand, SSHCFG_ALL },
580295367Sdes	{ "authorizedprincipalscommanduser", sAuthorizedPrincipalsCommandUser, SSHCFG_ALL },
581240075Sdes	{ "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL },
582248619Sdes	{ "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL },
583295367Sdes	{ "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_ALL },
584295367Sdes	{ "streamlocalbindunlink", sStreamLocalBindUnlink, SSHCFG_ALL },
585295367Sdes	{ "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL },
586295367Sdes	{ "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL },
587294693Sdes	{ "noneenabled", sUnsupported, SSHCFG_ALL },
588294693Sdes	{ "hpndisabled", sDeprecated, SSHCFG_ALL },
589294693Sdes	{ "hpnbuffersize", sDeprecated, SSHCFG_ALL },
590294693Sdes	{ "tcprcvbufpoll", sDeprecated, SSHCFG_ALL },
591162856Sdes	{ NULL, sBadOption, 0 }
59257429Smarkm};
59357429Smarkm
594181111Sdesstatic struct {
595181111Sdes	int val;
596181111Sdes	char *text;
597181111Sdes} tunmode_desc[] = {
598181111Sdes	{ SSH_TUNMODE_NO, "no" },
599181111Sdes	{ SSH_TUNMODE_POINTOPOINT, "point-to-point" },
600181111Sdes	{ SSH_TUNMODE_ETHERNET, "ethernet" },
601181111Sdes	{ SSH_TUNMODE_YES, "yes" },
602181111Sdes	{ -1, NULL }
603181111Sdes};
604181111Sdes
60557429Smarkm/*
60676262Sgreen * Returns the number of the token pointed to by cp or sBadOption.
60757429Smarkm */
60857429Smarkm
60960576Skrisstatic ServerOpCodes
61057429Smarkmparse_token(const char *cp, const char *filename,
611162856Sdes	    int linenum, u_int *flags)
61257429Smarkm{
61376262Sgreen	u_int i;
61457429Smarkm
61557429Smarkm	for (i = 0; keywords[i].name; i++)
616162856Sdes		if (strcasecmp(cp, keywords[i].name) == 0) {
617162856Sdes			*flags = keywords[i].flags;
61857429Smarkm			return keywords[i].opcode;
619162856Sdes		}
62057429Smarkm
62176262Sgreen	error("%s: line %d: Bad configuration option: %s",
62276262Sgreen	    filename, linenum, cp);
62357429Smarkm	return sBadOption;
62457429Smarkm}
62557429Smarkm
626204917Sdeschar *
627204917Sdesderelativise_path(const char *path)
628204917Sdes{
629295367Sdes	char *expanded, *ret, cwd[PATH_MAX];
630204917Sdes
631295367Sdes	if (strcasecmp(path, "none") == 0)
632295367Sdes		return xstrdup("none");
633204917Sdes	expanded = tilde_expand_filename(path, getuid());
634204917Sdes	if (*expanded == '/')
635204917Sdes		return expanded;
636207319Sdes	if (getcwd(cwd, sizeof(cwd)) == NULL)
637204917Sdes		fatal("%s: getcwd: %s", __func__, strerror(errno));
638204917Sdes	xasprintf(&ret, "%s/%s", cwd, expanded);
639255767Sdes	free(expanded);
640204917Sdes	return ret;
641204917Sdes}
642204917Sdes
64392559Sdesstatic void
644192595Sdesadd_listen_addr(ServerOptions *options, char *addr, int port)
64557429Smarkm{
646149753Sdes	u_int i;
64757429Smarkm
64876262Sgreen	if (port == 0)
64976262Sgreen		for (i = 0; i < options->num_ports; i++)
65076262Sgreen			add_one_listen_addr(options, addr, options->ports[i]);
65176262Sgreen	else
65276262Sgreen		add_one_listen_addr(options, addr, port);
65357429Smarkm}
65457429Smarkm
65592559Sdesstatic void
656192595Sdesadd_one_listen_addr(ServerOptions *options, char *addr, int port)
65776262Sgreen{
65876262Sgreen	struct addrinfo hints, *ai, *aitop;
65976262Sgreen	char strport[NI_MAXSERV];
66076262Sgreen	int gaierr;
66176262Sgreen
66276262Sgreen	memset(&hints, 0, sizeof(hints));
663147005Sdes	hints.ai_family = options->address_family;
66476262Sgreen	hints.ai_socktype = SOCK_STREAM;
66576262Sgreen	hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
666192595Sdes	snprintf(strport, sizeof strport, "%d", port);
66776262Sgreen	if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
66876262Sgreen		fatal("bad addr or host: %s (%s)",
66976262Sgreen		    addr ? addr : "<NULL>",
670181111Sdes		    ssh_gai_strerror(gaierr));
67176262Sgreen	for (ai = aitop; ai->ai_next; ai = ai->ai_next)
67276262Sgreen		;
67376262Sgreen	ai->ai_next = options->listen_addrs;
67476262Sgreen	options->listen_addrs = aitop;
67576262Sgreen}
67676262Sgreen
677295367Sdes/*
678295367Sdes * Queue a ListenAddress to be processed once we have all of the Ports
679295367Sdes * and AddressFamily options.
680295367Sdes */
681295367Sdesstatic void
682295367Sdesqueue_listen_addr(ServerOptions *options, char *addr, int port)
683295367Sdes{
684295367Sdes	options->queued_listen_addrs = xreallocarray(
685295367Sdes	    options->queued_listen_addrs, options->num_queued_listens + 1,
686295367Sdes	    sizeof(addr));
687295367Sdes	options->queued_listen_ports = xreallocarray(
688295367Sdes	    options->queued_listen_ports, options->num_queued_listens + 1,
689295367Sdes	    sizeof(port));
690295367Sdes	options->queued_listen_addrs[options->num_queued_listens] =
691295367Sdes	    xstrdup(addr);
692295367Sdes	options->queued_listen_ports[options->num_queued_listens] = port;
693295367Sdes	options->num_queued_listens++;
694295367Sdes}
695295367Sdes
696295367Sdes/*
697295367Sdes * Process queued (text) ListenAddress entries.
698295367Sdes */
699295367Sdesstatic void
700295367Sdesprocess_queued_listen_addrs(ServerOptions *options)
701295367Sdes{
702295367Sdes	u_int i;
703295367Sdes
704295367Sdes	if (options->num_ports == 0)
705295367Sdes		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
706295367Sdes	if (options->address_family == -1)
707295367Sdes		options->address_family = AF_UNSPEC;
708295367Sdes
709295367Sdes	for (i = 0; i < options->num_queued_listens; i++) {
710295367Sdes		add_listen_addr(options, options->queued_listen_addrs[i],
711295367Sdes		    options->queued_listen_ports[i]);
712295367Sdes		free(options->queued_listen_addrs[i]);
713295367Sdes		options->queued_listen_addrs[i] = NULL;
714295367Sdes	}
715295367Sdes	free(options->queued_listen_addrs);
716295367Sdes	options->queued_listen_addrs = NULL;
717295367Sdes	free(options->queued_listen_ports);
718295367Sdes	options->queued_listen_ports = NULL;
719295367Sdes	options->num_queued_listens = 0;
720295367Sdes}
721295367Sdes
722240075Sdesstruct connection_info *
723240075Sdesget_connection_info(int populate, int use_dns)
724240075Sdes{
725323124Sdes	struct ssh *ssh = active_state; /* XXX */
726240075Sdes	static struct connection_info ci;
727240075Sdes
728240075Sdes	if (!populate)
729240075Sdes		return &ci;
730323124Sdes	ci.host = auth_get_canonical_hostname(ssh, use_dns);
731323124Sdes	ci.address = ssh_remote_ipaddr(ssh);
732323124Sdes	ci.laddress = ssh_local_ipaddr(ssh);
733323124Sdes	ci.lport = ssh_local_port(ssh);
734240075Sdes	return &ci;
735240075Sdes}
736240075Sdes
737162856Sdes/*
738162856Sdes * The strategy for the Match blocks is that the config file is parsed twice.
739162856Sdes *
740162856Sdes * The first time is at startup.  activep is initialized to 1 and the
741162856Sdes * directives in the global context are processed and acted on.  Hitting a
742162856Sdes * Match directive unsets activep and the directives inside the block are
743162856Sdes * checked for syntax only.
744162856Sdes *
745162856Sdes * The second time is after a connection has been established but before
746162856Sdes * authentication.  activep is initialized to 2 and global config directives
747162856Sdes * are ignored since they have already been processed.  If the criteria in a
748162856Sdes * Match block is met, activep is set and the subsequent directives
749162856Sdes * processed and actioned until EOF or another Match block unsets it.  Any
750162856Sdes * options set are copied into the main server config.
751162856Sdes *
752162856Sdes * Potential additions/improvements:
753162856Sdes *  - Add Match support for pre-kex directives, eg Protocol, Ciphers.
754162856Sdes *
755162856Sdes *  - Add a Tag directive (idea from David Leonard) ala pf, eg:
756162856Sdes *	Match Address 192.168.0.*
757162856Sdes *		Tag trusted
758162856Sdes *	Match Group wheel
759162856Sdes *		Tag trusted
760162856Sdes *	Match Tag trusted
761162856Sdes *		AllowTcpForwarding yes
762162856Sdes *		GatewayPorts clientspecified
763162856Sdes *		[...]
764162856Sdes *
765162856Sdes *  - Add a PermittedChannelRequests directive
766162856Sdes *	Match Group shell
767162856Sdes *		PermittedChannelRequests session,forwarded-tcpip
768162856Sdes */
769162856Sdes
770162856Sdesstatic int
771162856Sdesmatch_cfg_line_group(const char *grps, int line, const char *user)
772162856Sdes{
773162856Sdes	int result = 0;
774162856Sdes	struct passwd *pw;
775162856Sdes
776162856Sdes	if (user == NULL)
777162856Sdes		goto out;
778162856Sdes
779162856Sdes	if ((pw = getpwnam(user)) == NULL) {
780162856Sdes		debug("Can't match group at line %d because user %.100s does "
781162856Sdes		    "not exist", line, user);
782162856Sdes	} else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
783162856Sdes		debug("Can't Match group because user %.100s not in any group "
784162856Sdes		    "at line %d", user, line);
785181111Sdes	} else if (ga_match_pattern_list(grps) != 1) {
786181111Sdes		debug("user %.100s does not match group list %.100s at line %d",
787181111Sdes		    user, grps, line);
788162856Sdes	} else {
789181111Sdes		debug("user %.100s matched group list %.100s at line %d", user,
790181111Sdes		    grps, line);
791162856Sdes		result = 1;
792162856Sdes	}
793162856Sdesout:
794162856Sdes	ga_free();
795162856Sdes	return result;
796162856Sdes}
797162856Sdes
798240075Sdes/*
799248619Sdes * All of the attributes on a single Match line are ANDed together, so we need
800262566Sdes * to check every attribute and set the result to zero if any attribute does
801248619Sdes * not match.
802240075Sdes */
803162856Sdesstatic int
804240075Sdesmatch_cfg_line(char **condition, int line, struct connection_info *ci)
805162856Sdes{
806262566Sdes	int result = 1, attributes = 0, port;
807162856Sdes	char *arg, *attrib, *cp = *condition;
808162856Sdes
809240075Sdes	if (ci == NULL)
810162856Sdes		debug3("checking syntax for 'Match %s'", cp);
811162856Sdes	else
812240075Sdes		debug3("checking match for '%s' user %s host %s addr %s "
813240075Sdes		    "laddr %s lport %d", cp, ci->user ? ci->user : "(null)",
814240075Sdes		    ci->host ? ci->host : "(null)",
815240075Sdes		    ci->address ? ci->address : "(null)",
816240075Sdes		    ci->laddress ? ci->laddress : "(null)", ci->lport);
817162856Sdes
818162856Sdes	while ((attrib = strdelim(&cp)) && *attrib != '\0') {
819262566Sdes		attributes++;
820262566Sdes		if (strcasecmp(attrib, "all") == 0) {
821262566Sdes			if (attributes != 1 ||
822262566Sdes			    ((arg = strdelim(&cp)) != NULL && *arg != '\0')) {
823262566Sdes				error("'all' cannot be combined with other "
824262566Sdes				    "Match attributes");
825262566Sdes				return -1;
826262566Sdes			}
827262566Sdes			*condition = cp;
828262566Sdes			return 1;
829262566Sdes		}
830162856Sdes		if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
831162856Sdes			error("Missing Match criteria for %s", attrib);
832162856Sdes			return -1;
833162856Sdes		}
834162856Sdes		if (strcasecmp(attrib, "user") == 0) {
835240075Sdes			if (ci == NULL || ci->user == NULL) {
836162856Sdes				result = 0;
837162856Sdes				continue;
838162856Sdes			}
839295367Sdes			if (match_pattern_list(ci->user, arg, 0) != 1)
840162856Sdes				result = 0;
841162856Sdes			else
842162856Sdes				debug("user %.100s matched 'User %.100s' at "
843240075Sdes				    "line %d", ci->user, arg, line);
844162856Sdes		} else if (strcasecmp(attrib, "group") == 0) {
845240075Sdes			if (ci == NULL || ci->user == NULL) {
846240075Sdes				result = 0;
847240075Sdes				continue;
848240075Sdes			}
849240075Sdes			switch (match_cfg_line_group(arg, line, ci->user)) {
850162856Sdes			case -1:
851162856Sdes				return -1;
852162856Sdes			case 0:
853162856Sdes				result = 0;
854162856Sdes			}
855162856Sdes		} else if (strcasecmp(attrib, "host") == 0) {
856240075Sdes			if (ci == NULL || ci->host == NULL) {
857162856Sdes				result = 0;
858162856Sdes				continue;
859162856Sdes			}
860295367Sdes			if (match_hostname(ci->host, arg) != 1)
861162856Sdes				result = 0;
862162856Sdes			else
863162856Sdes				debug("connection from %.100s matched 'Host "
864240075Sdes				    "%.100s' at line %d", ci->host, arg, line);
865162856Sdes		} else if (strcasecmp(attrib, "address") == 0) {
866240075Sdes			if (ci == NULL || ci->address == NULL) {
867240075Sdes				result = 0;
868240075Sdes				continue;
869240075Sdes			}
870240075Sdes			switch (addr_match_list(ci->address, arg)) {
871181111Sdes			case 1:
872181111Sdes				debug("connection from %.100s matched 'Address "
873240075Sdes				    "%.100s' at line %d", ci->address, arg, line);
874181111Sdes				break;
875181111Sdes			case 0:
876181111Sdes			case -1:
877162856Sdes				result = 0;
878181111Sdes				break;
879181111Sdes			case -2:
880181111Sdes				return -1;
881162856Sdes			}
882240075Sdes		} else if (strcasecmp(attrib, "localaddress") == 0){
883240075Sdes			if (ci == NULL || ci->laddress == NULL) {
884240075Sdes				result = 0;
885240075Sdes				continue;
886240075Sdes			}
887240075Sdes			switch (addr_match_list(ci->laddress, arg)) {
888240075Sdes			case 1:
889240075Sdes				debug("connection from %.100s matched "
890240075Sdes				    "'LocalAddress %.100s' at line %d",
891240075Sdes				    ci->laddress, arg, line);
892240075Sdes				break;
893240075Sdes			case 0:
894240075Sdes			case -1:
895240075Sdes				result = 0;
896240075Sdes				break;
897240075Sdes			case -2:
898240075Sdes				return -1;
899240075Sdes			}
900240075Sdes		} else if (strcasecmp(attrib, "localport") == 0) {
901240075Sdes			if ((port = a2port(arg)) == -1) {
902240075Sdes				error("Invalid LocalPort '%s' on Match line",
903240075Sdes				    arg);
904240075Sdes				return -1;
905240075Sdes			}
906240075Sdes			if (ci == NULL || ci->lport == 0) {
907240075Sdes				result = 0;
908240075Sdes				continue;
909240075Sdes			}
910240075Sdes			/* TODO support port lists */
911240075Sdes			if (port == ci->lport)
912240075Sdes				debug("connection from %.100s matched "
913240075Sdes				    "'LocalPort %d' at line %d",
914240075Sdes				    ci->laddress, port, line);
915240075Sdes			else
916240075Sdes				result = 0;
917162856Sdes		} else {
918162856Sdes			error("Unsupported Match attribute %s", attrib);
919162856Sdes			return -1;
920162856Sdes		}
921162856Sdes	}
922262566Sdes	if (attributes == 0) {
923262566Sdes		error("One or more attributes required for Match");
924262566Sdes		return -1;
925262566Sdes	}
926240075Sdes	if (ci != NULL)
927162856Sdes		debug3("match %sfound", result ? "" : "not ");
928162856Sdes	*condition = cp;
929162856Sdes	return result;
930162856Sdes}
931162856Sdes
932162856Sdes#define WHITESPACE " \t\r\n"
933162856Sdes
934226046Sdes/* Multistate option parsing */
935226046Sdesstruct multistate {
936226046Sdes	char *key;
937226046Sdes	int value;
938226046Sdes};
939226046Sdesstatic const struct multistate multistate_addressfamily[] = {
940226046Sdes	{ "inet",			AF_INET },
941226046Sdes	{ "inet6",			AF_INET6 },
942226046Sdes	{ "any",			AF_UNSPEC },
943226046Sdes	{ NULL, -1 }
944226046Sdes};
945226046Sdesstatic const struct multistate multistate_permitrootlogin[] = {
946226046Sdes	{ "without-password",		PERMIT_NO_PASSWD },
947295367Sdes	{ "prohibit-password",		PERMIT_NO_PASSWD },
948226046Sdes	{ "forced-commands-only",	PERMIT_FORCED_ONLY },
949226046Sdes	{ "yes",			PERMIT_YES },
950226046Sdes	{ "no",				PERMIT_NO },
951226046Sdes	{ NULL, -1 }
952226046Sdes};
953226046Sdesstatic const struct multistate multistate_compression[] = {
954226046Sdes	{ "delayed",			COMP_DELAYED },
955226046Sdes	{ "yes",			COMP_ZLIB },
956226046Sdes	{ "no",				COMP_NONE },
957226046Sdes	{ NULL, -1 }
958226046Sdes};
959226046Sdesstatic const struct multistate multistate_gatewayports[] = {
960226046Sdes	{ "clientspecified",		2 },
961226046Sdes	{ "yes",			1 },
962226046Sdes	{ "no",				0 },
963226046Sdes	{ NULL, -1 }
964226046Sdes};
965226046Sdesstatic const struct multistate multistate_privsep[] = {
966240075Sdes	{ "yes",			PRIVSEP_NOSANDBOX },
967240075Sdes	{ "sandbox",			PRIVSEP_ON },
968240075Sdes	{ "nosandbox",			PRIVSEP_NOSANDBOX },
969226046Sdes	{ "no",				PRIVSEP_OFF },
970226046Sdes	{ NULL, -1 }
971226046Sdes};
972248619Sdesstatic const struct multistate multistate_tcpfwd[] = {
973248619Sdes	{ "yes",			FORWARD_ALLOW },
974248619Sdes	{ "all",			FORWARD_ALLOW },
975248619Sdes	{ "no",				FORWARD_DENY },
976248619Sdes	{ "remote",			FORWARD_REMOTE },
977248619Sdes	{ "local",			FORWARD_LOCAL },
978248619Sdes	{ NULL, -1 }
979248619Sdes};
980226046Sdes
98192559Sdesint
98292559Sdesprocess_server_config_line(ServerOptions *options, char *line,
983240075Sdes    const char *filename, int linenum, int *activep,
984240075Sdes    struct connection_info *connectinfo)
98557429Smarkm{
98676262Sgreen	char *cp, **charptr, *arg, *p;
987255767Sdes	int cmdline = 0, *intptr, value, value2, n, port;
988181111Sdes	SyslogFacility *log_facility_ptr;
989181111Sdes	LogLevel *log_level_ptr;
99057429Smarkm	ServerOpCodes opcode;
991162856Sdes	u_int i, flags = 0;
992162856Sdes	size_t len;
993255767Sdes	long long val64;
994226046Sdes	const struct multistate *multistate_ptr;
99557429Smarkm
99692559Sdes	cp = line;
997162856Sdes	if ((arg = strdelim(&cp)) == NULL)
998162856Sdes		return 0;
99992559Sdes	/* Ignore leading whitespace */
100092559Sdes	if (*arg == '\0')
100165674Skris		arg = strdelim(&cp);
100292559Sdes	if (!arg || !*arg || *arg == '#')
100392559Sdes		return 0;
100492559Sdes	intptr = NULL;
100592559Sdes	charptr = NULL;
1006162856Sdes	opcode = parse_token(arg, filename, linenum, &flags);
1007162856Sdes
1008162856Sdes	if (activep == NULL) { /* We are processing a command line directive */
1009162856Sdes		cmdline = 1;
1010162856Sdes		activep = &cmdline;
1011162856Sdes	}
1012162856Sdes	if (*activep && opcode != sMatch)
1013162856Sdes		debug3("%s:%d setting %s %s", filename, linenum, arg, cp);
1014162856Sdes	if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
1015240075Sdes		if (connectinfo == NULL) {
1016162856Sdes			fatal("%s line %d: Directive '%s' is not allowed "
1017162856Sdes			    "within a Match block", filename, linenum, arg);
1018162856Sdes		} else { /* this is a directive we have already processed */
1019162856Sdes			while (arg)
1020162856Sdes				arg = strdelim(&cp);
1021162856Sdes			return 0;
1022162856Sdes		}
1023162856Sdes	}
1024162856Sdes
102592559Sdes	switch (opcode) {
102698941Sdes	/* Portable-specific options */
1027124211Sdes	case sUsePAM:
1028124211Sdes		intptr = &options->use_pam;
102998941Sdes		goto parse_flag;
103098941Sdes
103198941Sdes	/* Standard Options */
103292559Sdes	case sBadOption:
103392559Sdes		return -1;
103492559Sdes	case sPort:
103592559Sdes		/* ignore ports from configfile if cmdline specifies ports */
103692559Sdes		if (options->ports_from_cmdline)
103792559Sdes			return 0;
103892559Sdes		if (options->num_ports >= MAX_PORTS)
103992559Sdes			fatal("%s line %d: too many ports.",
104092559Sdes			    filename, linenum);
104192559Sdes		arg = strdelim(&cp);
104292559Sdes		if (!arg || *arg == '\0')
104392559Sdes			fatal("%s line %d: missing port number.",
104492559Sdes			    filename, linenum);
104592559Sdes		options->ports[options->num_ports++] = a2port(arg);
1046192595Sdes		if (options->ports[options->num_ports-1] <= 0)
104792559Sdes			fatal("%s line %d: Badly formatted port number.",
104892559Sdes			    filename, linenum);
104992559Sdes		break;
105057429Smarkm
105192559Sdes	case sServerKeyBits:
105292559Sdes		intptr = &options->server_key_bits;
1053181111Sdes parse_int:
105492559Sdes		arg = strdelim(&cp);
105592559Sdes		if (!arg || *arg == '\0')
105692559Sdes			fatal("%s line %d: missing integer value.",
105792559Sdes			    filename, linenum);
105892559Sdes		value = atoi(arg);
1059162856Sdes		if (*activep && *intptr == -1)
106092559Sdes			*intptr = value;
106192559Sdes		break;
106257429Smarkm
106392559Sdes	case sLoginGraceTime:
106492559Sdes		intptr = &options->login_grace_time;
1065181111Sdes parse_time:
106692559Sdes		arg = strdelim(&cp);
106792559Sdes		if (!arg || *arg == '\0')
106892559Sdes			fatal("%s line %d: missing time value.",
106992559Sdes			    filename, linenum);
107092559Sdes		if ((value = convtime(arg)) == -1)
107192559Sdes			fatal("%s line %d: invalid time value.",
107292559Sdes			    filename, linenum);
1073295367Sdes		if (*activep && *intptr == -1)
107492559Sdes			*intptr = value;
107592559Sdes		break;
107657429Smarkm
107792559Sdes	case sKeyRegenerationTime:
107892559Sdes		intptr = &options->key_regeneration_time;
107992559Sdes		goto parse_time;
108057429Smarkm
108192559Sdes	case sListenAddress:
108292559Sdes		arg = strdelim(&cp);
1083147005Sdes		if (arg == NULL || *arg == '\0')
1084147005Sdes			fatal("%s line %d: missing address",
108592559Sdes			    filename, linenum);
1086149753Sdes		/* check for bare IPv6 address: no "[]" and 2 or more ":" */
1087149753Sdes		if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL
1088149753Sdes		    && strchr(p+1, ':') != NULL) {
1089295367Sdes			queue_listen_addr(options, arg, 0);
1090149753Sdes			break;
1091149753Sdes		}
1092147005Sdes		p = hpdelim(&arg);
1093147005Sdes		if (p == NULL)
1094147005Sdes			fatal("%s line %d: bad address:port usage",
1095147005Sdes			    filename, linenum);
1096147005Sdes		p = cleanhostname(p);
1097147005Sdes		if (arg == NULL)
1098147005Sdes			port = 0;
1099192595Sdes		else if ((port = a2port(arg)) <= 0)
1100147005Sdes			fatal("%s line %d: bad port number", filename, linenum);
110157429Smarkm
1102295367Sdes		queue_listen_addr(options, p, port);
1103147005Sdes
1104147005Sdes		break;
1105147005Sdes
1106147005Sdes	case sAddressFamily:
1107226046Sdes		intptr = &options->address_family;
1108226046Sdes		multistate_ptr = multistate_addressfamily;
1109226046Sdes parse_multistate:
1110147005Sdes		arg = strdelim(&cp);
1111149753Sdes		if (!arg || *arg == '\0')
1112226046Sdes			fatal("%s line %d: missing argument.",
1113149753Sdes			    filename, linenum);
1114226046Sdes		value = -1;
1115226046Sdes		for (i = 0; multistate_ptr[i].key != NULL; i++) {
1116226046Sdes			if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
1117226046Sdes				value = multistate_ptr[i].value;
1118226046Sdes				break;
1119226046Sdes			}
1120226046Sdes		}
1121226046Sdes		if (value == -1)
1122226046Sdes			fatal("%s line %d: unsupported option \"%s\".",
1123147005Sdes			    filename, linenum, arg);
1124226046Sdes		if (*activep && *intptr == -1)
1125147005Sdes			*intptr = value;
112692559Sdes		break;
112757429Smarkm
112892559Sdes	case sHostKeyFile:
112992559Sdes		intptr = &options->num_host_key_files;
113092559Sdes		if (*intptr >= MAX_HOSTKEYS)
113192559Sdes			fatal("%s line %d: too many host keys specified (max %d).",
113292559Sdes			    filename, linenum, MAX_HOSTKEYS);
113392559Sdes		charptr = &options->host_key_files[*intptr];
1134181111Sdes parse_filename:
113592559Sdes		arg = strdelim(&cp);
113692559Sdes		if (!arg || *arg == '\0')
113792559Sdes			fatal("%s line %d: missing file name.",
113892559Sdes			    filename, linenum);
1139162856Sdes		if (*activep && *charptr == NULL) {
1140204917Sdes			*charptr = derelativise_path(arg);
114192559Sdes			/* increase optional counter */
114292559Sdes			if (intptr != NULL)
114392559Sdes				*intptr = *intptr + 1;
114492559Sdes		}
114592559Sdes		break;
114660576Skris
1147255767Sdes	case sHostKeyAgent:
1148255767Sdes		charptr = &options->host_key_agent;
1149255767Sdes		arg = strdelim(&cp);
1150255767Sdes		if (!arg || *arg == '\0')
1151255767Sdes			fatal("%s line %d: missing socket name.",
1152255767Sdes			    filename, linenum);
1153255767Sdes		if (*activep && *charptr == NULL)
1154255767Sdes			*charptr = !strcmp(arg, SSH_AUTHSOCKET_ENV_NAME) ?
1155255767Sdes			    xstrdup(arg) : derelativise_path(arg);
1156255767Sdes		break;
1157255767Sdes
1158204917Sdes	case sHostCertificate:
1159204917Sdes		intptr = &options->num_host_cert_files;
1160204917Sdes		if (*intptr >= MAX_HOSTKEYS)
1161204917Sdes			fatal("%s line %d: too many host certificates "
1162204917Sdes			    "specified (max %d).", filename, linenum,
1163204917Sdes			    MAX_HOSTCERTS);
1164204917Sdes		charptr = &options->host_cert_files[*intptr];
1165204917Sdes		goto parse_filename;
1166204917Sdes		break;
1167204917Sdes
116892559Sdes	case sPidFile:
116992559Sdes		charptr = &options->pid_file;
117092559Sdes		goto parse_filename;
117157429Smarkm
117292559Sdes	case sPermitRootLogin:
117392559Sdes		intptr = &options->permit_root_login;
1174226046Sdes		multistate_ptr = multistate_permitrootlogin;
1175226046Sdes		goto parse_multistate;
117692559Sdes
117792559Sdes	case sIgnoreRhosts:
117892559Sdes		intptr = &options->ignore_rhosts;
1179181111Sdes parse_flag:
118092559Sdes		arg = strdelim(&cp);
118192559Sdes		if (!arg || *arg == '\0')
118292559Sdes			fatal("%s line %d: missing yes/no argument.",
118392559Sdes			    filename, linenum);
118492559Sdes		value = 0;	/* silence compiler */
118592559Sdes		if (strcmp(arg, "yes") == 0)
118692559Sdes			value = 1;
118792559Sdes		else if (strcmp(arg, "no") == 0)
118892559Sdes			value = 0;
118992559Sdes		else
119092559Sdes			fatal("%s line %d: Bad yes/no argument: %s",
119192559Sdes				filename, linenum, arg);
1192162856Sdes		if (*activep && *intptr == -1)
119392559Sdes			*intptr = value;
119492559Sdes		break;
119557429Smarkm
119692559Sdes	case sIgnoreUserKnownHosts:
119792559Sdes		intptr = &options->ignore_user_known_hosts;
119892559Sdes		goto parse_flag;
119957429Smarkm
120092559Sdes	case sRhostsRSAAuthentication:
120192559Sdes		intptr = &options->rhosts_rsa_authentication;
120292559Sdes		goto parse_flag;
120357429Smarkm
120492559Sdes	case sHostbasedAuthentication:
120592559Sdes		intptr = &options->hostbased_authentication;
120692559Sdes		goto parse_flag;
120776262Sgreen
120892559Sdes	case sHostbasedUsesNameFromPacketOnly:
120992559Sdes		intptr = &options->hostbased_uses_name_from_packet_only;
121092559Sdes		goto parse_flag;
121176262Sgreen
1212295367Sdes	case sHostbasedAcceptedKeyTypes:
1213295367Sdes		charptr = &options->hostbased_key_types;
1214295367Sdes parse_keytypes:
1215295367Sdes		arg = strdelim(&cp);
1216295367Sdes		if (!arg || *arg == '\0')
1217295367Sdes			fatal("%s line %d: Missing argument.",
1218295367Sdes			    filename, linenum);
1219295367Sdes		if (!sshkey_names_valid2(*arg == '+' ? arg + 1 : arg, 1))
1220295367Sdes			fatal("%s line %d: Bad key types '%s'.",
1221295367Sdes			    filename, linenum, arg ? arg : "<NONE>");
1222295367Sdes		if (*activep && *charptr == NULL)
1223295367Sdes			*charptr = xstrdup(arg);
1224295367Sdes		break;
1225295367Sdes
1226295367Sdes	case sHostKeyAlgorithms:
1227295367Sdes		charptr = &options->hostkeyalgorithms;
1228295367Sdes		goto parse_keytypes;
1229295367Sdes
123092559Sdes	case sRSAAuthentication:
123192559Sdes		intptr = &options->rsa_authentication;
123292559Sdes		goto parse_flag;
123357429Smarkm
123492559Sdes	case sPubkeyAuthentication:
123592559Sdes		intptr = &options->pubkey_authentication;
123692559Sdes		goto parse_flag;
1237124211Sdes
1238295367Sdes	case sPubkeyAcceptedKeyTypes:
1239295367Sdes		charptr = &options->pubkey_key_types;
1240295367Sdes		goto parse_keytypes;
1241295367Sdes
124292559Sdes	case sKerberosAuthentication:
124392559Sdes		intptr = &options->kerberos_authentication;
124492559Sdes		goto parse_flag;
124557429Smarkm
124692559Sdes	case sKerberosOrLocalPasswd:
124792559Sdes		intptr = &options->kerberos_or_local_passwd;
124892559Sdes		goto parse_flag;
124992559Sdes
125092559Sdes	case sKerberosTicketCleanup:
125192559Sdes		intptr = &options->kerberos_ticket_cleanup;
125292559Sdes		goto parse_flag;
1253124211Sdes
1254126277Sdes	case sKerberosGetAFSToken:
1255126277Sdes		intptr = &options->kerberos_get_afs_token;
1256126277Sdes		goto parse_flag;
1257126277Sdes
1258124211Sdes	case sGssAuthentication:
1259124211Sdes		intptr = &options->gss_authentication;
126092559Sdes		goto parse_flag;
1261124211Sdes
1262124211Sdes	case sGssCleanupCreds:
1263124211Sdes		intptr = &options->gss_cleanup_creds;
126492559Sdes		goto parse_flag;
126557429Smarkm
1266295367Sdes	case sGssStrictAcceptor:
1267295367Sdes		intptr = &options->gss_strict_acceptor;
1268295367Sdes		goto parse_flag;
1269295367Sdes
127092559Sdes	case sPasswordAuthentication:
127192559Sdes		intptr = &options->password_authentication;
127292559Sdes		goto parse_flag;
127357565Smarkm
127492559Sdes	case sKbdInteractiveAuthentication:
127592559Sdes		intptr = &options->kbd_interactive_authentication;
127692559Sdes		goto parse_flag;
127757429Smarkm
127892559Sdes	case sChallengeResponseAuthentication:
127992559Sdes		intptr = &options->challenge_response_authentication;
128092559Sdes		goto parse_flag;
128157429Smarkm
128292559Sdes	case sPrintMotd:
128392559Sdes		intptr = &options->print_motd;
128492559Sdes		goto parse_flag;
128557429Smarkm
128692559Sdes	case sPrintLastLog:
128792559Sdes		intptr = &options->print_lastlog;
128892559Sdes		goto parse_flag;
128969591Sgreen
129092559Sdes	case sX11Forwarding:
129192559Sdes		intptr = &options->x11_forwarding;
129292559Sdes		goto parse_flag;
129357429Smarkm
129492559Sdes	case sX11DisplayOffset:
129592559Sdes		intptr = &options->x11_display_offset;
129692559Sdes		goto parse_int;
129757429Smarkm
129892559Sdes	case sX11UseLocalhost:
129992559Sdes		intptr = &options->x11_use_localhost;
130092559Sdes		goto parse_flag;
130157429Smarkm
130292559Sdes	case sXAuthLocation:
130392559Sdes		charptr = &options->xauth_location;
130492559Sdes		goto parse_filename;
130576262Sgreen
1306262566Sdes	case sPermitTTY:
1307262566Sdes		intptr = &options->permit_tty;
1308262566Sdes		goto parse_flag;
1309262566Sdes
1310295367Sdes	case sPermitUserRC:
1311295367Sdes		intptr = &options->permit_user_rc;
1312295367Sdes		goto parse_flag;
1313295367Sdes
131492559Sdes	case sStrictModes:
131592559Sdes		intptr = &options->strict_modes;
131692559Sdes		goto parse_flag;
131757429Smarkm
1318126277Sdes	case sTCPKeepAlive:
1319126277Sdes		intptr = &options->tcp_keep_alive;
132092559Sdes		goto parse_flag;
132157429Smarkm
132292559Sdes	case sEmptyPasswd:
132392559Sdes		intptr = &options->permit_empty_passwd;
132492559Sdes		goto parse_flag;
132576262Sgreen
1326106130Sdes	case sPermitUserEnvironment:
1327106130Sdes		intptr = &options->permit_user_env;
1328106130Sdes		goto parse_flag;
1329106130Sdes
133092559Sdes	case sUseLogin:
133192559Sdes		intptr = &options->use_login;
133292559Sdes		goto parse_flag;
133357429Smarkm
133498684Sdes	case sCompression:
133598684Sdes		intptr = &options->compression;
1336226046Sdes		multistate_ptr = multistate_compression;
1337226046Sdes		goto parse_multistate;
133898684Sdes
1339255767Sdes	case sRekeyLimit:
1340255767Sdes		arg = strdelim(&cp);
1341255767Sdes		if (!arg || *arg == '\0')
1342255767Sdes			fatal("%.200s line %d: Missing argument.", filename,
1343255767Sdes			    linenum);
1344255767Sdes		if (strcmp(arg, "default") == 0) {
1345255767Sdes			val64 = 0;
1346255767Sdes		} else {
1347255767Sdes			if (scan_scaled(arg, &val64) == -1)
1348255767Sdes				fatal("%.200s line %d: Bad number '%s': %s",
1349255767Sdes				    filename, linenum, arg, strerror(errno));
1350255767Sdes			if (val64 != 0 && val64 < 16)
1351255767Sdes				fatal("%.200s line %d: RekeyLimit too small",
1352255767Sdes				    filename, linenum);
1353255767Sdes		}
1354255767Sdes		if (*activep && options->rekey_limit == -1)
1355296781Sdes			options->rekey_limit = val64;
1356255767Sdes		if (cp != NULL) { /* optional rekey interval present */
1357255767Sdes			if (strcmp(cp, "none") == 0) {
1358255767Sdes				(void)strdelim(&cp);	/* discard */
1359255767Sdes				break;
1360255767Sdes			}
1361255767Sdes			intptr = &options->rekey_interval;
1362255767Sdes			goto parse_time;
1363255767Sdes		}
1364255767Sdes		break;
1365255767Sdes
136692559Sdes	case sGatewayPorts:
1367295367Sdes		intptr = &options->fwd_opts.gateway_ports;
1368226046Sdes		multistate_ptr = multistate_gatewayports;
1369226046Sdes		goto parse_multistate;
137057429Smarkm
1371124211Sdes	case sUseDNS:
1372124211Sdes		intptr = &options->use_dns;
137392559Sdes		goto parse_flag;
137457429Smarkm
137592559Sdes	case sLogFacility:
1376181111Sdes		log_facility_ptr = &options->log_facility;
137792559Sdes		arg = strdelim(&cp);
137892559Sdes		value = log_facility_number(arg);
137992559Sdes		if (value == SYSLOG_FACILITY_NOT_SET)
138092559Sdes			fatal("%.200s line %d: unsupported log facility '%s'",
138192559Sdes			    filename, linenum, arg ? arg : "<NONE>");
1382181111Sdes		if (*log_facility_ptr == -1)
1383181111Sdes			*log_facility_ptr = (SyslogFacility) value;
138492559Sdes		break;
138557429Smarkm
138692559Sdes	case sLogLevel:
1387181111Sdes		log_level_ptr = &options->log_level;
138892559Sdes		arg = strdelim(&cp);
138992559Sdes		value = log_level_number(arg);
139092559Sdes		if (value == SYSLOG_LEVEL_NOT_SET)
139192559Sdes			fatal("%.200s line %d: unsupported log level '%s'",
139292559Sdes			    filename, linenum, arg ? arg : "<NONE>");
1393181111Sdes		if (*log_level_ptr == -1)
1394181111Sdes			*log_level_ptr = (LogLevel) value;
139592559Sdes		break;
139660576Skris
139792559Sdes	case sAllowTcpForwarding:
139892559Sdes		intptr = &options->allow_tcp_forwarding;
1399248619Sdes		multistate_ptr = multistate_tcpfwd;
1400248619Sdes		goto parse_multistate;
140176262Sgreen
1402295367Sdes	case sAllowStreamLocalForwarding:
1403295367Sdes		intptr = &options->allow_streamlocal_forwarding;
1404295367Sdes		multistate_ptr = multistate_tcpfwd;
1405295367Sdes		goto parse_multistate;
1406295367Sdes
1407181111Sdes	case sAllowAgentForwarding:
1408181111Sdes		intptr = &options->allow_agent_forwarding;
1409181111Sdes		goto parse_flag;
1410181111Sdes
141198684Sdes	case sUsePrivilegeSeparation:
141298684Sdes		intptr = &use_privsep;
1413226046Sdes		multistate_ptr = multistate_privsep;
1414226046Sdes		goto parse_multistate;
141598684Sdes
141692559Sdes	case sAllowUsers:
141792559Sdes		while ((arg = strdelim(&cp)) && *arg != '\0') {
141892559Sdes			if (options->num_allow_users >= MAX_ALLOW_USERS)
141992559Sdes				fatal("%s line %d: too many allow users.",
142092559Sdes				    filename, linenum);
1421240075Sdes			if (!*activep)
1422240075Sdes				continue;
142399063Sdes			options->allow_users[options->num_allow_users++] =
142499063Sdes			    xstrdup(arg);
142592559Sdes		}
142692559Sdes		break;
142757429Smarkm
142892559Sdes	case sDenyUsers:
142992559Sdes		while ((arg = strdelim(&cp)) && *arg != '\0') {
143092559Sdes			if (options->num_deny_users >= MAX_DENY_USERS)
1431162856Sdes				fatal("%s line %d: too many deny users.",
143292559Sdes				    filename, linenum);
1433240075Sdes			if (!*activep)
1434240075Sdes				continue;
143599063Sdes			options->deny_users[options->num_deny_users++] =
143699063Sdes			    xstrdup(arg);
143792559Sdes		}
143892559Sdes		break;
143957429Smarkm
144092559Sdes	case sAllowGroups:
144192559Sdes		while ((arg = strdelim(&cp)) && *arg != '\0') {
144292559Sdes			if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
144392559Sdes				fatal("%s line %d: too many allow groups.",
144492559Sdes				    filename, linenum);
1445240075Sdes			if (!*activep)
1446240075Sdes				continue;
144799063Sdes			options->allow_groups[options->num_allow_groups++] =
144899063Sdes			    xstrdup(arg);
144992559Sdes		}
145092559Sdes		break;
145169591Sgreen
145292559Sdes	case sDenyGroups:
145392559Sdes		while ((arg = strdelim(&cp)) && *arg != '\0') {
145492559Sdes			if (options->num_deny_groups >= MAX_DENY_GROUPS)
145592559Sdes				fatal("%s line %d: too many deny groups.",
145692559Sdes				    filename, linenum);
1457240075Sdes			if (!*activep)
1458240075Sdes				continue;
1459240075Sdes			options->deny_groups[options->num_deny_groups++] =
1460240075Sdes			    xstrdup(arg);
146192559Sdes		}
146292559Sdes		break;
146357429Smarkm
146492559Sdes	case sCiphers:
146592559Sdes		arg = strdelim(&cp);
146692559Sdes		if (!arg || *arg == '\0')
146792559Sdes			fatal("%s line %d: Missing argument.", filename, linenum);
1468295367Sdes		if (!ciphers_valid(*arg == '+' ? arg + 1 : arg))
146992559Sdes			fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
147092559Sdes			    filename, linenum, arg ? arg : "<NONE>");
147192559Sdes		if (options->ciphers == NULL)
147292559Sdes			options->ciphers = xstrdup(arg);
147392559Sdes		break;
147457429Smarkm
147592559Sdes	case sMacs:
147692559Sdes		arg = strdelim(&cp);
147792559Sdes		if (!arg || *arg == '\0')
147892559Sdes			fatal("%s line %d: Missing argument.", filename, linenum);
1479295367Sdes		if (!mac_valid(*arg == '+' ? arg + 1 : arg))
148092559Sdes			fatal("%s line %d: Bad SSH2 mac spec '%s'.",
148192559Sdes			    filename, linenum, arg ? arg : "<NONE>");
148292559Sdes		if (options->macs == NULL)
148392559Sdes			options->macs = xstrdup(arg);
148492559Sdes		break;
148557429Smarkm
1486221420Sdes	case sKexAlgorithms:
1487221420Sdes		arg = strdelim(&cp);
1488221420Sdes		if (!arg || *arg == '\0')
1489221420Sdes			fatal("%s line %d: Missing argument.",
1490221420Sdes			    filename, linenum);
1491295367Sdes		if (!kex_names_valid(*arg == '+' ? arg + 1 : arg))
1492221420Sdes			fatal("%s line %d: Bad SSH2 KexAlgorithms '%s'.",
1493221420Sdes			    filename, linenum, arg ? arg : "<NONE>");
1494221420Sdes		if (options->kex_algorithms == NULL)
1495221420Sdes			options->kex_algorithms = xstrdup(arg);
1496221420Sdes		break;
1497221420Sdes
149892559Sdes	case sProtocol:
149992559Sdes		intptr = &options->protocol;
150092559Sdes		arg = strdelim(&cp);
150192559Sdes		if (!arg || *arg == '\0')
150292559Sdes			fatal("%s line %d: Missing argument.", filename, linenum);
150392559Sdes		value = proto_spec(arg);
150492559Sdes		if (value == SSH_PROTO_UNKNOWN)
150592559Sdes			fatal("%s line %d: Bad protocol spec '%s'.",
150692559Sdes			    filename, linenum, arg ? arg : "<NONE>");
150792559Sdes		if (*intptr == SSH_PROTO_UNKNOWN)
150892559Sdes			*intptr = value;
150992559Sdes		break;
151057429Smarkm
151192559Sdes	case sSubsystem:
151292559Sdes		if (options->num_subsystems >= MAX_SUBSYSTEMS) {
151392559Sdes			fatal("%s line %d: too many subsystems defined.",
151492559Sdes			    filename, linenum);
151592559Sdes		}
151692559Sdes		arg = strdelim(&cp);
151792559Sdes		if (!arg || *arg == '\0')
151892559Sdes			fatal("%s line %d: Missing subsystem name.",
151992559Sdes			    filename, linenum);
1520162856Sdes		if (!*activep) {
1521162856Sdes			arg = strdelim(&cp);
1522162856Sdes			break;
1523162856Sdes		}
152492559Sdes		for (i = 0; i < options->num_subsystems; i++)
152592559Sdes			if (strcmp(arg, options->subsystem_name[i]) == 0)
152692559Sdes				fatal("%s line %d: Subsystem '%s' already defined.",
152792559Sdes				    filename, linenum, arg);
152892559Sdes		options->subsystem_name[options->num_subsystems] = xstrdup(arg);
152992559Sdes		arg = strdelim(&cp);
153092559Sdes		if (!arg || *arg == '\0')
153192559Sdes			fatal("%s line %d: Missing subsystem command.",
153292559Sdes			    filename, linenum);
153392559Sdes		options->subsystem_command[options->num_subsystems] = xstrdup(arg);
1534162856Sdes
1535162856Sdes		/* Collect arguments (separate to executable) */
1536162856Sdes		p = xstrdup(arg);
1537162856Sdes		len = strlen(p) + 1;
1538162856Sdes		while ((arg = strdelim(&cp)) != NULL && *arg != '\0') {
1539162856Sdes			len += 1 + strlen(arg);
1540295367Sdes			p = xreallocarray(p, 1, len);
1541162856Sdes			strlcat(p, " ", len);
1542162856Sdes			strlcat(p, arg, len);
1543162856Sdes		}
1544162856Sdes		options->subsystem_args[options->num_subsystems] = p;
154592559Sdes		options->num_subsystems++;
154692559Sdes		break;
154760576Skris
154892559Sdes	case sMaxStartups:
154992559Sdes		arg = strdelim(&cp);
155092559Sdes		if (!arg || *arg == '\0')
155192559Sdes			fatal("%s line %d: Missing MaxStartups spec.",
155292559Sdes			    filename, linenum);
155392559Sdes		if ((n = sscanf(arg, "%d:%d:%d",
155492559Sdes		    &options->max_startups_begin,
155592559Sdes		    &options->max_startups_rate,
155692559Sdes		    &options->max_startups)) == 3) {
155792559Sdes			if (options->max_startups_begin >
155892559Sdes			    options->max_startups ||
155992559Sdes			    options->max_startups_rate > 100 ||
156092559Sdes			    options->max_startups_rate < 1)
156192559Sdes				fatal("%s line %d: Illegal MaxStartups spec.",
156292559Sdes				    filename, linenum);
156392559Sdes		} else if (n != 1)
156492559Sdes			fatal("%s line %d: Illegal MaxStartups spec.",
156592559Sdes			    filename, linenum);
156692559Sdes		else
156792559Sdes			options->max_startups = options->max_startups_begin;
156892559Sdes		break;
156976262Sgreen
1570137019Sdes	case sMaxAuthTries:
1571137019Sdes		intptr = &options->max_authtries;
1572137019Sdes		goto parse_int;
1573137019Sdes
1574181111Sdes	case sMaxSessions:
1575181111Sdes		intptr = &options->max_sessions;
1576181111Sdes		goto parse_int;
1577181111Sdes
157892559Sdes	case sBanner:
157992559Sdes		charptr = &options->banner;
158092559Sdes		goto parse_filename;
1581181111Sdes
158292559Sdes	/*
158392559Sdes	 * These options can contain %X options expanded at
158492559Sdes	 * connect time, so that you can specify paths like:
158592559Sdes	 *
158692559Sdes	 * AuthorizedKeysFile	/etc/ssh_keys/%u
158792559Sdes	 */
158892559Sdes	case sAuthorizedKeysFile:
1589226046Sdes		if (*activep && options->num_authkeys_files == 0) {
1590226046Sdes			while ((arg = strdelim(&cp)) && *arg != '\0') {
1591226046Sdes				if (options->num_authkeys_files >=
1592226046Sdes				    MAX_AUTHKEYS_FILES)
1593226046Sdes					fatal("%s line %d: "
1594226046Sdes					    "too many authorized keys files.",
1595226046Sdes					    filename, linenum);
1596226046Sdes				options->authorized_keys_files[
1597226046Sdes				    options->num_authkeys_files++] =
1598226046Sdes				    tilde_expand_filename(arg, getuid());
1599226046Sdes			}
1600226046Sdes		}
1601226046Sdes		return 0;
1602226046Sdes
1603215116Sdes	case sAuthorizedPrincipalsFile:
1604215116Sdes		charptr = &options->authorized_principals_file;
1605207319Sdes		arg = strdelim(&cp);
1606207319Sdes		if (!arg || *arg == '\0')
1607207319Sdes			fatal("%s line %d: missing file name.",
1608207319Sdes			    filename, linenum);
1609207319Sdes		if (*activep && *charptr == NULL) {
1610207319Sdes			*charptr = tilde_expand_filename(arg, getuid());
1611207319Sdes			/* increase optional counter */
1612207319Sdes			if (intptr != NULL)
1613207319Sdes				*intptr = *intptr + 1;
1614207319Sdes		}
1615207319Sdes		break;
161660576Skris
161792559Sdes	case sClientAliveInterval:
161892559Sdes		intptr = &options->client_alive_interval;
161992559Sdes		goto parse_time;
162057432Smarkm
162192559Sdes	case sClientAliveCountMax:
162292559Sdes		intptr = &options->client_alive_count_max;
162392559Sdes		goto parse_int;
162465674Skris
1625137019Sdes	case sAcceptEnv:
1626137019Sdes		while ((arg = strdelim(&cp)) && *arg != '\0') {
1627137019Sdes			if (strchr(arg, '=') != NULL)
1628137019Sdes				fatal("%s line %d: Invalid environment name.",
1629137019Sdes				    filename, linenum);
1630137019Sdes			if (options->num_accept_env >= MAX_ACCEPT_ENV)
1631137019Sdes				fatal("%s line %d: too many allow env.",
1632137019Sdes				    filename, linenum);
1633162856Sdes			if (!*activep)
1634240075Sdes				continue;
1635137019Sdes			options->accept_env[options->num_accept_env++] =
1636137019Sdes			    xstrdup(arg);
1637137019Sdes		}
1638137019Sdes		break;
1639137019Sdes
1640157019Sdes	case sPermitTunnel:
1641157019Sdes		intptr = &options->permit_tun;
1642157019Sdes		arg = strdelim(&cp);
1643157019Sdes		if (!arg || *arg == '\0')
1644157019Sdes			fatal("%s line %d: Missing yes/point-to-point/"
1645157019Sdes			    "ethernet/no argument.", filename, linenum);
1646181111Sdes		value = -1;
1647181111Sdes		for (i = 0; tunmode_desc[i].val != -1; i++)
1648181111Sdes			if (strcmp(tunmode_desc[i].text, arg) == 0) {
1649181111Sdes				value = tunmode_desc[i].val;
1650181111Sdes				break;
1651181111Sdes			}
1652181111Sdes		if (value == -1)
1653157019Sdes			fatal("%s line %d: Bad yes/point-to-point/ethernet/"
1654157019Sdes			    "no argument: %s", filename, linenum, arg);
1655295367Sdes		if (*activep && *intptr == -1)
1656157019Sdes			*intptr = value;
1657157019Sdes		break;
1658157019Sdes
1659162856Sdes	case sMatch:
1660162856Sdes		if (cmdline)
1661162856Sdes			fatal("Match directive not supported as a command-line "
1662162856Sdes			   "option");
1663240075Sdes		value = match_cfg_line(&cp, linenum, connectinfo);
1664162856Sdes		if (value < 0)
1665162856Sdes			fatal("%s line %d: Bad Match condition", filename,
1666162856Sdes			    linenum);
1667162856Sdes		*activep = value;
1668162856Sdes		break;
1669162856Sdes
1670162856Sdes	case sPermitOpen:
1671162856Sdes		arg = strdelim(&cp);
1672162856Sdes		if (!arg || *arg == '\0')
1673162856Sdes			fatal("%s line %d: missing PermitOpen specification",
1674162856Sdes			    filename, linenum);
1675181111Sdes		n = options->num_permitted_opens;	/* modified later */
1676162856Sdes		if (strcmp(arg, "any") == 0) {
1677181111Sdes			if (*activep && n == -1) {
1678162856Sdes				channel_clear_adm_permitted_opens();
1679162856Sdes				options->num_permitted_opens = 0;
1680162856Sdes			}
1681162856Sdes			break;
1682162856Sdes		}
1683240075Sdes		if (strcmp(arg, "none") == 0) {
1684240075Sdes			if (*activep && n == -1) {
1685240075Sdes				options->num_permitted_opens = 1;
1686240075Sdes				channel_disable_adm_local_opens();
1687240075Sdes			}
1688240075Sdes			break;
1689240075Sdes		}
1690181111Sdes		if (*activep && n == -1)
1691181111Sdes			channel_clear_adm_permitted_opens();
1692162856Sdes		for (; arg != NULL && *arg != '\0'; arg = strdelim(&cp)) {
1693162856Sdes			p = hpdelim(&arg);
1694162856Sdes			if (p == NULL)
1695162856Sdes				fatal("%s line %d: missing host in PermitOpen",
1696162856Sdes				    filename, linenum);
1697162856Sdes			p = cleanhostname(p);
1698240075Sdes			if (arg == NULL || ((port = permitopen_port(arg)) < 0))
1699162856Sdes				fatal("%s line %d: bad port number in "
1700162856Sdes				    "PermitOpen", filename, linenum);
1701181111Sdes			if (*activep && n == -1)
1702162856Sdes				options->num_permitted_opens =
1703162856Sdes				    channel_add_adm_permitted_opens(p, port);
1704162856Sdes		}
1705162856Sdes		break;
1706162856Sdes
1707162856Sdes	case sForceCommand:
1708295367Sdes		if (cp == NULL || *cp == '\0')
1709162856Sdes			fatal("%.200s line %d: Missing argument.", filename,
1710162856Sdes			    linenum);
1711162856Sdes		len = strspn(cp, WHITESPACE);
1712162856Sdes		if (*activep && options->adm_forced_command == NULL)
1713162856Sdes			options->adm_forced_command = xstrdup(cp + len);
1714162856Sdes		return 0;
1715162856Sdes
1716181111Sdes	case sChrootDirectory:
1717181111Sdes		charptr = &options->chroot_directory;
1718181111Sdes
1719181111Sdes		arg = strdelim(&cp);
1720181111Sdes		if (!arg || *arg == '\0')
1721181111Sdes			fatal("%s line %d: missing file name.",
1722181111Sdes			    filename, linenum);
1723181111Sdes		if (*activep && *charptr == NULL)
1724181111Sdes			*charptr = xstrdup(arg);
1725181111Sdes		break;
1726181111Sdes
1727204917Sdes	case sTrustedUserCAKeys:
1728204917Sdes		charptr = &options->trusted_user_ca_keys;
1729204917Sdes		goto parse_filename;
1730204917Sdes
1731204917Sdes	case sRevokedKeys:
1732204917Sdes		charptr = &options->revoked_keys_file;
1733204917Sdes		goto parse_filename;
1734204917Sdes
1735221420Sdes	case sIPQoS:
1736221420Sdes		arg = strdelim(&cp);
1737221420Sdes		if ((value = parse_ipqos(arg)) == -1)
1738221420Sdes			fatal("%s line %d: Bad IPQoS value: %s",
1739221420Sdes			    filename, linenum, arg);
1740221420Sdes		arg = strdelim(&cp);
1741221420Sdes		if (arg == NULL)
1742221420Sdes			value2 = value;
1743221420Sdes		else if ((value2 = parse_ipqos(arg)) == -1)
1744221420Sdes			fatal("%s line %d: Bad IPQoS value: %s",
1745221420Sdes			    filename, linenum, arg);
1746221420Sdes		if (*activep) {
1747221420Sdes			options->ip_qos_interactive = value;
1748221420Sdes			options->ip_qos_bulk = value2;
1749221420Sdes		}
1750221420Sdes		break;
1751221420Sdes
175299047Sdes	case sVersionAddendum:
1753295367Sdes		if (cp == NULL || *cp == '\0')
1754240075Sdes			fatal("%.200s line %d: Missing argument.", filename,
1755240075Sdes			    linenum);
1756240075Sdes		len = strspn(cp, WHITESPACE);
1757240075Sdes		if (*activep && options->version_addendum == NULL) {
1758240075Sdes			if (strcasecmp(cp + len, "none") == 0)
1759240075Sdes				options->version_addendum = xstrdup("");
1760240075Sdes			else if (strchr(cp + len, '\r') != NULL)
1761240075Sdes				fatal("%.200s line %d: Invalid argument",
1762240075Sdes				    filename, linenum);
1763240075Sdes			else
1764240075Sdes				options->version_addendum = xstrdup(cp + len);
1765240075Sdes		}
1766240075Sdes		return 0;
176799047Sdes
1768248619Sdes	case sAuthorizedKeysCommand:
1769295367Sdes		if (cp == NULL)
1770295367Sdes			fatal("%.200s line %d: Missing argument.", filename,
1771295367Sdes			    linenum);
1772248619Sdes		len = strspn(cp, WHITESPACE);
1773248619Sdes		if (*activep && options->authorized_keys_command == NULL) {
1774248619Sdes			if (cp[len] != '/' && strcasecmp(cp + len, "none") != 0)
1775248619Sdes				fatal("%.200s line %d: AuthorizedKeysCommand "
1776248619Sdes				    "must be an absolute path",
1777248619Sdes				    filename, linenum);
1778248619Sdes			options->authorized_keys_command = xstrdup(cp + len);
1779248619Sdes		}
1780248619Sdes		return 0;
1781248619Sdes
1782248619Sdes	case sAuthorizedKeysCommandUser:
1783248619Sdes		charptr = &options->authorized_keys_command_user;
1784248619Sdes
1785248619Sdes		arg = strdelim(&cp);
1786295367Sdes		if (!arg || *arg == '\0')
1787295367Sdes			fatal("%s line %d: missing AuthorizedKeysCommandUser "
1788295367Sdes			    "argument.", filename, linenum);
1789248619Sdes		if (*activep && *charptr == NULL)
1790248619Sdes			*charptr = xstrdup(arg);
1791248619Sdes		break;
1792248619Sdes
1793295367Sdes	case sAuthorizedPrincipalsCommand:
1794295367Sdes		if (cp == NULL)
1795295367Sdes			fatal("%.200s line %d: Missing argument.", filename,
1796295367Sdes			    linenum);
1797295367Sdes		len = strspn(cp, WHITESPACE);
1798295367Sdes		if (*activep &&
1799295367Sdes		    options->authorized_principals_command == NULL) {
1800295367Sdes			if (cp[len] != '/' && strcasecmp(cp + len, "none") != 0)
1801295367Sdes				fatal("%.200s line %d: "
1802295367Sdes				    "AuthorizedPrincipalsCommand must be "
1803295367Sdes				    "an absolute path", filename, linenum);
1804295367Sdes			options->authorized_principals_command =
1805295367Sdes			    xstrdup(cp + len);
1806295367Sdes		}
1807295367Sdes		return 0;
1808295367Sdes
1809295367Sdes	case sAuthorizedPrincipalsCommandUser:
1810295367Sdes		charptr = &options->authorized_principals_command_user;
1811295367Sdes
1812295367Sdes		arg = strdelim(&cp);
1813295367Sdes		if (!arg || *arg == '\0')
1814295367Sdes			fatal("%s line %d: missing "
1815295367Sdes			    "AuthorizedPrincipalsCommandUser argument.",
1816295367Sdes			    filename, linenum);
1817295367Sdes		if (*activep && *charptr == NULL)
1818295367Sdes			*charptr = xstrdup(arg);
1819295367Sdes		break;
1820295367Sdes
1821248619Sdes	case sAuthenticationMethods:
1822295367Sdes		if (options->num_auth_methods == 0) {
1823323124Sdes			value = 0; /* seen "any" pseudo-method */
1824323124Sdes			value2 = 0; /* sucessfully parsed any method */
1825248619Sdes			while ((arg = strdelim(&cp)) && *arg != '\0') {
1826248619Sdes				if (options->num_auth_methods >=
1827248619Sdes				    MAX_AUTH_METHODS)
1828248619Sdes					fatal("%s line %d: "
1829248619Sdes					    "too many authentication methods.",
1830248619Sdes					    filename, linenum);
1831323124Sdes				if (strcmp(arg, "any") == 0) {
1832323124Sdes					if (options->num_auth_methods > 0) {
1833323124Sdes						fatal("%s line %d: \"any\" "
1834323124Sdes						    "must appear alone in "
1835323124Sdes						    "AuthenticationMethods",
1836323124Sdes						    filename, linenum);
1837323124Sdes					}
1838323124Sdes					value = 1;
1839323124Sdes				} else if (value) {
1840323124Sdes					fatal("%s line %d: \"any\" must appear "
1841323124Sdes					    "alone in AuthenticationMethods",
1842323124Sdes					    filename, linenum);
1843323124Sdes				} else if (auth2_methods_valid(arg, 0) != 0) {
1844248619Sdes					fatal("%s line %d: invalid "
1845248619Sdes					    "authentication method list.",
1846248619Sdes					    filename, linenum);
1847323124Sdes				}
1848323124Sdes				value2 = 1;
1849295367Sdes				if (!*activep)
1850295367Sdes					continue;
1851248619Sdes				options->auth_methods[
1852248619Sdes				    options->num_auth_methods++] = xstrdup(arg);
1853248619Sdes			}
1854323124Sdes			if (value2 == 0) {
1855323124Sdes				fatal("%s line %d: no AuthenticationMethods "
1856323124Sdes				    "specified", filename, linenum);
1857323124Sdes			}
1858248619Sdes		}
1859248619Sdes		return 0;
1860248619Sdes
1861295367Sdes	case sStreamLocalBindMask:
1862295367Sdes		arg = strdelim(&cp);
1863295367Sdes		if (!arg || *arg == '\0')
1864295367Sdes			fatal("%s line %d: missing StreamLocalBindMask "
1865295367Sdes			    "argument.", filename, linenum);
1866295367Sdes		/* Parse mode in octal format */
1867295367Sdes		value = strtol(arg, &p, 8);
1868295367Sdes		if (arg == p || value < 0 || value > 0777)
1869295367Sdes			fatal("%s line %d: Bad mask.", filename, linenum);
1870295367Sdes		if (*activep)
1871295367Sdes			options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
1872295367Sdes		break;
1873295367Sdes
1874295367Sdes	case sStreamLocalBindUnlink:
1875295367Sdes		intptr = &options->fwd_opts.streamlocal_bind_unlink;
1876295367Sdes		goto parse_flag;
1877295367Sdes
1878295367Sdes	case sFingerprintHash:
1879295367Sdes		arg = strdelim(&cp);
1880295367Sdes		if (!arg || *arg == '\0')
1881295367Sdes			fatal("%.200s line %d: Missing argument.",
1882295367Sdes			    filename, linenum);
1883295367Sdes		if ((value = ssh_digest_alg_by_name(arg)) == -1)
1884295367Sdes			fatal("%.200s line %d: Invalid hash algorithm \"%s\".",
1885295367Sdes			    filename, linenum, arg);
1886295367Sdes		if (*activep)
1887295367Sdes			options->fingerprint_hash = value;
1888295367Sdes		break;
1889295367Sdes
189092559Sdes	case sDeprecated:
1891124211Sdes		logit("%s line %d: Deprecated option %s",
189292559Sdes		    filename, linenum, arg);
189392559Sdes		while (arg)
189492559Sdes		    arg = strdelim(&cp);
189592559Sdes		break;
189692559Sdes
1897124211Sdes	case sUnsupported:
1898124211Sdes		logit("%s line %d: Unsupported option %s",
1899124211Sdes		    filename, linenum, arg);
1900124211Sdes		while (arg)
1901124211Sdes		    arg = strdelim(&cp);
1902124211Sdes		break;
1903124211Sdes
190492559Sdes	default:
190592559Sdes		fatal("%s line %d: Missing handler for opcode %s (%d)",
190692559Sdes		    filename, linenum, arg, opcode);
190792559Sdes	}
190892559Sdes	if ((arg = strdelim(&cp)) != NULL && *arg != '\0')
190992559Sdes		fatal("%s line %d: garbage at end of line; \"%.200s\".",
191092559Sdes		    filename, linenum, arg);
191192559Sdes	return 0;
191292559Sdes}
191376227Sgreen
191492559Sdes/* Reads the server configuration file. */
191592559Sdes
191692559Sdesvoid
1917137019Sdesload_server_config(const char *filename, Buffer *conf)
191892559Sdes{
1919240075Sdes	char line[4096], *cp;
192092559Sdes	FILE *f;
1921240075Sdes	int lineno = 0;
192292559Sdes
1923137019Sdes	debug2("%s: filename %s", __func__, filename);
1924137019Sdes	if ((f = fopen(filename, "r")) == NULL) {
192592559Sdes		perror(filename);
192692559Sdes		exit(1);
192757429Smarkm	}
1928137019Sdes	buffer_clear(conf);
192992559Sdes	while (fgets(line, sizeof(line), f)) {
1930240075Sdes		lineno++;
1931240075Sdes		if (strlen(line) == sizeof(line) - 1)
1932240075Sdes			fatal("%s line %d too long", filename, lineno);
1933137019Sdes		/*
1934137019Sdes		 * Trim out comments and strip whitespace
1935137019Sdes		 * NB - preserve newlines, they are needed to reproduce
1936137019Sdes		 * line numbers later for error messages
1937137019Sdes		 */
1938137019Sdes		if ((cp = strchr(line, '#')) != NULL)
1939137019Sdes			memcpy(cp, "\n", 2);
1940137019Sdes		cp = line + strspn(line, " \t\r");
1941137019Sdes
1942137019Sdes		buffer_append(conf, cp, strlen(cp));
1943137019Sdes	}
1944137019Sdes	buffer_append(conf, "\0", 1);
1945137019Sdes	fclose(f);
1946137019Sdes	debug2("%s: done config len = %d", __func__, buffer_len(conf));
1947137019Sdes}
1948137019Sdes
1949137019Sdesvoid
1950240075Sdesparse_server_match_config(ServerOptions *options,
1951240075Sdes   struct connection_info *connectinfo)
1952137019Sdes{
1953162856Sdes	ServerOptions mo;
1954162856Sdes
1955162856Sdes	initialize_server_options(&mo);
1956240075Sdes	parse_server_config(&mo, "reprocess config", &cfg, connectinfo);
1957181111Sdes	copy_set_server_options(options, &mo, 0);
1958162856Sdes}
1959162856Sdes
1960240075Sdesint parse_server_match_testspec(struct connection_info *ci, char *spec)
1961240075Sdes{
1962240075Sdes	char *p;
1963240075Sdes
1964240075Sdes	while ((p = strsep(&spec, ",")) && *p != '\0') {
1965240075Sdes		if (strncmp(p, "addr=", 5) == 0) {
1966240075Sdes			ci->address = xstrdup(p + 5);
1967240075Sdes		} else if (strncmp(p, "host=", 5) == 0) {
1968240075Sdes			ci->host = xstrdup(p + 5);
1969240075Sdes		} else if (strncmp(p, "user=", 5) == 0) {
1970240075Sdes			ci->user = xstrdup(p + 5);
1971240075Sdes		} else if (strncmp(p, "laddr=", 6) == 0) {
1972240075Sdes			ci->laddress = xstrdup(p + 6);
1973240075Sdes		} else if (strncmp(p, "lport=", 6) == 0) {
1974240075Sdes			ci->lport = a2port(p + 6);
1975240075Sdes			if (ci->lport == -1) {
1976240075Sdes				fprintf(stderr, "Invalid port '%s' in test mode"
1977240075Sdes				   " specification %s\n", p+6, p);
1978240075Sdes				return -1;
1979240075Sdes			}
1980240075Sdes		} else {
1981240075Sdes			fprintf(stderr, "Invalid test mode specification %s\n",
1982240075Sdes			   p);
1983240075Sdes			return -1;
1984240075Sdes		}
1985240075Sdes	}
1986240075Sdes	return 0;
1987240075Sdes}
1988240075Sdes
1989240075Sdes/*
1990240075Sdes * returns 1 for a complete spec, 0 for partial spec and -1 for an
1991240075Sdes * empty spec.
1992240075Sdes */
1993240075Sdesint server_match_spec_complete(struct connection_info *ci)
1994240075Sdes{
1995240075Sdes	if (ci->user && ci->host && ci->address)
1996240075Sdes		return 1;	/* complete */
1997240075Sdes	if (!ci->user && !ci->host && !ci->address)
1998240075Sdes		return -1;	/* empty */
1999240075Sdes	return 0;	/* partial */
2000240075Sdes}
2001240075Sdes
2002181111Sdes/*
2003181111Sdes * Copy any supported values that are set.
2004181111Sdes *
2005197679Sdes * If the preauth flag is set, we do not bother copying the string or
2006181111Sdes * array values that are not used pre-authentication, because any that we
2007181111Sdes * do use must be explictly sent in mm_getpwnamallow().
2008181111Sdes */
2009162856Sdesvoid
2010181111Sdescopy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
2011162856Sdes{
2012262566Sdes#define M_CP_INTOPT(n) do {\
2013262566Sdes	if (src->n != -1) \
2014262566Sdes		dst->n = src->n; \
2015262566Sdes} while (0)
2016262566Sdes
2017181111Sdes	M_CP_INTOPT(password_authentication);
2018181111Sdes	M_CP_INTOPT(gss_authentication);
2019181111Sdes	M_CP_INTOPT(rsa_authentication);
2020181111Sdes	M_CP_INTOPT(pubkey_authentication);
2021181111Sdes	M_CP_INTOPT(kerberos_authentication);
2022181111Sdes	M_CP_INTOPT(hostbased_authentication);
2023215116Sdes	M_CP_INTOPT(hostbased_uses_name_from_packet_only);
2024181111Sdes	M_CP_INTOPT(kbd_interactive_authentication);
2025181111Sdes	M_CP_INTOPT(permit_root_login);
2026192595Sdes	M_CP_INTOPT(permit_empty_passwd);
2027181111Sdes
2028181111Sdes	M_CP_INTOPT(allow_tcp_forwarding);
2029295367Sdes	M_CP_INTOPT(allow_streamlocal_forwarding);
2030181111Sdes	M_CP_INTOPT(allow_agent_forwarding);
2031215116Sdes	M_CP_INTOPT(permit_tun);
2032295367Sdes	M_CP_INTOPT(fwd_opts.gateway_ports);
2033323124Sdes	M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink);
2034181111Sdes	M_CP_INTOPT(x11_display_offset);
2035181111Sdes	M_CP_INTOPT(x11_forwarding);
2036181111Sdes	M_CP_INTOPT(x11_use_localhost);
2037262566Sdes	M_CP_INTOPT(permit_tty);
2038295367Sdes	M_CP_INTOPT(permit_user_rc);
2039181111Sdes	M_CP_INTOPT(max_sessions);
2040181111Sdes	M_CP_INTOPT(max_authtries);
2041221420Sdes	M_CP_INTOPT(ip_qos_interactive);
2042221420Sdes	M_CP_INTOPT(ip_qos_bulk);
2043255767Sdes	M_CP_INTOPT(rekey_limit);
2044255767Sdes	M_CP_INTOPT(rekey_interval);
2045181111Sdes
2046323124Sdes	/*
2047323124Sdes	 * The bind_mask is a mode_t that may be unsigned, so we can't use
2048323124Sdes	 * M_CP_INTOPT - it does a signed comparison that causes compiler
2049323124Sdes	 * warnings.
2050323124Sdes	 */
2051323124Sdes	if (src->fwd_opts.streamlocal_bind_mask != (mode_t)-1) {
2052323124Sdes		dst->fwd_opts.streamlocal_bind_mask =
2053323124Sdes		    src->fwd_opts.streamlocal_bind_mask;
2054323124Sdes	}
2055323124Sdes
2056262566Sdes	/* M_CP_STROPT and M_CP_STRARRAYOPT should not appear before here */
2057262566Sdes#define M_CP_STROPT(n) do {\
2058262566Sdes	if (src->n != NULL && dst->n != src->n) { \
2059262566Sdes		free(dst->n); \
2060262566Sdes		dst->n = src->n; \
2061262566Sdes	} \
2062262566Sdes} while(0)
2063262566Sdes#define M_CP_STRARRAYOPT(n, num_n) do {\
2064262566Sdes	if (src->num_n != 0) { \
2065262566Sdes		for (dst->num_n = 0; dst->num_n < src->num_n; dst->num_n++) \
2066262566Sdes			dst->n[dst->num_n] = xstrdup(src->n[dst->num_n]); \
2067262566Sdes	} \
2068262566Sdes} while(0)
2069262566Sdes
2070226046Sdes	/* See comment in servconf.h */
2071226046Sdes	COPY_MATCH_STRING_OPTS();
2072226046Sdes
2073296781Sdes	/* Arguments that accept '+...' need to be expanded */
2074296781Sdes	assemble_algorithms(dst);
2075296781Sdes
2076226046Sdes	/*
2077226046Sdes	 * The only things that should be below this point are string options
2078226046Sdes	 * which are only used after authentication.
2079226046Sdes	 */
2080181111Sdes	if (preauth)
2081181111Sdes		return;
2082226046Sdes
2083296781Sdes	/* These options may be "none" to clear a global setting */
2084181111Sdes	M_CP_STROPT(adm_forced_command);
2085296781Sdes	if (option_clear_or_none(dst->adm_forced_command)) {
2086296781Sdes		free(dst->adm_forced_command);
2087296781Sdes		dst->adm_forced_command = NULL;
2088296781Sdes	}
2089181111Sdes	M_CP_STROPT(chroot_directory);
2090296781Sdes	if (option_clear_or_none(dst->chroot_directory)) {
2091296781Sdes		free(dst->chroot_directory);
2092296781Sdes		dst->chroot_directory = NULL;
2093296781Sdes	}
2094162856Sdes}
2095162856Sdes
2096181111Sdes#undef M_CP_INTOPT
2097181111Sdes#undef M_CP_STROPT
2098226046Sdes#undef M_CP_STRARRAYOPT
2099181111Sdes
2100162856Sdesvoid
2101162856Sdesparse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
2102240075Sdes    struct connection_info *connectinfo)
2103162856Sdes{
2104162856Sdes	int active, linenum, bad_options = 0;
2105137019Sdes	char *cp, *obuf, *cbuf;
2106137019Sdes
2107137019Sdes	debug2("%s: config %s len %d", __func__, filename, buffer_len(conf));
2108137019Sdes
2109323124Sdes	if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL)
2110323124Sdes		fatal("%s: sshbuf_dup_string failed", __func__);
2111240075Sdes	active = connectinfo ? 0 : 1;
2112137019Sdes	linenum = 1;
2113147005Sdes	while ((cp = strsep(&cbuf, "\n")) != NULL) {
2114137019Sdes		if (process_server_config_line(options, cp, filename,
2115240075Sdes		    linenum++, &active, connectinfo) != 0)
211692559Sdes			bad_options++;
211792559Sdes	}
2118255767Sdes	free(obuf);
211976262Sgreen	if (bad_options > 0)
212092559Sdes		fatal("%s: terminating, %d bad configuration options",
212176262Sgreen		    filename, bad_options);
2122295367Sdes	process_queued_listen_addrs(options);
212357429Smarkm}
2124181111Sdes
2125181111Sdesstatic const char *
2126226046Sdesfmt_multistate_int(int val, const struct multistate *m)
2127226046Sdes{
2128226046Sdes	u_int i;
2129226046Sdes
2130226046Sdes	for (i = 0; m[i].key != NULL; i++) {
2131226046Sdes		if (m[i].value == val)
2132226046Sdes			return m[i].key;
2133226046Sdes	}
2134226046Sdes	return "UNKNOWN";
2135226046Sdes}
2136226046Sdes
2137226046Sdesstatic const char *
2138181111Sdesfmt_intarg(ServerOpCodes code, int val)
2139181111Sdes{
2140226046Sdes	if (val == -1)
2141226046Sdes		return "unset";
2142226046Sdes	switch (code) {
2143226046Sdes	case sAddressFamily:
2144226046Sdes		return fmt_multistate_int(val, multistate_addressfamily);
2145226046Sdes	case sPermitRootLogin:
2146226046Sdes		return fmt_multistate_int(val, multistate_permitrootlogin);
2147226046Sdes	case sGatewayPorts:
2148226046Sdes		return fmt_multistate_int(val, multistate_gatewayports);
2149226046Sdes	case sCompression:
2150226046Sdes		return fmt_multistate_int(val, multistate_compression);
2151226046Sdes	case sUsePrivilegeSeparation:
2152226046Sdes		return fmt_multistate_int(val, multistate_privsep);
2153248619Sdes	case sAllowTcpForwarding:
2154248619Sdes		return fmt_multistate_int(val, multistate_tcpfwd);
2155295367Sdes	case sAllowStreamLocalForwarding:
2156295367Sdes		return fmt_multistate_int(val, multistate_tcpfwd);
2157295367Sdes	case sFingerprintHash:
2158295367Sdes		return ssh_digest_alg_name(val);
2159226046Sdes	case sProtocol:
2160181111Sdes		switch (val) {
2161181111Sdes		case SSH_PROTO_1:
2162181111Sdes			return "1";
2163181111Sdes		case SSH_PROTO_2:
2164181111Sdes			return "2";
2165181111Sdes		case (SSH_PROTO_1|SSH_PROTO_2):
2166181111Sdes			return "2,1";
2167181111Sdes		default:
2168181111Sdes			return "UNKNOWN";
2169181111Sdes		}
2170226046Sdes	default:
2171226046Sdes		switch (val) {
2172226046Sdes		case 0:
2173226046Sdes			return "no";
2174226046Sdes		case 1:
2175226046Sdes			return "yes";
2176226046Sdes		default:
2177226046Sdes			return "UNKNOWN";
2178226046Sdes		}
2179181111Sdes	}
2180181111Sdes}
2181181111Sdes
2182181111Sdesstatic const char *
2183181111Sdeslookup_opcode_name(ServerOpCodes code)
2184181111Sdes{
2185181111Sdes	u_int i;
2186181111Sdes
2187181111Sdes	for (i = 0; keywords[i].name != NULL; i++)
2188181111Sdes		if (keywords[i].opcode == code)
2189181111Sdes			return(keywords[i].name);
2190181111Sdes	return "UNKNOWN";
2191181111Sdes}
2192181111Sdes
2193181111Sdesstatic void
2194181111Sdesdump_cfg_int(ServerOpCodes code, int val)
2195181111Sdes{
2196181111Sdes	printf("%s %d\n", lookup_opcode_name(code), val);
2197181111Sdes}
2198181111Sdes
2199181111Sdesstatic void
2200295367Sdesdump_cfg_oct(ServerOpCodes code, int val)
2201295367Sdes{
2202295367Sdes	printf("%s 0%o\n", lookup_opcode_name(code), val);
2203295367Sdes}
2204295367Sdes
2205295367Sdesstatic void
2206181111Sdesdump_cfg_fmtint(ServerOpCodes code, int val)
2207181111Sdes{
2208181111Sdes	printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
2209181111Sdes}
2210181111Sdes
2211181111Sdesstatic void
2212181111Sdesdump_cfg_string(ServerOpCodes code, const char *val)
2213181111Sdes{
2214181111Sdes	if (val == NULL)
2215181111Sdes		return;
2216295367Sdes	printf("%s %s\n", lookup_opcode_name(code),
2217295367Sdes	    val == NULL ? "none" : val);
2218181111Sdes}
2219181111Sdes
2220181111Sdesstatic void
2221181111Sdesdump_cfg_strarray(ServerOpCodes code, u_int count, char **vals)
2222181111Sdes{
2223181111Sdes	u_int i;
2224181111Sdes
2225181111Sdes	for (i = 0; i < count; i++)
2226226046Sdes		printf("%s %s\n", lookup_opcode_name(code), vals[i]);
2227181111Sdes}
2228181111Sdes
2229226046Sdesstatic void
2230226046Sdesdump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals)
2231226046Sdes{
2232226046Sdes	u_int i;
2233226046Sdes
2234323124Sdes	if (count <= 0 && code != sAuthenticationMethods)
2235295367Sdes		return;
2236226046Sdes	printf("%s", lookup_opcode_name(code));
2237226046Sdes	for (i = 0; i < count; i++)
2238226046Sdes		printf(" %s",  vals[i]);
2239323124Sdes	if (code == sAuthenticationMethods && count == 0)
2240323124Sdes		printf(" any");
2241226046Sdes	printf("\n");
2242226046Sdes}
2243226046Sdes
2244181111Sdesvoid
2245181111Sdesdump_config(ServerOptions *o)
2246181111Sdes{
2247181111Sdes	u_int i;
2248181111Sdes	int ret;
2249181111Sdes	struct addrinfo *ai;
2250181111Sdes	char addr[NI_MAXHOST], port[NI_MAXSERV], *s = NULL;
2251295367Sdes	char *laddr1 = xstrdup(""), *laddr2 = NULL;
2252181111Sdes
2253181111Sdes	/* these are usually at the top of the config */
2254181111Sdes	for (i = 0; i < o->num_ports; i++)
2255181111Sdes		printf("port %d\n", o->ports[i]);
2256181111Sdes	dump_cfg_fmtint(sProtocol, o->protocol);
2257181111Sdes	dump_cfg_fmtint(sAddressFamily, o->address_family);
2258181111Sdes
2259295367Sdes	/*
2260295367Sdes	 * ListenAddress must be after Port.  add_one_listen_addr pushes
2261295367Sdes	 * addresses onto a stack, so to maintain ordering we need to
2262295367Sdes	 * print these in reverse order.
2263295367Sdes	 */
2264181111Sdes	for (ai = o->listen_addrs; ai; ai = ai->ai_next) {
2265181111Sdes		if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
2266181111Sdes		    sizeof(addr), port, sizeof(port),
2267181111Sdes		    NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
2268181111Sdes			error("getnameinfo failed: %.100s",
2269181111Sdes			    (ret != EAI_SYSTEM) ? gai_strerror(ret) :
2270181111Sdes			    strerror(errno));
2271181111Sdes		} else {
2272295367Sdes			laddr2 = laddr1;
2273181111Sdes			if (ai->ai_family == AF_INET6)
2274295367Sdes				xasprintf(&laddr1, "listenaddress [%s]:%s\n%s",
2275295367Sdes				    addr, port, laddr2);
2276181111Sdes			else
2277295367Sdes				xasprintf(&laddr1, "listenaddress %s:%s\n%s",
2278295367Sdes				    addr, port, laddr2);
2279295367Sdes			free(laddr2);
2280181111Sdes		}
2281181111Sdes	}
2282295367Sdes	printf("%s", laddr1);
2283295367Sdes	free(laddr1);
2284181111Sdes
2285181111Sdes	/* integer arguments */
2286192595Sdes#ifdef USE_PAM
2287295367Sdes	dump_cfg_fmtint(sUsePAM, o->use_pam);
2288192595Sdes#endif
2289181111Sdes	dump_cfg_int(sServerKeyBits, o->server_key_bits);
2290181111Sdes	dump_cfg_int(sLoginGraceTime, o->login_grace_time);
2291181111Sdes	dump_cfg_int(sKeyRegenerationTime, o->key_regeneration_time);
2292181111Sdes	dump_cfg_int(sX11DisplayOffset, o->x11_display_offset);
2293181111Sdes	dump_cfg_int(sMaxAuthTries, o->max_authtries);
2294192595Sdes	dump_cfg_int(sMaxSessions, o->max_sessions);
2295181111Sdes	dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
2296181111Sdes	dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
2297295367Sdes	dump_cfg_oct(sStreamLocalBindMask, o->fwd_opts.streamlocal_bind_mask);
2298181111Sdes
2299181111Sdes	/* formatted integer arguments */
2300181111Sdes	dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login);
2301181111Sdes	dump_cfg_fmtint(sIgnoreRhosts, o->ignore_rhosts);
2302181111Sdes	dump_cfg_fmtint(sIgnoreUserKnownHosts, o->ignore_user_known_hosts);
2303181111Sdes	dump_cfg_fmtint(sRhostsRSAAuthentication, o->rhosts_rsa_authentication);
2304181111Sdes	dump_cfg_fmtint(sHostbasedAuthentication, o->hostbased_authentication);
2305181111Sdes	dump_cfg_fmtint(sHostbasedUsesNameFromPacketOnly,
2306181111Sdes	    o->hostbased_uses_name_from_packet_only);
2307181111Sdes	dump_cfg_fmtint(sRSAAuthentication, o->rsa_authentication);
2308181111Sdes	dump_cfg_fmtint(sPubkeyAuthentication, o->pubkey_authentication);
2309192595Sdes#ifdef KRB5
2310181111Sdes	dump_cfg_fmtint(sKerberosAuthentication, o->kerberos_authentication);
2311181111Sdes	dump_cfg_fmtint(sKerberosOrLocalPasswd, o->kerberos_or_local_passwd);
2312181111Sdes	dump_cfg_fmtint(sKerberosTicketCleanup, o->kerberos_ticket_cleanup);
2313192595Sdes# ifdef USE_AFS
2314181111Sdes	dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
2315192595Sdes# endif
2316192595Sdes#endif
2317192595Sdes#ifdef GSSAPI
2318181111Sdes	dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
2319181111Sdes	dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
2320192595Sdes#endif
2321181111Sdes	dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
2322181111Sdes	dump_cfg_fmtint(sKbdInteractiveAuthentication,
2323181111Sdes	    o->kbd_interactive_authentication);
2324181111Sdes	dump_cfg_fmtint(sChallengeResponseAuthentication,
2325181111Sdes	    o->challenge_response_authentication);
2326181111Sdes	dump_cfg_fmtint(sPrintMotd, o->print_motd);
2327296781Sdes#ifndef DISABLE_LASTLOG
2328181111Sdes	dump_cfg_fmtint(sPrintLastLog, o->print_lastlog);
2329296781Sdes#endif
2330181111Sdes	dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding);
2331181111Sdes	dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost);
2332262566Sdes	dump_cfg_fmtint(sPermitTTY, o->permit_tty);
2333295367Sdes	dump_cfg_fmtint(sPermitUserRC, o->permit_user_rc);
2334181111Sdes	dump_cfg_fmtint(sStrictModes, o->strict_modes);
2335181111Sdes	dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive);
2336181111Sdes	dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd);
2337181111Sdes	dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
2338181111Sdes	dump_cfg_fmtint(sUseLogin, o->use_login);
2339181111Sdes	dump_cfg_fmtint(sCompression, o->compression);
2340295367Sdes	dump_cfg_fmtint(sGatewayPorts, o->fwd_opts.gateway_ports);
2341181111Sdes	dump_cfg_fmtint(sUseDNS, o->use_dns);
2342181111Sdes	dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
2343295367Sdes	dump_cfg_fmtint(sAllowAgentForwarding, o->allow_agent_forwarding);
2344295367Sdes	dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding);
2345323124Sdes	dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
2346181111Sdes	dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep);
2347295367Sdes	dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash);
2348181111Sdes
2349181111Sdes	/* string arguments */
2350181111Sdes	dump_cfg_string(sPidFile, o->pid_file);
2351181111Sdes	dump_cfg_string(sXAuthLocation, o->xauth_location);
2352295367Sdes	dump_cfg_string(sCiphers, o->ciphers ? o->ciphers : KEX_SERVER_ENCRYPT);
2353295367Sdes	dump_cfg_string(sMacs, o->macs ? o->macs : KEX_SERVER_MAC);
2354181111Sdes	dump_cfg_string(sBanner, o->banner);
2355181111Sdes	dump_cfg_string(sForceCommand, o->adm_forced_command);
2356204917Sdes	dump_cfg_string(sChrootDirectory, o->chroot_directory);
2357204917Sdes	dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys);
2358204917Sdes	dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
2359215116Sdes	dump_cfg_string(sAuthorizedPrincipalsFile,
2360215116Sdes	    o->authorized_principals_file);
2361295367Sdes	dump_cfg_string(sVersionAddendum, *o->version_addendum == '\0'
2362295367Sdes	    ? "none" : o->version_addendum);
2363248619Sdes	dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command);
2364248619Sdes	dump_cfg_string(sAuthorizedKeysCommandUser, o->authorized_keys_command_user);
2365295367Sdes	dump_cfg_string(sAuthorizedPrincipalsCommand, o->authorized_principals_command);
2366295367Sdes	dump_cfg_string(sAuthorizedPrincipalsCommandUser, o->authorized_principals_command_user);
2367255767Sdes	dump_cfg_string(sHostKeyAgent, o->host_key_agent);
2368295367Sdes	dump_cfg_string(sKexAlgorithms,
2369295367Sdes	    o->kex_algorithms ? o->kex_algorithms : KEX_SERVER_KEX);
2370295367Sdes	dump_cfg_string(sHostbasedAcceptedKeyTypes, o->hostbased_key_types ?
2371295367Sdes	    o->hostbased_key_types : KEX_DEFAULT_PK_ALG);
2372295367Sdes	dump_cfg_string(sHostKeyAlgorithms, o->hostkeyalgorithms ?
2373295367Sdes	    o->hostkeyalgorithms : KEX_DEFAULT_PK_ALG);
2374295367Sdes	dump_cfg_string(sPubkeyAcceptedKeyTypes, o->pubkey_key_types ?
2375295367Sdes	    o->pubkey_key_types : KEX_DEFAULT_PK_ALG);
2376181111Sdes
2377181111Sdes	/* string arguments requiring a lookup */
2378181111Sdes	dump_cfg_string(sLogLevel, log_level_name(o->log_level));
2379181111Sdes	dump_cfg_string(sLogFacility, log_facility_name(o->log_facility));
2380181111Sdes
2381181111Sdes	/* string array arguments */
2382226046Sdes	dump_cfg_strarray_oneline(sAuthorizedKeysFile, o->num_authkeys_files,
2383226046Sdes	    o->authorized_keys_files);
2384181111Sdes	dump_cfg_strarray(sHostKeyFile, o->num_host_key_files,
2385181111Sdes	     o->host_key_files);
2386295367Sdes	dump_cfg_strarray(sHostCertificate, o->num_host_cert_files,
2387204917Sdes	     o->host_cert_files);
2388181111Sdes	dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users);
2389181111Sdes	dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users);
2390181111Sdes	dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups);
2391181111Sdes	dump_cfg_strarray(sDenyGroups, o->num_deny_groups, o->deny_groups);
2392181111Sdes	dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env);
2393248619Sdes	dump_cfg_strarray_oneline(sAuthenticationMethods,
2394248619Sdes	    o->num_auth_methods, o->auth_methods);
2395181111Sdes
2396181111Sdes	/* other arguments */
2397181111Sdes	for (i = 0; i < o->num_subsystems; i++)
2398181111Sdes		printf("subsystem %s %s\n", o->subsystem_name[i],
2399181111Sdes		    o->subsystem_args[i]);
2400181111Sdes
2401181111Sdes	printf("maxstartups %d:%d:%d\n", o->max_startups_begin,
2402181111Sdes	    o->max_startups_rate, o->max_startups);
2403181111Sdes
2404181111Sdes	for (i = 0; tunmode_desc[i].val != -1; i++)
2405181111Sdes		if (tunmode_desc[i].val == o->permit_tun) {
2406181111Sdes			s = tunmode_desc[i].text;
2407181111Sdes			break;
2408181111Sdes		}
2409181111Sdes	dump_cfg_string(sPermitTunnel, s);
2410181111Sdes
2411226046Sdes	printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
2412226046Sdes	printf("%s\n", iptos2str(o->ip_qos_bulk));
2413221420Sdes
2414296781Sdes	printf("rekeylimit %llu %d\n", (unsigned long long)o->rekey_limit,
2415255767Sdes	    o->rekey_interval);
2416255767Sdes
2417181111Sdes	channel_print_adm_permitted_opens();
2418181111Sdes}
2419