1240075Sdes
2264377Sdes/* $OpenBSD: servconf.c,v 1.249 2014/01/29 06:18:35 djm Exp $ */
3224638Sbrooks/* $FreeBSD$ */
457429Smarkm/*
557429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
657429Smarkm *                    All rights reserved
760576Skris *
865674Skris * As far as I am concerned, the code I have written for this software
965674Skris * can be used freely for any purpose.  Any derived versions of this
1065674Skris * software must be clearly marked as such, and if the derived work is
1165674Skris * incompatible with the protocol description in the RFC file, it must be
1265674Skris * called by a name other than "ssh" or "Secure Shell".
1357429Smarkm */
1457429Smarkm
1557429Smarkm#include "includes.h"
16162856Sdes__RCSID("$FreeBSD$");
1757429Smarkm
18162856Sdes#include <sys/types.h>
19162856Sdes#include <sys/socket.h>
20162856Sdes
21221420Sdes#include <netinet/in.h>
22221420Sdes#include <netinet/in_systm.h>
23221420Sdes#include <netinet/ip.h>
24221420Sdes
25255767Sdes#include <ctype.h>
26162856Sdes#include <netdb.h>
27162856Sdes#include <pwd.h>
28162856Sdes#include <stdio.h>
29162856Sdes#include <stdlib.h>
30162856Sdes#include <string.h>
31162856Sdes#include <signal.h>
32162856Sdes#include <unistd.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"
4457429Smarkm#include "servconf.h"
4560576Skris#include "compat.h"
4676262Sgreen#include "pathnames.h"
4776262Sgreen#include "misc.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"
59204917Sdes#include "version.h"
6057429Smarkm
61192595Sdesstatic void add_listen_addr(ServerOptions *, char *, int);
62192595Sdesstatic void add_one_listen_addr(ServerOptions *, char *, int);
6357429Smarkm
6498684Sdes/* Use of privilege separation or not */
6598684Sdesextern int use_privsep;
66162856Sdesextern Buffer cfg;
6776262Sgreen
6857429Smarkm/* Initializes the server options to their default values. */
6957429Smarkm
7060576Skrisvoid
7157429Smarkminitialize_server_options(ServerOptions *options)
7257429Smarkm{
7357429Smarkm	memset(options, 0, sizeof(*options));
7498941Sdes
7598941Sdes	/* Portable-specific options */
76124211Sdes	options->use_pam = -1;
7798941Sdes
7898941Sdes	/* Standard Options */
7957429Smarkm	options->num_ports = 0;
8057429Smarkm	options->ports_from_cmdline = 0;
8157429Smarkm	options->listen_addrs = NULL;
82147005Sdes	options->address_family = -1;
8376262Sgreen	options->num_host_key_files = 0;
84204917Sdes	options->num_host_cert_files = 0;
85255767Sdes	options->host_key_agent = NULL;
8660576Skris	options->pid_file = NULL;
8757429Smarkm	options->server_key_bits = -1;
8857429Smarkm	options->login_grace_time = -1;
8957429Smarkm	options->key_regeneration_time = -1;
9076262Sgreen	options->permit_root_login = PERMIT_NOT_SET;
9157429Smarkm	options->ignore_rhosts = -1;
9257429Smarkm	options->ignore_user_known_hosts = -1;
9357429Smarkm	options->print_motd = -1;
9476262Sgreen	options->print_lastlog = -1;
9557429Smarkm	options->x11_forwarding = -1;
9657429Smarkm	options->x11_display_offset = -1;
9792559Sdes	options->x11_use_localhost = -1;
98262566Sdes	options->permit_tty = -1;
9965674Skris	options->xauth_location = NULL;
10057429Smarkm	options->strict_modes = -1;
101126277Sdes	options->tcp_keep_alive = -1;
10292559Sdes	options->log_facility = SYSLOG_FACILITY_NOT_SET;
10392559Sdes	options->log_level = SYSLOG_LEVEL_NOT_SET;
10457429Smarkm	options->rhosts_rsa_authentication = -1;
10576262Sgreen	options->hostbased_authentication = -1;
10676262Sgreen	options->hostbased_uses_name_from_packet_only = -1;
10757429Smarkm	options->rsa_authentication = -1;
10876262Sgreen	options->pubkey_authentication = -1;
10973400Sassar	options->kerberos_authentication = -1;
11092559Sdes	options->kerberos_or_local_passwd = -1;
11192559Sdes	options->kerberos_ticket_cleanup = -1;
112126277Sdes	options->kerberos_get_afs_token = -1;
113124211Sdes	options->gss_authentication=-1;
114124211Sdes	options->gss_cleanup_creds = -1;
11557429Smarkm	options->password_authentication = -1;
11669591Sgreen	options->kbd_interactive_authentication = -1;
11792559Sdes	options->challenge_response_authentication = -1;
11857429Smarkm	options->permit_empty_passwd = -1;
119106130Sdes	options->permit_user_env = -1;
12057429Smarkm	options->use_login = -1;
12198684Sdes	options->compression = -1;
122255767Sdes	options->rekey_limit = -1;
123255767Sdes	options->rekey_interval = -1;
12469591Sgreen	options->allow_tcp_forwarding = -1;
125181111Sdes	options->allow_agent_forwarding = -1;
12657429Smarkm	options->num_allow_users = 0;
12757429Smarkm	options->num_deny_users = 0;
12857429Smarkm	options->num_allow_groups = 0;
12957429Smarkm	options->num_deny_groups = 0;
13060576Skris	options->ciphers = NULL;
13176262Sgreen	options->macs = NULL;
132221420Sdes	options->kex_algorithms = NULL;
13360576Skris	options->protocol = SSH_PROTO_UNKNOWN;
13460576Skris	options->gateway_ports = -1;
13565674Skris	options->num_subsystems = 0;
13665674Skris	options->max_startups_begin = -1;
13765674Skris	options->max_startups_rate = -1;
13865674Skris	options->max_startups = -1;
139137019Sdes	options->max_authtries = -1;
140181111Sdes	options->max_sessions = -1;
14176262Sgreen	options->banner = NULL;
142124211Sdes	options->use_dns = -1;
14376262Sgreen	options->client_alive_interval = -1;
14476262Sgreen	options->client_alive_count_max = -1;
145226046Sdes	options->num_authkeys_files = 0;
146137019Sdes	options->num_accept_env = 0;
147157019Sdes	options->permit_tun = -1;
148162856Sdes	options->num_permitted_opens = -1;
149162856Sdes	options->adm_forced_command = NULL;
150181111Sdes	options->chroot_directory = NULL;
151248619Sdes	options->authorized_keys_command = NULL;
152248619Sdes	options->authorized_keys_command_user = NULL;
153204917Sdes	options->revoked_keys_file = NULL;
154204917Sdes	options->trusted_user_ca_keys = NULL;
155215116Sdes	options->authorized_principals_file = NULL;
156221420Sdes	options->ip_qos_interactive = -1;
157221420Sdes	options->ip_qos_bulk = -1;
158240075Sdes	options->version_addendum = NULL;
159224638Sbrooks	options->hpn_disabled = -1;
160224638Sbrooks	options->hpn_buffer_size = -1;
161224638Sbrooks	options->tcp_rcv_buf_poll = -1;
162224638Sbrooks#ifdef	NONE_CIPHER_ENABLED
163224638Sbrooks	options->none_enabled = -1;
164224638Sbrooks#endif
16557429Smarkm}
16657429Smarkm
16760576Skrisvoid
16857429Smarkmfill_default_server_options(ServerOptions *options)
16957429Smarkm{
17098941Sdes	/* Portable-specific options */
171124211Sdes	if (options->use_pam == -1)
172124279Sdes		options->use_pam = 1;
17398941Sdes
17498941Sdes	/* Standard Options */
17576262Sgreen	if (options->protocol == SSH_PROTO_UNKNOWN)
176126271Sdes		options->protocol = SSH_PROTO_2;
17776262Sgreen	if (options->num_host_key_files == 0) {
17876262Sgreen		/* fill default hostkeys for protocols */
17976262Sgreen		if (options->protocol & SSH_PROTO_1)
18092559Sdes			options->host_key_files[options->num_host_key_files++] =
18192559Sdes			    _PATH_HOST_KEY_FILE;
18292559Sdes		if (options->protocol & SSH_PROTO_2) {
18392559Sdes			options->host_key_files[options->num_host_key_files++] =
184231584Sed			    _PATH_HOST_RSA_KEY_FILE;
185181111Sdes			options->host_key_files[options->num_host_key_files++] =
18692559Sdes			    _PATH_HOST_DSA_KEY_FILE;
187221420Sdes#ifdef OPENSSL_HAS_ECC
188221420Sdes			options->host_key_files[options->num_host_key_files++] =
189221420Sdes			    _PATH_HOST_ECDSA_KEY_FILE;
190221420Sdes#endif
191262566Sdes			options->host_key_files[options->num_host_key_files++] =
192262566Sdes			    _PATH_HOST_ED25519_KEY_FILE;
19392559Sdes		}
19476262Sgreen	}
195204917Sdes	/* No certificates by default */
19657429Smarkm	if (options->num_ports == 0)
19757429Smarkm		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
19857429Smarkm	if (options->listen_addrs == NULL)
19976262Sgreen		add_listen_addr(options, NULL, 0);
20060576Skris	if (options->pid_file == NULL)
20176262Sgreen		options->pid_file = _PATH_SSH_DAEMON_PID_FILE;
20257429Smarkm	if (options->server_key_bits == -1)
203181111Sdes		options->server_key_bits = 1024;
20457429Smarkm	if (options->login_grace_time == -1)
20599048Sdes		options->login_grace_time = 120;
20657429Smarkm	if (options->key_regeneration_time == -1)
20757429Smarkm		options->key_regeneration_time = 3600;
20876262Sgreen	if (options->permit_root_login == PERMIT_NOT_SET)
20999048Sdes		options->permit_root_login = PERMIT_NO;
21057429Smarkm	if (options->ignore_rhosts == -1)
21157565Smarkm		options->ignore_rhosts = 1;
21257429Smarkm	if (options->ignore_user_known_hosts == -1)
21357429Smarkm		options->ignore_user_known_hosts = 0;
21457429Smarkm	if (options->print_motd == -1)
21557429Smarkm		options->print_motd = 1;
21676262Sgreen	if (options->print_lastlog == -1)
21776262Sgreen		options->print_lastlog = 1;
21857429Smarkm	if (options->x11_forwarding == -1)
21999048Sdes		options->x11_forwarding = 1;
22057429Smarkm	if (options->x11_display_offset == -1)
22157565Smarkm		options->x11_display_offset = 10;
22292559Sdes	if (options->x11_use_localhost == -1)
22392559Sdes		options->x11_use_localhost = 1;
22465674Skris	if (options->xauth_location == NULL)
22592559Sdes		options->xauth_location = _PATH_XAUTH;
226262566Sdes	if (options->permit_tty == -1)
227262566Sdes		options->permit_tty = 1;
22857429Smarkm	if (options->strict_modes == -1)
22957429Smarkm		options->strict_modes = 1;
230126277Sdes	if (options->tcp_keep_alive == -1)
231126277Sdes		options->tcp_keep_alive = 1;
23292559Sdes	if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
23357429Smarkm		options->log_facility = SYSLOG_FACILITY_AUTH;
23492559Sdes	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
23557429Smarkm		options->log_level = SYSLOG_LEVEL_INFO;
23657429Smarkm	if (options->rhosts_rsa_authentication == -1)
23757565Smarkm		options->rhosts_rsa_authentication = 0;
23876262Sgreen	if (options->hostbased_authentication == -1)
23976262Sgreen		options->hostbased_authentication = 0;
24076262Sgreen	if (options->hostbased_uses_name_from_packet_only == -1)
24176262Sgreen		options->hostbased_uses_name_from_packet_only = 0;
24257429Smarkm	if (options->rsa_authentication == -1)
24357429Smarkm		options->rsa_authentication = 1;
24476262Sgreen	if (options->pubkey_authentication == -1)
24576262Sgreen		options->pubkey_authentication = 1;
24699048Sdes	if (options->kerberos_authentication == -1)
247124211Sdes		options->kerberos_authentication = 0;
24892559Sdes	if (options->kerberos_or_local_passwd == -1)
24992559Sdes		options->kerberos_or_local_passwd = 1;
25092559Sdes	if (options->kerberos_ticket_cleanup == -1)
25192559Sdes		options->kerberos_ticket_cleanup = 1;
252126277Sdes	if (options->kerberos_get_afs_token == -1)
253126277Sdes		options->kerberos_get_afs_token = 0;
254124211Sdes	if (options->gss_authentication == -1)
255124211Sdes		options->gss_authentication = 0;
256124211Sdes	if (options->gss_cleanup_creds == -1)
257124211Sdes		options->gss_cleanup_creds = 1;
25857429Smarkm	if (options->password_authentication == -1)
259126009Sdes		options->password_authentication = 0;
26069591Sgreen	if (options->kbd_interactive_authentication == -1)
26169591Sgreen		options->kbd_interactive_authentication = 0;
26292559Sdes	if (options->challenge_response_authentication == -1)
26395456Sdes		options->challenge_response_authentication = 1;
26457429Smarkm	if (options->permit_empty_passwd == -1)
26557565Smarkm		options->permit_empty_passwd = 0;
266106130Sdes	if (options->permit_user_env == -1)
267106130Sdes		options->permit_user_env = 0;
26857429Smarkm	if (options->use_login == -1)
26957429Smarkm		options->use_login = 0;
27098684Sdes	if (options->compression == -1)
271149753Sdes		options->compression = COMP_DELAYED;
272255767Sdes	if (options->rekey_limit == -1)
273255767Sdes		options->rekey_limit = 0;
274255767Sdes	if (options->rekey_interval == -1)
275255767Sdes		options->rekey_interval = 0;
27669591Sgreen	if (options->allow_tcp_forwarding == -1)
277248619Sdes		options->allow_tcp_forwarding = FORWARD_ALLOW;
278181111Sdes	if (options->allow_agent_forwarding == -1)
279181111Sdes		options->allow_agent_forwarding = 1;
28060576Skris	if (options->gateway_ports == -1)
28160576Skris		options->gateway_ports = 0;
28265674Skris	if (options->max_startups == -1)
283248619Sdes		options->max_startups = 100;
28465674Skris	if (options->max_startups_rate == -1)
285248619Sdes		options->max_startups_rate = 30;		/* 30% */
28665674Skris	if (options->max_startups_begin == -1)
287248619Sdes		options->max_startups_begin = 10;
288137019Sdes	if (options->max_authtries == -1)
289137019Sdes		options->max_authtries = DEFAULT_AUTH_FAIL_MAX;
290181111Sdes	if (options->max_sessions == -1)
291181111Sdes		options->max_sessions = DEFAULT_SESSIONS_MAX;
292124211Sdes	if (options->use_dns == -1)
293124211Sdes		options->use_dns = 1;
29476262Sgreen	if (options->client_alive_interval == -1)
29592559Sdes		options->client_alive_interval = 0;
29676262Sgreen	if (options->client_alive_count_max == -1)
29776262Sgreen		options->client_alive_count_max = 3;
298226046Sdes	if (options->num_authkeys_files == 0) {
299226046Sdes		options->authorized_keys_files[options->num_authkeys_files++] =
300226046Sdes		    xstrdup(_PATH_SSH_USER_PERMITTED_KEYS);
301226046Sdes		options->authorized_keys_files[options->num_authkeys_files++] =
302226046Sdes		    xstrdup(_PATH_SSH_USER_PERMITTED_KEYS2);
30392559Sdes	}
304157019Sdes	if (options->permit_tun == -1)
305157019Sdes		options->permit_tun = SSH_TUNMODE_NO;
306221420Sdes	if (options->ip_qos_interactive == -1)
307221420Sdes		options->ip_qos_interactive = IPTOS_LOWDELAY;
308221420Sdes	if (options->ip_qos_bulk == -1)
309221420Sdes		options->ip_qos_bulk = IPTOS_THROUGHPUT;
310240075Sdes	if (options->version_addendum == NULL)
311240075Sdes		options->version_addendum = xstrdup(SSH_VERSION_FREEBSD);
312240075Sdes	/* Turn privilege separation on by default */
313240075Sdes	if (use_privsep == -1)
314262566Sdes		use_privsep = PRIVSEP_ON;
315240075Sdes
316240075Sdes#ifndef HAVE_MMAP
317240075Sdes	if (use_privsep && options->compression == 1) {
318240075Sdes		error("This platform does not support both privilege "
319240075Sdes		    "separation and compression");
320240075Sdes		error("Compression disabled");
321240075Sdes		options->compression = 0;
322240075Sdes	}
323240075Sdes#endif
324240075Sdes
325231584Sed	if (options->hpn_disabled == -1)
326224638Sbrooks		options->hpn_disabled = 0;
327224638Sbrooks	if (options->hpn_buffer_size == -1) {
328224638Sbrooks		/*
329224638Sbrooks		 * HPN buffer size option not explicitly set.  Try to figure
330224638Sbrooks		 * out what value to use or resort to default.
331224638Sbrooks		 */
332224638Sbrooks		options->hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT;
333224638Sbrooks		if (!options->hpn_disabled) {
334224638Sbrooks			sock_get_rcvbuf(&options->hpn_buffer_size, 0);
335224638Sbrooks			debug ("HPN Buffer Size: %d", options->hpn_buffer_size);
336224638Sbrooks		}
337224638Sbrooks	} else {
338224638Sbrooks		/*
339224638Sbrooks		 * In the case that the user sets both values in a
340224638Sbrooks		 * contradictory manner hpn_disabled overrrides hpn_buffer_size.
341224638Sbrooks		 */
342224638Sbrooks		if (options->hpn_disabled <= 0) {
343224638Sbrooks			u_int maxlen;
34498684Sdes
345224638Sbrooks			maxlen = buffer_get_max_len();
346224638Sbrooks			if (options->hpn_buffer_size == 0)
347224638Sbrooks				options->hpn_buffer_size = 1;
348224638Sbrooks			/* Limit the maximum buffer to BUFFER_MAX_LEN. */
349224638Sbrooks			if (options->hpn_buffer_size > maxlen / 1024)
350224638Sbrooks				options->hpn_buffer_size = maxlen;
351224638Sbrooks			else
352224638Sbrooks				options->hpn_buffer_size *= 1024;
353240075Sdes		} else {
354224638Sbrooks			options->hpn_buffer_size = CHAN_TCP_WINDOW_DEFAULT;
355240075Sdes		}
356224638Sbrooks	}
35757429Smarkm}
35857429Smarkm
35957429Smarkm/* Keyword tokens. */
36057429Smarkmtypedef enum {
36157429Smarkm	sBadOption,		/* == unknown option */
36298941Sdes	/* Portable-specific options */
363124211Sdes	sUsePAM,
36498941Sdes	/* Standard Options */
36557429Smarkm	sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
36657429Smarkm	sPermitRootLogin, sLogFacility, sLogLevel,
367124211Sdes	sRhostsRSAAuthentication, sRSAAuthentication,
36892559Sdes	sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
369126277Sdes	sKerberosGetAFSToken,
370124211Sdes	sKerberosTgtPassing, sChallengeResponseAuthentication,
371147005Sdes	sPasswordAuthentication, sKbdInteractiveAuthentication,
372147005Sdes	sListenAddress, sAddressFamily,
37376262Sgreen	sPrintMotd, sPrintLastLog, sIgnoreRhosts,
37492559Sdes	sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
375262566Sdes	sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive,
376106130Sdes	sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression,
377255767Sdes	sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
37876262Sgreen	sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
379137019Sdes	sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem,
380181111Sdes	sMaxStartups, sMaxAuthTries, sMaxSessions,
381124211Sdes	sBanner, sUseDNS, sHostbasedAuthentication,
38292559Sdes	sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
383226046Sdes	sClientAliveCountMax, sAuthorizedKeysFile,
384157019Sdes	sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
385181111Sdes	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
386181111Sdes	sUsePrivilegeSeparation, sAllowAgentForwarding,
387264377Sdes	sHostCertificate,
388215116Sdes	sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
389240075Sdes	sKexAlgorithms, sIPQoS, sVersionAddendum,
390248619Sdes	sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
391255767Sdes	sAuthenticationMethods, sHostKeyAgent,
392224638Sbrooks	sHPNDisabled, sHPNBufferSize, sTcpRcvBufPoll,
393224638Sbrooks#ifdef NONE_CIPHER_ENABLED
394224638Sbrooks	sNoneEnabled,
395224638Sbrooks#endif
396124211Sdes	sDeprecated, sUnsupported
39757429Smarkm} ServerOpCodes;
39857429Smarkm
399162856Sdes#define SSHCFG_GLOBAL	0x01	/* allowed in main section of sshd_config */
400162856Sdes#define SSHCFG_MATCH	0x02	/* allowed inside a Match section */
401162856Sdes#define SSHCFG_ALL	(SSHCFG_GLOBAL|SSHCFG_MATCH)
402162856Sdes
40357429Smarkm/* Textual representation of the tokens. */
40457429Smarkmstatic struct {
40557429Smarkm	const char *name;
40657429Smarkm	ServerOpCodes opcode;
407162856Sdes	u_int flags;
40857429Smarkm} keywords[] = {
40998941Sdes	/* Portable-specific options */
410124211Sdes#ifdef USE_PAM
411162856Sdes	{ "usepam", sUsePAM, SSHCFG_GLOBAL },
412124211Sdes#else
413162856Sdes	{ "usepam", sUnsupported, SSHCFG_GLOBAL },
41499048Sdes#endif
415162856Sdes	{ "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
41698941Sdes	/* Standard Options */
417162856Sdes	{ "port", sPort, SSHCFG_GLOBAL },
418162856Sdes	{ "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
419162856Sdes	{ "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL },		/* alias */
420255767Sdes	{ "hostkeyagent", sHostKeyAgent, SSHCFG_GLOBAL },
421162856Sdes	{ "pidfile", sPidFile, SSHCFG_GLOBAL },
422162856Sdes	{ "serverkeybits", sServerKeyBits, SSHCFG_GLOBAL },
423162856Sdes	{ "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL },
424162856Sdes	{ "keyregenerationinterval", sKeyRegenerationTime, SSHCFG_GLOBAL },
425181111Sdes	{ "permitrootlogin", sPermitRootLogin, SSHCFG_ALL },
426162856Sdes	{ "syslogfacility", sLogFacility, SSHCFG_GLOBAL },
427162856Sdes	{ "loglevel", sLogLevel, SSHCFG_GLOBAL },
428162856Sdes	{ "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL },
429181111Sdes	{ "rhostsrsaauthentication", sRhostsRSAAuthentication, SSHCFG_ALL },
430181111Sdes	{ "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL },
431215116Sdes	{ "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_ALL },
432181111Sdes	{ "rsaauthentication", sRSAAuthentication, SSHCFG_ALL },
433181111Sdes	{ "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL },
434197679Sdes	{ "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */
435124211Sdes#ifdef KRB5
436181111Sdes	{ "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL },
437162856Sdes	{ "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL },
438162856Sdes	{ "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL },
439126277Sdes#ifdef USE_AFS
440162856Sdes	{ "kerberosgetafstoken", sKerberosGetAFSToken, SSHCFG_GLOBAL },
441124211Sdes#else
442162856Sdes	{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
443126277Sdes#endif
444126277Sdes#else
445181111Sdes	{ "kerberosauthentication", sUnsupported, SSHCFG_ALL },
446162856Sdes	{ "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
447162856Sdes	{ "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
448162856Sdes	{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
44973400Sassar#endif
450162856Sdes	{ "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
451162856Sdes	{ "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
452124211Sdes#ifdef GSSAPI
453181111Sdes	{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
454162856Sdes	{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
455124211Sdes#else
456181111Sdes	{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
457162856Sdes	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
45857429Smarkm#endif
459181111Sdes	{ "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
460181111Sdes	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
461162856Sdes	{ "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
462162856Sdes	{ "skeyauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, /* alias */
463162856Sdes	{ "checkmail", sDeprecated, SSHCFG_GLOBAL },
464162856Sdes	{ "listenaddress", sListenAddress, SSHCFG_GLOBAL },
465162856Sdes	{ "addressfamily", sAddressFamily, SSHCFG_GLOBAL },
466162856Sdes	{ "printmotd", sPrintMotd, SSHCFG_GLOBAL },
467162856Sdes	{ "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
468162856Sdes	{ "ignorerhosts", sIgnoreRhosts, SSHCFG_GLOBAL },
469162856Sdes	{ "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
470162856Sdes	{ "x11forwarding", sX11Forwarding, SSHCFG_ALL },
471162856Sdes	{ "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
472162856Sdes	{ "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
473162856Sdes	{ "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
474162856Sdes	{ "strictmodes", sStrictModes, SSHCFG_GLOBAL },
475192595Sdes	{ "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL },
476162856Sdes	{ "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
477162856Sdes	{ "uselogin", sUseLogin, SSHCFG_GLOBAL },
478162856Sdes	{ "compression", sCompression, SSHCFG_GLOBAL },
479255767Sdes	{ "rekeylimit", sRekeyLimit, SSHCFG_ALL },
480162856Sdes	{ "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
481162856Sdes	{ "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL },	/* obsolete alias */
482162856Sdes	{ "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
483181111Sdes	{ "allowagentforwarding", sAllowAgentForwarding, SSHCFG_ALL },
484240075Sdes	{ "allowusers", sAllowUsers, SSHCFG_ALL },
485240075Sdes	{ "denyusers", sDenyUsers, SSHCFG_ALL },
486240075Sdes	{ "allowgroups", sAllowGroups, SSHCFG_ALL },
487240075Sdes	{ "denygroups", sDenyGroups, SSHCFG_ALL },
488162856Sdes	{ "ciphers", sCiphers, SSHCFG_GLOBAL },
489162856Sdes	{ "macs", sMacs, SSHCFG_GLOBAL },
490162856Sdes	{ "protocol", sProtocol, SSHCFG_GLOBAL },
491162856Sdes	{ "gatewayports", sGatewayPorts, SSHCFG_ALL },
492162856Sdes	{ "subsystem", sSubsystem, SSHCFG_GLOBAL },
493162856Sdes	{ "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
494181111Sdes	{ "maxauthtries", sMaxAuthTries, SSHCFG_ALL },
495181111Sdes	{ "maxsessions", sMaxSessions, SSHCFG_ALL },
496181111Sdes	{ "banner", sBanner, SSHCFG_ALL },
497162856Sdes	{ "usedns", sUseDNS, SSHCFG_GLOBAL },
498162856Sdes	{ "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
499162856Sdes	{ "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL },
500162856Sdes	{ "clientaliveinterval", sClientAliveInterval, SSHCFG_GLOBAL },
501162856Sdes	{ "clientalivecountmax", sClientAliveCountMax, SSHCFG_GLOBAL },
502215116Sdes	{ "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_ALL },
503226046Sdes	{ "authorizedkeysfile2", sDeprecated, SSHCFG_ALL },
504197679Sdes	{ "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL},
505240075Sdes	{ "acceptenv", sAcceptEnv, SSHCFG_ALL },
506215116Sdes	{ "permittunnel", sPermitTunnel, SSHCFG_ALL },
507262566Sdes	{ "permittty", sPermitTTY, SSHCFG_ALL },
508197679Sdes	{ "match", sMatch, SSHCFG_ALL },
509162856Sdes	{ "permitopen", sPermitOpen, SSHCFG_ALL },
510162856Sdes	{ "forcecommand", sForceCommand, SSHCFG_ALL },
511181111Sdes	{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
512204917Sdes	{ "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
513204917Sdes	{ "revokedkeys", sRevokedKeys, SSHCFG_ALL },
514204917Sdes	{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
515215116Sdes	{ "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
516221420Sdes	{ "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
517221420Sdes	{ "ipqos", sIPQoS, SSHCFG_ALL },
518248619Sdes	{ "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
519248619Sdes	{ "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
520240075Sdes	{ "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL },
521248619Sdes	{ "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL },
522224638Sbrooks	{ "hpndisabled", sHPNDisabled, SSHCFG_ALL },
523224638Sbrooks	{ "hpnbuffersize", sHPNBufferSize, SSHCFG_ALL },
524224638Sbrooks	{ "tcprcvbufpoll", sTcpRcvBufPoll, SSHCFG_ALL },
525224638Sbrooks#ifdef NONE_CIPHER_ENABLED
526224638Sbrooks	{ "noneenabled", sNoneEnabled, SSHCFG_ALL },
527224638Sbrooks#endif
528162856Sdes	{ NULL, sBadOption, 0 }
52957429Smarkm};
53057429Smarkm
531181111Sdesstatic struct {
532181111Sdes	int val;
533181111Sdes	char *text;
534181111Sdes} tunmode_desc[] = {
535181111Sdes	{ SSH_TUNMODE_NO, "no" },
536181111Sdes	{ SSH_TUNMODE_POINTOPOINT, "point-to-point" },
537181111Sdes	{ SSH_TUNMODE_ETHERNET, "ethernet" },
538181111Sdes	{ SSH_TUNMODE_YES, "yes" },
539181111Sdes	{ -1, NULL }
540181111Sdes};
541181111Sdes
54257429Smarkm/*
54376262Sgreen * Returns the number of the token pointed to by cp or sBadOption.
54457429Smarkm */
54557429Smarkm
54660576Skrisstatic ServerOpCodes
54757429Smarkmparse_token(const char *cp, const char *filename,
548162856Sdes	    int linenum, u_int *flags)
54957429Smarkm{
55076262Sgreen	u_int i;
55157429Smarkm
55257429Smarkm	for (i = 0; keywords[i].name; i++)
553162856Sdes		if (strcasecmp(cp, keywords[i].name) == 0) {
554162856Sdes			*flags = keywords[i].flags;
55557429Smarkm			return keywords[i].opcode;
556162856Sdes		}
55757429Smarkm
55876262Sgreen	error("%s: line %d: Bad configuration option: %s",
55976262Sgreen	    filename, linenum, cp);
56057429Smarkm	return sBadOption;
56157429Smarkm}
56257429Smarkm
563204917Sdeschar *
564204917Sdesderelativise_path(const char *path)
565204917Sdes{
566207319Sdes	char *expanded, *ret, cwd[MAXPATHLEN];
567204917Sdes
568204917Sdes	expanded = tilde_expand_filename(path, getuid());
569204917Sdes	if (*expanded == '/')
570204917Sdes		return expanded;
571207319Sdes	if (getcwd(cwd, sizeof(cwd)) == NULL)
572204917Sdes		fatal("%s: getcwd: %s", __func__, strerror(errno));
573204917Sdes	xasprintf(&ret, "%s/%s", cwd, expanded);
574255767Sdes	free(expanded);
575204917Sdes	return ret;
576204917Sdes}
577204917Sdes
57892559Sdesstatic void
579192595Sdesadd_listen_addr(ServerOptions *options, char *addr, int port)
58057429Smarkm{
581149753Sdes	u_int i;
58257429Smarkm
58357429Smarkm	if (options->num_ports == 0)
58457429Smarkm		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
585147005Sdes	if (options->address_family == -1)
586147005Sdes		options->address_family = AF_UNSPEC;
58776262Sgreen	if (port == 0)
58876262Sgreen		for (i = 0; i < options->num_ports; i++)
58976262Sgreen			add_one_listen_addr(options, addr, options->ports[i]);
59076262Sgreen	else
59176262Sgreen		add_one_listen_addr(options, addr, port);
59257429Smarkm}
59357429Smarkm
59492559Sdesstatic void
595192595Sdesadd_one_listen_addr(ServerOptions *options, char *addr, int port)
59676262Sgreen{
59776262Sgreen	struct addrinfo hints, *ai, *aitop;
59876262Sgreen	char strport[NI_MAXSERV];
59976262Sgreen	int gaierr;
60076262Sgreen
60176262Sgreen	memset(&hints, 0, sizeof(hints));
602147005Sdes	hints.ai_family = options->address_family;
60376262Sgreen	hints.ai_socktype = SOCK_STREAM;
60476262Sgreen	hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
605192595Sdes	snprintf(strport, sizeof strport, "%d", port);
60676262Sgreen	if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
60776262Sgreen		fatal("bad addr or host: %s (%s)",
60876262Sgreen		    addr ? addr : "<NULL>",
609181111Sdes		    ssh_gai_strerror(gaierr));
61076262Sgreen	for (ai = aitop; ai->ai_next; ai = ai->ai_next)
61176262Sgreen		;
61276262Sgreen	ai->ai_next = options->listen_addrs;
61376262Sgreen	options->listen_addrs = aitop;
61476262Sgreen}
61576262Sgreen
616240075Sdesstruct connection_info *
617240075Sdesget_connection_info(int populate, int use_dns)
618240075Sdes{
619240075Sdes	static struct connection_info ci;
620240075Sdes
621240075Sdes	if (!populate)
622240075Sdes		return &ci;
623240075Sdes	ci.host = get_canonical_hostname(use_dns);
624240075Sdes	ci.address = get_remote_ipaddr();
625240075Sdes	ci.laddress = get_local_ipaddr(packet_get_connection_in());
626240075Sdes	ci.lport = get_local_port();
627240075Sdes	return &ci;
628240075Sdes}
629240075Sdes
630162856Sdes/*
631162856Sdes * The strategy for the Match blocks is that the config file is parsed twice.
632162856Sdes *
633162856Sdes * The first time is at startup.  activep is initialized to 1 and the
634162856Sdes * directives in the global context are processed and acted on.  Hitting a
635162856Sdes * Match directive unsets activep and the directives inside the block are
636162856Sdes * checked for syntax only.
637162856Sdes *
638162856Sdes * The second time is after a connection has been established but before
639162856Sdes * authentication.  activep is initialized to 2 and global config directives
640162856Sdes * are ignored since they have already been processed.  If the criteria in a
641162856Sdes * Match block is met, activep is set and the subsequent directives
642162856Sdes * processed and actioned until EOF or another Match block unsets it.  Any
643162856Sdes * options set are copied into the main server config.
644162856Sdes *
645162856Sdes * Potential additions/improvements:
646162856Sdes *  - Add Match support for pre-kex directives, eg Protocol, Ciphers.
647162856Sdes *
648162856Sdes *  - Add a Tag directive (idea from David Leonard) ala pf, eg:
649162856Sdes *	Match Address 192.168.0.*
650162856Sdes *		Tag trusted
651162856Sdes *	Match Group wheel
652162856Sdes *		Tag trusted
653162856Sdes *	Match Tag trusted
654162856Sdes *		AllowTcpForwarding yes
655162856Sdes *		GatewayPorts clientspecified
656162856Sdes *		[...]
657162856Sdes *
658162856Sdes *  - Add a PermittedChannelRequests directive
659162856Sdes *	Match Group shell
660162856Sdes *		PermittedChannelRequests session,forwarded-tcpip
661162856Sdes */
662162856Sdes
663162856Sdesstatic int
664162856Sdesmatch_cfg_line_group(const char *grps, int line, const char *user)
665162856Sdes{
666162856Sdes	int result = 0;
667162856Sdes	struct passwd *pw;
668162856Sdes
669162856Sdes	if (user == NULL)
670162856Sdes		goto out;
671162856Sdes
672162856Sdes	if ((pw = getpwnam(user)) == NULL) {
673162856Sdes		debug("Can't match group at line %d because user %.100s does "
674162856Sdes		    "not exist", line, user);
675162856Sdes	} else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
676162856Sdes		debug("Can't Match group because user %.100s not in any group "
677162856Sdes		    "at line %d", user, line);
678181111Sdes	} else if (ga_match_pattern_list(grps) != 1) {
679181111Sdes		debug("user %.100s does not match group list %.100s at line %d",
680181111Sdes		    user, grps, line);
681162856Sdes	} else {
682181111Sdes		debug("user %.100s matched group list %.100s at line %d", user,
683181111Sdes		    grps, line);
684162856Sdes		result = 1;
685162856Sdes	}
686162856Sdesout:
687162856Sdes	ga_free();
688162856Sdes	return result;
689162856Sdes}
690162856Sdes
691240075Sdes/*
692248619Sdes * All of the attributes on a single Match line are ANDed together, so we need
693262566Sdes * to check every attribute and set the result to zero if any attribute does
694248619Sdes * not match.
695240075Sdes */
696162856Sdesstatic int
697240075Sdesmatch_cfg_line(char **condition, int line, struct connection_info *ci)
698162856Sdes{
699262566Sdes	int result = 1, attributes = 0, port;
700162856Sdes	char *arg, *attrib, *cp = *condition;
701162856Sdes	size_t len;
702162856Sdes
703240075Sdes	if (ci == NULL)
704162856Sdes		debug3("checking syntax for 'Match %s'", cp);
705162856Sdes	else
706240075Sdes		debug3("checking match for '%s' user %s host %s addr %s "
707240075Sdes		    "laddr %s lport %d", cp, ci->user ? ci->user : "(null)",
708240075Sdes		    ci->host ? ci->host : "(null)",
709240075Sdes		    ci->address ? ci->address : "(null)",
710240075Sdes		    ci->laddress ? ci->laddress : "(null)", ci->lport);
711162856Sdes
712162856Sdes	while ((attrib = strdelim(&cp)) && *attrib != '\0') {
713262566Sdes		attributes++;
714262566Sdes		if (strcasecmp(attrib, "all") == 0) {
715262566Sdes			if (attributes != 1 ||
716262566Sdes			    ((arg = strdelim(&cp)) != NULL && *arg != '\0')) {
717262566Sdes				error("'all' cannot be combined with other "
718262566Sdes				    "Match attributes");
719262566Sdes				return -1;
720262566Sdes			}
721262566Sdes			*condition = cp;
722262566Sdes			return 1;
723262566Sdes		}
724162856Sdes		if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
725162856Sdes			error("Missing Match criteria for %s", attrib);
726162856Sdes			return -1;
727162856Sdes		}
728162856Sdes		len = strlen(arg);
729162856Sdes		if (strcasecmp(attrib, "user") == 0) {
730240075Sdes			if (ci == NULL || ci->user == NULL) {
731162856Sdes				result = 0;
732162856Sdes				continue;
733162856Sdes			}
734240075Sdes			if (match_pattern_list(ci->user, arg, len, 0) != 1)
735162856Sdes				result = 0;
736162856Sdes			else
737162856Sdes				debug("user %.100s matched 'User %.100s' at "
738240075Sdes				    "line %d", ci->user, arg, line);
739162856Sdes		} else if (strcasecmp(attrib, "group") == 0) {
740240075Sdes			if (ci == NULL || ci->user == NULL) {
741240075Sdes				result = 0;
742240075Sdes				continue;
743240075Sdes			}
744240075Sdes			switch (match_cfg_line_group(arg, line, ci->user)) {
745162856Sdes			case -1:
746162856Sdes				return -1;
747162856Sdes			case 0:
748162856Sdes				result = 0;
749162856Sdes			}
750162856Sdes		} else if (strcasecmp(attrib, "host") == 0) {
751240075Sdes			if (ci == NULL || ci->host == NULL) {
752162856Sdes				result = 0;
753162856Sdes				continue;
754162856Sdes			}
755240075Sdes			if (match_hostname(ci->host, arg, len) != 1)
756162856Sdes				result = 0;
757162856Sdes			else
758162856Sdes				debug("connection from %.100s matched 'Host "
759240075Sdes				    "%.100s' at line %d", ci->host, arg, line);
760162856Sdes		} else if (strcasecmp(attrib, "address") == 0) {
761240075Sdes			if (ci == NULL || ci->address == NULL) {
762240075Sdes				result = 0;
763240075Sdes				continue;
764240075Sdes			}
765240075Sdes			switch (addr_match_list(ci->address, arg)) {
766181111Sdes			case 1:
767181111Sdes				debug("connection from %.100s matched 'Address "
768240075Sdes				    "%.100s' at line %d", ci->address, arg, line);
769181111Sdes				break;
770181111Sdes			case 0:
771181111Sdes			case -1:
772162856Sdes				result = 0;
773181111Sdes				break;
774181111Sdes			case -2:
775181111Sdes				return -1;
776162856Sdes			}
777240075Sdes		} else if (strcasecmp(attrib, "localaddress") == 0){
778240075Sdes			if (ci == NULL || ci->laddress == NULL) {
779240075Sdes				result = 0;
780240075Sdes				continue;
781240075Sdes			}
782240075Sdes			switch (addr_match_list(ci->laddress, arg)) {
783240075Sdes			case 1:
784240075Sdes				debug("connection from %.100s matched "
785240075Sdes				    "'LocalAddress %.100s' at line %d",
786240075Sdes				    ci->laddress, arg, line);
787240075Sdes				break;
788240075Sdes			case 0:
789240075Sdes			case -1:
790240075Sdes				result = 0;
791240075Sdes				break;
792240075Sdes			case -2:
793240075Sdes				return -1;
794240075Sdes			}
795240075Sdes		} else if (strcasecmp(attrib, "localport") == 0) {
796240075Sdes			if ((port = a2port(arg)) == -1) {
797240075Sdes				error("Invalid LocalPort '%s' on Match line",
798240075Sdes				    arg);
799240075Sdes				return -1;
800240075Sdes			}
801240075Sdes			if (ci == NULL || ci->lport == 0) {
802240075Sdes				result = 0;
803240075Sdes				continue;
804240075Sdes			}
805240075Sdes			/* TODO support port lists */
806240075Sdes			if (port == ci->lport)
807240075Sdes				debug("connection from %.100s matched "
808240075Sdes				    "'LocalPort %d' at line %d",
809240075Sdes				    ci->laddress, port, line);
810240075Sdes			else
811240075Sdes				result = 0;
812162856Sdes		} else {
813162856Sdes			error("Unsupported Match attribute %s", attrib);
814162856Sdes			return -1;
815162856Sdes		}
816162856Sdes	}
817262566Sdes	if (attributes == 0) {
818262566Sdes		error("One or more attributes required for Match");
819262566Sdes		return -1;
820262566Sdes	}
821240075Sdes	if (ci != NULL)
822162856Sdes		debug3("match %sfound", result ? "" : "not ");
823162856Sdes	*condition = cp;
824162856Sdes	return result;
825162856Sdes}
826162856Sdes
827162856Sdes#define WHITESPACE " \t\r\n"
828162856Sdes
829226046Sdes/* Multistate option parsing */
830226046Sdesstruct multistate {
831226046Sdes	char *key;
832226046Sdes	int value;
833226046Sdes};
834226046Sdesstatic const struct multistate multistate_addressfamily[] = {
835226046Sdes	{ "inet",			AF_INET },
836226046Sdes	{ "inet6",			AF_INET6 },
837226046Sdes	{ "any",			AF_UNSPEC },
838226046Sdes	{ NULL, -1 }
839226046Sdes};
840226046Sdesstatic const struct multistate multistate_permitrootlogin[] = {
841226046Sdes	{ "without-password",		PERMIT_NO_PASSWD },
842226046Sdes	{ "forced-commands-only",	PERMIT_FORCED_ONLY },
843226046Sdes	{ "yes",			PERMIT_YES },
844226046Sdes	{ "no",				PERMIT_NO },
845226046Sdes	{ NULL, -1 }
846226046Sdes};
847226046Sdesstatic const struct multistate multistate_compression[] = {
848226046Sdes	{ "delayed",			COMP_DELAYED },
849226046Sdes	{ "yes",			COMP_ZLIB },
850226046Sdes	{ "no",				COMP_NONE },
851226046Sdes	{ NULL, -1 }
852226046Sdes};
853226046Sdesstatic const struct multistate multistate_gatewayports[] = {
854226046Sdes	{ "clientspecified",		2 },
855226046Sdes	{ "yes",			1 },
856226046Sdes	{ "no",				0 },
857226046Sdes	{ NULL, -1 }
858226046Sdes};
859226046Sdesstatic const struct multistate multistate_privsep[] = {
860240075Sdes	{ "yes",			PRIVSEP_NOSANDBOX },
861240075Sdes	{ "sandbox",			PRIVSEP_ON },
862240075Sdes	{ "nosandbox",			PRIVSEP_NOSANDBOX },
863226046Sdes	{ "no",				PRIVSEP_OFF },
864226046Sdes	{ NULL, -1 }
865226046Sdes};
866248619Sdesstatic const struct multistate multistate_tcpfwd[] = {
867248619Sdes	{ "yes",			FORWARD_ALLOW },
868248619Sdes	{ "all",			FORWARD_ALLOW },
869248619Sdes	{ "no",				FORWARD_DENY },
870248619Sdes	{ "remote",			FORWARD_REMOTE },
871248619Sdes	{ "local",			FORWARD_LOCAL },
872248619Sdes	{ NULL, -1 }
873248619Sdes};
874226046Sdes
87592559Sdesint
87692559Sdesprocess_server_config_line(ServerOptions *options, char *line,
877240075Sdes    const char *filename, int linenum, int *activep,
878240075Sdes    struct connection_info *connectinfo)
87957429Smarkm{
88076262Sgreen	char *cp, **charptr, *arg, *p;
881255767Sdes	int cmdline = 0, *intptr, value, value2, n, port;
882181111Sdes	SyslogFacility *log_facility_ptr;
883181111Sdes	LogLevel *log_level_ptr;
88457429Smarkm	ServerOpCodes opcode;
885162856Sdes	u_int i, flags = 0;
886162856Sdes	size_t len;
887255767Sdes	long long val64;
888226046Sdes	const struct multistate *multistate_ptr;
88957429Smarkm
89092559Sdes	cp = line;
891162856Sdes	if ((arg = strdelim(&cp)) == NULL)
892162856Sdes		return 0;
89392559Sdes	/* Ignore leading whitespace */
89492559Sdes	if (*arg == '\0')
89565674Skris		arg = strdelim(&cp);
89692559Sdes	if (!arg || !*arg || *arg == '#')
89792559Sdes		return 0;
89892559Sdes	intptr = NULL;
89992559Sdes	charptr = NULL;
900162856Sdes	opcode = parse_token(arg, filename, linenum, &flags);
901162856Sdes
902162856Sdes	if (activep == NULL) { /* We are processing a command line directive */
903162856Sdes		cmdline = 1;
904162856Sdes		activep = &cmdline;
905162856Sdes	}
906162856Sdes	if (*activep && opcode != sMatch)
907162856Sdes		debug3("%s:%d setting %s %s", filename, linenum, arg, cp);
908162856Sdes	if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
909240075Sdes		if (connectinfo == NULL) {
910162856Sdes			fatal("%s line %d: Directive '%s' is not allowed "
911162856Sdes			    "within a Match block", filename, linenum, arg);
912162856Sdes		} else { /* this is a directive we have already processed */
913162856Sdes			while (arg)
914162856Sdes				arg = strdelim(&cp);
915162856Sdes			return 0;
916162856Sdes		}
917162856Sdes	}
918162856Sdes
91992559Sdes	switch (opcode) {
92098941Sdes	/* Portable-specific options */
921124211Sdes	case sUsePAM:
922124211Sdes		intptr = &options->use_pam;
92398941Sdes		goto parse_flag;
92498941Sdes
92598941Sdes	/* Standard Options */
92692559Sdes	case sBadOption:
92792559Sdes		return -1;
92892559Sdes	case sPort:
92992559Sdes		/* ignore ports from configfile if cmdline specifies ports */
93092559Sdes		if (options->ports_from_cmdline)
93192559Sdes			return 0;
93292559Sdes		if (options->listen_addrs != NULL)
93392559Sdes			fatal("%s line %d: ports must be specified before "
93492559Sdes			    "ListenAddress.", filename, linenum);
93592559Sdes		if (options->num_ports >= MAX_PORTS)
93692559Sdes			fatal("%s line %d: too many ports.",
93792559Sdes			    filename, linenum);
93892559Sdes		arg = strdelim(&cp);
93992559Sdes		if (!arg || *arg == '\0')
94092559Sdes			fatal("%s line %d: missing port number.",
94192559Sdes			    filename, linenum);
94292559Sdes		options->ports[options->num_ports++] = a2port(arg);
943192595Sdes		if (options->ports[options->num_ports-1] <= 0)
94492559Sdes			fatal("%s line %d: Badly formatted port number.",
94592559Sdes			    filename, linenum);
94692559Sdes		break;
94757429Smarkm
94892559Sdes	case sServerKeyBits:
94992559Sdes		intptr = &options->server_key_bits;
950181111Sdes parse_int:
95192559Sdes		arg = strdelim(&cp);
95292559Sdes		if (!arg || *arg == '\0')
95392559Sdes			fatal("%s line %d: missing integer value.",
95492559Sdes			    filename, linenum);
95592559Sdes		value = atoi(arg);
956162856Sdes		if (*activep && *intptr == -1)
95792559Sdes			*intptr = value;
95892559Sdes		break;
95957429Smarkm
96092559Sdes	case sLoginGraceTime:
96192559Sdes		intptr = &options->login_grace_time;
962181111Sdes parse_time:
96392559Sdes		arg = strdelim(&cp);
96492559Sdes		if (!arg || *arg == '\0')
96592559Sdes			fatal("%s line %d: missing time value.",
96692559Sdes			    filename, linenum);
96792559Sdes		if ((value = convtime(arg)) == -1)
96892559Sdes			fatal("%s line %d: invalid time value.",
96992559Sdes			    filename, linenum);
97092559Sdes		if (*intptr == -1)
97192559Sdes			*intptr = value;
97292559Sdes		break;
97357429Smarkm
97492559Sdes	case sKeyRegenerationTime:
97592559Sdes		intptr = &options->key_regeneration_time;
97692559Sdes		goto parse_time;
97757429Smarkm
97892559Sdes	case sListenAddress:
97992559Sdes		arg = strdelim(&cp);
980147005Sdes		if (arg == NULL || *arg == '\0')
981147005Sdes			fatal("%s line %d: missing address",
98292559Sdes			    filename, linenum);
983149753Sdes		/* check for bare IPv6 address: no "[]" and 2 or more ":" */
984149753Sdes		if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL
985149753Sdes		    && strchr(p+1, ':') != NULL) {
986149753Sdes			add_listen_addr(options, arg, 0);
987149753Sdes			break;
988149753Sdes		}
989147005Sdes		p = hpdelim(&arg);
990147005Sdes		if (p == NULL)
991147005Sdes			fatal("%s line %d: bad address:port usage",
992147005Sdes			    filename, linenum);
993147005Sdes		p = cleanhostname(p);
994147005Sdes		if (arg == NULL)
995147005Sdes			port = 0;
996192595Sdes		else if ((port = a2port(arg)) <= 0)
997147005Sdes			fatal("%s line %d: bad port number", filename, linenum);
99857429Smarkm
999147005Sdes		add_listen_addr(options, p, port);
1000147005Sdes
1001147005Sdes		break;
1002147005Sdes
1003147005Sdes	case sAddressFamily:
1004226046Sdes		intptr = &options->address_family;
1005226046Sdes		multistate_ptr = multistate_addressfamily;
1006226046Sdes		if (options->listen_addrs != NULL)
1007226046Sdes			fatal("%s line %d: address family must be specified "
1008226046Sdes			    "before ListenAddress.", filename, linenum);
1009226046Sdes parse_multistate:
1010147005Sdes		arg = strdelim(&cp);
1011149753Sdes		if (!arg || *arg == '\0')
1012226046Sdes			fatal("%s line %d: missing argument.",
1013149753Sdes			    filename, linenum);
1014226046Sdes		value = -1;
1015226046Sdes		for (i = 0; multistate_ptr[i].key != NULL; i++) {
1016226046Sdes			if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
1017226046Sdes				value = multistate_ptr[i].value;
1018226046Sdes				break;
1019226046Sdes			}
1020226046Sdes		}
1021226046Sdes		if (value == -1)
1022226046Sdes			fatal("%s line %d: unsupported option \"%s\".",
1023147005Sdes			    filename, linenum, arg);
1024226046Sdes		if (*activep && *intptr == -1)
1025147005Sdes			*intptr = value;
102692559Sdes		break;
102757429Smarkm
102892559Sdes	case sHostKeyFile:
102992559Sdes		intptr = &options->num_host_key_files;
103092559Sdes		if (*intptr >= MAX_HOSTKEYS)
103192559Sdes			fatal("%s line %d: too many host keys specified (max %d).",
103292559Sdes			    filename, linenum, MAX_HOSTKEYS);
103392559Sdes		charptr = &options->host_key_files[*intptr];
1034181111Sdes parse_filename:
103592559Sdes		arg = strdelim(&cp);
103692559Sdes		if (!arg || *arg == '\0')
103792559Sdes			fatal("%s line %d: missing file name.",
103892559Sdes			    filename, linenum);
1039162856Sdes		if (*activep && *charptr == NULL) {
1040204917Sdes			*charptr = derelativise_path(arg);
104192559Sdes			/* increase optional counter */
104292559Sdes			if (intptr != NULL)
104392559Sdes				*intptr = *intptr + 1;
104492559Sdes		}
104592559Sdes		break;
104660576Skris
1047255767Sdes	case sHostKeyAgent:
1048255767Sdes		charptr = &options->host_key_agent;
1049255767Sdes		arg = strdelim(&cp);
1050255767Sdes		if (!arg || *arg == '\0')
1051255767Sdes			fatal("%s line %d: missing socket name.",
1052255767Sdes			    filename, linenum);
1053255767Sdes		if (*activep && *charptr == NULL)
1054255767Sdes			*charptr = !strcmp(arg, SSH_AUTHSOCKET_ENV_NAME) ?
1055255767Sdes			    xstrdup(arg) : derelativise_path(arg);
1056255767Sdes		break;
1057255767Sdes
1058204917Sdes	case sHostCertificate:
1059204917Sdes		intptr = &options->num_host_cert_files;
1060204917Sdes		if (*intptr >= MAX_HOSTKEYS)
1061204917Sdes			fatal("%s line %d: too many host certificates "
1062204917Sdes			    "specified (max %d).", filename, linenum,
1063204917Sdes			    MAX_HOSTCERTS);
1064204917Sdes		charptr = &options->host_cert_files[*intptr];
1065204917Sdes		goto parse_filename;
1066204917Sdes		break;
1067204917Sdes
106892559Sdes	case sPidFile:
106992559Sdes		charptr = &options->pid_file;
107092559Sdes		goto parse_filename;
107157429Smarkm
107292559Sdes	case sPermitRootLogin:
107392559Sdes		intptr = &options->permit_root_login;
1074226046Sdes		multistate_ptr = multistate_permitrootlogin;
1075226046Sdes		goto parse_multistate;
107692559Sdes
107792559Sdes	case sIgnoreRhosts:
107892559Sdes		intptr = &options->ignore_rhosts;
1079181111Sdes parse_flag:
108092559Sdes		arg = strdelim(&cp);
108192559Sdes		if (!arg || *arg == '\0')
108292559Sdes			fatal("%s line %d: missing yes/no argument.",
108392559Sdes			    filename, linenum);
108492559Sdes		value = 0;	/* silence compiler */
108592559Sdes		if (strcmp(arg, "yes") == 0)
108692559Sdes			value = 1;
108792559Sdes		else if (strcmp(arg, "no") == 0)
108892559Sdes			value = 0;
108992559Sdes		else
109092559Sdes			fatal("%s line %d: Bad yes/no argument: %s",
109192559Sdes				filename, linenum, arg);
1092162856Sdes		if (*activep && *intptr == -1)
109392559Sdes			*intptr = value;
109492559Sdes		break;
109557429Smarkm
109692559Sdes	case sIgnoreUserKnownHosts:
109792559Sdes		intptr = &options->ignore_user_known_hosts;
109892559Sdes		goto parse_flag;
109957429Smarkm
110092559Sdes	case sRhostsRSAAuthentication:
110192559Sdes		intptr = &options->rhosts_rsa_authentication;
110292559Sdes		goto parse_flag;
110357429Smarkm
110492559Sdes	case sHostbasedAuthentication:
110592559Sdes		intptr = &options->hostbased_authentication;
110692559Sdes		goto parse_flag;
110776262Sgreen
110892559Sdes	case sHostbasedUsesNameFromPacketOnly:
110992559Sdes		intptr = &options->hostbased_uses_name_from_packet_only;
111092559Sdes		goto parse_flag;
111176262Sgreen
111292559Sdes	case sRSAAuthentication:
111392559Sdes		intptr = &options->rsa_authentication;
111492559Sdes		goto parse_flag;
111557429Smarkm
111692559Sdes	case sPubkeyAuthentication:
111792559Sdes		intptr = &options->pubkey_authentication;
111892559Sdes		goto parse_flag;
1119124211Sdes
112092559Sdes	case sKerberosAuthentication:
112192559Sdes		intptr = &options->kerberos_authentication;
112292559Sdes		goto parse_flag;
112357429Smarkm
112492559Sdes	case sKerberosOrLocalPasswd:
112592559Sdes		intptr = &options->kerberos_or_local_passwd;
112692559Sdes		goto parse_flag;
112792559Sdes
112892559Sdes	case sKerberosTicketCleanup:
112992559Sdes		intptr = &options->kerberos_ticket_cleanup;
113092559Sdes		goto parse_flag;
1131124211Sdes
1132126277Sdes	case sKerberosGetAFSToken:
1133126277Sdes		intptr = &options->kerberos_get_afs_token;
1134126277Sdes		goto parse_flag;
1135126277Sdes
1136124211Sdes	case sGssAuthentication:
1137124211Sdes		intptr = &options->gss_authentication;
113892559Sdes		goto parse_flag;
1139124211Sdes
1140124211Sdes	case sGssCleanupCreds:
1141124211Sdes		intptr = &options->gss_cleanup_creds;
114292559Sdes		goto parse_flag;
114357429Smarkm
114492559Sdes	case sPasswordAuthentication:
114592559Sdes		intptr = &options->password_authentication;
114692559Sdes		goto parse_flag;
114757565Smarkm
114892559Sdes	case sKbdInteractiveAuthentication:
114992559Sdes		intptr = &options->kbd_interactive_authentication;
115092559Sdes		goto parse_flag;
115157429Smarkm
115292559Sdes	case sChallengeResponseAuthentication:
115392559Sdes		intptr = &options->challenge_response_authentication;
115492559Sdes		goto parse_flag;
115557429Smarkm
115692559Sdes	case sPrintMotd:
115792559Sdes		intptr = &options->print_motd;
115892559Sdes		goto parse_flag;
115957429Smarkm
116092559Sdes	case sPrintLastLog:
116192559Sdes		intptr = &options->print_lastlog;
116292559Sdes		goto parse_flag;
116369591Sgreen
116492559Sdes	case sX11Forwarding:
116592559Sdes		intptr = &options->x11_forwarding;
116692559Sdes		goto parse_flag;
116757429Smarkm
116892559Sdes	case sX11DisplayOffset:
116992559Sdes		intptr = &options->x11_display_offset;
117092559Sdes		goto parse_int;
117157429Smarkm
117292559Sdes	case sX11UseLocalhost:
117392559Sdes		intptr = &options->x11_use_localhost;
117492559Sdes		goto parse_flag;
117557429Smarkm
117692559Sdes	case sXAuthLocation:
117792559Sdes		charptr = &options->xauth_location;
117892559Sdes		goto parse_filename;
117976262Sgreen
1180262566Sdes	case sPermitTTY:
1181262566Sdes		intptr = &options->permit_tty;
1182262566Sdes		goto parse_flag;
1183262566Sdes
118492559Sdes	case sStrictModes:
118592559Sdes		intptr = &options->strict_modes;
118692559Sdes		goto parse_flag;
118757429Smarkm
1188126277Sdes	case sTCPKeepAlive:
1189126277Sdes		intptr = &options->tcp_keep_alive;
119092559Sdes		goto parse_flag;
119157429Smarkm
119292559Sdes	case sEmptyPasswd:
119392559Sdes		intptr = &options->permit_empty_passwd;
119492559Sdes		goto parse_flag;
119576262Sgreen
1196106130Sdes	case sPermitUserEnvironment:
1197106130Sdes		intptr = &options->permit_user_env;
1198106130Sdes		goto parse_flag;
1199106130Sdes
120092559Sdes	case sUseLogin:
120192559Sdes		intptr = &options->use_login;
120292559Sdes		goto parse_flag;
120357429Smarkm
120498684Sdes	case sCompression:
120598684Sdes		intptr = &options->compression;
1206226046Sdes		multistate_ptr = multistate_compression;
1207226046Sdes		goto parse_multistate;
120898684Sdes
1209255767Sdes	case sRekeyLimit:
1210255767Sdes		arg = strdelim(&cp);
1211255767Sdes		if (!arg || *arg == '\0')
1212255767Sdes			fatal("%.200s line %d: Missing argument.", filename,
1213255767Sdes			    linenum);
1214255767Sdes		if (strcmp(arg, "default") == 0) {
1215255767Sdes			val64 = 0;
1216255767Sdes		} else {
1217255767Sdes			if (scan_scaled(arg, &val64) == -1)
1218255767Sdes				fatal("%.200s line %d: Bad number '%s': %s",
1219255767Sdes				    filename, linenum, arg, strerror(errno));
1220255767Sdes			/* check for too-large or too-small limits */
1221255767Sdes			if (val64 > UINT_MAX)
1222255767Sdes				fatal("%.200s line %d: RekeyLimit too large",
1223255767Sdes				    filename, linenum);
1224255767Sdes			if (val64 != 0 && val64 < 16)
1225255767Sdes				fatal("%.200s line %d: RekeyLimit too small",
1226255767Sdes				    filename, linenum);
1227255767Sdes		}
1228255767Sdes		if (*activep && options->rekey_limit == -1)
1229255767Sdes			options->rekey_limit = (u_int32_t)val64;
1230255767Sdes		if (cp != NULL) { /* optional rekey interval present */
1231255767Sdes			if (strcmp(cp, "none") == 0) {
1232255767Sdes				(void)strdelim(&cp);	/* discard */
1233255767Sdes				break;
1234255767Sdes			}
1235255767Sdes			intptr = &options->rekey_interval;
1236255767Sdes			goto parse_time;
1237255767Sdes		}
1238255767Sdes		break;
1239255767Sdes
124092559Sdes	case sGatewayPorts:
124192559Sdes		intptr = &options->gateway_ports;
1242226046Sdes		multistate_ptr = multistate_gatewayports;
1243226046Sdes		goto parse_multistate;
124457429Smarkm
1245124211Sdes	case sUseDNS:
1246124211Sdes		intptr = &options->use_dns;
124792559Sdes		goto parse_flag;
124857429Smarkm
124992559Sdes	case sLogFacility:
1250181111Sdes		log_facility_ptr = &options->log_facility;
125192559Sdes		arg = strdelim(&cp);
125292559Sdes		value = log_facility_number(arg);
125392559Sdes		if (value == SYSLOG_FACILITY_NOT_SET)
125492559Sdes			fatal("%.200s line %d: unsupported log facility '%s'",
125592559Sdes			    filename, linenum, arg ? arg : "<NONE>");
1256181111Sdes		if (*log_facility_ptr == -1)
1257181111Sdes			*log_facility_ptr = (SyslogFacility) value;
125892559Sdes		break;
125957429Smarkm
126092559Sdes	case sLogLevel:
1261181111Sdes		log_level_ptr = &options->log_level;
126292559Sdes		arg = strdelim(&cp);
126392559Sdes		value = log_level_number(arg);
126492559Sdes		if (value == SYSLOG_LEVEL_NOT_SET)
126592559Sdes			fatal("%.200s line %d: unsupported log level '%s'",
126692559Sdes			    filename, linenum, arg ? arg : "<NONE>");
1267181111Sdes		if (*log_level_ptr == -1)
1268181111Sdes			*log_level_ptr = (LogLevel) value;
126992559Sdes		break;
127060576Skris
127192559Sdes	case sAllowTcpForwarding:
127292559Sdes		intptr = &options->allow_tcp_forwarding;
1273248619Sdes		multistate_ptr = multistate_tcpfwd;
1274248619Sdes		goto parse_multistate;
127576262Sgreen
1276181111Sdes	case sAllowAgentForwarding:
1277181111Sdes		intptr = &options->allow_agent_forwarding;
1278181111Sdes		goto parse_flag;
1279181111Sdes
128098684Sdes	case sUsePrivilegeSeparation:
128198684Sdes		intptr = &use_privsep;
1282226046Sdes		multistate_ptr = multistate_privsep;
1283226046Sdes		goto parse_multistate;
128498684Sdes
128592559Sdes	case sAllowUsers:
128692559Sdes		while ((arg = strdelim(&cp)) && *arg != '\0') {
128792559Sdes			if (options->num_allow_users >= MAX_ALLOW_USERS)
128892559Sdes				fatal("%s line %d: too many allow users.",
128992559Sdes				    filename, linenum);
1290240075Sdes			if (!*activep)
1291240075Sdes				continue;
129299063Sdes			options->allow_users[options->num_allow_users++] =
129399063Sdes			    xstrdup(arg);
129492559Sdes		}
129592559Sdes		break;
129657429Smarkm
129792559Sdes	case sDenyUsers:
129892559Sdes		while ((arg = strdelim(&cp)) && *arg != '\0') {
129992559Sdes			if (options->num_deny_users >= MAX_DENY_USERS)
1300162856Sdes				fatal("%s line %d: too many deny users.",
130192559Sdes				    filename, linenum);
1302240075Sdes			if (!*activep)
1303240075Sdes				continue;
130499063Sdes			options->deny_users[options->num_deny_users++] =
130599063Sdes			    xstrdup(arg);
130692559Sdes		}
130792559Sdes		break;
130857429Smarkm
130992559Sdes	case sAllowGroups:
131092559Sdes		while ((arg = strdelim(&cp)) && *arg != '\0') {
131192559Sdes			if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
131292559Sdes				fatal("%s line %d: too many allow groups.",
131392559Sdes				    filename, linenum);
1314240075Sdes			if (!*activep)
1315240075Sdes				continue;
131699063Sdes			options->allow_groups[options->num_allow_groups++] =
131799063Sdes			    xstrdup(arg);
131892559Sdes		}
131992559Sdes		break;
132069591Sgreen
132192559Sdes	case sDenyGroups:
132292559Sdes		while ((arg = strdelim(&cp)) && *arg != '\0') {
132392559Sdes			if (options->num_deny_groups >= MAX_DENY_GROUPS)
132492559Sdes				fatal("%s line %d: too many deny groups.",
132592559Sdes				    filename, linenum);
1326240075Sdes			if (!*activep)
1327240075Sdes				continue;
1328240075Sdes			options->deny_groups[options->num_deny_groups++] =
1329240075Sdes			    xstrdup(arg);
133092559Sdes		}
133192559Sdes		break;
133257429Smarkm
133392559Sdes	case sCiphers:
133492559Sdes		arg = strdelim(&cp);
133592559Sdes		if (!arg || *arg == '\0')
133692559Sdes			fatal("%s line %d: Missing argument.", filename, linenum);
133792559Sdes		if (!ciphers_valid(arg))
133892559Sdes			fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
133992559Sdes			    filename, linenum, arg ? arg : "<NONE>");
134092559Sdes		if (options->ciphers == NULL)
134192559Sdes			options->ciphers = xstrdup(arg);
134292559Sdes		break;
134357429Smarkm
134492559Sdes	case sMacs:
134592559Sdes		arg = strdelim(&cp);
134692559Sdes		if (!arg || *arg == '\0')
134792559Sdes			fatal("%s line %d: Missing argument.", filename, linenum);
134892559Sdes		if (!mac_valid(arg))
134992559Sdes			fatal("%s line %d: Bad SSH2 mac spec '%s'.",
135092559Sdes			    filename, linenum, arg ? arg : "<NONE>");
135192559Sdes		if (options->macs == NULL)
135292559Sdes			options->macs = xstrdup(arg);
135392559Sdes		break;
135457429Smarkm
1355221420Sdes	case sKexAlgorithms:
1356221420Sdes		arg = strdelim(&cp);
1357221420Sdes		if (!arg || *arg == '\0')
1358221420Sdes			fatal("%s line %d: Missing argument.",
1359221420Sdes			    filename, linenum);
1360221420Sdes		if (!kex_names_valid(arg))
1361221420Sdes			fatal("%s line %d: Bad SSH2 KexAlgorithms '%s'.",
1362221420Sdes			    filename, linenum, arg ? arg : "<NONE>");
1363221420Sdes		if (options->kex_algorithms == NULL)
1364221420Sdes			options->kex_algorithms = xstrdup(arg);
1365221420Sdes		break;
1366221420Sdes
136792559Sdes	case sProtocol:
136892559Sdes		intptr = &options->protocol;
136992559Sdes		arg = strdelim(&cp);
137092559Sdes		if (!arg || *arg == '\0')
137192559Sdes			fatal("%s line %d: Missing argument.", filename, linenum);
137292559Sdes		value = proto_spec(arg);
137392559Sdes		if (value == SSH_PROTO_UNKNOWN)
137492559Sdes			fatal("%s line %d: Bad protocol spec '%s'.",
137592559Sdes			    filename, linenum, arg ? arg : "<NONE>");
137692559Sdes		if (*intptr == SSH_PROTO_UNKNOWN)
137792559Sdes			*intptr = value;
137892559Sdes		break;
137957429Smarkm
138092559Sdes	case sSubsystem:
138192559Sdes		if (options->num_subsystems >= MAX_SUBSYSTEMS) {
138292559Sdes			fatal("%s line %d: too many subsystems defined.",
138392559Sdes			    filename, linenum);
138492559Sdes		}
138592559Sdes		arg = strdelim(&cp);
138692559Sdes		if (!arg || *arg == '\0')
138792559Sdes			fatal("%s line %d: Missing subsystem name.",
138892559Sdes			    filename, linenum);
1389162856Sdes		if (!*activep) {
1390162856Sdes			arg = strdelim(&cp);
1391162856Sdes			break;
1392162856Sdes		}
139392559Sdes		for (i = 0; i < options->num_subsystems; i++)
139492559Sdes			if (strcmp(arg, options->subsystem_name[i]) == 0)
139592559Sdes				fatal("%s line %d: Subsystem '%s' already defined.",
139692559Sdes				    filename, linenum, arg);
139792559Sdes		options->subsystem_name[options->num_subsystems] = xstrdup(arg);
139892559Sdes		arg = strdelim(&cp);
139992559Sdes		if (!arg || *arg == '\0')
140092559Sdes			fatal("%s line %d: Missing subsystem command.",
140192559Sdes			    filename, linenum);
140292559Sdes		options->subsystem_command[options->num_subsystems] = xstrdup(arg);
1403162856Sdes
1404162856Sdes		/* Collect arguments (separate to executable) */
1405162856Sdes		p = xstrdup(arg);
1406162856Sdes		len = strlen(p) + 1;
1407162856Sdes		while ((arg = strdelim(&cp)) != NULL && *arg != '\0') {
1408162856Sdes			len += 1 + strlen(arg);
1409162856Sdes			p = xrealloc(p, 1, len);
1410162856Sdes			strlcat(p, " ", len);
1411162856Sdes			strlcat(p, arg, len);
1412162856Sdes		}
1413162856Sdes		options->subsystem_args[options->num_subsystems] = p;
141492559Sdes		options->num_subsystems++;
141592559Sdes		break;
141660576Skris
141792559Sdes	case sMaxStartups:
141892559Sdes		arg = strdelim(&cp);
141992559Sdes		if (!arg || *arg == '\0')
142092559Sdes			fatal("%s line %d: Missing MaxStartups spec.",
142192559Sdes			    filename, linenum);
142292559Sdes		if ((n = sscanf(arg, "%d:%d:%d",
142392559Sdes		    &options->max_startups_begin,
142492559Sdes		    &options->max_startups_rate,
142592559Sdes		    &options->max_startups)) == 3) {
142692559Sdes			if (options->max_startups_begin >
142792559Sdes			    options->max_startups ||
142892559Sdes			    options->max_startups_rate > 100 ||
142992559Sdes			    options->max_startups_rate < 1)
143092559Sdes				fatal("%s line %d: Illegal MaxStartups spec.",
143192559Sdes				    filename, linenum);
143292559Sdes		} else if (n != 1)
143392559Sdes			fatal("%s line %d: Illegal MaxStartups spec.",
143492559Sdes			    filename, linenum);
143592559Sdes		else
143692559Sdes			options->max_startups = options->max_startups_begin;
143792559Sdes		break;
143876262Sgreen
1439137019Sdes	case sMaxAuthTries:
1440137019Sdes		intptr = &options->max_authtries;
1441137019Sdes		goto parse_int;
1442137019Sdes
1443181111Sdes	case sMaxSessions:
1444181111Sdes		intptr = &options->max_sessions;
1445181111Sdes		goto parse_int;
1446181111Sdes
144792559Sdes	case sBanner:
144892559Sdes		charptr = &options->banner;
144992559Sdes		goto parse_filename;
1450181111Sdes
145192559Sdes	/*
145292559Sdes	 * These options can contain %X options expanded at
145392559Sdes	 * connect time, so that you can specify paths like:
145492559Sdes	 *
145592559Sdes	 * AuthorizedKeysFile	/etc/ssh_keys/%u
145692559Sdes	 */
145792559Sdes	case sAuthorizedKeysFile:
1458226046Sdes		if (*activep && options->num_authkeys_files == 0) {
1459226046Sdes			while ((arg = strdelim(&cp)) && *arg != '\0') {
1460226046Sdes				if (options->num_authkeys_files >=
1461226046Sdes				    MAX_AUTHKEYS_FILES)
1462226046Sdes					fatal("%s line %d: "
1463226046Sdes					    "too many authorized keys files.",
1464226046Sdes					    filename, linenum);
1465226046Sdes				options->authorized_keys_files[
1466226046Sdes				    options->num_authkeys_files++] =
1467226046Sdes				    tilde_expand_filename(arg, getuid());
1468226046Sdes			}
1469226046Sdes		}
1470226046Sdes		return 0;
1471226046Sdes
1472215116Sdes	case sAuthorizedPrincipalsFile:
1473215116Sdes		charptr = &options->authorized_principals_file;
1474207319Sdes		arg = strdelim(&cp);
1475207319Sdes		if (!arg || *arg == '\0')
1476207319Sdes			fatal("%s line %d: missing file name.",
1477207319Sdes			    filename, linenum);
1478207319Sdes		if (*activep && *charptr == NULL) {
1479207319Sdes			*charptr = tilde_expand_filename(arg, getuid());
1480207319Sdes			/* increase optional counter */
1481207319Sdes			if (intptr != NULL)
1482207319Sdes				*intptr = *intptr + 1;
1483207319Sdes		}
1484207319Sdes		break;
148560576Skris
148692559Sdes	case sClientAliveInterval:
148792559Sdes		intptr = &options->client_alive_interval;
148892559Sdes		goto parse_time;
148957432Smarkm
149092559Sdes	case sClientAliveCountMax:
149192559Sdes		intptr = &options->client_alive_count_max;
149292559Sdes		goto parse_int;
149365674Skris
1494137019Sdes	case sAcceptEnv:
1495137019Sdes		while ((arg = strdelim(&cp)) && *arg != '\0') {
1496137019Sdes			if (strchr(arg, '=') != NULL)
1497137019Sdes				fatal("%s line %d: Invalid environment name.",
1498137019Sdes				    filename, linenum);
1499137019Sdes			if (options->num_accept_env >= MAX_ACCEPT_ENV)
1500137019Sdes				fatal("%s line %d: too many allow env.",
1501137019Sdes				    filename, linenum);
1502162856Sdes			if (!*activep)
1503240075Sdes				continue;
1504137019Sdes			options->accept_env[options->num_accept_env++] =
1505137019Sdes			    xstrdup(arg);
1506137019Sdes		}
1507137019Sdes		break;
1508137019Sdes
1509157019Sdes	case sPermitTunnel:
1510157019Sdes		intptr = &options->permit_tun;
1511157019Sdes		arg = strdelim(&cp);
1512157019Sdes		if (!arg || *arg == '\0')
1513157019Sdes			fatal("%s line %d: Missing yes/point-to-point/"
1514157019Sdes			    "ethernet/no argument.", filename, linenum);
1515181111Sdes		value = -1;
1516181111Sdes		for (i = 0; tunmode_desc[i].val != -1; i++)
1517181111Sdes			if (strcmp(tunmode_desc[i].text, arg) == 0) {
1518181111Sdes				value = tunmode_desc[i].val;
1519181111Sdes				break;
1520181111Sdes			}
1521181111Sdes		if (value == -1)
1522157019Sdes			fatal("%s line %d: Bad yes/point-to-point/ethernet/"
1523157019Sdes			    "no argument: %s", filename, linenum, arg);
1524157019Sdes		if (*intptr == -1)
1525157019Sdes			*intptr = value;
1526157019Sdes		break;
1527157019Sdes
1528162856Sdes	case sMatch:
1529162856Sdes		if (cmdline)
1530162856Sdes			fatal("Match directive not supported as a command-line "
1531162856Sdes			   "option");
1532240075Sdes		value = match_cfg_line(&cp, linenum, connectinfo);
1533162856Sdes		if (value < 0)
1534162856Sdes			fatal("%s line %d: Bad Match condition", filename,
1535162856Sdes			    linenum);
1536162856Sdes		*activep = value;
1537162856Sdes		break;
1538162856Sdes
1539162856Sdes	case sPermitOpen:
1540162856Sdes		arg = strdelim(&cp);
1541162856Sdes		if (!arg || *arg == '\0')
1542162856Sdes			fatal("%s line %d: missing PermitOpen specification",
1543162856Sdes			    filename, linenum);
1544181111Sdes		n = options->num_permitted_opens;	/* modified later */
1545162856Sdes		if (strcmp(arg, "any") == 0) {
1546181111Sdes			if (*activep && n == -1) {
1547162856Sdes				channel_clear_adm_permitted_opens();
1548162856Sdes				options->num_permitted_opens = 0;
1549162856Sdes			}
1550162856Sdes			break;
1551162856Sdes		}
1552240075Sdes		if (strcmp(arg, "none") == 0) {
1553240075Sdes			if (*activep && n == -1) {
1554240075Sdes				options->num_permitted_opens = 1;
1555240075Sdes				channel_disable_adm_local_opens();
1556240075Sdes			}
1557240075Sdes			break;
1558240075Sdes		}
1559181111Sdes		if (*activep && n == -1)
1560181111Sdes			channel_clear_adm_permitted_opens();
1561162856Sdes		for (; arg != NULL && *arg != '\0'; arg = strdelim(&cp)) {
1562162856Sdes			p = hpdelim(&arg);
1563162856Sdes			if (p == NULL)
1564162856Sdes				fatal("%s line %d: missing host in PermitOpen",
1565162856Sdes				    filename, linenum);
1566162856Sdes			p = cleanhostname(p);
1567240075Sdes			if (arg == NULL || ((port = permitopen_port(arg)) < 0))
1568162856Sdes				fatal("%s line %d: bad port number in "
1569162856Sdes				    "PermitOpen", filename, linenum);
1570181111Sdes			if (*activep && n == -1)
1571162856Sdes				options->num_permitted_opens =
1572162856Sdes				    channel_add_adm_permitted_opens(p, port);
1573162856Sdes		}
1574162856Sdes		break;
1575162856Sdes
1576162856Sdes	case sForceCommand:
1577162856Sdes		if (cp == NULL)
1578162856Sdes			fatal("%.200s line %d: Missing argument.", filename,
1579162856Sdes			    linenum);
1580162856Sdes		len = strspn(cp, WHITESPACE);
1581162856Sdes		if (*activep && options->adm_forced_command == NULL)
1582162856Sdes			options->adm_forced_command = xstrdup(cp + len);
1583162856Sdes		return 0;
1584162856Sdes
1585181111Sdes	case sChrootDirectory:
1586181111Sdes		charptr = &options->chroot_directory;
1587181111Sdes
1588181111Sdes		arg = strdelim(&cp);
1589181111Sdes		if (!arg || *arg == '\0')
1590181111Sdes			fatal("%s line %d: missing file name.",
1591181111Sdes			    filename, linenum);
1592181111Sdes		if (*activep && *charptr == NULL)
1593181111Sdes			*charptr = xstrdup(arg);
1594181111Sdes		break;
1595181111Sdes
1596204917Sdes	case sTrustedUserCAKeys:
1597204917Sdes		charptr = &options->trusted_user_ca_keys;
1598204917Sdes		goto parse_filename;
1599204917Sdes
1600204917Sdes	case sRevokedKeys:
1601204917Sdes		charptr = &options->revoked_keys_file;
1602204917Sdes		goto parse_filename;
1603204917Sdes
1604221420Sdes	case sIPQoS:
1605221420Sdes		arg = strdelim(&cp);
1606221420Sdes		if ((value = parse_ipqos(arg)) == -1)
1607221420Sdes			fatal("%s line %d: Bad IPQoS value: %s",
1608221420Sdes			    filename, linenum, arg);
1609221420Sdes		arg = strdelim(&cp);
1610221420Sdes		if (arg == NULL)
1611221420Sdes			value2 = value;
1612221420Sdes		else if ((value2 = parse_ipqos(arg)) == -1)
1613221420Sdes			fatal("%s line %d: Bad IPQoS value: %s",
1614221420Sdes			    filename, linenum, arg);
1615221420Sdes		if (*activep) {
1616221420Sdes			options->ip_qos_interactive = value;
1617221420Sdes			options->ip_qos_bulk = value2;
1618221420Sdes		}
1619221420Sdes		break;
1620221420Sdes
162199047Sdes	case sVersionAddendum:
1622240075Sdes		if (cp == NULL)
1623240075Sdes			fatal("%.200s line %d: Missing argument.", filename,
1624240075Sdes			    linenum);
1625240075Sdes		len = strspn(cp, WHITESPACE);
1626240075Sdes		if (*activep && options->version_addendum == NULL) {
1627240075Sdes			if (strcasecmp(cp + len, "none") == 0)
1628240075Sdes				options->version_addendum = xstrdup("");
1629240075Sdes			else if (strchr(cp + len, '\r') != NULL)
1630240075Sdes				fatal("%.200s line %d: Invalid argument",
1631240075Sdes				    filename, linenum);
1632240075Sdes			else
1633240075Sdes				options->version_addendum = xstrdup(cp + len);
1634240075Sdes		}
1635240075Sdes		return 0;
163699047Sdes
1637248619Sdes	case sAuthorizedKeysCommand:
1638248619Sdes		len = strspn(cp, WHITESPACE);
1639248619Sdes		if (*activep && options->authorized_keys_command == NULL) {
1640248619Sdes			if (cp[len] != '/' && strcasecmp(cp + len, "none") != 0)
1641248619Sdes				fatal("%.200s line %d: AuthorizedKeysCommand "
1642248619Sdes				    "must be an absolute path",
1643248619Sdes				    filename, linenum);
1644248619Sdes			options->authorized_keys_command = xstrdup(cp + len);
1645248619Sdes		}
1646248619Sdes		return 0;
1647248619Sdes
1648248619Sdes	case sAuthorizedKeysCommandUser:
1649248619Sdes		charptr = &options->authorized_keys_command_user;
1650248619Sdes
1651248619Sdes		arg = strdelim(&cp);
1652248619Sdes		if (*activep && *charptr == NULL)
1653248619Sdes			*charptr = xstrdup(arg);
1654248619Sdes		break;
1655248619Sdes
1656248619Sdes	case sAuthenticationMethods:
1657248619Sdes		if (*activep && options->num_auth_methods == 0) {
1658248619Sdes			while ((arg = strdelim(&cp)) && *arg != '\0') {
1659248619Sdes				if (options->num_auth_methods >=
1660248619Sdes				    MAX_AUTH_METHODS)
1661248619Sdes					fatal("%s line %d: "
1662248619Sdes					    "too many authentication methods.",
1663248619Sdes					    filename, linenum);
1664248619Sdes				if (auth2_methods_valid(arg, 0) != 0)
1665248619Sdes					fatal("%s line %d: invalid "
1666248619Sdes					    "authentication method list.",
1667248619Sdes					    filename, linenum);
1668248619Sdes				options->auth_methods[
1669248619Sdes				    options->num_auth_methods++] = xstrdup(arg);
1670248619Sdes			}
1671248619Sdes		}
1672248619Sdes		return 0;
1673248619Sdes
1674224638Sbrooks	case sHPNDisabled:
1675224638Sbrooks		intptr = &options->hpn_disabled;
1676224638Sbrooks		goto parse_flag;
1677224638Sbrooks
1678224638Sbrooks	case sHPNBufferSize:
1679224638Sbrooks		intptr = &options->hpn_buffer_size;
1680224638Sbrooks		goto parse_int;
1681224638Sbrooks
1682224638Sbrooks	case sTcpRcvBufPoll:
1683224638Sbrooks		intptr = &options->tcp_rcv_buf_poll;
1684224638Sbrooks		goto parse_flag;
1685224638Sbrooks
1686224638Sbrooks#ifdef	NONE_CIPHER_ENABLED
1687224638Sbrooks	case sNoneEnabled:
1688224638Sbrooks		intptr = &options->none_enabled;
1689224638Sbrooks		goto parse_flag;
1690224638Sbrooks#endif
1691224638Sbrooks
169292559Sdes	case sDeprecated:
1693124211Sdes		logit("%s line %d: Deprecated option %s",
169492559Sdes		    filename, linenum, arg);
169592559Sdes		while (arg)
169692559Sdes		    arg = strdelim(&cp);
169792559Sdes		break;
169892559Sdes
1699124211Sdes	case sUnsupported:
1700124211Sdes		logit("%s line %d: Unsupported option %s",
1701124211Sdes		    filename, linenum, arg);
1702124211Sdes		while (arg)
1703124211Sdes		    arg = strdelim(&cp);
1704124211Sdes		break;
1705124211Sdes
170692559Sdes	default:
170792559Sdes		fatal("%s line %d: Missing handler for opcode %s (%d)",
170892559Sdes		    filename, linenum, arg, opcode);
170992559Sdes	}
171092559Sdes	if ((arg = strdelim(&cp)) != NULL && *arg != '\0')
171192559Sdes		fatal("%s line %d: garbage at end of line; \"%.200s\".",
171292559Sdes		    filename, linenum, arg);
171392559Sdes	return 0;
171492559Sdes}
171576227Sgreen
171692559Sdes/* Reads the server configuration file. */
171792559Sdes
171892559Sdesvoid
1719137019Sdesload_server_config(const char *filename, Buffer *conf)
172092559Sdes{
1721240075Sdes	char line[4096], *cp;
172292559Sdes	FILE *f;
1723240075Sdes	int lineno = 0;
172492559Sdes
1725137019Sdes	debug2("%s: filename %s", __func__, filename);
1726137019Sdes	if ((f = fopen(filename, "r")) == NULL) {
172792559Sdes		perror(filename);
172892559Sdes		exit(1);
172957429Smarkm	}
1730137019Sdes	buffer_clear(conf);
173192559Sdes	while (fgets(line, sizeof(line), f)) {
1732240075Sdes		lineno++;
1733240075Sdes		if (strlen(line) == sizeof(line) - 1)
1734240075Sdes			fatal("%s line %d too long", filename, lineno);
1735137019Sdes		/*
1736137019Sdes		 * Trim out comments and strip whitespace
1737137019Sdes		 * NB - preserve newlines, they are needed to reproduce
1738137019Sdes		 * line numbers later for error messages
1739137019Sdes		 */
1740137019Sdes		if ((cp = strchr(line, '#')) != NULL)
1741137019Sdes			memcpy(cp, "\n", 2);
1742137019Sdes		cp = line + strspn(line, " \t\r");
1743137019Sdes
1744137019Sdes		buffer_append(conf, cp, strlen(cp));
1745137019Sdes	}
1746137019Sdes	buffer_append(conf, "\0", 1);
1747137019Sdes	fclose(f);
1748137019Sdes	debug2("%s: done config len = %d", __func__, buffer_len(conf));
1749137019Sdes}
1750137019Sdes
1751137019Sdesvoid
1752240075Sdesparse_server_match_config(ServerOptions *options,
1753240075Sdes   struct connection_info *connectinfo)
1754137019Sdes{
1755162856Sdes	ServerOptions mo;
1756162856Sdes
1757162856Sdes	initialize_server_options(&mo);
1758240075Sdes	parse_server_config(&mo, "reprocess config", &cfg, connectinfo);
1759181111Sdes	copy_set_server_options(options, &mo, 0);
1760162856Sdes}
1761162856Sdes
1762240075Sdesint parse_server_match_testspec(struct connection_info *ci, char *spec)
1763240075Sdes{
1764240075Sdes	char *p;
1765240075Sdes
1766240075Sdes	while ((p = strsep(&spec, ",")) && *p != '\0') {
1767240075Sdes		if (strncmp(p, "addr=", 5) == 0) {
1768240075Sdes			ci->address = xstrdup(p + 5);
1769240075Sdes		} else if (strncmp(p, "host=", 5) == 0) {
1770240075Sdes			ci->host = xstrdup(p + 5);
1771240075Sdes		} else if (strncmp(p, "user=", 5) == 0) {
1772240075Sdes			ci->user = xstrdup(p + 5);
1773240075Sdes		} else if (strncmp(p, "laddr=", 6) == 0) {
1774240075Sdes			ci->laddress = xstrdup(p + 6);
1775240075Sdes		} else if (strncmp(p, "lport=", 6) == 0) {
1776240075Sdes			ci->lport = a2port(p + 6);
1777240075Sdes			if (ci->lport == -1) {
1778240075Sdes				fprintf(stderr, "Invalid port '%s' in test mode"
1779240075Sdes				   " specification %s\n", p+6, p);
1780240075Sdes				return -1;
1781240075Sdes			}
1782240075Sdes		} else {
1783240075Sdes			fprintf(stderr, "Invalid test mode specification %s\n",
1784240075Sdes			   p);
1785240075Sdes			return -1;
1786240075Sdes		}
1787240075Sdes	}
1788240075Sdes	return 0;
1789240075Sdes}
1790240075Sdes
1791240075Sdes/*
1792240075Sdes * returns 1 for a complete spec, 0 for partial spec and -1 for an
1793240075Sdes * empty spec.
1794240075Sdes */
1795240075Sdesint server_match_spec_complete(struct connection_info *ci)
1796240075Sdes{
1797240075Sdes	if (ci->user && ci->host && ci->address)
1798240075Sdes		return 1;	/* complete */
1799240075Sdes	if (!ci->user && !ci->host && !ci->address)
1800240075Sdes		return -1;	/* empty */
1801240075Sdes	return 0;	/* partial */
1802240075Sdes}
1803240075Sdes
1804181111Sdes/*
1805181111Sdes * Copy any supported values that are set.
1806181111Sdes *
1807197679Sdes * If the preauth flag is set, we do not bother copying the string or
1808181111Sdes * array values that are not used pre-authentication, because any that we
1809181111Sdes * do use must be explictly sent in mm_getpwnamallow().
1810181111Sdes */
1811162856Sdesvoid
1812181111Sdescopy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
1813162856Sdes{
1814262566Sdes#define M_CP_INTOPT(n) do {\
1815262566Sdes	if (src->n != -1) \
1816262566Sdes		dst->n = src->n; \
1817262566Sdes} while (0)
1818262566Sdes
1819181111Sdes	M_CP_INTOPT(password_authentication);
1820181111Sdes	M_CP_INTOPT(gss_authentication);
1821181111Sdes	M_CP_INTOPT(rsa_authentication);
1822181111Sdes	M_CP_INTOPT(pubkey_authentication);
1823181111Sdes	M_CP_INTOPT(kerberos_authentication);
1824181111Sdes	M_CP_INTOPT(hostbased_authentication);
1825215116Sdes	M_CP_INTOPT(hostbased_uses_name_from_packet_only);
1826181111Sdes	M_CP_INTOPT(kbd_interactive_authentication);
1827181111Sdes	M_CP_INTOPT(permit_root_login);
1828192595Sdes	M_CP_INTOPT(permit_empty_passwd);
1829181111Sdes
1830181111Sdes	M_CP_INTOPT(allow_tcp_forwarding);
1831181111Sdes	M_CP_INTOPT(allow_agent_forwarding);
1832215116Sdes	M_CP_INTOPT(permit_tun);
1833181111Sdes	M_CP_INTOPT(gateway_ports);
1834181111Sdes	M_CP_INTOPT(x11_display_offset);
1835181111Sdes	M_CP_INTOPT(x11_forwarding);
1836181111Sdes	M_CP_INTOPT(x11_use_localhost);
1837262566Sdes	M_CP_INTOPT(permit_tty);
1838181111Sdes	M_CP_INTOPT(max_sessions);
1839181111Sdes	M_CP_INTOPT(max_authtries);
1840221420Sdes	M_CP_INTOPT(ip_qos_interactive);
1841221420Sdes	M_CP_INTOPT(ip_qos_bulk);
1842255767Sdes	M_CP_INTOPT(rekey_limit);
1843255767Sdes	M_CP_INTOPT(rekey_interval);
1844181111Sdes
1845262566Sdes	/* M_CP_STROPT and M_CP_STRARRAYOPT should not appear before here */
1846262566Sdes#define M_CP_STROPT(n) do {\
1847262566Sdes	if (src->n != NULL && dst->n != src->n) { \
1848262566Sdes		free(dst->n); \
1849262566Sdes		dst->n = src->n; \
1850262566Sdes	} \
1851262566Sdes} while(0)
1852262566Sdes#define M_CP_STRARRAYOPT(n, num_n) do {\
1853262566Sdes	if (src->num_n != 0) { \
1854262566Sdes		for (dst->num_n = 0; dst->num_n < src->num_n; dst->num_n++) \
1855262566Sdes			dst->n[dst->num_n] = xstrdup(src->n[dst->num_n]); \
1856262566Sdes	} \
1857262566Sdes} while(0)
1858262566Sdes
1859226046Sdes	/* See comment in servconf.h */
1860226046Sdes	COPY_MATCH_STRING_OPTS();
1861226046Sdes
1862226046Sdes	/*
1863226046Sdes	 * The only things that should be below this point are string options
1864226046Sdes	 * which are only used after authentication.
1865226046Sdes	 */
1866181111Sdes	if (preauth)
1867181111Sdes		return;
1868226046Sdes
1869181111Sdes	M_CP_STROPT(adm_forced_command);
1870181111Sdes	M_CP_STROPT(chroot_directory);
1871162856Sdes}
1872162856Sdes
1873181111Sdes#undef M_CP_INTOPT
1874181111Sdes#undef M_CP_STROPT
1875226046Sdes#undef M_CP_STRARRAYOPT
1876181111Sdes
1877162856Sdesvoid
1878162856Sdesparse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
1879240075Sdes    struct connection_info *connectinfo)
1880162856Sdes{
1881162856Sdes	int active, linenum, bad_options = 0;
1882137019Sdes	char *cp, *obuf, *cbuf;
1883137019Sdes
1884137019Sdes	debug2("%s: config %s len %d", __func__, filename, buffer_len(conf));
1885137019Sdes
1886137019Sdes	obuf = cbuf = xstrdup(buffer_ptr(conf));
1887240075Sdes	active = connectinfo ? 0 : 1;
1888137019Sdes	linenum = 1;
1889147005Sdes	while ((cp = strsep(&cbuf, "\n")) != NULL) {
1890137019Sdes		if (process_server_config_line(options, cp, filename,
1891240075Sdes		    linenum++, &active, connectinfo) != 0)
189292559Sdes			bad_options++;
189392559Sdes	}
1894255767Sdes	free(obuf);
189576262Sgreen	if (bad_options > 0)
189692559Sdes		fatal("%s: terminating, %d bad configuration options",
189776262Sgreen		    filename, bad_options);
189857429Smarkm}
1899181111Sdes
1900181111Sdesstatic const char *
1901226046Sdesfmt_multistate_int(int val, const struct multistate *m)
1902226046Sdes{
1903226046Sdes	u_int i;
1904226046Sdes
1905226046Sdes	for (i = 0; m[i].key != NULL; i++) {
1906226046Sdes		if (m[i].value == val)
1907226046Sdes			return m[i].key;
1908226046Sdes	}
1909226046Sdes	return "UNKNOWN";
1910226046Sdes}
1911226046Sdes
1912226046Sdesstatic const char *
1913181111Sdesfmt_intarg(ServerOpCodes code, int val)
1914181111Sdes{
1915226046Sdes	if (val == -1)
1916226046Sdes		return "unset";
1917226046Sdes	switch (code) {
1918226046Sdes	case sAddressFamily:
1919226046Sdes		return fmt_multistate_int(val, multistate_addressfamily);
1920226046Sdes	case sPermitRootLogin:
1921226046Sdes		return fmt_multistate_int(val, multistate_permitrootlogin);
1922226046Sdes	case sGatewayPorts:
1923226046Sdes		return fmt_multistate_int(val, multistate_gatewayports);
1924226046Sdes	case sCompression:
1925226046Sdes		return fmt_multistate_int(val, multistate_compression);
1926226046Sdes	case sUsePrivilegeSeparation:
1927226046Sdes		return fmt_multistate_int(val, multistate_privsep);
1928248619Sdes	case sAllowTcpForwarding:
1929248619Sdes		return fmt_multistate_int(val, multistate_tcpfwd);
1930226046Sdes	case sProtocol:
1931181111Sdes		switch (val) {
1932181111Sdes		case SSH_PROTO_1:
1933181111Sdes			return "1";
1934181111Sdes		case SSH_PROTO_2:
1935181111Sdes			return "2";
1936181111Sdes		case (SSH_PROTO_1|SSH_PROTO_2):
1937181111Sdes			return "2,1";
1938181111Sdes		default:
1939181111Sdes			return "UNKNOWN";
1940181111Sdes		}
1941226046Sdes	default:
1942226046Sdes		switch (val) {
1943226046Sdes		case 0:
1944226046Sdes			return "no";
1945226046Sdes		case 1:
1946226046Sdes			return "yes";
1947226046Sdes		default:
1948226046Sdes			return "UNKNOWN";
1949226046Sdes		}
1950181111Sdes	}
1951181111Sdes}
1952181111Sdes
1953181111Sdesstatic const char *
1954181111Sdeslookup_opcode_name(ServerOpCodes code)
1955181111Sdes{
1956181111Sdes	u_int i;
1957181111Sdes
1958181111Sdes	for (i = 0; keywords[i].name != NULL; i++)
1959181111Sdes		if (keywords[i].opcode == code)
1960181111Sdes			return(keywords[i].name);
1961181111Sdes	return "UNKNOWN";
1962181111Sdes}
1963181111Sdes
1964181111Sdesstatic void
1965181111Sdesdump_cfg_int(ServerOpCodes code, int val)
1966181111Sdes{
1967181111Sdes	printf("%s %d\n", lookup_opcode_name(code), val);
1968181111Sdes}
1969181111Sdes
1970181111Sdesstatic void
1971181111Sdesdump_cfg_fmtint(ServerOpCodes code, int val)
1972181111Sdes{
1973181111Sdes	printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
1974181111Sdes}
1975181111Sdes
1976181111Sdesstatic void
1977181111Sdesdump_cfg_string(ServerOpCodes code, const char *val)
1978181111Sdes{
1979181111Sdes	if (val == NULL)
1980181111Sdes		return;
1981181111Sdes	printf("%s %s\n", lookup_opcode_name(code), val);
1982181111Sdes}
1983181111Sdes
1984181111Sdesstatic void
1985181111Sdesdump_cfg_strarray(ServerOpCodes code, u_int count, char **vals)
1986181111Sdes{
1987181111Sdes	u_int i;
1988181111Sdes
1989181111Sdes	for (i = 0; i < count; i++)
1990226046Sdes		printf("%s %s\n", lookup_opcode_name(code), vals[i]);
1991181111Sdes}
1992181111Sdes
1993226046Sdesstatic void
1994226046Sdesdump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals)
1995226046Sdes{
1996226046Sdes	u_int i;
1997226046Sdes
1998226046Sdes	printf("%s", lookup_opcode_name(code));
1999226046Sdes	for (i = 0; i < count; i++)
2000226046Sdes		printf(" %s",  vals[i]);
2001226046Sdes	printf("\n");
2002226046Sdes}
2003226046Sdes
2004181111Sdesvoid
2005181111Sdesdump_config(ServerOptions *o)
2006181111Sdes{
2007181111Sdes	u_int i;
2008181111Sdes	int ret;
2009181111Sdes	struct addrinfo *ai;
2010181111Sdes	char addr[NI_MAXHOST], port[NI_MAXSERV], *s = NULL;
2011181111Sdes
2012181111Sdes	/* these are usually at the top of the config */
2013181111Sdes	for (i = 0; i < o->num_ports; i++)
2014181111Sdes		printf("port %d\n", o->ports[i]);
2015181111Sdes	dump_cfg_fmtint(sProtocol, o->protocol);
2016181111Sdes	dump_cfg_fmtint(sAddressFamily, o->address_family);
2017181111Sdes
2018181111Sdes	/* ListenAddress must be after Port */
2019181111Sdes	for (ai = o->listen_addrs; ai; ai = ai->ai_next) {
2020181111Sdes		if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
2021181111Sdes		    sizeof(addr), port, sizeof(port),
2022181111Sdes		    NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
2023181111Sdes			error("getnameinfo failed: %.100s",
2024181111Sdes			    (ret != EAI_SYSTEM) ? gai_strerror(ret) :
2025181111Sdes			    strerror(errno));
2026181111Sdes		} else {
2027181111Sdes			if (ai->ai_family == AF_INET6)
2028181111Sdes				printf("listenaddress [%s]:%s\n", addr, port);
2029181111Sdes			else
2030181111Sdes				printf("listenaddress %s:%s\n", addr, port);
2031181111Sdes		}
2032181111Sdes	}
2033181111Sdes
2034181111Sdes	/* integer arguments */
2035192595Sdes#ifdef USE_PAM
2036192595Sdes	dump_cfg_int(sUsePAM, o->use_pam);
2037192595Sdes#endif
2038181111Sdes	dump_cfg_int(sServerKeyBits, o->server_key_bits);
2039181111Sdes	dump_cfg_int(sLoginGraceTime, o->login_grace_time);
2040181111Sdes	dump_cfg_int(sKeyRegenerationTime, o->key_regeneration_time);
2041181111Sdes	dump_cfg_int(sX11DisplayOffset, o->x11_display_offset);
2042181111Sdes	dump_cfg_int(sMaxAuthTries, o->max_authtries);
2043192595Sdes	dump_cfg_int(sMaxSessions, o->max_sessions);
2044181111Sdes	dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
2045181111Sdes	dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
2046181111Sdes
2047181111Sdes	/* formatted integer arguments */
2048181111Sdes	dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login);
2049181111Sdes	dump_cfg_fmtint(sIgnoreRhosts, o->ignore_rhosts);
2050181111Sdes	dump_cfg_fmtint(sIgnoreUserKnownHosts, o->ignore_user_known_hosts);
2051181111Sdes	dump_cfg_fmtint(sRhostsRSAAuthentication, o->rhosts_rsa_authentication);
2052181111Sdes	dump_cfg_fmtint(sHostbasedAuthentication, o->hostbased_authentication);
2053181111Sdes	dump_cfg_fmtint(sHostbasedUsesNameFromPacketOnly,
2054181111Sdes	    o->hostbased_uses_name_from_packet_only);
2055181111Sdes	dump_cfg_fmtint(sRSAAuthentication, o->rsa_authentication);
2056181111Sdes	dump_cfg_fmtint(sPubkeyAuthentication, o->pubkey_authentication);
2057192595Sdes#ifdef KRB5
2058181111Sdes	dump_cfg_fmtint(sKerberosAuthentication, o->kerberos_authentication);
2059181111Sdes	dump_cfg_fmtint(sKerberosOrLocalPasswd, o->kerberos_or_local_passwd);
2060181111Sdes	dump_cfg_fmtint(sKerberosTicketCleanup, o->kerberos_ticket_cleanup);
2061192595Sdes# ifdef USE_AFS
2062181111Sdes	dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
2063192595Sdes# endif
2064192595Sdes#endif
2065192595Sdes#ifdef GSSAPI
2066181111Sdes	dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
2067181111Sdes	dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
2068192595Sdes#endif
2069181111Sdes	dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
2070181111Sdes	dump_cfg_fmtint(sKbdInteractiveAuthentication,
2071181111Sdes	    o->kbd_interactive_authentication);
2072181111Sdes	dump_cfg_fmtint(sChallengeResponseAuthentication,
2073181111Sdes	    o->challenge_response_authentication);
2074181111Sdes	dump_cfg_fmtint(sPrintMotd, o->print_motd);
2075181111Sdes	dump_cfg_fmtint(sPrintLastLog, o->print_lastlog);
2076181111Sdes	dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding);
2077181111Sdes	dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost);
2078262566Sdes	dump_cfg_fmtint(sPermitTTY, o->permit_tty);
2079181111Sdes	dump_cfg_fmtint(sStrictModes, o->strict_modes);
2080181111Sdes	dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive);
2081181111Sdes	dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd);
2082181111Sdes	dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
2083181111Sdes	dump_cfg_fmtint(sUseLogin, o->use_login);
2084181111Sdes	dump_cfg_fmtint(sCompression, o->compression);
2085181111Sdes	dump_cfg_fmtint(sGatewayPorts, o->gateway_ports);
2086181111Sdes	dump_cfg_fmtint(sUseDNS, o->use_dns);
2087181111Sdes	dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
2088181111Sdes	dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep);
2089181111Sdes
2090181111Sdes	/* string arguments */
2091181111Sdes	dump_cfg_string(sPidFile, o->pid_file);
2092181111Sdes	dump_cfg_string(sXAuthLocation, o->xauth_location);
2093262566Sdes	dump_cfg_string(sCiphers, o->ciphers ? o->ciphers :
2094262566Sdes	    cipher_alg_list(',', 0));
2095262566Sdes	dump_cfg_string(sMacs, o->macs ? o->macs : mac_alg_list(','));
2096181111Sdes	dump_cfg_string(sBanner, o->banner);
2097181111Sdes	dump_cfg_string(sForceCommand, o->adm_forced_command);
2098204917Sdes	dump_cfg_string(sChrootDirectory, o->chroot_directory);
2099204917Sdes	dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys);
2100204917Sdes	dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
2101215116Sdes	dump_cfg_string(sAuthorizedPrincipalsFile,
2102215116Sdes	    o->authorized_principals_file);
2103240075Sdes	dump_cfg_string(sVersionAddendum, o->version_addendum);
2104248619Sdes	dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command);
2105248619Sdes	dump_cfg_string(sAuthorizedKeysCommandUser, o->authorized_keys_command_user);
2106255767Sdes	dump_cfg_string(sHostKeyAgent, o->host_key_agent);
2107262566Sdes	dump_cfg_string(sKexAlgorithms, o->kex_algorithms ? o->kex_algorithms :
2108262566Sdes	    kex_alg_list(','));
2109181111Sdes
2110181111Sdes	/* string arguments requiring a lookup */
2111181111Sdes	dump_cfg_string(sLogLevel, log_level_name(o->log_level));
2112181111Sdes	dump_cfg_string(sLogFacility, log_facility_name(o->log_facility));
2113181111Sdes
2114181111Sdes	/* string array arguments */
2115226046Sdes	dump_cfg_strarray_oneline(sAuthorizedKeysFile, o->num_authkeys_files,
2116226046Sdes	    o->authorized_keys_files);
2117181111Sdes	dump_cfg_strarray(sHostKeyFile, o->num_host_key_files,
2118181111Sdes	     o->host_key_files);
2119204917Sdes	dump_cfg_strarray(sHostKeyFile, o->num_host_cert_files,
2120204917Sdes	     o->host_cert_files);
2121181111Sdes	dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users);
2122181111Sdes	dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users);
2123181111Sdes	dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups);
2124181111Sdes	dump_cfg_strarray(sDenyGroups, o->num_deny_groups, o->deny_groups);
2125181111Sdes	dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env);
2126248619Sdes	dump_cfg_strarray_oneline(sAuthenticationMethods,
2127248619Sdes	    o->num_auth_methods, o->auth_methods);
2128181111Sdes
2129181111Sdes	/* other arguments */
2130181111Sdes	for (i = 0; i < o->num_subsystems; i++)
2131181111Sdes		printf("subsystem %s %s\n", o->subsystem_name[i],
2132181111Sdes		    o->subsystem_args[i]);
2133181111Sdes
2134181111Sdes	printf("maxstartups %d:%d:%d\n", o->max_startups_begin,
2135181111Sdes	    o->max_startups_rate, o->max_startups);
2136181111Sdes
2137181111Sdes	for (i = 0; tunmode_desc[i].val != -1; i++)
2138181111Sdes		if (tunmode_desc[i].val == o->permit_tun) {
2139181111Sdes			s = tunmode_desc[i].text;
2140181111Sdes			break;
2141181111Sdes		}
2142181111Sdes	dump_cfg_string(sPermitTunnel, s);
2143181111Sdes
2144226046Sdes	printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
2145226046Sdes	printf("%s\n", iptos2str(o->ip_qos_bulk));
2146221420Sdes
2147255767Sdes	printf("rekeylimit %lld %d\n", (long long)o->rekey_limit,
2148255767Sdes	    o->rekey_interval);
2149255767Sdes
2150181111Sdes	channel_print_adm_permitted_opens();
2151181111Sdes}
2152