servconf.c revision 99063
157429Smarkm/*
257429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
357429Smarkm *                    All rights reserved
460576Skris *
565674Skris * As far as I am concerned, the code I have written for this software
665674Skris * can be used freely for any purpose.  Any derived versions of this
765674Skris * software must be clearly marked as such, and if the derived work is
865674Skris * incompatible with the protocol description in the RFC file, it must be
965674Skris * called by a name other than "ssh" or "Secure Shell".
1057429Smarkm */
1157429Smarkm
1257429Smarkm#include "includes.h"
1399063SdesRCSID("$OpenBSD: servconf.c,v 1.112 2002/06/23 09:46:51 deraadt Exp $");
1499048SdesRCSID("$FreeBSD: head/crypto/openssh/servconf.c 99063 2002-06-29 11:48:59Z des $");
1557429Smarkm
1692708Sdes#if defined(KRB4)
1776262Sgreen#include <krb.h>
1876262Sgreen#endif
1992708Sdes#if defined(KRB5)
2098941Sdes#ifdef HEIMDAL
2199048Sdes#include <krb5.h>
2298941Sdes#else
2398941Sdes/* Bodge - but then, so is using the kerberos IV KEYFILE to get a Kerberos V
2498941Sdes * keytab */
2598941Sdes#define KEYFILE "/etc/krb5.keytab"
2692708Sdes#endif
2798941Sdes#endif
2876262Sgreen#ifdef AFS
2976262Sgreen#include <kafs.h>
3076262Sgreen#endif
3176262Sgreen
3257429Smarkm#include "ssh.h"
3376262Sgreen#include "log.h"
3457429Smarkm#include "servconf.h"
3557429Smarkm#include "xmalloc.h"
3660576Skris#include "compat.h"
3776262Sgreen#include "pathnames.h"
3876262Sgreen#include "tildexpand.h"
3976262Sgreen#include "misc.h"
4076262Sgreen#include "cipher.h"
4176262Sgreen#include "kex.h"
4276262Sgreen#include "mac.h"
4357429Smarkm
4492559Sdesstatic void add_listen_addr(ServerOptions *, char *, u_short);
4592559Sdesstatic void add_one_listen_addr(ServerOptions *, char *, u_short);
4657429Smarkm
4776262Sgreen/* AF_UNSPEC or AF_INET or AF_INET6 */
4876262Sgreenextern int IPv4or6;
4998684Sdes/* Use of privilege separation or not */
5098684Sdesextern int use_privsep;
5176262Sgreen
5257429Smarkm/* Initializes the server options to their default values. */
5357429Smarkm
5460576Skrisvoid
5557429Smarkminitialize_server_options(ServerOptions *options)
5657429Smarkm{
5757429Smarkm	memset(options, 0, sizeof(*options));
5898941Sdes
5998941Sdes	/* Portable-specific options */
6098941Sdes	options->pam_authentication_via_kbd_int = -1;
6198941Sdes
6298941Sdes	/* Standard Options */
6357429Smarkm	options->num_ports = 0;
6457429Smarkm	options->ports_from_cmdline = 0;
6557429Smarkm	options->listen_addrs = NULL;
6676262Sgreen	options->num_host_key_files = 0;
6760576Skris	options->pid_file = NULL;
6857429Smarkm	options->server_key_bits = -1;
6957429Smarkm	options->login_grace_time = -1;
7057429Smarkm	options->key_regeneration_time = -1;
7176262Sgreen	options->permit_root_login = PERMIT_NOT_SET;
7257429Smarkm	options->ignore_rhosts = -1;
7357429Smarkm	options->ignore_user_known_hosts = -1;
7457429Smarkm	options->print_motd = -1;
7576262Sgreen	options->print_lastlog = -1;
7657429Smarkm	options->x11_forwarding = -1;
7757429Smarkm	options->x11_display_offset = -1;
7892559Sdes	options->x11_use_localhost = -1;
7965674Skris	options->xauth_location = NULL;
8057429Smarkm	options->strict_modes = -1;
8157429Smarkm	options->keepalives = -1;
8292559Sdes	options->log_facility = SYSLOG_FACILITY_NOT_SET;
8392559Sdes	options->log_level = SYSLOG_LEVEL_NOT_SET;
8457429Smarkm	options->rhosts_authentication = -1;
8557429Smarkm	options->rhosts_rsa_authentication = -1;
8676262Sgreen	options->hostbased_authentication = -1;
8776262Sgreen	options->hostbased_uses_name_from_packet_only = -1;
8857429Smarkm	options->rsa_authentication = -1;
8976262Sgreen	options->pubkey_authentication = -1;
9073400Sassar#if defined(KRB4) || defined(KRB5)
9173400Sassar	options->kerberos_authentication = -1;
9292559Sdes	options->kerberos_or_local_passwd = -1;
9392559Sdes	options->kerberos_ticket_cleanup = -1;
9473400Sassar#endif
9592559Sdes#if defined(AFS) || defined(KRB5)
9692559Sdes	options->kerberos_tgt_passing = -1;
9757429Smarkm#endif
9857429Smarkm#ifdef AFS
9957429Smarkm	options->afs_token_passing = -1;
10057429Smarkm#endif
10157429Smarkm	options->password_authentication = -1;
10269591Sgreen	options->kbd_interactive_authentication = -1;
10392559Sdes	options->challenge_response_authentication = -1;
10457429Smarkm	options->permit_empty_passwd = -1;
10557429Smarkm	options->use_login = -1;
10698684Sdes	options->compression = -1;
10769591Sgreen	options->allow_tcp_forwarding = -1;
10857429Smarkm	options->num_allow_users = 0;
10957429Smarkm	options->num_deny_users = 0;
11057429Smarkm	options->num_allow_groups = 0;
11157429Smarkm	options->num_deny_groups = 0;
11260576Skris	options->ciphers = NULL;
11376262Sgreen	options->macs = NULL;
11460576Skris	options->protocol = SSH_PROTO_UNKNOWN;
11560576Skris	options->gateway_ports = -1;
11665674Skris	options->num_subsystems = 0;
11765674Skris	options->max_startups_begin = -1;
11865674Skris	options->max_startups_rate = -1;
11965674Skris	options->max_startups = -1;
12076262Sgreen	options->banner = NULL;
12192559Sdes	options->verify_reverse_mapping = -1;
12276262Sgreen	options->client_alive_interval = -1;
12376262Sgreen	options->client_alive_count_max = -1;
12492559Sdes	options->authorized_keys_file = NULL;
12592559Sdes	options->authorized_keys_file2 = NULL;
12698684Sdes
12798684Sdes	/* Needs to be accessable in many places */
12898684Sdes	use_privsep = -1;
12957429Smarkm}
13057429Smarkm
13160576Skrisvoid
13257429Smarkmfill_default_server_options(ServerOptions *options)
13357429Smarkm{
13498941Sdes	/* Portable-specific options */
13598941Sdes	if (options->pam_authentication_via_kbd_int == -1)
13698941Sdes		options->pam_authentication_via_kbd_int = 0;
13798941Sdes
13898941Sdes	/* Standard Options */
13976262Sgreen	if (options->protocol == SSH_PROTO_UNKNOWN)
14076262Sgreen		options->protocol = SSH_PROTO_1|SSH_PROTO_2;
14176262Sgreen	if (options->num_host_key_files == 0) {
14276262Sgreen		/* fill default hostkeys for protocols */
14376262Sgreen		if (options->protocol & SSH_PROTO_1)
14492559Sdes			options->host_key_files[options->num_host_key_files++] =
14592559Sdes			    _PATH_HOST_KEY_FILE;
14692559Sdes		if (options->protocol & SSH_PROTO_2) {
14792559Sdes			options->host_key_files[options->num_host_key_files++] =
14892559Sdes			    _PATH_HOST_DSA_KEY_FILE;
14992559Sdes		}
15076262Sgreen	}
15157429Smarkm	if (options->num_ports == 0)
15257429Smarkm		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
15357429Smarkm	if (options->listen_addrs == NULL)
15476262Sgreen		add_listen_addr(options, NULL, 0);
15560576Skris	if (options->pid_file == NULL)
15676262Sgreen		options->pid_file = _PATH_SSH_DAEMON_PID_FILE;
15757429Smarkm	if (options->server_key_bits == -1)
15857429Smarkm		options->server_key_bits = 768;
15957429Smarkm	if (options->login_grace_time == -1)
16099048Sdes		options->login_grace_time = 120;
16157429Smarkm	if (options->key_regeneration_time == -1)
16257429Smarkm		options->key_regeneration_time = 3600;
16376262Sgreen	if (options->permit_root_login == PERMIT_NOT_SET)
16499048Sdes		options->permit_root_login = PERMIT_NO;
16557429Smarkm	if (options->ignore_rhosts == -1)
16657565Smarkm		options->ignore_rhosts = 1;
16757429Smarkm	if (options->ignore_user_known_hosts == -1)
16857429Smarkm		options->ignore_user_known_hosts = 0;
16957429Smarkm	if (options->print_motd == -1)
17057429Smarkm		options->print_motd = 1;
17176262Sgreen	if (options->print_lastlog == -1)
17276262Sgreen		options->print_lastlog = 1;
17357429Smarkm	if (options->x11_forwarding == -1)
17499048Sdes		options->x11_forwarding = 1;
17557429Smarkm	if (options->x11_display_offset == -1)
17657565Smarkm		options->x11_display_offset = 10;
17792559Sdes	if (options->x11_use_localhost == -1)
17892559Sdes		options->x11_use_localhost = 1;
17965674Skris	if (options->xauth_location == NULL)
18092559Sdes		options->xauth_location = _PATH_XAUTH;
18157429Smarkm	if (options->strict_modes == -1)
18257429Smarkm		options->strict_modes = 1;
18357429Smarkm	if (options->keepalives == -1)
18457429Smarkm		options->keepalives = 1;
18592559Sdes	if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
18657429Smarkm		options->log_facility = SYSLOG_FACILITY_AUTH;
18792559Sdes	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
18857429Smarkm		options->log_level = SYSLOG_LEVEL_INFO;
18957429Smarkm	if (options->rhosts_authentication == -1)
19057429Smarkm		options->rhosts_authentication = 0;
19157429Smarkm	if (options->rhosts_rsa_authentication == -1)
19257565Smarkm		options->rhosts_rsa_authentication = 0;
19376262Sgreen	if (options->hostbased_authentication == -1)
19476262Sgreen		options->hostbased_authentication = 0;
19576262Sgreen	if (options->hostbased_uses_name_from_packet_only == -1)
19676262Sgreen		options->hostbased_uses_name_from_packet_only = 0;
19757429Smarkm	if (options->rsa_authentication == -1)
19857429Smarkm		options->rsa_authentication = 1;
19976262Sgreen	if (options->pubkey_authentication == -1)
20076262Sgreen		options->pubkey_authentication = 1;
20199048Sdes#if defined(KRB4) && defined(KRB5)
20299048Sdes        if (options->kerberos_authentication == -1)
20399048Sdes                options->kerberos_authentication =
20499048Sdes                    (access(KEYFILE, R_OK) == 0 ||
20599048Sdes		    access(krb5_defkeyname, R_OK) == 0);
20699048Sdes#elif defined(KRB4)
20799048Sdes        if (options->kerberos_authentication == -1)
20899048Sdes                options->kerberos_authentication =
20999048Sdes		    (access(KEYFILE, R_OK) == 0);
21099048Sdes#elif defined(KRB5)
21199048Sdes	if (options->kerberos_authentication == -1)
21299048Sdes                options->kerberos_authentication =
21399048Sdes                    (access(krb5_defkeyname, R_OK) == 0);
21499048Sdes#endif
21598941Sdes#if defined(KRB4) || defined(KRB5)
21692559Sdes	if (options->kerberos_or_local_passwd == -1)
21792559Sdes		options->kerberos_or_local_passwd = 1;
21892559Sdes	if (options->kerberos_ticket_cleanup == -1)
21992559Sdes		options->kerberos_ticket_cleanup = 1;
22073400Sassar#endif
22192559Sdes#if defined(AFS) || defined(KRB5)
22292559Sdes	if (options->kerberos_tgt_passing == -1)
22392559Sdes		options->kerberos_tgt_passing = 0;
22492559Sdes#endif
22557429Smarkm#ifdef AFS
22657429Smarkm	if (options->afs_token_passing == -1)
22798684Sdes		options->afs_token_passing = 0;
22892559Sdes#endif
22957429Smarkm	if (options->password_authentication == -1)
23057429Smarkm		options->password_authentication = 1;
23169591Sgreen	if (options->kbd_interactive_authentication == -1)
23269591Sgreen		options->kbd_interactive_authentication = 0;
23392559Sdes	if (options->challenge_response_authentication == -1)
23495456Sdes		options->challenge_response_authentication = 1;
23557429Smarkm	if (options->permit_empty_passwd == -1)
23657565Smarkm		options->permit_empty_passwd = 0;
23757429Smarkm	if (options->use_login == -1)
23857429Smarkm		options->use_login = 0;
23998684Sdes	if (options->compression == -1)
24098684Sdes		options->compression = 1;
24169591Sgreen	if (options->allow_tcp_forwarding == -1)
24269591Sgreen		options->allow_tcp_forwarding = 1;
24360576Skris	if (options->gateway_ports == -1)
24460576Skris		options->gateway_ports = 0;
24565674Skris	if (options->max_startups == -1)
24665674Skris		options->max_startups = 10;
24765674Skris	if (options->max_startups_rate == -1)
24865674Skris		options->max_startups_rate = 100;		/* 100% */
24965674Skris	if (options->max_startups_begin == -1)
25065674Skris		options->max_startups_begin = options->max_startups;
25192559Sdes	if (options->verify_reverse_mapping == -1)
25292559Sdes		options->verify_reverse_mapping = 0;
25376262Sgreen	if (options->client_alive_interval == -1)
25492559Sdes		options->client_alive_interval = 0;
25576262Sgreen	if (options->client_alive_count_max == -1)
25676262Sgreen		options->client_alive_count_max = 3;
25792559Sdes	if (options->authorized_keys_file2 == NULL) {
25892559Sdes		/* authorized_keys_file2 falls back to authorized_keys_file */
25992559Sdes		if (options->authorized_keys_file != NULL)
26092559Sdes			options->authorized_keys_file2 = options->authorized_keys_file;
26192559Sdes		else
26292559Sdes			options->authorized_keys_file2 = _PATH_SSH_USER_PERMITTED_KEYS2;
26392559Sdes	}
26492559Sdes	if (options->authorized_keys_file == NULL)
26592559Sdes		options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS;
26698684Sdes
26798941Sdes	/* Turn privilege separation on by default */
26898684Sdes	if (use_privsep == -1)
26998941Sdes		use_privsep = 1;
27098941Sdes
27199063Sdes#if !defined(HAVE_MMAP_ANON_SHARED)
27298941Sdes	if (use_privsep && options->compression == 1) {
27398941Sdes		error("This platform does not support both privilege "
27498941Sdes		    "separation and compression");
27598941Sdes		error("Compression disabled");
27698941Sdes		options->compression = 0;
27798941Sdes	}
27898941Sdes#endif
27998941Sdes
28057429Smarkm}
28157429Smarkm
28257429Smarkm/* Keyword tokens. */
28357429Smarkmtypedef enum {
28457429Smarkm	sBadOption,		/* == unknown option */
28598941Sdes	/* Portable-specific options */
28698941Sdes	sPAMAuthenticationViaKbdInt,
28798941Sdes	/* Standard Options */
28857429Smarkm	sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
28957429Smarkm	sPermitRootLogin, sLogFacility, sLogLevel,
29057429Smarkm	sRhostsAuthentication, sRhostsRSAAuthentication, sRSAAuthentication,
29173400Sassar#if defined(KRB4) || defined(KRB5)
29292559Sdes	sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
29373400Sassar#endif
29492559Sdes#if defined(AFS) || defined(KRB5)
29592559Sdes	sKerberosTgtPassing,
29657429Smarkm#endif
29757429Smarkm#ifdef AFS
29892559Sdes	sAFSTokenPassing,
29957429Smarkm#endif
30076262Sgreen	sChallengeResponseAuthentication,
30169591Sgreen	sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress,
30276262Sgreen	sPrintMotd, sPrintLastLog, sIgnoreRhosts,
30392559Sdes	sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
30492559Sdes	sStrictModes, sEmptyPasswd, sKeepAlives,
30598684Sdes	sUseLogin, sAllowTcpForwarding, sCompression,
30669591Sgreen	sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
30776262Sgreen	sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
30876262Sgreen	sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups,
30992559Sdes	sBanner, sVerifyReverseMapping, sHostbasedAuthentication,
31092559Sdes	sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
31192559Sdes	sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
31298684Sdes	sUsePrivilegeSeparation,
31399047Sdes	sVersionAddendum,
31492559Sdes	sDeprecated
31557429Smarkm} ServerOpCodes;
31657429Smarkm
31757429Smarkm/* Textual representation of the tokens. */
31857429Smarkmstatic struct {
31957429Smarkm	const char *name;
32057429Smarkm	ServerOpCodes opcode;
32157429Smarkm} keywords[] = {
32298941Sdes	/* Portable-specific options */
32399048Sdes#if 0
32498941Sdes	{ "PAMAuthenticationViaKbdInt", sPAMAuthenticationViaKbdInt },
32599048Sdes#endif
32698941Sdes	/* Standard Options */
32757429Smarkm	{ "port", sPort },
32857429Smarkm	{ "hostkey", sHostKeyFile },
32976262Sgreen	{ "hostdsakey", sHostKeyFile },					/* alias */
33076262Sgreen	{ "pidfile", sPidFile },
33157429Smarkm	{ "serverkeybits", sServerKeyBits },
33257429Smarkm	{ "logingracetime", sLoginGraceTime },
33357429Smarkm	{ "keyregenerationinterval", sKeyRegenerationTime },
33457429Smarkm	{ "permitrootlogin", sPermitRootLogin },
33557429Smarkm	{ "syslogfacility", sLogFacility },
33657429Smarkm	{ "loglevel", sLogLevel },
33757429Smarkm	{ "rhostsauthentication", sRhostsAuthentication },
33857429Smarkm	{ "rhostsrsaauthentication", sRhostsRSAAuthentication },
33976262Sgreen	{ "hostbasedauthentication", sHostbasedAuthentication },
34076262Sgreen	{ "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly },
34192559Sdes	{ "rsaauthentication", sRSAAuthentication },
34276262Sgreen	{ "pubkeyauthentication", sPubkeyAuthentication },
34376262Sgreen	{ "dsaauthentication", sPubkeyAuthentication },			/* alias */
34473400Sassar#if defined(KRB4) || defined(KRB5)
34573400Sassar	{ "kerberosauthentication", sKerberosAuthentication },
34692559Sdes	{ "kerberosorlocalpasswd", sKerberosOrLocalPasswd },
34792559Sdes	{ "kerberosticketcleanup", sKerberosTicketCleanup },
34873400Sassar#endif
34992559Sdes#if defined(AFS) || defined(KRB5)
35092559Sdes	{ "kerberostgtpassing", sKerberosTgtPassing },
35157429Smarkm#endif
35257429Smarkm#ifdef AFS
35357429Smarkm	{ "afstokenpassing", sAFSTokenPassing },
35457429Smarkm#endif
35557429Smarkm	{ "passwordauthentication", sPasswordAuthentication },
35669591Sgreen	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication },
35776262Sgreen	{ "challengeresponseauthentication", sChallengeResponseAuthentication },
35876262Sgreen	{ "skeyauthentication", sChallengeResponseAuthentication }, /* alias */
35998941Sdes	{ "checkmail", sDeprecated },
36057429Smarkm	{ "listenaddress", sListenAddress },
36157429Smarkm	{ "printmotd", sPrintMotd },
36276262Sgreen	{ "printlastlog", sPrintLastLog },
36357429Smarkm	{ "ignorerhosts", sIgnoreRhosts },
36457429Smarkm	{ "ignoreuserknownhosts", sIgnoreUserKnownHosts },
36557429Smarkm	{ "x11forwarding", sX11Forwarding },
36657429Smarkm	{ "x11displayoffset", sX11DisplayOffset },
36792559Sdes	{ "x11uselocalhost", sX11UseLocalhost },
36865674Skris	{ "xauthlocation", sXAuthLocation },
36957429Smarkm	{ "strictmodes", sStrictModes },
37057429Smarkm	{ "permitemptypasswords", sEmptyPasswd },
37157429Smarkm	{ "uselogin", sUseLogin },
37298684Sdes	{ "compression", sCompression },
37357429Smarkm	{ "keepalive", sKeepAlives },
37469591Sgreen	{ "allowtcpforwarding", sAllowTcpForwarding },
37557429Smarkm	{ "allowusers", sAllowUsers },
37657429Smarkm	{ "denyusers", sDenyUsers },
37757429Smarkm	{ "allowgroups", sAllowGroups },
37857429Smarkm	{ "denygroups", sDenyGroups },
37960576Skris	{ "ciphers", sCiphers },
38076262Sgreen	{ "macs", sMacs },
38160576Skris	{ "protocol", sProtocol },
38260576Skris	{ "gatewayports", sGatewayPorts },
38365674Skris	{ "subsystem", sSubsystem },
38465674Skris	{ "maxstartups", sMaxStartups },
38576262Sgreen	{ "banner", sBanner },
38692559Sdes	{ "verifyreversemapping", sVerifyReverseMapping },
38792559Sdes	{ "reversemappingcheck", sVerifyReverseMapping },
38876262Sgreen	{ "clientaliveinterval", sClientAliveInterval },
38976262Sgreen	{ "clientalivecountmax", sClientAliveCountMax },
39092559Sdes	{ "authorizedkeysfile", sAuthorizedKeysFile },
39192559Sdes	{ "authorizedkeysfile2", sAuthorizedKeysFile2 },
39298684Sdes	{ "useprivilegeseparation", sUsePrivilegeSeparation},
39399047Sdes	{ "versionaddendum", sVersionAddendum },
39492559Sdes	{ NULL, sBadOption }
39557429Smarkm};
39657429Smarkm
39757429Smarkm/*
39876262Sgreen * Returns the number of the token pointed to by cp or sBadOption.
39957429Smarkm */
40057429Smarkm
40160576Skrisstatic ServerOpCodes
40257429Smarkmparse_token(const char *cp, const char *filename,
40357429Smarkm	    int linenum)
40457429Smarkm{
40576262Sgreen	u_int i;
40657429Smarkm
40757429Smarkm	for (i = 0; keywords[i].name; i++)
40857429Smarkm		if (strcasecmp(cp, keywords[i].name) == 0)
40957429Smarkm			return keywords[i].opcode;
41057429Smarkm
41176262Sgreen	error("%s: line %d: Bad configuration option: %s",
41276262Sgreen	    filename, linenum, cp);
41357429Smarkm	return sBadOption;
41457429Smarkm}
41557429Smarkm
41692559Sdesstatic void
41776262Sgreenadd_listen_addr(ServerOptions *options, char *addr, u_short port)
41857429Smarkm{
41957429Smarkm	int i;
42057429Smarkm
42157429Smarkm	if (options->num_ports == 0)
42257429Smarkm		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
42376262Sgreen	if (port == 0)
42476262Sgreen		for (i = 0; i < options->num_ports; i++)
42576262Sgreen			add_one_listen_addr(options, addr, options->ports[i]);
42676262Sgreen	else
42776262Sgreen		add_one_listen_addr(options, addr, port);
42857429Smarkm}
42957429Smarkm
43092559Sdesstatic void
43176262Sgreenadd_one_listen_addr(ServerOptions *options, char *addr, u_short port)
43276262Sgreen{
43376262Sgreen	struct addrinfo hints, *ai, *aitop;
43476262Sgreen	char strport[NI_MAXSERV];
43576262Sgreen	int gaierr;
43676262Sgreen
43776262Sgreen	memset(&hints, 0, sizeof(hints));
43876262Sgreen	hints.ai_family = IPv4or6;
43976262Sgreen	hints.ai_socktype = SOCK_STREAM;
44076262Sgreen	hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
44199063Sdes	snprintf(strport, sizeof strport, "%u", port);
44276262Sgreen	if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
44376262Sgreen		fatal("bad addr or host: %s (%s)",
44476262Sgreen		    addr ? addr : "<NULL>",
44576262Sgreen		    gai_strerror(gaierr));
44676262Sgreen	for (ai = aitop; ai->ai_next; ai = ai->ai_next)
44776262Sgreen		;
44876262Sgreen	ai->ai_next = options->listen_addrs;
44976262Sgreen	options->listen_addrs = aitop;
45076262Sgreen}
45176262Sgreen
45292559Sdesint
45392559Sdesprocess_server_config_line(ServerOptions *options, char *line,
45492559Sdes    const char *filename, int linenum)
45557429Smarkm{
45676262Sgreen	char *cp, **charptr, *arg, *p;
45799063Sdes	int *intptr, value, i, n;
45857429Smarkm	ServerOpCodes opcode;
45957429Smarkm
46092559Sdes	cp = line;
46192559Sdes	arg = strdelim(&cp);
46292559Sdes	/* Ignore leading whitespace */
46392559Sdes	if (*arg == '\0')
46465674Skris		arg = strdelim(&cp);
46592559Sdes	if (!arg || !*arg || *arg == '#')
46692559Sdes		return 0;
46792559Sdes	intptr = NULL;
46892559Sdes	charptr = NULL;
46992559Sdes	opcode = parse_token(arg, filename, linenum);
47092559Sdes	switch (opcode) {
47198941Sdes	/* Portable-specific options */
47298941Sdes	case sPAMAuthenticationViaKbdInt:
47398941Sdes		intptr = &options->pam_authentication_via_kbd_int;
47498941Sdes		goto parse_flag;
47598941Sdes
47698941Sdes	/* Standard Options */
47792559Sdes	case sBadOption:
47892559Sdes		return -1;
47992559Sdes	case sPort:
48092559Sdes		/* ignore ports from configfile if cmdline specifies ports */
48192559Sdes		if (options->ports_from_cmdline)
48292559Sdes			return 0;
48392559Sdes		if (options->listen_addrs != NULL)
48492559Sdes			fatal("%s line %d: ports must be specified before "
48592559Sdes			    "ListenAddress.", filename, linenum);
48692559Sdes		if (options->num_ports >= MAX_PORTS)
48792559Sdes			fatal("%s line %d: too many ports.",
48892559Sdes			    filename, linenum);
48992559Sdes		arg = strdelim(&cp);
49092559Sdes		if (!arg || *arg == '\0')
49192559Sdes			fatal("%s line %d: missing port number.",
49292559Sdes			    filename, linenum);
49392559Sdes		options->ports[options->num_ports++] = a2port(arg);
49492559Sdes		if (options->ports[options->num_ports-1] == 0)
49592559Sdes			fatal("%s line %d: Badly formatted port number.",
49692559Sdes			    filename, linenum);
49792559Sdes		break;
49857429Smarkm
49992559Sdes	case sServerKeyBits:
50092559Sdes		intptr = &options->server_key_bits;
50157429Smarkmparse_int:
50292559Sdes		arg = strdelim(&cp);
50392559Sdes		if (!arg || *arg == '\0')
50492559Sdes			fatal("%s line %d: missing integer value.",
50592559Sdes			    filename, linenum);
50692559Sdes		value = atoi(arg);
50792559Sdes		if (*intptr == -1)
50892559Sdes			*intptr = value;
50992559Sdes		break;
51057429Smarkm
51192559Sdes	case sLoginGraceTime:
51292559Sdes		intptr = &options->login_grace_time;
51392559Sdesparse_time:
51492559Sdes		arg = strdelim(&cp);
51592559Sdes		if (!arg || *arg == '\0')
51692559Sdes			fatal("%s line %d: missing time value.",
51792559Sdes			    filename, linenum);
51892559Sdes		if ((value = convtime(arg)) == -1)
51992559Sdes			fatal("%s line %d: invalid time value.",
52092559Sdes			    filename, linenum);
52192559Sdes		if (*intptr == -1)
52292559Sdes			*intptr = value;
52392559Sdes		break;
52457429Smarkm
52592559Sdes	case sKeyRegenerationTime:
52692559Sdes		intptr = &options->key_regeneration_time;
52792559Sdes		goto parse_time;
52857429Smarkm
52992559Sdes	case sListenAddress:
53092559Sdes		arg = strdelim(&cp);
53192559Sdes		if (!arg || *arg == '\0' || strncmp(arg, "[]", 2) == 0)
53292559Sdes			fatal("%s line %d: missing inet addr.",
53392559Sdes			    filename, linenum);
53492559Sdes		if (*arg == '[') {
53592559Sdes			if ((p = strchr(arg, ']')) == NULL)
53692559Sdes				fatal("%s line %d: bad ipv6 inet addr usage.",
53757429Smarkm				    filename, linenum);
53892559Sdes			arg++;
53992559Sdes			memmove(p, p+1, strlen(p+1)+1);
54092559Sdes		} else if (((p = strchr(arg, ':')) == NULL) ||
54192559Sdes			    (strchr(p+1, ':') != NULL)) {
54292559Sdes			add_listen_addr(options, arg, 0);
54357429Smarkm			break;
54492559Sdes		}
54592559Sdes		if (*p == ':') {
54692559Sdes			u_short port;
54757429Smarkm
54892559Sdes			p++;
54992559Sdes			if (*p == '\0')
55092559Sdes				fatal("%s line %d: bad inet addr:port usage.",
55160576Skris				    filename, linenum);
55292559Sdes			else {
55392559Sdes				*(p-1) = '\0';
55492559Sdes				if ((port = a2port(p)) == 0)
55592559Sdes					fatal("%s line %d: bad port number.",
55692559Sdes					    filename, linenum);
55792559Sdes				add_listen_addr(options, arg, port);
55857429Smarkm			}
55992559Sdes		} else if (*p == '\0')
56092559Sdes			add_listen_addr(options, arg, 0);
56192559Sdes		else
56292559Sdes			fatal("%s line %d: bad inet addr usage.",
56392559Sdes			    filename, linenum);
56492559Sdes		break;
56557429Smarkm
56692559Sdes	case sHostKeyFile:
56792559Sdes		intptr = &options->num_host_key_files;
56892559Sdes		if (*intptr >= MAX_HOSTKEYS)
56992559Sdes			fatal("%s line %d: too many host keys specified (max %d).",
57092559Sdes			    filename, linenum, MAX_HOSTKEYS);
57192559Sdes		charptr = &options->host_key_files[*intptr];
57292559Sdesparse_filename:
57392559Sdes		arg = strdelim(&cp);
57492559Sdes		if (!arg || *arg == '\0')
57592559Sdes			fatal("%s line %d: missing file name.",
57692559Sdes			    filename, linenum);
57792559Sdes		if (*charptr == NULL) {
57892559Sdes			*charptr = tilde_expand_filename(arg, getuid());
57992559Sdes			/* increase optional counter */
58092559Sdes			if (intptr != NULL)
58192559Sdes				*intptr = *intptr + 1;
58292559Sdes		}
58392559Sdes		break;
58460576Skris
58592559Sdes	case sPidFile:
58692559Sdes		charptr = &options->pid_file;
58792559Sdes		goto parse_filename;
58857429Smarkm
58992559Sdes	case sPermitRootLogin:
59092559Sdes		intptr = &options->permit_root_login;
59192559Sdes		arg = strdelim(&cp);
59292559Sdes		if (!arg || *arg == '\0')
59392559Sdes			fatal("%s line %d: missing yes/"
59492559Sdes			    "without-password/forced-commands-only/no "
59592559Sdes			    "argument.", filename, linenum);
59692559Sdes		value = 0;	/* silence compiler */
59792559Sdes		if (strcmp(arg, "without-password") == 0)
59892559Sdes			value = PERMIT_NO_PASSWD;
59992559Sdes		else if (strcmp(arg, "forced-commands-only") == 0)
60092559Sdes			value = PERMIT_FORCED_ONLY;
60192559Sdes		else if (strcmp(arg, "yes") == 0)
60292559Sdes			value = PERMIT_YES;
60392559Sdes		else if (strcmp(arg, "no") == 0)
60492559Sdes			value = PERMIT_NO;
60592559Sdes		else
60692559Sdes			fatal("%s line %d: Bad yes/"
60792559Sdes			    "without-password/forced-commands-only/no "
60892559Sdes			    "argument: %s", filename, linenum, arg);
60992559Sdes		if (*intptr == -1)
61092559Sdes			*intptr = value;
61192559Sdes		break;
61292559Sdes
61392559Sdes	case sIgnoreRhosts:
61492559Sdes		intptr = &options->ignore_rhosts;
61557429Smarkmparse_flag:
61692559Sdes		arg = strdelim(&cp);
61792559Sdes		if (!arg || *arg == '\0')
61892559Sdes			fatal("%s line %d: missing yes/no argument.",
61992559Sdes			    filename, linenum);
62092559Sdes		value = 0;	/* silence compiler */
62192559Sdes		if (strcmp(arg, "yes") == 0)
62292559Sdes			value = 1;
62392559Sdes		else if (strcmp(arg, "no") == 0)
62492559Sdes			value = 0;
62592559Sdes		else
62692559Sdes			fatal("%s line %d: Bad yes/no argument: %s",
62792559Sdes				filename, linenum, arg);
62892559Sdes		if (*intptr == -1)
62992559Sdes			*intptr = value;
63092559Sdes		break;
63157429Smarkm
63292559Sdes	case sIgnoreUserKnownHosts:
63392559Sdes		intptr = &options->ignore_user_known_hosts;
63492559Sdes		goto parse_flag;
63557429Smarkm
63692559Sdes	case sRhostsAuthentication:
63792559Sdes		intptr = &options->rhosts_authentication;
63892559Sdes		goto parse_flag;
63957429Smarkm
64092559Sdes	case sRhostsRSAAuthentication:
64192559Sdes		intptr = &options->rhosts_rsa_authentication;
64292559Sdes		goto parse_flag;
64357429Smarkm
64492559Sdes	case sHostbasedAuthentication:
64592559Sdes		intptr = &options->hostbased_authentication;
64692559Sdes		goto parse_flag;
64776262Sgreen
64892559Sdes	case sHostbasedUsesNameFromPacketOnly:
64992559Sdes		intptr = &options->hostbased_uses_name_from_packet_only;
65092559Sdes		goto parse_flag;
65176262Sgreen
65292559Sdes	case sRSAAuthentication:
65392559Sdes		intptr = &options->rsa_authentication;
65492559Sdes		goto parse_flag;
65557429Smarkm
65692559Sdes	case sPubkeyAuthentication:
65792559Sdes		intptr = &options->pubkey_authentication;
65892559Sdes		goto parse_flag;
65973400Sassar#if defined(KRB4) || defined(KRB5)
66092559Sdes	case sKerberosAuthentication:
66192559Sdes		intptr = &options->kerberos_authentication;
66292559Sdes		goto parse_flag;
66357429Smarkm
66492559Sdes	case sKerberosOrLocalPasswd:
66592559Sdes		intptr = &options->kerberos_or_local_passwd;
66692559Sdes		goto parse_flag;
66792559Sdes
66892559Sdes	case sKerberosTicketCleanup:
66992559Sdes		intptr = &options->kerberos_ticket_cleanup;
67092559Sdes		goto parse_flag;
67157429Smarkm#endif
67292559Sdes#if defined(AFS) || defined(KRB5)
67392559Sdes	case sKerberosTgtPassing:
67492559Sdes		intptr = &options->kerberos_tgt_passing;
67592559Sdes		goto parse_flag;
67692559Sdes#endif
67792559Sdes#ifdef AFS
67892559Sdes	case sAFSTokenPassing:
67992559Sdes		intptr = &options->afs_token_passing;
68092559Sdes		goto parse_flag;
68192559Sdes#endif
68257429Smarkm
68392559Sdes	case sPasswordAuthentication:
68492559Sdes		intptr = &options->password_authentication;
68592559Sdes		goto parse_flag;
68657565Smarkm
68792559Sdes	case sKbdInteractiveAuthentication:
68892559Sdes		intptr = &options->kbd_interactive_authentication;
68992559Sdes		goto parse_flag;
69057429Smarkm
69192559Sdes	case sChallengeResponseAuthentication:
69292559Sdes		intptr = &options->challenge_response_authentication;
69392559Sdes		goto parse_flag;
69457429Smarkm
69592559Sdes	case sPrintMotd:
69692559Sdes		intptr = &options->print_motd;
69792559Sdes		goto parse_flag;
69857429Smarkm
69992559Sdes	case sPrintLastLog:
70092559Sdes		intptr = &options->print_lastlog;
70192559Sdes		goto parse_flag;
70269591Sgreen
70392559Sdes	case sX11Forwarding:
70492559Sdes		intptr = &options->x11_forwarding;
70592559Sdes		goto parse_flag;
70657429Smarkm
70792559Sdes	case sX11DisplayOffset:
70892559Sdes		intptr = &options->x11_display_offset;
70992559Sdes		goto parse_int;
71057429Smarkm
71192559Sdes	case sX11UseLocalhost:
71292559Sdes		intptr = &options->x11_use_localhost;
71392559Sdes		goto parse_flag;
71457429Smarkm
71592559Sdes	case sXAuthLocation:
71692559Sdes		charptr = &options->xauth_location;
71792559Sdes		goto parse_filename;
71876262Sgreen
71992559Sdes	case sStrictModes:
72092559Sdes		intptr = &options->strict_modes;
72192559Sdes		goto parse_flag;
72257429Smarkm
72392559Sdes	case sKeepAlives:
72492559Sdes		intptr = &options->keepalives;
72592559Sdes		goto parse_flag;
72657429Smarkm
72792559Sdes	case sEmptyPasswd:
72892559Sdes		intptr = &options->permit_empty_passwd;
72992559Sdes		goto parse_flag;
73076262Sgreen
73192559Sdes	case sUseLogin:
73292559Sdes		intptr = &options->use_login;
73392559Sdes		goto parse_flag;
73457429Smarkm
73598684Sdes	case sCompression:
73698684Sdes		intptr = &options->compression;
73798684Sdes		goto parse_flag;
73898684Sdes
73992559Sdes	case sGatewayPorts:
74092559Sdes		intptr = &options->gateway_ports;
74192559Sdes		goto parse_flag;
74257429Smarkm
74392559Sdes	case sVerifyReverseMapping:
74492559Sdes		intptr = &options->verify_reverse_mapping;
74592559Sdes		goto parse_flag;
74657429Smarkm
74792559Sdes	case sLogFacility:
74892559Sdes		intptr = (int *) &options->log_facility;
74992559Sdes		arg = strdelim(&cp);
75092559Sdes		value = log_facility_number(arg);
75192559Sdes		if (value == SYSLOG_FACILITY_NOT_SET)
75292559Sdes			fatal("%.200s line %d: unsupported log facility '%s'",
75392559Sdes			    filename, linenum, arg ? arg : "<NONE>");
75492559Sdes		if (*intptr == -1)
75592559Sdes			*intptr = (SyslogFacility) value;
75692559Sdes		break;
75757429Smarkm
75892559Sdes	case sLogLevel:
75992559Sdes		intptr = (int *) &options->log_level;
76092559Sdes		arg = strdelim(&cp);
76192559Sdes		value = log_level_number(arg);
76292559Sdes		if (value == SYSLOG_LEVEL_NOT_SET)
76392559Sdes			fatal("%.200s line %d: unsupported log level '%s'",
76492559Sdes			    filename, linenum, arg ? arg : "<NONE>");
76592559Sdes		if (*intptr == -1)
76692559Sdes			*intptr = (LogLevel) value;
76792559Sdes		break;
76860576Skris
76992559Sdes	case sAllowTcpForwarding:
77092559Sdes		intptr = &options->allow_tcp_forwarding;
77192559Sdes		goto parse_flag;
77276262Sgreen
77398684Sdes	case sUsePrivilegeSeparation:
77498684Sdes		intptr = &use_privsep;
77598684Sdes		goto parse_flag;
77698684Sdes
77792559Sdes	case sAllowUsers:
77892559Sdes		while ((arg = strdelim(&cp)) && *arg != '\0') {
77992559Sdes			if (options->num_allow_users >= MAX_ALLOW_USERS)
78092559Sdes				fatal("%s line %d: too many allow users.",
78192559Sdes				    filename, linenum);
78299063Sdes			options->allow_users[options->num_allow_users++] =
78399063Sdes			    xstrdup(arg);
78492559Sdes		}
78592559Sdes		break;
78657429Smarkm
78792559Sdes	case sDenyUsers:
78892559Sdes		while ((arg = strdelim(&cp)) && *arg != '\0') {
78992559Sdes			if (options->num_deny_users >= MAX_DENY_USERS)
79092559Sdes				fatal( "%s line %d: too many deny users.",
79192559Sdes				    filename, linenum);
79299063Sdes			options->deny_users[options->num_deny_users++] =
79399063Sdes			    xstrdup(arg);
79492559Sdes		}
79592559Sdes		break;
79657429Smarkm
79792559Sdes	case sAllowGroups:
79892559Sdes		while ((arg = strdelim(&cp)) && *arg != '\0') {
79992559Sdes			if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
80092559Sdes				fatal("%s line %d: too many allow groups.",
80192559Sdes				    filename, linenum);
80299063Sdes			options->allow_groups[options->num_allow_groups++] =
80399063Sdes			    xstrdup(arg);
80492559Sdes		}
80592559Sdes		break;
80669591Sgreen
80792559Sdes	case sDenyGroups:
80892559Sdes		while ((arg = strdelim(&cp)) && *arg != '\0') {
80992559Sdes			if (options->num_deny_groups >= MAX_DENY_GROUPS)
81092559Sdes				fatal("%s line %d: too many deny groups.",
81192559Sdes				    filename, linenum);
81292559Sdes			options->deny_groups[options->num_deny_groups++] = xstrdup(arg);
81392559Sdes		}
81492559Sdes		break;
81557429Smarkm
81692559Sdes	case sCiphers:
81792559Sdes		arg = strdelim(&cp);
81892559Sdes		if (!arg || *arg == '\0')
81992559Sdes			fatal("%s line %d: Missing argument.", filename, linenum);
82092559Sdes		if (!ciphers_valid(arg))
82192559Sdes			fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
82292559Sdes			    filename, linenum, arg ? arg : "<NONE>");
82392559Sdes		if (options->ciphers == NULL)
82492559Sdes			options->ciphers = xstrdup(arg);
82592559Sdes		break;
82657429Smarkm
82792559Sdes	case sMacs:
82892559Sdes		arg = strdelim(&cp);
82992559Sdes		if (!arg || *arg == '\0')
83092559Sdes			fatal("%s line %d: Missing argument.", filename, linenum);
83192559Sdes		if (!mac_valid(arg))
83292559Sdes			fatal("%s line %d: Bad SSH2 mac spec '%s'.",
83392559Sdes			    filename, linenum, arg ? arg : "<NONE>");
83492559Sdes		if (options->macs == NULL)
83592559Sdes			options->macs = xstrdup(arg);
83692559Sdes		break;
83757429Smarkm
83892559Sdes	case sProtocol:
83992559Sdes		intptr = &options->protocol;
84092559Sdes		arg = strdelim(&cp);
84192559Sdes		if (!arg || *arg == '\0')
84292559Sdes			fatal("%s line %d: Missing argument.", filename, linenum);
84392559Sdes		value = proto_spec(arg);
84492559Sdes		if (value == SSH_PROTO_UNKNOWN)
84592559Sdes			fatal("%s line %d: Bad protocol spec '%s'.",
84692559Sdes			    filename, linenum, arg ? arg : "<NONE>");
84792559Sdes		if (*intptr == SSH_PROTO_UNKNOWN)
84892559Sdes			*intptr = value;
84992559Sdes		break;
85057429Smarkm
85192559Sdes	case sSubsystem:
85292559Sdes		if (options->num_subsystems >= MAX_SUBSYSTEMS) {
85392559Sdes			fatal("%s line %d: too many subsystems defined.",
85492559Sdes			    filename, linenum);
85592559Sdes		}
85692559Sdes		arg = strdelim(&cp);
85792559Sdes		if (!arg || *arg == '\0')
85892559Sdes			fatal("%s line %d: Missing subsystem name.",
85992559Sdes			    filename, linenum);
86092559Sdes		for (i = 0; i < options->num_subsystems; i++)
86192559Sdes			if (strcmp(arg, options->subsystem_name[i]) == 0)
86292559Sdes				fatal("%s line %d: Subsystem '%s' already defined.",
86392559Sdes				    filename, linenum, arg);
86492559Sdes		options->subsystem_name[options->num_subsystems] = xstrdup(arg);
86592559Sdes		arg = strdelim(&cp);
86692559Sdes		if (!arg || *arg == '\0')
86792559Sdes			fatal("%s line %d: Missing subsystem command.",
86892559Sdes			    filename, linenum);
86992559Sdes		options->subsystem_command[options->num_subsystems] = xstrdup(arg);
87092559Sdes		options->num_subsystems++;
87192559Sdes		break;
87260576Skris
87392559Sdes	case sMaxStartups:
87492559Sdes		arg = strdelim(&cp);
87592559Sdes		if (!arg || *arg == '\0')
87692559Sdes			fatal("%s line %d: Missing MaxStartups spec.",
87792559Sdes			    filename, linenum);
87892559Sdes		if ((n = sscanf(arg, "%d:%d:%d",
87992559Sdes		    &options->max_startups_begin,
88092559Sdes		    &options->max_startups_rate,
88192559Sdes		    &options->max_startups)) == 3) {
88292559Sdes			if (options->max_startups_begin >
88392559Sdes			    options->max_startups ||
88492559Sdes			    options->max_startups_rate > 100 ||
88592559Sdes			    options->max_startups_rate < 1)
88692559Sdes				fatal("%s line %d: Illegal MaxStartups spec.",
88792559Sdes				    filename, linenum);
88892559Sdes		} else if (n != 1)
88992559Sdes			fatal("%s line %d: Illegal MaxStartups spec.",
89092559Sdes			    filename, linenum);
89192559Sdes		else
89292559Sdes			options->max_startups = options->max_startups_begin;
89392559Sdes		break;
89476262Sgreen
89592559Sdes	case sBanner:
89692559Sdes		charptr = &options->banner;
89792559Sdes		goto parse_filename;
89892559Sdes	/*
89992559Sdes	 * These options can contain %X options expanded at
90092559Sdes	 * connect time, so that you can specify paths like:
90192559Sdes	 *
90292559Sdes	 * AuthorizedKeysFile	/etc/ssh_keys/%u
90392559Sdes	 */
90492559Sdes	case sAuthorizedKeysFile:
90592559Sdes	case sAuthorizedKeysFile2:
90692559Sdes		charptr = (opcode == sAuthorizedKeysFile ) ?
90792559Sdes		    &options->authorized_keys_file :
90892559Sdes		    &options->authorized_keys_file2;
90992559Sdes		goto parse_filename;
91060576Skris
91192559Sdes	case sClientAliveInterval:
91292559Sdes		intptr = &options->client_alive_interval;
91392559Sdes		goto parse_time;
91457432Smarkm
91592559Sdes	case sClientAliveCountMax:
91692559Sdes		intptr = &options->client_alive_count_max;
91792559Sdes		goto parse_int;
91865674Skris
91999047Sdes	case sVersionAddendum:
92099047Sdes                ssh_version_set_addendum(strtok(cp, "\n"));
92199047Sdes                do {
92299047Sdes                        arg = strdelim(&cp);
92399047Sdes                } while (arg != NULL && *arg != '\0');
92499047Sdes		break;
92599047Sdes
92692559Sdes	case sDeprecated:
92792559Sdes		log("%s line %d: Deprecated option %s",
92892559Sdes		    filename, linenum, arg);
92992559Sdes		while (arg)
93092559Sdes		    arg = strdelim(&cp);
93192559Sdes		break;
93292559Sdes
93392559Sdes	default:
93492559Sdes		fatal("%s line %d: Missing handler for opcode %s (%d)",
93592559Sdes		    filename, linenum, arg, opcode);
93692559Sdes	}
93792559Sdes	if ((arg = strdelim(&cp)) != NULL && *arg != '\0')
93892559Sdes		fatal("%s line %d: garbage at end of line; \"%.200s\".",
93992559Sdes		    filename, linenum, arg);
94092559Sdes	return 0;
94192559Sdes}
94276227Sgreen
94392559Sdes/* Reads the server configuration file. */
94492559Sdes
94592559Sdesvoid
94692559Sdesread_server_config(ServerOptions *options, const char *filename)
94792559Sdes{
94899063Sdes	int linenum, bad_options = 0;
94999063Sdes	char line[1024];
95092559Sdes	FILE *f;
95192559Sdes
95292559Sdes	f = fopen(filename, "r");
95392559Sdes	if (!f) {
95492559Sdes		perror(filename);
95592559Sdes		exit(1);
95657429Smarkm	}
95792559Sdes	linenum = 0;
95892559Sdes	while (fgets(line, sizeof(line), f)) {
95992559Sdes		/* Update line number counter. */
96092559Sdes		linenum++;
96192559Sdes		if (process_server_config_line(options, line, filename, linenum) != 0)
96292559Sdes			bad_options++;
96392559Sdes	}
96457429Smarkm	fclose(f);
96576262Sgreen	if (bad_options > 0)
96692559Sdes		fatal("%s: terminating, %d bad configuration options",
96776262Sgreen		    filename, bad_options);
96857429Smarkm}
969