1240075Sdes
2255767Sdes/* $OpenBSD: servconf.c,v 1.240 2013/07/19 07:37:48 markus 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;
9865674Skris	options->xauth_location = NULL;
9957429Smarkm	options->strict_modes = -1;
100126277Sdes	options->tcp_keep_alive = -1;
10192559Sdes	options->log_facility = SYSLOG_FACILITY_NOT_SET;
10292559Sdes	options->log_level = SYSLOG_LEVEL_NOT_SET;
10357429Smarkm	options->rhosts_rsa_authentication = -1;
10476262Sgreen	options->hostbased_authentication = -1;
10576262Sgreen	options->hostbased_uses_name_from_packet_only = -1;
10657429Smarkm	options->rsa_authentication = -1;
10776262Sgreen	options->pubkey_authentication = -1;
10873400Sassar	options->kerberos_authentication = -1;
10992559Sdes	options->kerberos_or_local_passwd = -1;
11092559Sdes	options->kerberos_ticket_cleanup = -1;
111126277Sdes	options->kerberos_get_afs_token = -1;
112124211Sdes	options->gss_authentication=-1;
113124211Sdes	options->gss_cleanup_creds = -1;
11457429Smarkm	options->password_authentication = -1;
11569591Sgreen	options->kbd_interactive_authentication = -1;
11692559Sdes	options->challenge_response_authentication = -1;
11757429Smarkm	options->permit_empty_passwd = -1;
118106130Sdes	options->permit_user_env = -1;
11957429Smarkm	options->use_login = -1;
12098684Sdes	options->compression = -1;
121255767Sdes	options->rekey_limit = -1;
122255767Sdes	options->rekey_interval = -1;
12369591Sgreen	options->allow_tcp_forwarding = -1;
124181111Sdes	options->allow_agent_forwarding = -1;
12557429Smarkm	options->num_allow_users = 0;
12657429Smarkm	options->num_deny_users = 0;
12757429Smarkm	options->num_allow_groups = 0;
12857429Smarkm	options->num_deny_groups = 0;
12960576Skris	options->ciphers = NULL;
13076262Sgreen	options->macs = NULL;
131221420Sdes	options->kex_algorithms = NULL;
13260576Skris	options->protocol = SSH_PROTO_UNKNOWN;
13360576Skris	options->gateway_ports = -1;
13465674Skris	options->num_subsystems = 0;
13565674Skris	options->max_startups_begin = -1;
13665674Skris	options->max_startups_rate = -1;
13765674Skris	options->max_startups = -1;
138137019Sdes	options->max_authtries = -1;
139181111Sdes	options->max_sessions = -1;
14076262Sgreen	options->banner = NULL;
141124211Sdes	options->use_dns = -1;
14276262Sgreen	options->client_alive_interval = -1;
14376262Sgreen	options->client_alive_count_max = -1;
144226046Sdes	options->num_authkeys_files = 0;
145137019Sdes	options->num_accept_env = 0;
146157019Sdes	options->permit_tun = -1;
147162856Sdes	options->num_permitted_opens = -1;
148162856Sdes	options->adm_forced_command = NULL;
149181111Sdes	options->chroot_directory = NULL;
150248619Sdes	options->authorized_keys_command = NULL;
151248619Sdes	options->authorized_keys_command_user = NULL;
152192595Sdes	options->zero_knowledge_password_authentication = -1;
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
19192559Sdes		}
19276262Sgreen	}
193204917Sdes	/* No certificates by default */
19457429Smarkm	if (options->num_ports == 0)
19557429Smarkm		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
19657429Smarkm	if (options->listen_addrs == NULL)
19776262Sgreen		add_listen_addr(options, NULL, 0);
19860576Skris	if (options->pid_file == NULL)
19976262Sgreen		options->pid_file = _PATH_SSH_DAEMON_PID_FILE;
20057429Smarkm	if (options->server_key_bits == -1)
201181111Sdes		options->server_key_bits = 1024;
20257429Smarkm	if (options->login_grace_time == -1)
20399048Sdes		options->login_grace_time = 120;
20457429Smarkm	if (options->key_regeneration_time == -1)
20557429Smarkm		options->key_regeneration_time = 3600;
20676262Sgreen	if (options->permit_root_login == PERMIT_NOT_SET)
20799048Sdes		options->permit_root_login = PERMIT_NO;
20857429Smarkm	if (options->ignore_rhosts == -1)
20957565Smarkm		options->ignore_rhosts = 1;
21057429Smarkm	if (options->ignore_user_known_hosts == -1)
21157429Smarkm		options->ignore_user_known_hosts = 0;
21257429Smarkm	if (options->print_motd == -1)
21357429Smarkm		options->print_motd = 1;
21476262Sgreen	if (options->print_lastlog == -1)
21576262Sgreen		options->print_lastlog = 1;
21657429Smarkm	if (options->x11_forwarding == -1)
21799048Sdes		options->x11_forwarding = 1;
21857429Smarkm	if (options->x11_display_offset == -1)
21957565Smarkm		options->x11_display_offset = 10;
22092559Sdes	if (options->x11_use_localhost == -1)
22192559Sdes		options->x11_use_localhost = 1;
22265674Skris	if (options->xauth_location == NULL)
22392559Sdes		options->xauth_location = _PATH_XAUTH;
22457429Smarkm	if (options->strict_modes == -1)
22557429Smarkm		options->strict_modes = 1;
226126277Sdes	if (options->tcp_keep_alive == -1)
227126277Sdes		options->tcp_keep_alive = 1;
22892559Sdes	if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
22957429Smarkm		options->log_facility = SYSLOG_FACILITY_AUTH;
23092559Sdes	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
23157429Smarkm		options->log_level = SYSLOG_LEVEL_INFO;
23257429Smarkm	if (options->rhosts_rsa_authentication == -1)
23357565Smarkm		options->rhosts_rsa_authentication = 0;
23476262Sgreen	if (options->hostbased_authentication == -1)
23576262Sgreen		options->hostbased_authentication = 0;
23676262Sgreen	if (options->hostbased_uses_name_from_packet_only == -1)
23776262Sgreen		options->hostbased_uses_name_from_packet_only = 0;
23857429Smarkm	if (options->rsa_authentication == -1)
23957429Smarkm		options->rsa_authentication = 1;
24076262Sgreen	if (options->pubkey_authentication == -1)
24176262Sgreen		options->pubkey_authentication = 1;
24299048Sdes	if (options->kerberos_authentication == -1)
243124211Sdes		options->kerberos_authentication = 0;
24492559Sdes	if (options->kerberos_or_local_passwd == -1)
24592559Sdes		options->kerberos_or_local_passwd = 1;
24692559Sdes	if (options->kerberos_ticket_cleanup == -1)
24792559Sdes		options->kerberos_ticket_cleanup = 1;
248126277Sdes	if (options->kerberos_get_afs_token == -1)
249126277Sdes		options->kerberos_get_afs_token = 0;
250124211Sdes	if (options->gss_authentication == -1)
251124211Sdes		options->gss_authentication = 0;
252124211Sdes	if (options->gss_cleanup_creds == -1)
253124211Sdes		options->gss_cleanup_creds = 1;
25457429Smarkm	if (options->password_authentication == -1)
255126009Sdes		options->password_authentication = 0;
25669591Sgreen	if (options->kbd_interactive_authentication == -1)
25769591Sgreen		options->kbd_interactive_authentication = 0;
25892559Sdes	if (options->challenge_response_authentication == -1)
25995456Sdes		options->challenge_response_authentication = 1;
26057429Smarkm	if (options->permit_empty_passwd == -1)
26157565Smarkm		options->permit_empty_passwd = 0;
262106130Sdes	if (options->permit_user_env == -1)
263106130Sdes		options->permit_user_env = 0;
26457429Smarkm	if (options->use_login == -1)
26557429Smarkm		options->use_login = 0;
26698684Sdes	if (options->compression == -1)
267149753Sdes		options->compression = COMP_DELAYED;
268255767Sdes	if (options->rekey_limit == -1)
269255767Sdes		options->rekey_limit = 0;
270255767Sdes	if (options->rekey_interval == -1)
271255767Sdes		options->rekey_interval = 0;
27269591Sgreen	if (options->allow_tcp_forwarding == -1)
273248619Sdes		options->allow_tcp_forwarding = FORWARD_ALLOW;
274181111Sdes	if (options->allow_agent_forwarding == -1)
275181111Sdes		options->allow_agent_forwarding = 1;
27660576Skris	if (options->gateway_ports == -1)
27760576Skris		options->gateway_ports = 0;
27865674Skris	if (options->max_startups == -1)
279248619Sdes		options->max_startups = 100;
28065674Skris	if (options->max_startups_rate == -1)
281248619Sdes		options->max_startups_rate = 30;		/* 30% */
28265674Skris	if (options->max_startups_begin == -1)
283248619Sdes		options->max_startups_begin = 10;
284137019Sdes	if (options->max_authtries == -1)
285137019Sdes		options->max_authtries = DEFAULT_AUTH_FAIL_MAX;
286181111Sdes	if (options->max_sessions == -1)
287181111Sdes		options->max_sessions = DEFAULT_SESSIONS_MAX;
288124211Sdes	if (options->use_dns == -1)
289124211Sdes		options->use_dns = 1;
29076262Sgreen	if (options->client_alive_interval == -1)
29192559Sdes		options->client_alive_interval = 0;
29276262Sgreen	if (options->client_alive_count_max == -1)
29376262Sgreen		options->client_alive_count_max = 3;
294226046Sdes	if (options->num_authkeys_files == 0) {
295226046Sdes		options->authorized_keys_files[options->num_authkeys_files++] =
296226046Sdes		    xstrdup(_PATH_SSH_USER_PERMITTED_KEYS);
297226046Sdes		options->authorized_keys_files[options->num_authkeys_files++] =
298226046Sdes		    xstrdup(_PATH_SSH_USER_PERMITTED_KEYS2);
29992559Sdes	}
300157019Sdes	if (options->permit_tun == -1)
301157019Sdes		options->permit_tun = SSH_TUNMODE_NO;
302192595Sdes	if (options->zero_knowledge_password_authentication == -1)
303192595Sdes		options->zero_knowledge_password_authentication = 0;
304221420Sdes	if (options->ip_qos_interactive == -1)
305221420Sdes		options->ip_qos_interactive = IPTOS_LOWDELAY;
306221420Sdes	if (options->ip_qos_bulk == -1)
307221420Sdes		options->ip_qos_bulk = IPTOS_THROUGHPUT;
308240075Sdes	if (options->version_addendum == NULL)
309240075Sdes		options->version_addendum = xstrdup(SSH_VERSION_FREEBSD);
310240075Sdes	/* Turn privilege separation on by default */
311240075Sdes	if (use_privsep == -1)
312251088Sdes		use_privsep = PRIVSEP_NOSANDBOX;
313240075Sdes
314240075Sdes#ifndef HAVE_MMAP
315240075Sdes	if (use_privsep && options->compression == 1) {
316240075Sdes		error("This platform does not support both privilege "
317240075Sdes		    "separation and compression");
318240075Sdes		error("Compression disabled");
319240075Sdes		options->compression = 0;
320240075Sdes	}
321240075Sdes#endif
322240075Sdes
323231584Sed	if (options->hpn_disabled == -1)
324224638Sbrooks		options->hpn_disabled = 0;
325224638Sbrooks	if (options->hpn_buffer_size == -1) {
326224638Sbrooks		/*
327224638Sbrooks		 * HPN buffer size option not explicitly set.  Try to figure
328224638Sbrooks		 * out what value to use or resort to default.
329224638Sbrooks		 */
330224638Sbrooks		options->hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT;
331224638Sbrooks		if (!options->hpn_disabled) {
332224638Sbrooks			sock_get_rcvbuf(&options->hpn_buffer_size, 0);
333224638Sbrooks			debug ("HPN Buffer Size: %d", options->hpn_buffer_size);
334224638Sbrooks		}
335224638Sbrooks	} else {
336224638Sbrooks		/*
337224638Sbrooks		 * In the case that the user sets both values in a
338224638Sbrooks		 * contradictory manner hpn_disabled overrrides hpn_buffer_size.
339224638Sbrooks		 */
340224638Sbrooks		if (options->hpn_disabled <= 0) {
341224638Sbrooks			u_int maxlen;
34298684Sdes
343224638Sbrooks			maxlen = buffer_get_max_len();
344224638Sbrooks			if (options->hpn_buffer_size == 0)
345224638Sbrooks				options->hpn_buffer_size = 1;
346224638Sbrooks			/* Limit the maximum buffer to BUFFER_MAX_LEN. */
347224638Sbrooks			if (options->hpn_buffer_size > maxlen / 1024)
348224638Sbrooks				options->hpn_buffer_size = maxlen;
349224638Sbrooks			else
350224638Sbrooks				options->hpn_buffer_size *= 1024;
351240075Sdes		} else {
352224638Sbrooks			options->hpn_buffer_size = CHAN_TCP_WINDOW_DEFAULT;
353240075Sdes		}
354224638Sbrooks	}
35557429Smarkm}
35657429Smarkm
35757429Smarkm/* Keyword tokens. */
35857429Smarkmtypedef enum {
35957429Smarkm	sBadOption,		/* == unknown option */
36098941Sdes	/* Portable-specific options */
361124211Sdes	sUsePAM,
36298941Sdes	/* Standard Options */
36357429Smarkm	sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
36457429Smarkm	sPermitRootLogin, sLogFacility, sLogLevel,
365124211Sdes	sRhostsRSAAuthentication, sRSAAuthentication,
36692559Sdes	sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
367126277Sdes	sKerberosGetAFSToken,
368124211Sdes	sKerberosTgtPassing, sChallengeResponseAuthentication,
369147005Sdes	sPasswordAuthentication, sKbdInteractiveAuthentication,
370147005Sdes	sListenAddress, sAddressFamily,
37176262Sgreen	sPrintMotd, sPrintLastLog, sIgnoreRhosts,
37292559Sdes	sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
373126277Sdes	sStrictModes, sEmptyPasswd, sTCPKeepAlive,
374106130Sdes	sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression,
375255767Sdes	sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
37676262Sgreen	sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
377137019Sdes	sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem,
378181111Sdes	sMaxStartups, sMaxAuthTries, sMaxSessions,
379124211Sdes	sBanner, sUseDNS, sHostbasedAuthentication,
38092559Sdes	sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
381226046Sdes	sClientAliveCountMax, sAuthorizedKeysFile,
382157019Sdes	sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
383181111Sdes	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
384181111Sdes	sUsePrivilegeSeparation, sAllowAgentForwarding,
385204917Sdes	sZeroKnowledgePasswordAuthentication, sHostCertificate,
386215116Sdes	sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
387240075Sdes	sKexAlgorithms, sIPQoS, sVersionAddendum,
388248619Sdes	sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
389255767Sdes	sAuthenticationMethods, sHostKeyAgent,
390224638Sbrooks	sHPNDisabled, sHPNBufferSize, sTcpRcvBufPoll,
391224638Sbrooks#ifdef NONE_CIPHER_ENABLED
392224638Sbrooks	sNoneEnabled,
393224638Sbrooks#endif
394124211Sdes	sDeprecated, sUnsupported
39557429Smarkm} ServerOpCodes;
39657429Smarkm
397162856Sdes#define SSHCFG_GLOBAL	0x01	/* allowed in main section of sshd_config */
398162856Sdes#define SSHCFG_MATCH	0x02	/* allowed inside a Match section */
399162856Sdes#define SSHCFG_ALL	(SSHCFG_GLOBAL|SSHCFG_MATCH)
400162856Sdes
40157429Smarkm/* Textual representation of the tokens. */
40257429Smarkmstatic struct {
40357429Smarkm	const char *name;
40457429Smarkm	ServerOpCodes opcode;
405162856Sdes	u_int flags;
40657429Smarkm} keywords[] = {
40798941Sdes	/* Portable-specific options */
408124211Sdes#ifdef USE_PAM
409162856Sdes	{ "usepam", sUsePAM, SSHCFG_GLOBAL },
410124211Sdes#else
411162856Sdes	{ "usepam", sUnsupported, SSHCFG_GLOBAL },
41299048Sdes#endif
413162856Sdes	{ "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
41498941Sdes	/* Standard Options */
415162856Sdes	{ "port", sPort, SSHCFG_GLOBAL },
416162856Sdes	{ "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
417162856Sdes	{ "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL },		/* alias */
418255767Sdes	{ "hostkeyagent", sHostKeyAgent, SSHCFG_GLOBAL },
419162856Sdes	{ "pidfile", sPidFile, SSHCFG_GLOBAL },
420162856Sdes	{ "serverkeybits", sServerKeyBits, SSHCFG_GLOBAL },
421162856Sdes	{ "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL },
422162856Sdes	{ "keyregenerationinterval", sKeyRegenerationTime, SSHCFG_GLOBAL },
423181111Sdes	{ "permitrootlogin", sPermitRootLogin, SSHCFG_ALL },
424162856Sdes	{ "syslogfacility", sLogFacility, SSHCFG_GLOBAL },
425162856Sdes	{ "loglevel", sLogLevel, SSHCFG_GLOBAL },
426162856Sdes	{ "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL },
427181111Sdes	{ "rhostsrsaauthentication", sRhostsRSAAuthentication, SSHCFG_ALL },
428181111Sdes	{ "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL },
429215116Sdes	{ "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_ALL },
430181111Sdes	{ "rsaauthentication", sRSAAuthentication, SSHCFG_ALL },
431181111Sdes	{ "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL },
432197679Sdes	{ "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */
433124211Sdes#ifdef KRB5
434181111Sdes	{ "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL },
435162856Sdes	{ "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL },
436162856Sdes	{ "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL },
437126277Sdes#ifdef USE_AFS
438162856Sdes	{ "kerberosgetafstoken", sKerberosGetAFSToken, SSHCFG_GLOBAL },
439124211Sdes#else
440162856Sdes	{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
441126277Sdes#endif
442126277Sdes#else
443181111Sdes	{ "kerberosauthentication", sUnsupported, SSHCFG_ALL },
444162856Sdes	{ "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
445162856Sdes	{ "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
446162856Sdes	{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
44773400Sassar#endif
448162856Sdes	{ "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
449162856Sdes	{ "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
450124211Sdes#ifdef GSSAPI
451181111Sdes	{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
452162856Sdes	{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
453124211Sdes#else
454181111Sdes	{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
455162856Sdes	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
45657429Smarkm#endif
457181111Sdes	{ "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
458181111Sdes	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
459162856Sdes	{ "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
460162856Sdes	{ "skeyauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, /* alias */
461192595Sdes#ifdef JPAKE
462192595Sdes	{ "zeroknowledgepasswordauthentication", sZeroKnowledgePasswordAuthentication, SSHCFG_ALL },
463192595Sdes#else
464192595Sdes	{ "zeroknowledgepasswordauthentication", sUnsupported, SSHCFG_ALL },
465192595Sdes#endif
466162856Sdes	{ "checkmail", sDeprecated, SSHCFG_GLOBAL },
467162856Sdes	{ "listenaddress", sListenAddress, SSHCFG_GLOBAL },
468162856Sdes	{ "addressfamily", sAddressFamily, SSHCFG_GLOBAL },
469162856Sdes	{ "printmotd", sPrintMotd, SSHCFG_GLOBAL },
470162856Sdes	{ "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
471162856Sdes	{ "ignorerhosts", sIgnoreRhosts, SSHCFG_GLOBAL },
472162856Sdes	{ "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
473162856Sdes	{ "x11forwarding", sX11Forwarding, SSHCFG_ALL },
474162856Sdes	{ "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
475162856Sdes	{ "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
476162856Sdes	{ "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
477162856Sdes	{ "strictmodes", sStrictModes, SSHCFG_GLOBAL },
478192595Sdes	{ "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL },
479162856Sdes	{ "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
480162856Sdes	{ "uselogin", sUseLogin, SSHCFG_GLOBAL },
481162856Sdes	{ "compression", sCompression, SSHCFG_GLOBAL },
482255767Sdes	{ "rekeylimit", sRekeyLimit, SSHCFG_ALL },
483162856Sdes	{ "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
484162856Sdes	{ "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL },	/* obsolete alias */
485162856Sdes	{ "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
486181111Sdes	{ "allowagentforwarding", sAllowAgentForwarding, SSHCFG_ALL },
487240075Sdes	{ "allowusers", sAllowUsers, SSHCFG_ALL },
488240075Sdes	{ "denyusers", sDenyUsers, SSHCFG_ALL },
489240075Sdes	{ "allowgroups", sAllowGroups, SSHCFG_ALL },
490240075Sdes	{ "denygroups", sDenyGroups, SSHCFG_ALL },
491162856Sdes	{ "ciphers", sCiphers, SSHCFG_GLOBAL },
492162856Sdes	{ "macs", sMacs, SSHCFG_GLOBAL },
493162856Sdes	{ "protocol", sProtocol, SSHCFG_GLOBAL },
494162856Sdes	{ "gatewayports", sGatewayPorts, SSHCFG_ALL },
495162856Sdes	{ "subsystem", sSubsystem, SSHCFG_GLOBAL },
496162856Sdes	{ "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
497181111Sdes	{ "maxauthtries", sMaxAuthTries, SSHCFG_ALL },
498181111Sdes	{ "maxsessions", sMaxSessions, SSHCFG_ALL },
499181111Sdes	{ "banner", sBanner, SSHCFG_ALL },
500162856Sdes	{ "usedns", sUseDNS, SSHCFG_GLOBAL },
501162856Sdes	{ "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
502162856Sdes	{ "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL },
503162856Sdes	{ "clientaliveinterval", sClientAliveInterval, SSHCFG_GLOBAL },
504162856Sdes	{ "clientalivecountmax", sClientAliveCountMax, SSHCFG_GLOBAL },
505215116Sdes	{ "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_ALL },
506226046Sdes	{ "authorizedkeysfile2", sDeprecated, SSHCFG_ALL },
507197679Sdes	{ "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL},
508240075Sdes	{ "acceptenv", sAcceptEnv, SSHCFG_ALL },
509215116Sdes	{ "permittunnel", sPermitTunnel, SSHCFG_ALL },
510197679Sdes	{ "match", sMatch, SSHCFG_ALL },
511162856Sdes	{ "permitopen", sPermitOpen, SSHCFG_ALL },
512162856Sdes	{ "forcecommand", sForceCommand, SSHCFG_ALL },
513181111Sdes	{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
514204917Sdes	{ "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
515204917Sdes	{ "revokedkeys", sRevokedKeys, SSHCFG_ALL },
516204917Sdes	{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
517215116Sdes	{ "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
518221420Sdes	{ "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
519221420Sdes	{ "ipqos", sIPQoS, SSHCFG_ALL },
520248619Sdes	{ "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
521248619Sdes	{ "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
522240075Sdes	{ "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL },
523248619Sdes	{ "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL },
524224638Sbrooks	{ "hpndisabled", sHPNDisabled, SSHCFG_ALL },
525224638Sbrooks	{ "hpnbuffersize", sHPNBufferSize, SSHCFG_ALL },
526224638Sbrooks	{ "tcprcvbufpoll", sTcpRcvBufPoll, SSHCFG_ALL },
527224638Sbrooks#ifdef NONE_CIPHER_ENABLED
528224638Sbrooks	{ "noneenabled", sNoneEnabled, SSHCFG_ALL },
529224638Sbrooks#endif
530162856Sdes	{ NULL, sBadOption, 0 }
53157429Smarkm};
53257429Smarkm
533181111Sdesstatic struct {
534181111Sdes	int val;
535181111Sdes	char *text;
536181111Sdes} tunmode_desc[] = {
537181111Sdes	{ SSH_TUNMODE_NO, "no" },
538181111Sdes	{ SSH_TUNMODE_POINTOPOINT, "point-to-point" },
539181111Sdes	{ SSH_TUNMODE_ETHERNET, "ethernet" },
540181111Sdes	{ SSH_TUNMODE_YES, "yes" },
541181111Sdes	{ -1, NULL }
542181111Sdes};
543181111Sdes
54457429Smarkm/*
54576262Sgreen * Returns the number of the token pointed to by cp or sBadOption.
54657429Smarkm */
54757429Smarkm
54860576Skrisstatic ServerOpCodes
54957429Smarkmparse_token(const char *cp, const char *filename,
550162856Sdes	    int linenum, u_int *flags)
55157429Smarkm{
55276262Sgreen	u_int i;
55357429Smarkm
55457429Smarkm	for (i = 0; keywords[i].name; i++)
555162856Sdes		if (strcasecmp(cp, keywords[i].name) == 0) {
556162856Sdes			*flags = keywords[i].flags;
55757429Smarkm			return keywords[i].opcode;
558162856Sdes		}
55957429Smarkm
56076262Sgreen	error("%s: line %d: Bad configuration option: %s",
56176262Sgreen	    filename, linenum, cp);
56257429Smarkm	return sBadOption;
56357429Smarkm}
56457429Smarkm
565204917Sdeschar *
566204917Sdesderelativise_path(const char *path)
567204917Sdes{
568207319Sdes	char *expanded, *ret, cwd[MAXPATHLEN];
569204917Sdes
570204917Sdes	expanded = tilde_expand_filename(path, getuid());
571204917Sdes	if (*expanded == '/')
572204917Sdes		return expanded;
573207319Sdes	if (getcwd(cwd, sizeof(cwd)) == NULL)
574204917Sdes		fatal("%s: getcwd: %s", __func__, strerror(errno));
575204917Sdes	xasprintf(&ret, "%s/%s", cwd, expanded);
576255767Sdes	free(expanded);
577204917Sdes	return ret;
578204917Sdes}
579204917Sdes
58092559Sdesstatic void
581192595Sdesadd_listen_addr(ServerOptions *options, char *addr, int port)
58257429Smarkm{
583149753Sdes	u_int i;
58457429Smarkm
58557429Smarkm	if (options->num_ports == 0)
58657429Smarkm		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
587147005Sdes	if (options->address_family == -1)
588147005Sdes		options->address_family = AF_UNSPEC;
58976262Sgreen	if (port == 0)
59076262Sgreen		for (i = 0; i < options->num_ports; i++)
59176262Sgreen			add_one_listen_addr(options, addr, options->ports[i]);
59276262Sgreen	else
59376262Sgreen		add_one_listen_addr(options, addr, port);
59457429Smarkm}
59557429Smarkm
59692559Sdesstatic void
597192595Sdesadd_one_listen_addr(ServerOptions *options, char *addr, int port)
59876262Sgreen{
59976262Sgreen	struct addrinfo hints, *ai, *aitop;
60076262Sgreen	char strport[NI_MAXSERV];
60176262Sgreen	int gaierr;
60276262Sgreen
60376262Sgreen	memset(&hints, 0, sizeof(hints));
604147005Sdes	hints.ai_family = options->address_family;
60576262Sgreen	hints.ai_socktype = SOCK_STREAM;
60676262Sgreen	hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
607192595Sdes	snprintf(strport, sizeof strport, "%d", port);
60876262Sgreen	if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
60976262Sgreen		fatal("bad addr or host: %s (%s)",
61076262Sgreen		    addr ? addr : "<NULL>",
611181111Sdes		    ssh_gai_strerror(gaierr));
61276262Sgreen	for (ai = aitop; ai->ai_next; ai = ai->ai_next)
61376262Sgreen		;
61476262Sgreen	ai->ai_next = options->listen_addrs;
61576262Sgreen	options->listen_addrs = aitop;
61676262Sgreen}
61776262Sgreen
618240075Sdesstruct connection_info *
619240075Sdesget_connection_info(int populate, int use_dns)
620240075Sdes{
621240075Sdes	static struct connection_info ci;
622240075Sdes
623240075Sdes	if (!populate)
624240075Sdes		return &ci;
625240075Sdes	ci.host = get_canonical_hostname(use_dns);
626240075Sdes	ci.address = get_remote_ipaddr();
627240075Sdes	ci.laddress = get_local_ipaddr(packet_get_connection_in());
628240075Sdes	ci.lport = get_local_port();
629240075Sdes	return &ci;
630240075Sdes}
631240075Sdes
632162856Sdes/*
633162856Sdes * The strategy for the Match blocks is that the config file is parsed twice.
634162856Sdes *
635162856Sdes * The first time is at startup.  activep is initialized to 1 and the
636162856Sdes * directives in the global context are processed and acted on.  Hitting a
637162856Sdes * Match directive unsets activep and the directives inside the block are
638162856Sdes * checked for syntax only.
639162856Sdes *
640162856Sdes * The second time is after a connection has been established but before
641162856Sdes * authentication.  activep is initialized to 2 and global config directives
642162856Sdes * are ignored since they have already been processed.  If the criteria in a
643162856Sdes * Match block is met, activep is set and the subsequent directives
644162856Sdes * processed and actioned until EOF or another Match block unsets it.  Any
645162856Sdes * options set are copied into the main server config.
646162856Sdes *
647162856Sdes * Potential additions/improvements:
648162856Sdes *  - Add Match support for pre-kex directives, eg Protocol, Ciphers.
649162856Sdes *
650162856Sdes *  - Add a Tag directive (idea from David Leonard) ala pf, eg:
651162856Sdes *	Match Address 192.168.0.*
652162856Sdes *		Tag trusted
653162856Sdes *	Match Group wheel
654162856Sdes *		Tag trusted
655162856Sdes *	Match Tag trusted
656162856Sdes *		AllowTcpForwarding yes
657162856Sdes *		GatewayPorts clientspecified
658162856Sdes *		[...]
659162856Sdes *
660162856Sdes *  - Add a PermittedChannelRequests directive
661162856Sdes *	Match Group shell
662162856Sdes *		PermittedChannelRequests session,forwarded-tcpip
663162856Sdes */
664162856Sdes
665162856Sdesstatic int
666162856Sdesmatch_cfg_line_group(const char *grps, int line, const char *user)
667162856Sdes{
668162856Sdes	int result = 0;
669162856Sdes	struct passwd *pw;
670162856Sdes
671162856Sdes	if (user == NULL)
672162856Sdes		goto out;
673162856Sdes
674162856Sdes	if ((pw = getpwnam(user)) == NULL) {
675162856Sdes		debug("Can't match group at line %d because user %.100s does "
676162856Sdes		    "not exist", line, user);
677162856Sdes	} else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
678162856Sdes		debug("Can't Match group because user %.100s not in any group "
679162856Sdes		    "at line %d", user, line);
680181111Sdes	} else if (ga_match_pattern_list(grps) != 1) {
681181111Sdes		debug("user %.100s does not match group list %.100s at line %d",
682181111Sdes		    user, grps, line);
683162856Sdes	} else {
684181111Sdes		debug("user %.100s matched group list %.100s at line %d", user,
685181111Sdes		    grps, line);
686162856Sdes		result = 1;
687162856Sdes	}
688162856Sdesout:
689162856Sdes	ga_free();
690162856Sdes	return result;
691162856Sdes}
692162856Sdes
693240075Sdes/*
694248619Sdes * All of the attributes on a single Match line are ANDed together, so we need
695248619Sdes * to check every * attribute and set the result to zero if any attribute does
696248619Sdes * not match.
697240075Sdes */
698162856Sdesstatic int
699240075Sdesmatch_cfg_line(char **condition, int line, struct connection_info *ci)
700162856Sdes{
701240075Sdes	int result = 1, port;
702162856Sdes	char *arg, *attrib, *cp = *condition;
703162856Sdes	size_t len;
704162856Sdes
705240075Sdes	if (ci == NULL)
706162856Sdes		debug3("checking syntax for 'Match %s'", cp);
707162856Sdes	else
708240075Sdes		debug3("checking match for '%s' user %s host %s addr %s "
709240075Sdes		    "laddr %s lport %d", cp, ci->user ? ci->user : "(null)",
710240075Sdes		    ci->host ? ci->host : "(null)",
711240075Sdes		    ci->address ? ci->address : "(null)",
712240075Sdes		    ci->laddress ? ci->laddress : "(null)", ci->lport);
713162856Sdes
714162856Sdes	while ((attrib = strdelim(&cp)) && *attrib != '\0') {
715162856Sdes		if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
716162856Sdes			error("Missing Match criteria for %s", attrib);
717162856Sdes			return -1;
718162856Sdes		}
719162856Sdes		len = strlen(arg);
720162856Sdes		if (strcasecmp(attrib, "user") == 0) {
721240075Sdes			if (ci == NULL || ci->user == NULL) {
722162856Sdes				result = 0;
723162856Sdes				continue;
724162856Sdes			}
725240075Sdes			if (match_pattern_list(ci->user, arg, len, 0) != 1)
726162856Sdes				result = 0;
727162856Sdes			else
728162856Sdes				debug("user %.100s matched 'User %.100s' at "
729240075Sdes				    "line %d", ci->user, arg, line);
730162856Sdes		} else if (strcasecmp(attrib, "group") == 0) {
731240075Sdes			if (ci == NULL || ci->user == NULL) {
732240075Sdes				result = 0;
733240075Sdes				continue;
734240075Sdes			}
735240075Sdes			switch (match_cfg_line_group(arg, line, ci->user)) {
736162856Sdes			case -1:
737162856Sdes				return -1;
738162856Sdes			case 0:
739162856Sdes				result = 0;
740162856Sdes			}
741162856Sdes		} else if (strcasecmp(attrib, "host") == 0) {
742240075Sdes			if (ci == NULL || ci->host == NULL) {
743162856Sdes				result = 0;
744162856Sdes				continue;
745162856Sdes			}
746240075Sdes			if (match_hostname(ci->host, arg, len) != 1)
747162856Sdes				result = 0;
748162856Sdes			else
749162856Sdes				debug("connection from %.100s matched 'Host "
750240075Sdes				    "%.100s' at line %d", ci->host, arg, line);
751162856Sdes		} else if (strcasecmp(attrib, "address") == 0) {
752240075Sdes			if (ci == NULL || ci->address == NULL) {
753240075Sdes				result = 0;
754240075Sdes				continue;
755240075Sdes			}
756240075Sdes			switch (addr_match_list(ci->address, arg)) {
757181111Sdes			case 1:
758181111Sdes				debug("connection from %.100s matched 'Address "
759240075Sdes				    "%.100s' at line %d", ci->address, arg, line);
760181111Sdes				break;
761181111Sdes			case 0:
762181111Sdes			case -1:
763162856Sdes				result = 0;
764181111Sdes				break;
765181111Sdes			case -2:
766181111Sdes				return -1;
767162856Sdes			}
768240075Sdes		} else if (strcasecmp(attrib, "localaddress") == 0){
769240075Sdes			if (ci == NULL || ci->laddress == NULL) {
770240075Sdes				result = 0;
771240075Sdes				continue;
772240075Sdes			}
773240075Sdes			switch (addr_match_list(ci->laddress, arg)) {
774240075Sdes			case 1:
775240075Sdes				debug("connection from %.100s matched "
776240075Sdes				    "'LocalAddress %.100s' at line %d",
777240075Sdes				    ci->laddress, arg, line);
778240075Sdes				break;
779240075Sdes			case 0:
780240075Sdes			case -1:
781240075Sdes				result = 0;
782240075Sdes				break;
783240075Sdes			case -2:
784240075Sdes				return -1;
785240075Sdes			}
786240075Sdes		} else if (strcasecmp(attrib, "localport") == 0) {
787240075Sdes			if ((port = a2port(arg)) == -1) {
788240075Sdes				error("Invalid LocalPort '%s' on Match line",
789240075Sdes				    arg);
790240075Sdes				return -1;
791240075Sdes			}
792240075Sdes			if (ci == NULL || ci->lport == 0) {
793240075Sdes				result = 0;
794240075Sdes				continue;
795240075Sdes			}
796240075Sdes			/* TODO support port lists */
797240075Sdes			if (port == ci->lport)
798240075Sdes				debug("connection from %.100s matched "
799240075Sdes				    "'LocalPort %d' at line %d",
800240075Sdes				    ci->laddress, port, line);
801240075Sdes			else
802240075Sdes				result = 0;
803162856Sdes		} else {
804162856Sdes			error("Unsupported Match attribute %s", attrib);
805162856Sdes			return -1;
806162856Sdes		}
807162856Sdes	}
808240075Sdes	if (ci != NULL)
809162856Sdes		debug3("match %sfound", result ? "" : "not ");
810162856Sdes	*condition = cp;
811162856Sdes	return result;
812162856Sdes}
813162856Sdes
814162856Sdes#define WHITESPACE " \t\r\n"
815162856Sdes
816226046Sdes/* Multistate option parsing */
817226046Sdesstruct multistate {
818226046Sdes	char *key;
819226046Sdes	int value;
820226046Sdes};
821226046Sdesstatic const struct multistate multistate_addressfamily[] = {
822226046Sdes	{ "inet",			AF_INET },
823226046Sdes	{ "inet6",			AF_INET6 },
824226046Sdes	{ "any",			AF_UNSPEC },
825226046Sdes	{ NULL, -1 }
826226046Sdes};
827226046Sdesstatic const struct multistate multistate_permitrootlogin[] = {
828226046Sdes	{ "without-password",		PERMIT_NO_PASSWD },
829226046Sdes	{ "forced-commands-only",	PERMIT_FORCED_ONLY },
830226046Sdes	{ "yes",			PERMIT_YES },
831226046Sdes	{ "no",				PERMIT_NO },
832226046Sdes	{ NULL, -1 }
833226046Sdes};
834226046Sdesstatic const struct multistate multistate_compression[] = {
835226046Sdes	{ "delayed",			COMP_DELAYED },
836226046Sdes	{ "yes",			COMP_ZLIB },
837226046Sdes	{ "no",				COMP_NONE },
838226046Sdes	{ NULL, -1 }
839226046Sdes};
840226046Sdesstatic const struct multistate multistate_gatewayports[] = {
841226046Sdes	{ "clientspecified",		2 },
842226046Sdes	{ "yes",			1 },
843226046Sdes	{ "no",				0 },
844226046Sdes	{ NULL, -1 }
845226046Sdes};
846226046Sdesstatic const struct multistate multistate_privsep[] = {
847240075Sdes	{ "yes",			PRIVSEP_NOSANDBOX },
848240075Sdes	{ "sandbox",			PRIVSEP_ON },
849240075Sdes	{ "nosandbox",			PRIVSEP_NOSANDBOX },
850226046Sdes	{ "no",				PRIVSEP_OFF },
851226046Sdes	{ NULL, -1 }
852226046Sdes};
853248619Sdesstatic const struct multistate multistate_tcpfwd[] = {
854248619Sdes	{ "yes",			FORWARD_ALLOW },
855248619Sdes	{ "all",			FORWARD_ALLOW },
856248619Sdes	{ "no",				FORWARD_DENY },
857248619Sdes	{ "remote",			FORWARD_REMOTE },
858248619Sdes	{ "local",			FORWARD_LOCAL },
859248619Sdes	{ NULL, -1 }
860248619Sdes};
861226046Sdes
86292559Sdesint
86392559Sdesprocess_server_config_line(ServerOptions *options, char *line,
864240075Sdes    const char *filename, int linenum, int *activep,
865240075Sdes    struct connection_info *connectinfo)
86657429Smarkm{
86776262Sgreen	char *cp, **charptr, *arg, *p;
868255767Sdes	int cmdline = 0, *intptr, value, value2, n, port;
869181111Sdes	SyslogFacility *log_facility_ptr;
870181111Sdes	LogLevel *log_level_ptr;
87157429Smarkm	ServerOpCodes opcode;
872162856Sdes	u_int i, flags = 0;
873162856Sdes	size_t len;
874255767Sdes	long long val64;
875226046Sdes	const struct multistate *multistate_ptr;
87657429Smarkm
87792559Sdes	cp = line;
878162856Sdes	if ((arg = strdelim(&cp)) == NULL)
879162856Sdes		return 0;
88092559Sdes	/* Ignore leading whitespace */
88192559Sdes	if (*arg == '\0')
88265674Skris		arg = strdelim(&cp);
88392559Sdes	if (!arg || !*arg || *arg == '#')
88492559Sdes		return 0;
88592559Sdes	intptr = NULL;
88692559Sdes	charptr = NULL;
887162856Sdes	opcode = parse_token(arg, filename, linenum, &flags);
888162856Sdes
889162856Sdes	if (activep == NULL) { /* We are processing a command line directive */
890162856Sdes		cmdline = 1;
891162856Sdes		activep = &cmdline;
892162856Sdes	}
893162856Sdes	if (*activep && opcode != sMatch)
894162856Sdes		debug3("%s:%d setting %s %s", filename, linenum, arg, cp);
895162856Sdes	if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
896240075Sdes		if (connectinfo == NULL) {
897162856Sdes			fatal("%s line %d: Directive '%s' is not allowed "
898162856Sdes			    "within a Match block", filename, linenum, arg);
899162856Sdes		} else { /* this is a directive we have already processed */
900162856Sdes			while (arg)
901162856Sdes				arg = strdelim(&cp);
902162856Sdes			return 0;
903162856Sdes		}
904162856Sdes	}
905162856Sdes
90692559Sdes	switch (opcode) {
90798941Sdes	/* Portable-specific options */
908124211Sdes	case sUsePAM:
909124211Sdes		intptr = &options->use_pam;
91098941Sdes		goto parse_flag;
91198941Sdes
91298941Sdes	/* Standard Options */
91392559Sdes	case sBadOption:
91492559Sdes		return -1;
91592559Sdes	case sPort:
91692559Sdes		/* ignore ports from configfile if cmdline specifies ports */
91792559Sdes		if (options->ports_from_cmdline)
91892559Sdes			return 0;
91992559Sdes		if (options->listen_addrs != NULL)
92092559Sdes			fatal("%s line %d: ports must be specified before "
92192559Sdes			    "ListenAddress.", filename, linenum);
92292559Sdes		if (options->num_ports >= MAX_PORTS)
92392559Sdes			fatal("%s line %d: too many ports.",
92492559Sdes			    filename, linenum);
92592559Sdes		arg = strdelim(&cp);
92692559Sdes		if (!arg || *arg == '\0')
92792559Sdes			fatal("%s line %d: missing port number.",
92892559Sdes			    filename, linenum);
92992559Sdes		options->ports[options->num_ports++] = a2port(arg);
930192595Sdes		if (options->ports[options->num_ports-1] <= 0)
93192559Sdes			fatal("%s line %d: Badly formatted port number.",
93292559Sdes			    filename, linenum);
93392559Sdes		break;
93457429Smarkm
93592559Sdes	case sServerKeyBits:
93692559Sdes		intptr = &options->server_key_bits;
937181111Sdes parse_int:
93892559Sdes		arg = strdelim(&cp);
93992559Sdes		if (!arg || *arg == '\0')
94092559Sdes			fatal("%s line %d: missing integer value.",
94192559Sdes			    filename, linenum);
94292559Sdes		value = atoi(arg);
943162856Sdes		if (*activep && *intptr == -1)
94492559Sdes			*intptr = value;
94592559Sdes		break;
94657429Smarkm
94792559Sdes	case sLoginGraceTime:
94892559Sdes		intptr = &options->login_grace_time;
949181111Sdes parse_time:
95092559Sdes		arg = strdelim(&cp);
95192559Sdes		if (!arg || *arg == '\0')
95292559Sdes			fatal("%s line %d: missing time value.",
95392559Sdes			    filename, linenum);
95492559Sdes		if ((value = convtime(arg)) == -1)
95592559Sdes			fatal("%s line %d: invalid time value.",
95692559Sdes			    filename, linenum);
95792559Sdes		if (*intptr == -1)
95892559Sdes			*intptr = value;
95992559Sdes		break;
96057429Smarkm
96192559Sdes	case sKeyRegenerationTime:
96292559Sdes		intptr = &options->key_regeneration_time;
96392559Sdes		goto parse_time;
96457429Smarkm
96592559Sdes	case sListenAddress:
96692559Sdes		arg = strdelim(&cp);
967147005Sdes		if (arg == NULL || *arg == '\0')
968147005Sdes			fatal("%s line %d: missing address",
96992559Sdes			    filename, linenum);
970149753Sdes		/* check for bare IPv6 address: no "[]" and 2 or more ":" */
971149753Sdes		if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL
972149753Sdes		    && strchr(p+1, ':') != NULL) {
973149753Sdes			add_listen_addr(options, arg, 0);
974149753Sdes			break;
975149753Sdes		}
976147005Sdes		p = hpdelim(&arg);
977147005Sdes		if (p == NULL)
978147005Sdes			fatal("%s line %d: bad address:port usage",
979147005Sdes			    filename, linenum);
980147005Sdes		p = cleanhostname(p);
981147005Sdes		if (arg == NULL)
982147005Sdes			port = 0;
983192595Sdes		else if ((port = a2port(arg)) <= 0)
984147005Sdes			fatal("%s line %d: bad port number", filename, linenum);
98557429Smarkm
986147005Sdes		add_listen_addr(options, p, port);
987147005Sdes
988147005Sdes		break;
989147005Sdes
990147005Sdes	case sAddressFamily:
991226046Sdes		intptr = &options->address_family;
992226046Sdes		multistate_ptr = multistate_addressfamily;
993226046Sdes		if (options->listen_addrs != NULL)
994226046Sdes			fatal("%s line %d: address family must be specified "
995226046Sdes			    "before ListenAddress.", filename, linenum);
996226046Sdes parse_multistate:
997147005Sdes		arg = strdelim(&cp);
998149753Sdes		if (!arg || *arg == '\0')
999226046Sdes			fatal("%s line %d: missing argument.",
1000149753Sdes			    filename, linenum);
1001226046Sdes		value = -1;
1002226046Sdes		for (i = 0; multistate_ptr[i].key != NULL; i++) {
1003226046Sdes			if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
1004226046Sdes				value = multistate_ptr[i].value;
1005226046Sdes				break;
1006226046Sdes			}
1007226046Sdes		}
1008226046Sdes		if (value == -1)
1009226046Sdes			fatal("%s line %d: unsupported option \"%s\".",
1010147005Sdes			    filename, linenum, arg);
1011226046Sdes		if (*activep && *intptr == -1)
1012147005Sdes			*intptr = value;
101392559Sdes		break;
101457429Smarkm
101592559Sdes	case sHostKeyFile:
101692559Sdes		intptr = &options->num_host_key_files;
101792559Sdes		if (*intptr >= MAX_HOSTKEYS)
101892559Sdes			fatal("%s line %d: too many host keys specified (max %d).",
101992559Sdes			    filename, linenum, MAX_HOSTKEYS);
102092559Sdes		charptr = &options->host_key_files[*intptr];
1021181111Sdes parse_filename:
102292559Sdes		arg = strdelim(&cp);
102392559Sdes		if (!arg || *arg == '\0')
102492559Sdes			fatal("%s line %d: missing file name.",
102592559Sdes			    filename, linenum);
1026162856Sdes		if (*activep && *charptr == NULL) {
1027204917Sdes			*charptr = derelativise_path(arg);
102892559Sdes			/* increase optional counter */
102992559Sdes			if (intptr != NULL)
103092559Sdes				*intptr = *intptr + 1;
103192559Sdes		}
103292559Sdes		break;
103360576Skris
1034255767Sdes	case sHostKeyAgent:
1035255767Sdes		charptr = &options->host_key_agent;
1036255767Sdes		arg = strdelim(&cp);
1037255767Sdes		if (!arg || *arg == '\0')
1038255767Sdes			fatal("%s line %d: missing socket name.",
1039255767Sdes			    filename, linenum);
1040255767Sdes		if (*activep && *charptr == NULL)
1041255767Sdes			*charptr = !strcmp(arg, SSH_AUTHSOCKET_ENV_NAME) ?
1042255767Sdes			    xstrdup(arg) : derelativise_path(arg);
1043255767Sdes		break;
1044255767Sdes
1045204917Sdes	case sHostCertificate:
1046204917Sdes		intptr = &options->num_host_cert_files;
1047204917Sdes		if (*intptr >= MAX_HOSTKEYS)
1048204917Sdes			fatal("%s line %d: too many host certificates "
1049204917Sdes			    "specified (max %d).", filename, linenum,
1050204917Sdes			    MAX_HOSTCERTS);
1051204917Sdes		charptr = &options->host_cert_files[*intptr];
1052204917Sdes		goto parse_filename;
1053204917Sdes		break;
1054204917Sdes
105592559Sdes	case sPidFile:
105692559Sdes		charptr = &options->pid_file;
105792559Sdes		goto parse_filename;
105857429Smarkm
105992559Sdes	case sPermitRootLogin:
106092559Sdes		intptr = &options->permit_root_login;
1061226046Sdes		multistate_ptr = multistate_permitrootlogin;
1062226046Sdes		goto parse_multistate;
106392559Sdes
106492559Sdes	case sIgnoreRhosts:
106592559Sdes		intptr = &options->ignore_rhosts;
1066181111Sdes parse_flag:
106792559Sdes		arg = strdelim(&cp);
106892559Sdes		if (!arg || *arg == '\0')
106992559Sdes			fatal("%s line %d: missing yes/no argument.",
107092559Sdes			    filename, linenum);
107192559Sdes		value = 0;	/* silence compiler */
107292559Sdes		if (strcmp(arg, "yes") == 0)
107392559Sdes			value = 1;
107492559Sdes		else if (strcmp(arg, "no") == 0)
107592559Sdes			value = 0;
107692559Sdes		else
107792559Sdes			fatal("%s line %d: Bad yes/no argument: %s",
107892559Sdes				filename, linenum, arg);
1079162856Sdes		if (*activep && *intptr == -1)
108092559Sdes			*intptr = value;
108192559Sdes		break;
108257429Smarkm
108392559Sdes	case sIgnoreUserKnownHosts:
108492559Sdes		intptr = &options->ignore_user_known_hosts;
108592559Sdes		goto parse_flag;
108657429Smarkm
108792559Sdes	case sRhostsRSAAuthentication:
108892559Sdes		intptr = &options->rhosts_rsa_authentication;
108992559Sdes		goto parse_flag;
109057429Smarkm
109192559Sdes	case sHostbasedAuthentication:
109292559Sdes		intptr = &options->hostbased_authentication;
109392559Sdes		goto parse_flag;
109476262Sgreen
109592559Sdes	case sHostbasedUsesNameFromPacketOnly:
109692559Sdes		intptr = &options->hostbased_uses_name_from_packet_only;
109792559Sdes		goto parse_flag;
109876262Sgreen
109992559Sdes	case sRSAAuthentication:
110092559Sdes		intptr = &options->rsa_authentication;
110192559Sdes		goto parse_flag;
110257429Smarkm
110392559Sdes	case sPubkeyAuthentication:
110492559Sdes		intptr = &options->pubkey_authentication;
110592559Sdes		goto parse_flag;
1106124211Sdes
110792559Sdes	case sKerberosAuthentication:
110892559Sdes		intptr = &options->kerberos_authentication;
110992559Sdes		goto parse_flag;
111057429Smarkm
111192559Sdes	case sKerberosOrLocalPasswd:
111292559Sdes		intptr = &options->kerberos_or_local_passwd;
111392559Sdes		goto parse_flag;
111492559Sdes
111592559Sdes	case sKerberosTicketCleanup:
111692559Sdes		intptr = &options->kerberos_ticket_cleanup;
111792559Sdes		goto parse_flag;
1118124211Sdes
1119126277Sdes	case sKerberosGetAFSToken:
1120126277Sdes		intptr = &options->kerberos_get_afs_token;
1121126277Sdes		goto parse_flag;
1122126277Sdes
1123124211Sdes	case sGssAuthentication:
1124124211Sdes		intptr = &options->gss_authentication;
112592559Sdes		goto parse_flag;
1126124211Sdes
1127124211Sdes	case sGssCleanupCreds:
1128124211Sdes		intptr = &options->gss_cleanup_creds;
112992559Sdes		goto parse_flag;
113057429Smarkm
113192559Sdes	case sPasswordAuthentication:
113292559Sdes		intptr = &options->password_authentication;
113392559Sdes		goto parse_flag;
113457565Smarkm
1135192595Sdes	case sZeroKnowledgePasswordAuthentication:
1136192595Sdes		intptr = &options->zero_knowledge_password_authentication;
1137192595Sdes		goto parse_flag;
1138192595Sdes
113992559Sdes	case sKbdInteractiveAuthentication:
114092559Sdes		intptr = &options->kbd_interactive_authentication;
114192559Sdes		goto parse_flag;
114257429Smarkm
114392559Sdes	case sChallengeResponseAuthentication:
114492559Sdes		intptr = &options->challenge_response_authentication;
114592559Sdes		goto parse_flag;
114657429Smarkm
114792559Sdes	case sPrintMotd:
114892559Sdes		intptr = &options->print_motd;
114992559Sdes		goto parse_flag;
115057429Smarkm
115192559Sdes	case sPrintLastLog:
115292559Sdes		intptr = &options->print_lastlog;
115392559Sdes		goto parse_flag;
115469591Sgreen
115592559Sdes	case sX11Forwarding:
115692559Sdes		intptr = &options->x11_forwarding;
115792559Sdes		goto parse_flag;
115857429Smarkm
115992559Sdes	case sX11DisplayOffset:
116092559Sdes		intptr = &options->x11_display_offset;
116192559Sdes		goto parse_int;
116257429Smarkm
116392559Sdes	case sX11UseLocalhost:
116492559Sdes		intptr = &options->x11_use_localhost;
116592559Sdes		goto parse_flag;
116657429Smarkm
116792559Sdes	case sXAuthLocation:
116892559Sdes		charptr = &options->xauth_location;
116992559Sdes		goto parse_filename;
117076262Sgreen
117192559Sdes	case sStrictModes:
117292559Sdes		intptr = &options->strict_modes;
117392559Sdes		goto parse_flag;
117457429Smarkm
1175126277Sdes	case sTCPKeepAlive:
1176126277Sdes		intptr = &options->tcp_keep_alive;
117792559Sdes		goto parse_flag;
117857429Smarkm
117992559Sdes	case sEmptyPasswd:
118092559Sdes		intptr = &options->permit_empty_passwd;
118192559Sdes		goto parse_flag;
118276262Sgreen
1183106130Sdes	case sPermitUserEnvironment:
1184106130Sdes		intptr = &options->permit_user_env;
1185106130Sdes		goto parse_flag;
1186106130Sdes
118792559Sdes	case sUseLogin:
118892559Sdes		intptr = &options->use_login;
118992559Sdes		goto parse_flag;
119057429Smarkm
119198684Sdes	case sCompression:
119298684Sdes		intptr = &options->compression;
1193226046Sdes		multistate_ptr = multistate_compression;
1194226046Sdes		goto parse_multistate;
119598684Sdes
1196255767Sdes	case sRekeyLimit:
1197255767Sdes		arg = strdelim(&cp);
1198255767Sdes		if (!arg || *arg == '\0')
1199255767Sdes			fatal("%.200s line %d: Missing argument.", filename,
1200255767Sdes			    linenum);
1201255767Sdes		if (strcmp(arg, "default") == 0) {
1202255767Sdes			val64 = 0;
1203255767Sdes		} else {
1204255767Sdes			if (scan_scaled(arg, &val64) == -1)
1205255767Sdes				fatal("%.200s line %d: Bad number '%s': %s",
1206255767Sdes				    filename, linenum, arg, strerror(errno));
1207255767Sdes			/* check for too-large or too-small limits */
1208255767Sdes			if (val64 > UINT_MAX)
1209255767Sdes				fatal("%.200s line %d: RekeyLimit too large",
1210255767Sdes				    filename, linenum);
1211255767Sdes			if (val64 != 0 && val64 < 16)
1212255767Sdes				fatal("%.200s line %d: RekeyLimit too small",
1213255767Sdes				    filename, linenum);
1214255767Sdes		}
1215255767Sdes		if (*activep && options->rekey_limit == -1)
1216255767Sdes			options->rekey_limit = (u_int32_t)val64;
1217255767Sdes		if (cp != NULL) { /* optional rekey interval present */
1218255767Sdes			if (strcmp(cp, "none") == 0) {
1219255767Sdes				(void)strdelim(&cp);	/* discard */
1220255767Sdes				break;
1221255767Sdes			}
1222255767Sdes			intptr = &options->rekey_interval;
1223255767Sdes			goto parse_time;
1224255767Sdes		}
1225255767Sdes		break;
1226255767Sdes
122792559Sdes	case sGatewayPorts:
122892559Sdes		intptr = &options->gateway_ports;
1229226046Sdes		multistate_ptr = multistate_gatewayports;
1230226046Sdes		goto parse_multistate;
123157429Smarkm
1232124211Sdes	case sUseDNS:
1233124211Sdes		intptr = &options->use_dns;
123492559Sdes		goto parse_flag;
123557429Smarkm
123692559Sdes	case sLogFacility:
1237181111Sdes		log_facility_ptr = &options->log_facility;
123892559Sdes		arg = strdelim(&cp);
123992559Sdes		value = log_facility_number(arg);
124092559Sdes		if (value == SYSLOG_FACILITY_NOT_SET)
124192559Sdes			fatal("%.200s line %d: unsupported log facility '%s'",
124292559Sdes			    filename, linenum, arg ? arg : "<NONE>");
1243181111Sdes		if (*log_facility_ptr == -1)
1244181111Sdes			*log_facility_ptr = (SyslogFacility) value;
124592559Sdes		break;
124657429Smarkm
124792559Sdes	case sLogLevel:
1248181111Sdes		log_level_ptr = &options->log_level;
124992559Sdes		arg = strdelim(&cp);
125092559Sdes		value = log_level_number(arg);
125192559Sdes		if (value == SYSLOG_LEVEL_NOT_SET)
125292559Sdes			fatal("%.200s line %d: unsupported log level '%s'",
125392559Sdes			    filename, linenum, arg ? arg : "<NONE>");
1254181111Sdes		if (*log_level_ptr == -1)
1255181111Sdes			*log_level_ptr = (LogLevel) value;
125692559Sdes		break;
125760576Skris
125892559Sdes	case sAllowTcpForwarding:
125992559Sdes		intptr = &options->allow_tcp_forwarding;
1260248619Sdes		multistate_ptr = multistate_tcpfwd;
1261248619Sdes		goto parse_multistate;
126276262Sgreen
1263181111Sdes	case sAllowAgentForwarding:
1264181111Sdes		intptr = &options->allow_agent_forwarding;
1265181111Sdes		goto parse_flag;
1266181111Sdes
126798684Sdes	case sUsePrivilegeSeparation:
126898684Sdes		intptr = &use_privsep;
1269226046Sdes		multistate_ptr = multistate_privsep;
1270226046Sdes		goto parse_multistate;
127198684Sdes
127292559Sdes	case sAllowUsers:
127392559Sdes		while ((arg = strdelim(&cp)) && *arg != '\0') {
127492559Sdes			if (options->num_allow_users >= MAX_ALLOW_USERS)
127592559Sdes				fatal("%s line %d: too many allow users.",
127692559Sdes				    filename, linenum);
1277240075Sdes			if (!*activep)
1278240075Sdes				continue;
127999063Sdes			options->allow_users[options->num_allow_users++] =
128099063Sdes			    xstrdup(arg);
128192559Sdes		}
128292559Sdes		break;
128357429Smarkm
128492559Sdes	case sDenyUsers:
128592559Sdes		while ((arg = strdelim(&cp)) && *arg != '\0') {
128692559Sdes			if (options->num_deny_users >= MAX_DENY_USERS)
1287162856Sdes				fatal("%s line %d: too many deny users.",
128892559Sdes				    filename, linenum);
1289240075Sdes			if (!*activep)
1290240075Sdes				continue;
129199063Sdes			options->deny_users[options->num_deny_users++] =
129299063Sdes			    xstrdup(arg);
129392559Sdes		}
129492559Sdes		break;
129557429Smarkm
129692559Sdes	case sAllowGroups:
129792559Sdes		while ((arg = strdelim(&cp)) && *arg != '\0') {
129892559Sdes			if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
129992559Sdes				fatal("%s line %d: too many allow groups.",
130092559Sdes				    filename, linenum);
1301240075Sdes			if (!*activep)
1302240075Sdes				continue;
130399063Sdes			options->allow_groups[options->num_allow_groups++] =
130499063Sdes			    xstrdup(arg);
130592559Sdes		}
130692559Sdes		break;
130769591Sgreen
130892559Sdes	case sDenyGroups:
130992559Sdes		while ((arg = strdelim(&cp)) && *arg != '\0') {
131092559Sdes			if (options->num_deny_groups >= MAX_DENY_GROUPS)
131192559Sdes				fatal("%s line %d: too many deny groups.",
131292559Sdes				    filename, linenum);
1313240075Sdes			if (!*activep)
1314240075Sdes				continue;
1315240075Sdes			options->deny_groups[options->num_deny_groups++] =
1316240075Sdes			    xstrdup(arg);
131792559Sdes		}
131892559Sdes		break;
131957429Smarkm
132092559Sdes	case sCiphers:
132192559Sdes		arg = strdelim(&cp);
132292559Sdes		if (!arg || *arg == '\0')
132392559Sdes			fatal("%s line %d: Missing argument.", filename, linenum);
132492559Sdes		if (!ciphers_valid(arg))
132592559Sdes			fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
132692559Sdes			    filename, linenum, arg ? arg : "<NONE>");
132792559Sdes		if (options->ciphers == NULL)
132892559Sdes			options->ciphers = xstrdup(arg);
132992559Sdes		break;
133057429Smarkm
133192559Sdes	case sMacs:
133292559Sdes		arg = strdelim(&cp);
133392559Sdes		if (!arg || *arg == '\0')
133492559Sdes			fatal("%s line %d: Missing argument.", filename, linenum);
133592559Sdes		if (!mac_valid(arg))
133692559Sdes			fatal("%s line %d: Bad SSH2 mac spec '%s'.",
133792559Sdes			    filename, linenum, arg ? arg : "<NONE>");
133892559Sdes		if (options->macs == NULL)
133992559Sdes			options->macs = xstrdup(arg);
134092559Sdes		break;
134157429Smarkm
1342221420Sdes	case sKexAlgorithms:
1343221420Sdes		arg = strdelim(&cp);
1344221420Sdes		if (!arg || *arg == '\0')
1345221420Sdes			fatal("%s line %d: Missing argument.",
1346221420Sdes			    filename, linenum);
1347221420Sdes		if (!kex_names_valid(arg))
1348221420Sdes			fatal("%s line %d: Bad SSH2 KexAlgorithms '%s'.",
1349221420Sdes			    filename, linenum, arg ? arg : "<NONE>");
1350221420Sdes		if (options->kex_algorithms == NULL)
1351221420Sdes			options->kex_algorithms = xstrdup(arg);
1352221420Sdes		break;
1353221420Sdes
135492559Sdes	case sProtocol:
135592559Sdes		intptr = &options->protocol;
135692559Sdes		arg = strdelim(&cp);
135792559Sdes		if (!arg || *arg == '\0')
135892559Sdes			fatal("%s line %d: Missing argument.", filename, linenum);
135992559Sdes		value = proto_spec(arg);
136092559Sdes		if (value == SSH_PROTO_UNKNOWN)
136192559Sdes			fatal("%s line %d: Bad protocol spec '%s'.",
136292559Sdes			    filename, linenum, arg ? arg : "<NONE>");
136392559Sdes		if (*intptr == SSH_PROTO_UNKNOWN)
136492559Sdes			*intptr = value;
136592559Sdes		break;
136657429Smarkm
136792559Sdes	case sSubsystem:
136892559Sdes		if (options->num_subsystems >= MAX_SUBSYSTEMS) {
136992559Sdes			fatal("%s line %d: too many subsystems defined.",
137092559Sdes			    filename, linenum);
137192559Sdes		}
137292559Sdes		arg = strdelim(&cp);
137392559Sdes		if (!arg || *arg == '\0')
137492559Sdes			fatal("%s line %d: Missing subsystem name.",
137592559Sdes			    filename, linenum);
1376162856Sdes		if (!*activep) {
1377162856Sdes			arg = strdelim(&cp);
1378162856Sdes			break;
1379162856Sdes		}
138092559Sdes		for (i = 0; i < options->num_subsystems; i++)
138192559Sdes			if (strcmp(arg, options->subsystem_name[i]) == 0)
138292559Sdes				fatal("%s line %d: Subsystem '%s' already defined.",
138392559Sdes				    filename, linenum, arg);
138492559Sdes		options->subsystem_name[options->num_subsystems] = xstrdup(arg);
138592559Sdes		arg = strdelim(&cp);
138692559Sdes		if (!arg || *arg == '\0')
138792559Sdes			fatal("%s line %d: Missing subsystem command.",
138892559Sdes			    filename, linenum);
138992559Sdes		options->subsystem_command[options->num_subsystems] = xstrdup(arg);
1390162856Sdes
1391162856Sdes		/* Collect arguments (separate to executable) */
1392162856Sdes		p = xstrdup(arg);
1393162856Sdes		len = strlen(p) + 1;
1394162856Sdes		while ((arg = strdelim(&cp)) != NULL && *arg != '\0') {
1395162856Sdes			len += 1 + strlen(arg);
1396162856Sdes			p = xrealloc(p, 1, len);
1397162856Sdes			strlcat(p, " ", len);
1398162856Sdes			strlcat(p, arg, len);
1399162856Sdes		}
1400162856Sdes		options->subsystem_args[options->num_subsystems] = p;
140192559Sdes		options->num_subsystems++;
140292559Sdes		break;
140360576Skris
140492559Sdes	case sMaxStartups:
140592559Sdes		arg = strdelim(&cp);
140692559Sdes		if (!arg || *arg == '\0')
140792559Sdes			fatal("%s line %d: Missing MaxStartups spec.",
140892559Sdes			    filename, linenum);
140992559Sdes		if ((n = sscanf(arg, "%d:%d:%d",
141092559Sdes		    &options->max_startups_begin,
141192559Sdes		    &options->max_startups_rate,
141292559Sdes		    &options->max_startups)) == 3) {
141392559Sdes			if (options->max_startups_begin >
141492559Sdes			    options->max_startups ||
141592559Sdes			    options->max_startups_rate > 100 ||
141692559Sdes			    options->max_startups_rate < 1)
141792559Sdes				fatal("%s line %d: Illegal MaxStartups spec.",
141892559Sdes				    filename, linenum);
141992559Sdes		} else if (n != 1)
142092559Sdes			fatal("%s line %d: Illegal MaxStartups spec.",
142192559Sdes			    filename, linenum);
142292559Sdes		else
142392559Sdes			options->max_startups = options->max_startups_begin;
142492559Sdes		break;
142576262Sgreen
1426137019Sdes	case sMaxAuthTries:
1427137019Sdes		intptr = &options->max_authtries;
1428137019Sdes		goto parse_int;
1429137019Sdes
1430181111Sdes	case sMaxSessions:
1431181111Sdes		intptr = &options->max_sessions;
1432181111Sdes		goto parse_int;
1433181111Sdes
143492559Sdes	case sBanner:
143592559Sdes		charptr = &options->banner;
143692559Sdes		goto parse_filename;
1437181111Sdes
143892559Sdes	/*
143992559Sdes	 * These options can contain %X options expanded at
144092559Sdes	 * connect time, so that you can specify paths like:
144192559Sdes	 *
144292559Sdes	 * AuthorizedKeysFile	/etc/ssh_keys/%u
144392559Sdes	 */
144492559Sdes	case sAuthorizedKeysFile:
1445226046Sdes		if (*activep && options->num_authkeys_files == 0) {
1446226046Sdes			while ((arg = strdelim(&cp)) && *arg != '\0') {
1447226046Sdes				if (options->num_authkeys_files >=
1448226046Sdes				    MAX_AUTHKEYS_FILES)
1449226046Sdes					fatal("%s line %d: "
1450226046Sdes					    "too many authorized keys files.",
1451226046Sdes					    filename, linenum);
1452226046Sdes				options->authorized_keys_files[
1453226046Sdes				    options->num_authkeys_files++] =
1454226046Sdes				    tilde_expand_filename(arg, getuid());
1455226046Sdes			}
1456226046Sdes		}
1457226046Sdes		return 0;
1458226046Sdes
1459215116Sdes	case sAuthorizedPrincipalsFile:
1460215116Sdes		charptr = &options->authorized_principals_file;
1461207319Sdes		arg = strdelim(&cp);
1462207319Sdes		if (!arg || *arg == '\0')
1463207319Sdes			fatal("%s line %d: missing file name.",
1464207319Sdes			    filename, linenum);
1465207319Sdes		if (*activep && *charptr == NULL) {
1466207319Sdes			*charptr = tilde_expand_filename(arg, getuid());
1467207319Sdes			/* increase optional counter */
1468207319Sdes			if (intptr != NULL)
1469207319Sdes				*intptr = *intptr + 1;
1470207319Sdes		}
1471207319Sdes		break;
147260576Skris
147392559Sdes	case sClientAliveInterval:
147492559Sdes		intptr = &options->client_alive_interval;
147592559Sdes		goto parse_time;
147657432Smarkm
147792559Sdes	case sClientAliveCountMax:
147892559Sdes		intptr = &options->client_alive_count_max;
147992559Sdes		goto parse_int;
148065674Skris
1481137019Sdes	case sAcceptEnv:
1482137019Sdes		while ((arg = strdelim(&cp)) && *arg != '\0') {
1483137019Sdes			if (strchr(arg, '=') != NULL)
1484137019Sdes				fatal("%s line %d: Invalid environment name.",
1485137019Sdes				    filename, linenum);
1486137019Sdes			if (options->num_accept_env >= MAX_ACCEPT_ENV)
1487137019Sdes				fatal("%s line %d: too many allow env.",
1488137019Sdes				    filename, linenum);
1489162856Sdes			if (!*activep)
1490240075Sdes				continue;
1491137019Sdes			options->accept_env[options->num_accept_env++] =
1492137019Sdes			    xstrdup(arg);
1493137019Sdes		}
1494137019Sdes		break;
1495137019Sdes
1496157019Sdes	case sPermitTunnel:
1497157019Sdes		intptr = &options->permit_tun;
1498157019Sdes		arg = strdelim(&cp);
1499157019Sdes		if (!arg || *arg == '\0')
1500157019Sdes			fatal("%s line %d: Missing yes/point-to-point/"
1501157019Sdes			    "ethernet/no argument.", filename, linenum);
1502181111Sdes		value = -1;
1503181111Sdes		for (i = 0; tunmode_desc[i].val != -1; i++)
1504181111Sdes			if (strcmp(tunmode_desc[i].text, arg) == 0) {
1505181111Sdes				value = tunmode_desc[i].val;
1506181111Sdes				break;
1507181111Sdes			}
1508181111Sdes		if (value == -1)
1509157019Sdes			fatal("%s line %d: Bad yes/point-to-point/ethernet/"
1510157019Sdes			    "no argument: %s", filename, linenum, arg);
1511157019Sdes		if (*intptr == -1)
1512157019Sdes			*intptr = value;
1513157019Sdes		break;
1514157019Sdes
1515162856Sdes	case sMatch:
1516162856Sdes		if (cmdline)
1517162856Sdes			fatal("Match directive not supported as a command-line "
1518162856Sdes			   "option");
1519240075Sdes		value = match_cfg_line(&cp, linenum, connectinfo);
1520162856Sdes		if (value < 0)
1521162856Sdes			fatal("%s line %d: Bad Match condition", filename,
1522162856Sdes			    linenum);
1523162856Sdes		*activep = value;
1524162856Sdes		break;
1525162856Sdes
1526162856Sdes	case sPermitOpen:
1527162856Sdes		arg = strdelim(&cp);
1528162856Sdes		if (!arg || *arg == '\0')
1529162856Sdes			fatal("%s line %d: missing PermitOpen specification",
1530162856Sdes			    filename, linenum);
1531181111Sdes		n = options->num_permitted_opens;	/* modified later */
1532162856Sdes		if (strcmp(arg, "any") == 0) {
1533181111Sdes			if (*activep && n == -1) {
1534162856Sdes				channel_clear_adm_permitted_opens();
1535162856Sdes				options->num_permitted_opens = 0;
1536162856Sdes			}
1537162856Sdes			break;
1538162856Sdes		}
1539240075Sdes		if (strcmp(arg, "none") == 0) {
1540240075Sdes			if (*activep && n == -1) {
1541240075Sdes				options->num_permitted_opens = 1;
1542240075Sdes				channel_disable_adm_local_opens();
1543240075Sdes			}
1544240075Sdes			break;
1545240075Sdes		}
1546181111Sdes		if (*activep && n == -1)
1547181111Sdes			channel_clear_adm_permitted_opens();
1548162856Sdes		for (; arg != NULL && *arg != '\0'; arg = strdelim(&cp)) {
1549162856Sdes			p = hpdelim(&arg);
1550162856Sdes			if (p == NULL)
1551162856Sdes				fatal("%s line %d: missing host in PermitOpen",
1552162856Sdes				    filename, linenum);
1553162856Sdes			p = cleanhostname(p);
1554240075Sdes			if (arg == NULL || ((port = permitopen_port(arg)) < 0))
1555162856Sdes				fatal("%s line %d: bad port number in "
1556162856Sdes				    "PermitOpen", filename, linenum);
1557181111Sdes			if (*activep && n == -1)
1558162856Sdes				options->num_permitted_opens =
1559162856Sdes				    channel_add_adm_permitted_opens(p, port);
1560162856Sdes		}
1561162856Sdes		break;
1562162856Sdes
1563162856Sdes	case sForceCommand:
1564162856Sdes		if (cp == NULL)
1565162856Sdes			fatal("%.200s line %d: Missing argument.", filename,
1566162856Sdes			    linenum);
1567162856Sdes		len = strspn(cp, WHITESPACE);
1568162856Sdes		if (*activep && options->adm_forced_command == NULL)
1569162856Sdes			options->adm_forced_command = xstrdup(cp + len);
1570162856Sdes		return 0;
1571162856Sdes
1572181111Sdes	case sChrootDirectory:
1573181111Sdes		charptr = &options->chroot_directory;
1574181111Sdes
1575181111Sdes		arg = strdelim(&cp);
1576181111Sdes		if (!arg || *arg == '\0')
1577181111Sdes			fatal("%s line %d: missing file name.",
1578181111Sdes			    filename, linenum);
1579181111Sdes		if (*activep && *charptr == NULL)
1580181111Sdes			*charptr = xstrdup(arg);
1581181111Sdes		break;
1582181111Sdes
1583204917Sdes	case sTrustedUserCAKeys:
1584204917Sdes		charptr = &options->trusted_user_ca_keys;
1585204917Sdes		goto parse_filename;
1586204917Sdes
1587204917Sdes	case sRevokedKeys:
1588204917Sdes		charptr = &options->revoked_keys_file;
1589204917Sdes		goto parse_filename;
1590204917Sdes
1591221420Sdes	case sIPQoS:
1592221420Sdes		arg = strdelim(&cp);
1593221420Sdes		if ((value = parse_ipqos(arg)) == -1)
1594221420Sdes			fatal("%s line %d: Bad IPQoS value: %s",
1595221420Sdes			    filename, linenum, arg);
1596221420Sdes		arg = strdelim(&cp);
1597221420Sdes		if (arg == NULL)
1598221420Sdes			value2 = value;
1599221420Sdes		else if ((value2 = parse_ipqos(arg)) == -1)
1600221420Sdes			fatal("%s line %d: Bad IPQoS value: %s",
1601221420Sdes			    filename, linenum, arg);
1602221420Sdes		if (*activep) {
1603221420Sdes			options->ip_qos_interactive = value;
1604221420Sdes			options->ip_qos_bulk = value2;
1605221420Sdes		}
1606221420Sdes		break;
1607221420Sdes
160899047Sdes	case sVersionAddendum:
1609240075Sdes		if (cp == NULL)
1610240075Sdes			fatal("%.200s line %d: Missing argument.", filename,
1611240075Sdes			    linenum);
1612240075Sdes		len = strspn(cp, WHITESPACE);
1613240075Sdes		if (*activep && options->version_addendum == NULL) {
1614240075Sdes			if (strcasecmp(cp + len, "none") == 0)
1615240075Sdes				options->version_addendum = xstrdup("");
1616240075Sdes			else if (strchr(cp + len, '\r') != NULL)
1617240075Sdes				fatal("%.200s line %d: Invalid argument",
1618240075Sdes				    filename, linenum);
1619240075Sdes			else
1620240075Sdes				options->version_addendum = xstrdup(cp + len);
1621240075Sdes		}
1622240075Sdes		return 0;
162399047Sdes
1624248619Sdes	case sAuthorizedKeysCommand:
1625248619Sdes		len = strspn(cp, WHITESPACE);
1626248619Sdes		if (*activep && options->authorized_keys_command == NULL) {
1627248619Sdes			if (cp[len] != '/' && strcasecmp(cp + len, "none") != 0)
1628248619Sdes				fatal("%.200s line %d: AuthorizedKeysCommand "
1629248619Sdes				    "must be an absolute path",
1630248619Sdes				    filename, linenum);
1631248619Sdes			options->authorized_keys_command = xstrdup(cp + len);
1632248619Sdes		}
1633248619Sdes		return 0;
1634248619Sdes
1635248619Sdes	case sAuthorizedKeysCommandUser:
1636248619Sdes		charptr = &options->authorized_keys_command_user;
1637248619Sdes
1638248619Sdes		arg = strdelim(&cp);
1639248619Sdes		if (*activep && *charptr == NULL)
1640248619Sdes			*charptr = xstrdup(arg);
1641248619Sdes		break;
1642248619Sdes
1643248619Sdes	case sAuthenticationMethods:
1644248619Sdes		if (*activep && options->num_auth_methods == 0) {
1645248619Sdes			while ((arg = strdelim(&cp)) && *arg != '\0') {
1646248619Sdes				if (options->num_auth_methods >=
1647248619Sdes				    MAX_AUTH_METHODS)
1648248619Sdes					fatal("%s line %d: "
1649248619Sdes					    "too many authentication methods.",
1650248619Sdes					    filename, linenum);
1651248619Sdes				if (auth2_methods_valid(arg, 0) != 0)
1652248619Sdes					fatal("%s line %d: invalid "
1653248619Sdes					    "authentication method list.",
1654248619Sdes					    filename, linenum);
1655248619Sdes				options->auth_methods[
1656248619Sdes				    options->num_auth_methods++] = xstrdup(arg);
1657248619Sdes			}
1658248619Sdes		}
1659248619Sdes		return 0;
1660248619Sdes
1661224638Sbrooks	case sHPNDisabled:
1662224638Sbrooks		intptr = &options->hpn_disabled;
1663224638Sbrooks		goto parse_flag;
1664224638Sbrooks
1665224638Sbrooks	case sHPNBufferSize:
1666224638Sbrooks		intptr = &options->hpn_buffer_size;
1667224638Sbrooks		goto parse_int;
1668224638Sbrooks
1669224638Sbrooks	case sTcpRcvBufPoll:
1670224638Sbrooks		intptr = &options->tcp_rcv_buf_poll;
1671224638Sbrooks		goto parse_flag;
1672224638Sbrooks
1673224638Sbrooks#ifdef	NONE_CIPHER_ENABLED
1674224638Sbrooks	case sNoneEnabled:
1675224638Sbrooks		intptr = &options->none_enabled;
1676224638Sbrooks		goto parse_flag;
1677224638Sbrooks#endif
1678224638Sbrooks
167992559Sdes	case sDeprecated:
1680124211Sdes		logit("%s line %d: Deprecated option %s",
168192559Sdes		    filename, linenum, arg);
168292559Sdes		while (arg)
168392559Sdes		    arg = strdelim(&cp);
168492559Sdes		break;
168592559Sdes
1686124211Sdes	case sUnsupported:
1687124211Sdes		logit("%s line %d: Unsupported option %s",
1688124211Sdes		    filename, linenum, arg);
1689124211Sdes		while (arg)
1690124211Sdes		    arg = strdelim(&cp);
1691124211Sdes		break;
1692124211Sdes
169392559Sdes	default:
169492559Sdes		fatal("%s line %d: Missing handler for opcode %s (%d)",
169592559Sdes		    filename, linenum, arg, opcode);
169692559Sdes	}
169792559Sdes	if ((arg = strdelim(&cp)) != NULL && *arg != '\0')
169892559Sdes		fatal("%s line %d: garbage at end of line; \"%.200s\".",
169992559Sdes		    filename, linenum, arg);
170092559Sdes	return 0;
170192559Sdes}
170276227Sgreen
170392559Sdes/* Reads the server configuration file. */
170492559Sdes
170592559Sdesvoid
1706137019Sdesload_server_config(const char *filename, Buffer *conf)
170792559Sdes{
1708240075Sdes	char line[4096], *cp;
170992559Sdes	FILE *f;
1710240075Sdes	int lineno = 0;
171192559Sdes
1712137019Sdes	debug2("%s: filename %s", __func__, filename);
1713137019Sdes	if ((f = fopen(filename, "r")) == NULL) {
171492559Sdes		perror(filename);
171592559Sdes		exit(1);
171657429Smarkm	}
1717137019Sdes	buffer_clear(conf);
171892559Sdes	while (fgets(line, sizeof(line), f)) {
1719240075Sdes		lineno++;
1720240075Sdes		if (strlen(line) == sizeof(line) - 1)
1721240075Sdes			fatal("%s line %d too long", filename, lineno);
1722137019Sdes		/*
1723137019Sdes		 * Trim out comments and strip whitespace
1724137019Sdes		 * NB - preserve newlines, they are needed to reproduce
1725137019Sdes		 * line numbers later for error messages
1726137019Sdes		 */
1727137019Sdes		if ((cp = strchr(line, '#')) != NULL)
1728137019Sdes			memcpy(cp, "\n", 2);
1729137019Sdes		cp = line + strspn(line, " \t\r");
1730137019Sdes
1731137019Sdes		buffer_append(conf, cp, strlen(cp));
1732137019Sdes	}
1733137019Sdes	buffer_append(conf, "\0", 1);
1734137019Sdes	fclose(f);
1735137019Sdes	debug2("%s: done config len = %d", __func__, buffer_len(conf));
1736137019Sdes}
1737137019Sdes
1738137019Sdesvoid
1739240075Sdesparse_server_match_config(ServerOptions *options,
1740240075Sdes   struct connection_info *connectinfo)
1741137019Sdes{
1742162856Sdes	ServerOptions mo;
1743162856Sdes
1744162856Sdes	initialize_server_options(&mo);
1745240075Sdes	parse_server_config(&mo, "reprocess config", &cfg, connectinfo);
1746181111Sdes	copy_set_server_options(options, &mo, 0);
1747162856Sdes}
1748162856Sdes
1749240075Sdesint parse_server_match_testspec(struct connection_info *ci, char *spec)
1750240075Sdes{
1751240075Sdes	char *p;
1752240075Sdes
1753240075Sdes	while ((p = strsep(&spec, ",")) && *p != '\0') {
1754240075Sdes		if (strncmp(p, "addr=", 5) == 0) {
1755240075Sdes			ci->address = xstrdup(p + 5);
1756240075Sdes		} else if (strncmp(p, "host=", 5) == 0) {
1757240075Sdes			ci->host = xstrdup(p + 5);
1758240075Sdes		} else if (strncmp(p, "user=", 5) == 0) {
1759240075Sdes			ci->user = xstrdup(p + 5);
1760240075Sdes		} else if (strncmp(p, "laddr=", 6) == 0) {
1761240075Sdes			ci->laddress = xstrdup(p + 6);
1762240075Sdes		} else if (strncmp(p, "lport=", 6) == 0) {
1763240075Sdes			ci->lport = a2port(p + 6);
1764240075Sdes			if (ci->lport == -1) {
1765240075Sdes				fprintf(stderr, "Invalid port '%s' in test mode"
1766240075Sdes				   " specification %s\n", p+6, p);
1767240075Sdes				return -1;
1768240075Sdes			}
1769240075Sdes		} else {
1770240075Sdes			fprintf(stderr, "Invalid test mode specification %s\n",
1771240075Sdes			   p);
1772240075Sdes			return -1;
1773240075Sdes		}
1774240075Sdes	}
1775240075Sdes	return 0;
1776240075Sdes}
1777240075Sdes
1778240075Sdes/*
1779240075Sdes * returns 1 for a complete spec, 0 for partial spec and -1 for an
1780240075Sdes * empty spec.
1781240075Sdes */
1782240075Sdesint server_match_spec_complete(struct connection_info *ci)
1783240075Sdes{
1784240075Sdes	if (ci->user && ci->host && ci->address)
1785240075Sdes		return 1;	/* complete */
1786240075Sdes	if (!ci->user && !ci->host && !ci->address)
1787240075Sdes		return -1;	/* empty */
1788240075Sdes	return 0;	/* partial */
1789240075Sdes}
1790240075Sdes
1791181111Sdes/* Helper macros */
1792181111Sdes#define M_CP_INTOPT(n) do {\
1793181111Sdes	if (src->n != -1) \
1794181111Sdes		dst->n = src->n; \
1795181111Sdes} while (0)
1796181111Sdes#define M_CP_STROPT(n) do {\
1797181111Sdes	if (src->n != NULL) { \
1798255767Sdes		free(dst->n); \
1799181111Sdes		dst->n = src->n; \
1800181111Sdes	} \
1801181111Sdes} while(0)
1802226046Sdes#define M_CP_STRARRAYOPT(n, num_n) do {\
1803226046Sdes	if (src->num_n != 0) { \
1804226046Sdes		for (dst->num_n = 0; dst->num_n < src->num_n; dst->num_n++) \
1805226046Sdes			dst->n[dst->num_n] = xstrdup(src->n[dst->num_n]); \
1806226046Sdes	} \
1807226046Sdes} while(0)
1808181111Sdes
1809181111Sdes/*
1810181111Sdes * Copy any supported values that are set.
1811181111Sdes *
1812197679Sdes * If the preauth flag is set, we do not bother copying the string or
1813181111Sdes * array values that are not used pre-authentication, because any that we
1814181111Sdes * do use must be explictly sent in mm_getpwnamallow().
1815181111Sdes */
1816162856Sdesvoid
1817181111Sdescopy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
1818162856Sdes{
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);
1827192595Sdes	M_CP_INTOPT(zero_knowledge_password_authentication);
1828248619Sdes	M_CP_STROPT(authorized_keys_command);
1829248619Sdes	M_CP_STROPT(authorized_keys_command_user);
1830181111Sdes	M_CP_INTOPT(permit_root_login);
1831192595Sdes	M_CP_INTOPT(permit_empty_passwd);
1832181111Sdes
1833181111Sdes	M_CP_INTOPT(allow_tcp_forwarding);
1834181111Sdes	M_CP_INTOPT(allow_agent_forwarding);
1835215116Sdes	M_CP_INTOPT(permit_tun);
1836181111Sdes	M_CP_INTOPT(gateway_ports);
1837181111Sdes	M_CP_INTOPT(x11_display_offset);
1838181111Sdes	M_CP_INTOPT(x11_forwarding);
1839181111Sdes	M_CP_INTOPT(x11_use_localhost);
1840181111Sdes	M_CP_INTOPT(max_sessions);
1841181111Sdes	M_CP_INTOPT(max_authtries);
1842221420Sdes	M_CP_INTOPT(ip_qos_interactive);
1843221420Sdes	M_CP_INTOPT(ip_qos_bulk);
1844255767Sdes	M_CP_INTOPT(rekey_limit);
1845255767Sdes	M_CP_INTOPT(rekey_interval);
1846181111Sdes
1847226046Sdes	/* See comment in servconf.h */
1848226046Sdes	COPY_MATCH_STRING_OPTS();
1849226046Sdes
1850226046Sdes	/*
1851226046Sdes	 * The only things that should be below this point are string options
1852226046Sdes	 * which are only used after authentication.
1853226046Sdes	 */
1854181111Sdes	if (preauth)
1855181111Sdes		return;
1856226046Sdes
1857181111Sdes	M_CP_STROPT(adm_forced_command);
1858181111Sdes	M_CP_STROPT(chroot_directory);
1859162856Sdes}
1860162856Sdes
1861181111Sdes#undef M_CP_INTOPT
1862181111Sdes#undef M_CP_STROPT
1863226046Sdes#undef M_CP_STRARRAYOPT
1864181111Sdes
1865162856Sdesvoid
1866162856Sdesparse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
1867240075Sdes    struct connection_info *connectinfo)
1868162856Sdes{
1869162856Sdes	int active, linenum, bad_options = 0;
1870137019Sdes	char *cp, *obuf, *cbuf;
1871137019Sdes
1872137019Sdes	debug2("%s: config %s len %d", __func__, filename, buffer_len(conf));
1873137019Sdes
1874137019Sdes	obuf = cbuf = xstrdup(buffer_ptr(conf));
1875240075Sdes	active = connectinfo ? 0 : 1;
1876137019Sdes	linenum = 1;
1877147005Sdes	while ((cp = strsep(&cbuf, "\n")) != NULL) {
1878137019Sdes		if (process_server_config_line(options, cp, filename,
1879240075Sdes		    linenum++, &active, connectinfo) != 0)
188092559Sdes			bad_options++;
188192559Sdes	}
1882255767Sdes	free(obuf);
188376262Sgreen	if (bad_options > 0)
188492559Sdes		fatal("%s: terminating, %d bad configuration options",
188576262Sgreen		    filename, bad_options);
188657429Smarkm}
1887181111Sdes
1888181111Sdesstatic const char *
1889226046Sdesfmt_multistate_int(int val, const struct multistate *m)
1890226046Sdes{
1891226046Sdes	u_int i;
1892226046Sdes
1893226046Sdes	for (i = 0; m[i].key != NULL; i++) {
1894226046Sdes		if (m[i].value == val)
1895226046Sdes			return m[i].key;
1896226046Sdes	}
1897226046Sdes	return "UNKNOWN";
1898226046Sdes}
1899226046Sdes
1900226046Sdesstatic const char *
1901181111Sdesfmt_intarg(ServerOpCodes code, int val)
1902181111Sdes{
1903226046Sdes	if (val == -1)
1904226046Sdes		return "unset";
1905226046Sdes	switch (code) {
1906226046Sdes	case sAddressFamily:
1907226046Sdes		return fmt_multistate_int(val, multistate_addressfamily);
1908226046Sdes	case sPermitRootLogin:
1909226046Sdes		return fmt_multistate_int(val, multistate_permitrootlogin);
1910226046Sdes	case sGatewayPorts:
1911226046Sdes		return fmt_multistate_int(val, multistate_gatewayports);
1912226046Sdes	case sCompression:
1913226046Sdes		return fmt_multistate_int(val, multistate_compression);
1914226046Sdes	case sUsePrivilegeSeparation:
1915226046Sdes		return fmt_multistate_int(val, multistate_privsep);
1916248619Sdes	case sAllowTcpForwarding:
1917248619Sdes		return fmt_multistate_int(val, multistate_tcpfwd);
1918226046Sdes	case sProtocol:
1919181111Sdes		switch (val) {
1920181111Sdes		case SSH_PROTO_1:
1921181111Sdes			return "1";
1922181111Sdes		case SSH_PROTO_2:
1923181111Sdes			return "2";
1924181111Sdes		case (SSH_PROTO_1|SSH_PROTO_2):
1925181111Sdes			return "2,1";
1926181111Sdes		default:
1927181111Sdes			return "UNKNOWN";
1928181111Sdes		}
1929226046Sdes	default:
1930226046Sdes		switch (val) {
1931226046Sdes		case 0:
1932226046Sdes			return "no";
1933226046Sdes		case 1:
1934226046Sdes			return "yes";
1935226046Sdes		default:
1936226046Sdes			return "UNKNOWN";
1937226046Sdes		}
1938181111Sdes	}
1939181111Sdes}
1940181111Sdes
1941181111Sdesstatic const char *
1942181111Sdeslookup_opcode_name(ServerOpCodes code)
1943181111Sdes{
1944181111Sdes	u_int i;
1945181111Sdes
1946181111Sdes	for (i = 0; keywords[i].name != NULL; i++)
1947181111Sdes		if (keywords[i].opcode == code)
1948181111Sdes			return(keywords[i].name);
1949181111Sdes	return "UNKNOWN";
1950181111Sdes}
1951181111Sdes
1952181111Sdesstatic void
1953181111Sdesdump_cfg_int(ServerOpCodes code, int val)
1954181111Sdes{
1955181111Sdes	printf("%s %d\n", lookup_opcode_name(code), val);
1956181111Sdes}
1957181111Sdes
1958181111Sdesstatic void
1959181111Sdesdump_cfg_fmtint(ServerOpCodes code, int val)
1960181111Sdes{
1961181111Sdes	printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
1962181111Sdes}
1963181111Sdes
1964181111Sdesstatic void
1965181111Sdesdump_cfg_string(ServerOpCodes code, const char *val)
1966181111Sdes{
1967181111Sdes	if (val == NULL)
1968181111Sdes		return;
1969181111Sdes	printf("%s %s\n", lookup_opcode_name(code), val);
1970181111Sdes}
1971181111Sdes
1972181111Sdesstatic void
1973181111Sdesdump_cfg_strarray(ServerOpCodes code, u_int count, char **vals)
1974181111Sdes{
1975181111Sdes	u_int i;
1976181111Sdes
1977181111Sdes	for (i = 0; i < count; i++)
1978226046Sdes		printf("%s %s\n", lookup_opcode_name(code), vals[i]);
1979181111Sdes}
1980181111Sdes
1981226046Sdesstatic void
1982226046Sdesdump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals)
1983226046Sdes{
1984226046Sdes	u_int i;
1985226046Sdes
1986226046Sdes	printf("%s", lookup_opcode_name(code));
1987226046Sdes	for (i = 0; i < count; i++)
1988226046Sdes		printf(" %s",  vals[i]);
1989226046Sdes	printf("\n");
1990226046Sdes}
1991226046Sdes
1992181111Sdesvoid
1993181111Sdesdump_config(ServerOptions *o)
1994181111Sdes{
1995181111Sdes	u_int i;
1996181111Sdes	int ret;
1997181111Sdes	struct addrinfo *ai;
1998181111Sdes	char addr[NI_MAXHOST], port[NI_MAXSERV], *s = NULL;
1999181111Sdes
2000181111Sdes	/* these are usually at the top of the config */
2001181111Sdes	for (i = 0; i < o->num_ports; i++)
2002181111Sdes		printf("port %d\n", o->ports[i]);
2003181111Sdes	dump_cfg_fmtint(sProtocol, o->protocol);
2004181111Sdes	dump_cfg_fmtint(sAddressFamily, o->address_family);
2005181111Sdes
2006181111Sdes	/* ListenAddress must be after Port */
2007181111Sdes	for (ai = o->listen_addrs; ai; ai = ai->ai_next) {
2008181111Sdes		if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
2009181111Sdes		    sizeof(addr), port, sizeof(port),
2010181111Sdes		    NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
2011181111Sdes			error("getnameinfo failed: %.100s",
2012181111Sdes			    (ret != EAI_SYSTEM) ? gai_strerror(ret) :
2013181111Sdes			    strerror(errno));
2014181111Sdes		} else {
2015181111Sdes			if (ai->ai_family == AF_INET6)
2016181111Sdes				printf("listenaddress [%s]:%s\n", addr, port);
2017181111Sdes			else
2018181111Sdes				printf("listenaddress %s:%s\n", addr, port);
2019181111Sdes		}
2020181111Sdes	}
2021181111Sdes
2022181111Sdes	/* integer arguments */
2023192595Sdes#ifdef USE_PAM
2024192595Sdes	dump_cfg_int(sUsePAM, o->use_pam);
2025192595Sdes#endif
2026181111Sdes	dump_cfg_int(sServerKeyBits, o->server_key_bits);
2027181111Sdes	dump_cfg_int(sLoginGraceTime, o->login_grace_time);
2028181111Sdes	dump_cfg_int(sKeyRegenerationTime, o->key_regeneration_time);
2029181111Sdes	dump_cfg_int(sX11DisplayOffset, o->x11_display_offset);
2030181111Sdes	dump_cfg_int(sMaxAuthTries, o->max_authtries);
2031192595Sdes	dump_cfg_int(sMaxSessions, o->max_sessions);
2032181111Sdes	dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
2033181111Sdes	dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
2034181111Sdes
2035181111Sdes	/* formatted integer arguments */
2036181111Sdes	dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login);
2037181111Sdes	dump_cfg_fmtint(sIgnoreRhosts, o->ignore_rhosts);
2038181111Sdes	dump_cfg_fmtint(sIgnoreUserKnownHosts, o->ignore_user_known_hosts);
2039181111Sdes	dump_cfg_fmtint(sRhostsRSAAuthentication, o->rhosts_rsa_authentication);
2040181111Sdes	dump_cfg_fmtint(sHostbasedAuthentication, o->hostbased_authentication);
2041181111Sdes	dump_cfg_fmtint(sHostbasedUsesNameFromPacketOnly,
2042181111Sdes	    o->hostbased_uses_name_from_packet_only);
2043181111Sdes	dump_cfg_fmtint(sRSAAuthentication, o->rsa_authentication);
2044181111Sdes	dump_cfg_fmtint(sPubkeyAuthentication, o->pubkey_authentication);
2045192595Sdes#ifdef KRB5
2046181111Sdes	dump_cfg_fmtint(sKerberosAuthentication, o->kerberos_authentication);
2047181111Sdes	dump_cfg_fmtint(sKerberosOrLocalPasswd, o->kerberos_or_local_passwd);
2048181111Sdes	dump_cfg_fmtint(sKerberosTicketCleanup, o->kerberos_ticket_cleanup);
2049192595Sdes# ifdef USE_AFS
2050181111Sdes	dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
2051192595Sdes# endif
2052192595Sdes#endif
2053192595Sdes#ifdef GSSAPI
2054181111Sdes	dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
2055181111Sdes	dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
2056192595Sdes#endif
2057192595Sdes#ifdef JPAKE
2058192595Sdes	dump_cfg_fmtint(sZeroKnowledgePasswordAuthentication,
2059192595Sdes	    o->zero_knowledge_password_authentication);
2060192595Sdes#endif
2061181111Sdes	dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
2062181111Sdes	dump_cfg_fmtint(sKbdInteractiveAuthentication,
2063181111Sdes	    o->kbd_interactive_authentication);
2064181111Sdes	dump_cfg_fmtint(sChallengeResponseAuthentication,
2065181111Sdes	    o->challenge_response_authentication);
2066181111Sdes	dump_cfg_fmtint(sPrintMotd, o->print_motd);
2067181111Sdes	dump_cfg_fmtint(sPrintLastLog, o->print_lastlog);
2068181111Sdes	dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding);
2069181111Sdes	dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost);
2070181111Sdes	dump_cfg_fmtint(sStrictModes, o->strict_modes);
2071181111Sdes	dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive);
2072181111Sdes	dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd);
2073181111Sdes	dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
2074181111Sdes	dump_cfg_fmtint(sUseLogin, o->use_login);
2075181111Sdes	dump_cfg_fmtint(sCompression, o->compression);
2076181111Sdes	dump_cfg_fmtint(sGatewayPorts, o->gateway_ports);
2077181111Sdes	dump_cfg_fmtint(sUseDNS, o->use_dns);
2078181111Sdes	dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
2079181111Sdes	dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep);
2080181111Sdes
2081181111Sdes	/* string arguments */
2082181111Sdes	dump_cfg_string(sPidFile, o->pid_file);
2083181111Sdes	dump_cfg_string(sXAuthLocation, o->xauth_location);
2084181111Sdes	dump_cfg_string(sCiphers, o->ciphers);
2085181111Sdes	dump_cfg_string(sMacs, o->macs);
2086181111Sdes	dump_cfg_string(sBanner, o->banner);
2087181111Sdes	dump_cfg_string(sForceCommand, o->adm_forced_command);
2088204917Sdes	dump_cfg_string(sChrootDirectory, o->chroot_directory);
2089204917Sdes	dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys);
2090204917Sdes	dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
2091215116Sdes	dump_cfg_string(sAuthorizedPrincipalsFile,
2092215116Sdes	    o->authorized_principals_file);
2093240075Sdes	dump_cfg_string(sVersionAddendum, o->version_addendum);
2094248619Sdes	dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command);
2095248619Sdes	dump_cfg_string(sAuthorizedKeysCommandUser, o->authorized_keys_command_user);
2096255767Sdes	dump_cfg_string(sHostKeyAgent, o->host_key_agent);
2097181111Sdes
2098181111Sdes	/* string arguments requiring a lookup */
2099181111Sdes	dump_cfg_string(sLogLevel, log_level_name(o->log_level));
2100181111Sdes	dump_cfg_string(sLogFacility, log_facility_name(o->log_facility));
2101181111Sdes
2102181111Sdes	/* string array arguments */
2103226046Sdes	dump_cfg_strarray_oneline(sAuthorizedKeysFile, o->num_authkeys_files,
2104226046Sdes	    o->authorized_keys_files);
2105181111Sdes	dump_cfg_strarray(sHostKeyFile, o->num_host_key_files,
2106181111Sdes	     o->host_key_files);
2107204917Sdes	dump_cfg_strarray(sHostKeyFile, o->num_host_cert_files,
2108204917Sdes	     o->host_cert_files);
2109181111Sdes	dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users);
2110181111Sdes	dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users);
2111181111Sdes	dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups);
2112181111Sdes	dump_cfg_strarray(sDenyGroups, o->num_deny_groups, o->deny_groups);
2113181111Sdes	dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env);
2114248619Sdes	dump_cfg_strarray_oneline(sAuthenticationMethods,
2115248619Sdes	    o->num_auth_methods, o->auth_methods);
2116181111Sdes
2117181111Sdes	/* other arguments */
2118181111Sdes	for (i = 0; i < o->num_subsystems; i++)
2119181111Sdes		printf("subsystem %s %s\n", o->subsystem_name[i],
2120181111Sdes		    o->subsystem_args[i]);
2121181111Sdes
2122181111Sdes	printf("maxstartups %d:%d:%d\n", o->max_startups_begin,
2123181111Sdes	    o->max_startups_rate, o->max_startups);
2124181111Sdes
2125181111Sdes	for (i = 0; tunmode_desc[i].val != -1; i++)
2126181111Sdes		if (tunmode_desc[i].val == o->permit_tun) {
2127181111Sdes			s = tunmode_desc[i].text;
2128181111Sdes			break;
2129181111Sdes		}
2130181111Sdes	dump_cfg_string(sPermitTunnel, s);
2131181111Sdes
2132226046Sdes	printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
2133226046Sdes	printf("%s\n", iptos2str(o->ip_qos_bulk));
2134221420Sdes
2135255767Sdes	printf("rekeylimit %lld %d\n", (long long)o->rekey_limit,
2136255767Sdes	    o->rekey_interval);
2137255767Sdes
2138181111Sdes	channel_print_adm_permitted_opens();
2139181111Sdes}
2140