10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * Author: Tatu Ylonen <ylo@cs.hut.fi>
30Sstevel@tonic-gate  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
40Sstevel@tonic-gate  *                    All rights reserved
50Sstevel@tonic-gate  * Functions for reading the configuration files.
60Sstevel@tonic-gate  *
70Sstevel@tonic-gate  * As far as I am concerned, the code I have written for this software
80Sstevel@tonic-gate  * can be used freely for any purpose.  Any derived versions of this
90Sstevel@tonic-gate  * software must be clearly marked as such, and if the derived work is
100Sstevel@tonic-gate  * incompatible with the protocol description in the RFC file, it must be
110Sstevel@tonic-gate  * called by a name other than "ssh" or "Secure Shell".
120Sstevel@tonic-gate  */
130Sstevel@tonic-gate /*
143946Sjp161948  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
150Sstevel@tonic-gate  * Use is subject to license terms.
160Sstevel@tonic-gate  */
170Sstevel@tonic-gate 
180Sstevel@tonic-gate #include "includes.h"
190Sstevel@tonic-gate RCSID("$OpenBSD: readconf.c,v 1.100 2002/06/19 00:27:55 deraadt Exp $");
200Sstevel@tonic-gate 
210Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
220Sstevel@tonic-gate 
230Sstevel@tonic-gate #include "ssh.h"
240Sstevel@tonic-gate #include "xmalloc.h"
250Sstevel@tonic-gate #include "compat.h"
260Sstevel@tonic-gate #include "cipher.h"
270Sstevel@tonic-gate #include "pathnames.h"
280Sstevel@tonic-gate #include "log.h"
290Sstevel@tonic-gate #include "readconf.h"
300Sstevel@tonic-gate #include "match.h"
310Sstevel@tonic-gate #include "misc.h"
320Sstevel@tonic-gate #include "kex.h"
330Sstevel@tonic-gate #include "mac.h"
340Sstevel@tonic-gate 
350Sstevel@tonic-gate /* Format of the configuration file:
360Sstevel@tonic-gate 
370Sstevel@tonic-gate    # Configuration data is parsed as follows:
380Sstevel@tonic-gate    #  1. command line options
390Sstevel@tonic-gate    #  2. user-specific file
400Sstevel@tonic-gate    #  3. system-wide file
410Sstevel@tonic-gate    # Any configuration value is only changed the first time it is set.
420Sstevel@tonic-gate    # Thus, host-specific definitions should be at the beginning of the
430Sstevel@tonic-gate    # configuration file, and defaults at the end.
440Sstevel@tonic-gate 
450Sstevel@tonic-gate    # Host-specific declarations.  These may override anything above.  A single
460Sstevel@tonic-gate    # host may match multiple declarations; these are processed in the order
470Sstevel@tonic-gate    # that they are given in.
480Sstevel@tonic-gate 
490Sstevel@tonic-gate    Host *.ngs.fi ngs.fi
500Sstevel@tonic-gate      User foo
510Sstevel@tonic-gate 
520Sstevel@tonic-gate    Host fake.com
530Sstevel@tonic-gate      HostName another.host.name.real.org
540Sstevel@tonic-gate      User blaah
550Sstevel@tonic-gate      Port 34289
560Sstevel@tonic-gate      ForwardX11 no
570Sstevel@tonic-gate      ForwardAgent no
580Sstevel@tonic-gate 
590Sstevel@tonic-gate    Host books.com
600Sstevel@tonic-gate      RemoteForward 9999 shadows.cs.hut.fi:9999
610Sstevel@tonic-gate      Cipher 3des
620Sstevel@tonic-gate 
630Sstevel@tonic-gate    Host fascist.blob.com
640Sstevel@tonic-gate      Port 23123
650Sstevel@tonic-gate      User tylonen
660Sstevel@tonic-gate      RhostsAuthentication no
670Sstevel@tonic-gate      PasswordAuthentication no
680Sstevel@tonic-gate 
690Sstevel@tonic-gate    Host puukko.hut.fi
700Sstevel@tonic-gate      User t35124p
710Sstevel@tonic-gate      ProxyCommand ssh-proxy %h %p
720Sstevel@tonic-gate 
730Sstevel@tonic-gate    Host *.fr
740Sstevel@tonic-gate      PublicKeyAuthentication no
750Sstevel@tonic-gate 
760Sstevel@tonic-gate    Host *.su
770Sstevel@tonic-gate      Cipher none
780Sstevel@tonic-gate      PasswordAuthentication no
790Sstevel@tonic-gate 
800Sstevel@tonic-gate    # Defaults for various options
810Sstevel@tonic-gate    Host *
820Sstevel@tonic-gate      ForwardAgent no
830Sstevel@tonic-gate      ForwardX11 no
840Sstevel@tonic-gate      RhostsAuthentication yes
850Sstevel@tonic-gate      PasswordAuthentication yes
860Sstevel@tonic-gate      RSAAuthentication yes
870Sstevel@tonic-gate      RhostsRSAAuthentication yes
880Sstevel@tonic-gate      StrictHostKeyChecking yes
890Sstevel@tonic-gate      KeepAlives no
900Sstevel@tonic-gate      IdentityFile ~/.ssh/identity
910Sstevel@tonic-gate      Port 22
920Sstevel@tonic-gate      EscapeChar ~
930Sstevel@tonic-gate 
940Sstevel@tonic-gate */
950Sstevel@tonic-gate 
960Sstevel@tonic-gate /* Keyword tokens. */
970Sstevel@tonic-gate 
980Sstevel@tonic-gate typedef enum {
990Sstevel@tonic-gate 	oBadOption,
1004907Sjp161948 	oForwardAgent, oForwardX11, oForwardX11Trusted, oGatewayPorts,
1014907Sjp161948 	oRhostsAuthentication,
1020Sstevel@tonic-gate 	oPasswordAuthentication, oRSAAuthentication,
1030Sstevel@tonic-gate 	oChallengeResponseAuthentication, oXAuthLocation,
1040Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
1050Sstevel@tonic-gate 	oKerberosAuthentication,
1060Sstevel@tonic-gate #endif
1070Sstevel@tonic-gate #ifdef GSSAPI
1080Sstevel@tonic-gate 	oGssKeyEx, oGssAuthentication, oGssDelegateCreds,
1090Sstevel@tonic-gate #ifdef GSI
1100Sstevel@tonic-gate 	oGssGlobusDelegateLimitedCreds,
1110Sstevel@tonic-gate #endif /* GSI */
1120Sstevel@tonic-gate #endif /* GSSAPI */
1130Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
1140Sstevel@tonic-gate 	oKerberosTgtPassing,
1150Sstevel@tonic-gate #endif
1160Sstevel@tonic-gate #ifdef AFS
1170Sstevel@tonic-gate 	oAFSTokenPassing,
1180Sstevel@tonic-gate #endif
1190Sstevel@tonic-gate 	oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
1200Sstevel@tonic-gate 	oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
1210Sstevel@tonic-gate 	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
1220Sstevel@tonic-gate 	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
1230Sstevel@tonic-gate 	oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts,
1240Sstevel@tonic-gate 	oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
1250Sstevel@tonic-gate 	oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
1260Sstevel@tonic-gate 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
1270Sstevel@tonic-gate 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
1280Sstevel@tonic-gate 	oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
1290Sstevel@tonic-gate 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
1305243Sjp161948 	oFallBackToRsh, oUseRsh, oConnectTimeout, oHashKnownHosts,
1314958Sjp161948 	oServerAliveInterval, oServerAliveCountMax, oDisableBanner,
1325266Sjp161948 	oIgnoreIfUnknown, oDeprecated
1330Sstevel@tonic-gate } OpCodes;
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate /* Textual representations of the tokens. */
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate static struct {
1380Sstevel@tonic-gate 	const char *name;
1390Sstevel@tonic-gate 	OpCodes opcode;
1400Sstevel@tonic-gate } keywords[] = {
1410Sstevel@tonic-gate 	{ "forwardagent", oForwardAgent },
1420Sstevel@tonic-gate 	{ "forwardx11", oForwardX11 },
1434907Sjp161948 	{ "forwardx11trusted", oForwardX11Trusted },
1440Sstevel@tonic-gate 	{ "xauthlocation", oXAuthLocation },
1450Sstevel@tonic-gate 	{ "gatewayports", oGatewayPorts },
1460Sstevel@tonic-gate 	{ "useprivilegedport", oUsePrivilegedPort },
1470Sstevel@tonic-gate 	{ "rhostsauthentication", oRhostsAuthentication },
1480Sstevel@tonic-gate 	{ "passwordauthentication", oPasswordAuthentication },
1490Sstevel@tonic-gate 	{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
1500Sstevel@tonic-gate 	{ "kbdinteractivedevices", oKbdInteractiveDevices },
1510Sstevel@tonic-gate 	{ "rsaauthentication", oRSAAuthentication },
1520Sstevel@tonic-gate 	{ "pubkeyauthentication", oPubkeyAuthentication },
1530Sstevel@tonic-gate 	{ "dsaauthentication", oPubkeyAuthentication },		    /* alias */
1540Sstevel@tonic-gate 	{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
1550Sstevel@tonic-gate 	{ "hostbasedauthentication", oHostbasedAuthentication },
1560Sstevel@tonic-gate 	{ "challengeresponseauthentication", oChallengeResponseAuthentication },
1570Sstevel@tonic-gate 	{ "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
1580Sstevel@tonic-gate 	{ "tisauthentication", oChallengeResponseAuthentication },  /* alias */
1590Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
1600Sstevel@tonic-gate 	{ "kerberosauthentication", oKerberosAuthentication },
1610Sstevel@tonic-gate #endif
1620Sstevel@tonic-gate #ifdef GSSAPI
1630Sstevel@tonic-gate 	{ "gssapikeyexchange", oGssKeyEx },
1640Sstevel@tonic-gate 	{ "gssapiauthentication", oGssAuthentication },
1650Sstevel@tonic-gate 	{ "gssapidelegatecredentials", oGssDelegateCreds },
1660Sstevel@tonic-gate 	{ "gsskeyex", oGssKeyEx },				/* alias */
1670Sstevel@tonic-gate 	{ "gssauthentication", oGssAuthentication },		/* alias */
1680Sstevel@tonic-gate 	{ "gssdelegatecreds", oGssDelegateCreds },		/* alias */
1690Sstevel@tonic-gate #ifdef GSI
1700Sstevel@tonic-gate 	/* For backwards compatability with old 1.2.27 client code */
1710Sstevel@tonic-gate 	{ "forwardgssapiglobusproxy", oGssDelegateCreds }, /* alias */
1720Sstevel@tonic-gate 	{ "forwardgssapiglobuslimitedproxy", oGssGlobusDelegateLimitedCreds },
1730Sstevel@tonic-gate #endif /* GSI */
1740Sstevel@tonic-gate #endif /* GSSAPI */
1750Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
1760Sstevel@tonic-gate 	{ "kerberostgtpassing", oKerberosTgtPassing },
1770Sstevel@tonic-gate #endif
1780Sstevel@tonic-gate #ifdef AFS
1790Sstevel@tonic-gate 	{ "afstokenpassing", oAFSTokenPassing },
1800Sstevel@tonic-gate #endif
1810Sstevel@tonic-gate 	{ "fallbacktorsh", oFallBackToRsh },
1820Sstevel@tonic-gate 	{ "usersh", oUseRsh },
1830Sstevel@tonic-gate 	{ "identityfile", oIdentityFile },
1840Sstevel@tonic-gate 	{ "identityfile2", oIdentityFile },			/* alias */
1850Sstevel@tonic-gate 	{ "hostname", oHostName },
1860Sstevel@tonic-gate 	{ "hostkeyalias", oHostKeyAlias },
1870Sstevel@tonic-gate 	{ "proxycommand", oProxyCommand },
1880Sstevel@tonic-gate 	{ "port", oPort },
1890Sstevel@tonic-gate 	{ "cipher", oCipher },
1900Sstevel@tonic-gate 	{ "ciphers", oCiphers },
1910Sstevel@tonic-gate 	{ "macs", oMacs },
1920Sstevel@tonic-gate 	{ "protocol", oProtocol },
1930Sstevel@tonic-gate 	{ "remoteforward", oRemoteForward },
1940Sstevel@tonic-gate 	{ "localforward", oLocalForward },
1950Sstevel@tonic-gate 	{ "user", oUser },
1960Sstevel@tonic-gate 	{ "host", oHost },
1970Sstevel@tonic-gate 	{ "escapechar", oEscapeChar },
1980Sstevel@tonic-gate 	{ "globalknownhostsfile", oGlobalKnownHostsFile },
1990Sstevel@tonic-gate 	{ "userknownhostsfile", oUserKnownHostsFile },		/* obsolete */
2000Sstevel@tonic-gate 	{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },
2010Sstevel@tonic-gate 	{ "userknownhostsfile2", oUserKnownHostsFile2 },	/* obsolete */
2020Sstevel@tonic-gate 	{ "connectionattempts", oConnectionAttempts },
2030Sstevel@tonic-gate 	{ "batchmode", oBatchMode },
2040Sstevel@tonic-gate 	{ "checkhostip", oCheckHostIP },
2050Sstevel@tonic-gate 	{ "stricthostkeychecking", oStrictHostKeyChecking },
2060Sstevel@tonic-gate 	{ "compression", oCompression },
2070Sstevel@tonic-gate 	{ "compressionlevel", oCompressionLevel },
2080Sstevel@tonic-gate 	{ "keepalive", oKeepAlives },
2090Sstevel@tonic-gate 	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
2100Sstevel@tonic-gate 	{ "loglevel", oLogLevel },
2110Sstevel@tonic-gate 	{ "dynamicforward", oDynamicForward },
2120Sstevel@tonic-gate 	{ "preferredauthentications", oPreferredAuthentications },
2130Sstevel@tonic-gate 	{ "hostkeyalgorithms", oHostKeyAlgorithms },
2140Sstevel@tonic-gate 	{ "bindaddress", oBindAddress },
2150Sstevel@tonic-gate 	{ "smartcarddevice", oSmartcardDevice },
2160Sstevel@tonic-gate 	{ "clearallforwardings", oClearAllForwardings },
2170Sstevel@tonic-gate 	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
2183946Sjp161948 	{ "connecttimeout", oConnectTimeout },
2194668Sjp161948 	{ "serveraliveinterval", oServerAliveInterval },
2204668Sjp161948 	{ "serveralivecountmax", oServerAliveCountMax },
2214958Sjp161948 	{ "disablebanner", oDisableBanner },
2225243Sjp161948 	{ "hashknownhosts", oHashKnownHosts },
2235266Sjp161948 	{ "ignoreifunknown", oIgnoreIfUnknown },
2240Sstevel@tonic-gate 	{ NULL, oBadOption }
2250Sstevel@tonic-gate };
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate /*
2280Sstevel@tonic-gate  * Adds a local TCP/IP port forward to options.  Never returns if there is an
2290Sstevel@tonic-gate  * error.
2300Sstevel@tonic-gate  */
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate void
233*5334Sjp161948 add_local_forward(Options *options, const Forward *newfwd)
2340Sstevel@tonic-gate {
2350Sstevel@tonic-gate 	Forward *fwd;
2360Sstevel@tonic-gate #ifndef NO_IPPORT_RESERVED_CONCEPT
2370Sstevel@tonic-gate 	extern uid_t original_real_uid;
238*5334Sjp161948 	if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0)
2390Sstevel@tonic-gate 		fatal("Privileged ports can only be forwarded by root.");
2400Sstevel@tonic-gate #endif
2410Sstevel@tonic-gate 	if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
2420Sstevel@tonic-gate 		fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
2430Sstevel@tonic-gate 	fwd = &options->local_forwards[options->num_local_forwards++];
244*5334Sjp161948 
245*5334Sjp161948 	fwd->listen_host = (newfwd->listen_host == NULL) ?
246*5334Sjp161948 	    NULL : xstrdup(newfwd->listen_host);
247*5334Sjp161948 	fwd->listen_port = newfwd->listen_port;
248*5334Sjp161948 	fwd->connect_host = xstrdup(newfwd->connect_host);
249*5334Sjp161948 	fwd->connect_port = newfwd->connect_port;
2500Sstevel@tonic-gate }
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate /*
2530Sstevel@tonic-gate  * Adds a remote TCP/IP port forward to options.  Never returns if there is
2540Sstevel@tonic-gate  * an error.
2550Sstevel@tonic-gate  */
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate void
258*5334Sjp161948 add_remote_forward(Options *options, const Forward *newfwd)
2590Sstevel@tonic-gate {
2600Sstevel@tonic-gate 	Forward *fwd;
2610Sstevel@tonic-gate 	if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
2620Sstevel@tonic-gate 		fatal("Too many remote forwards (max %d).",
2630Sstevel@tonic-gate 		    SSH_MAX_FORWARDS_PER_DIRECTION);
2640Sstevel@tonic-gate 	fwd = &options->remote_forwards[options->num_remote_forwards++];
265*5334Sjp161948 
266*5334Sjp161948 	fwd->listen_host = (newfwd->listen_host == NULL) ?
267*5334Sjp161948 	    NULL : xstrdup(newfwd->listen_host);
268*5334Sjp161948 	fwd->listen_port = newfwd->listen_port;
269*5334Sjp161948 	fwd->connect_host = xstrdup(newfwd->connect_host);
270*5334Sjp161948 	fwd->connect_port = newfwd->connect_port;
2710Sstevel@tonic-gate }
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate static void
2740Sstevel@tonic-gate clear_forwardings(Options *options)
2750Sstevel@tonic-gate {
2760Sstevel@tonic-gate 	int i;
2770Sstevel@tonic-gate 
278*5334Sjp161948 	for (i = 0; i < options->num_local_forwards; i++) {
279*5334Sjp161948 		if (options->local_forwards[i].listen_host != NULL)
280*5334Sjp161948 			xfree(options->local_forwards[i].listen_host);
281*5334Sjp161948 		xfree(options->local_forwards[i].connect_host);
282*5334Sjp161948 	}
2830Sstevel@tonic-gate 	options->num_local_forwards = 0;
284*5334Sjp161948 	for (i = 0; i < options->num_remote_forwards; i++) {
285*5334Sjp161948 		if (options->remote_forwards[i].listen_host != NULL)
286*5334Sjp161948 			xfree(options->remote_forwards[i].listen_host);
287*5334Sjp161948 		xfree(options->remote_forwards[i].connect_host);
288*5334Sjp161948 	}
2890Sstevel@tonic-gate 	options->num_remote_forwards = 0;
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate /*
2930Sstevel@tonic-gate  * Returns the number of the token pointed to by cp or oBadOption.
2940Sstevel@tonic-gate  */
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate static OpCodes
2970Sstevel@tonic-gate parse_token(const char *cp, const char *filename, int linenum)
2980Sstevel@tonic-gate {
2990Sstevel@tonic-gate 	u_int i;
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	for (i = 0; keywords[i].name; i++)
3020Sstevel@tonic-gate 		if (strcasecmp(cp, keywords[i].name) == 0)
3030Sstevel@tonic-gate 			return keywords[i].opcode;
3040Sstevel@tonic-gate 
3055266Sjp161948 	debug("%s: line %d: unknown configuration option: %s",
3060Sstevel@tonic-gate 	    filename, linenum, cp);
3070Sstevel@tonic-gate 	return oBadOption;
3080Sstevel@tonic-gate }
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate /*
3110Sstevel@tonic-gate  * Processes a single option line as used in the configuration files. This
3120Sstevel@tonic-gate  * only sets those values that have not already been set.
3130Sstevel@tonic-gate  */
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate int
3160Sstevel@tonic-gate process_config_line(Options *options, const char *host,
3170Sstevel@tonic-gate 		    char *line, const char *filename, int linenum,
3180Sstevel@tonic-gate 		    int *activep)
3190Sstevel@tonic-gate {
320*5334Sjp161948 	char *s, *string, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256];
3215266Sjp161948 	int opcode, *intptr, value, i;
3225266Sjp161948 	StoredOption *so;
323*5334Sjp161948 	Forward fwd;
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	s = line;
3260Sstevel@tonic-gate 	/* Get the keyword. (Each line is supposed to begin with a keyword). */
3270Sstevel@tonic-gate 	keyword = strdelim(&s);
3280Sstevel@tonic-gate 	/* Ignore leading whitespace. */
3290Sstevel@tonic-gate 	if (*keyword == '\0')
3300Sstevel@tonic-gate 		keyword = strdelim(&s);
3310Sstevel@tonic-gate 	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
3320Sstevel@tonic-gate 		return 0;
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	opcode = parse_token(keyword, filename, linenum);
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	switch (opcode) {
3370Sstevel@tonic-gate 	case oBadOption:
3385266Sjp161948 		if (options->unknown_opts_num == MAX_UNKNOWN_OPTIONS) {
3395266Sjp161948 			error("we can't have more than %d unknown options:",
3405266Sjp161948 			    MAX_UNKNOWN_OPTIONS);
3415266Sjp161948 			for (i = 0; i < MAX_UNKNOWN_OPTIONS; ++i) {
3425266Sjp161948 				so = &options->unknown_opts[i];
3435266Sjp161948 				error("%s:%d:%s",
3445266Sjp161948 				    so->filename, so->linenum, so->keyword);
3455266Sjp161948 				xfree(so->keyword);
3465266Sjp161948 				xfree(so->filename);
3475266Sjp161948 			}
3485266Sjp161948 			fatal("too many unknown options found, can't continue");
3495266Sjp161948 		}
3505266Sjp161948 
3515266Sjp161948 		/* unknown options will be processed later */
3525266Sjp161948 		so = &options->unknown_opts[options->unknown_opts_num];
3535266Sjp161948 		so->keyword = xstrdup(keyword);
3545266Sjp161948 		so->filename = xstrdup(filename);
3555266Sjp161948 		so->linenum = linenum;
3565266Sjp161948 		options->unknown_opts_num++;
3575266Sjp161948 		return (0);
3585266Sjp161948 
3590Sstevel@tonic-gate 		/* NOTREACHED */
3603946Sjp161948 	case oConnectTimeout:
3613946Sjp161948 		intptr = &options->connection_timeout;
3623946Sjp161948 parse_time:
3633946Sjp161948 		arg = strdelim(&s);
3643946Sjp161948 		if (!arg || *arg == '\0')
3653946Sjp161948 			fatal("%s line %d: missing time value.",
3663946Sjp161948 			    filename, linenum);
3673946Sjp161948 		if ((value = convtime(arg)) == -1)
3683946Sjp161948 			fatal("%s line %d: invalid time value.",
3693946Sjp161948 			    filename, linenum);
3703984Sjp161948 		if (*activep && *intptr == -1)
3713946Sjp161948 			*intptr = value;
3723946Sjp161948 		break;
3733946Sjp161948 
3740Sstevel@tonic-gate 	case oForwardAgent:
3750Sstevel@tonic-gate 		intptr = &options->forward_agent;
3760Sstevel@tonic-gate parse_flag:
3770Sstevel@tonic-gate 		arg = strdelim(&s);
3780Sstevel@tonic-gate 		if (!arg || *arg == '\0')
3790Sstevel@tonic-gate 			fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
3800Sstevel@tonic-gate 		value = 0;	/* To avoid compiler warning... */
3810Sstevel@tonic-gate 		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
3820Sstevel@tonic-gate 			value = 1;
3830Sstevel@tonic-gate 		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
3840Sstevel@tonic-gate 			value = 0;
3850Sstevel@tonic-gate 		else
3860Sstevel@tonic-gate 			fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
3870Sstevel@tonic-gate 		if (*activep && *intptr == -1)
3880Sstevel@tonic-gate 			*intptr = value;
3890Sstevel@tonic-gate 		break;
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	case oForwardX11:
3920Sstevel@tonic-gate 		intptr = &options->forward_x11;
3930Sstevel@tonic-gate 		goto parse_flag;
3940Sstevel@tonic-gate 
3954907Sjp161948 	case oForwardX11Trusted:
3964907Sjp161948 		intptr = &options->forward_x11_trusted;
3974907Sjp161948 		goto parse_flag;
3984907Sjp161948 
3990Sstevel@tonic-gate 	case oGatewayPorts:
4000Sstevel@tonic-gate 		intptr = &options->gateway_ports;
4010Sstevel@tonic-gate 		goto parse_flag;
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	case oUsePrivilegedPort:
4040Sstevel@tonic-gate 		intptr = &options->use_privileged_port;
4050Sstevel@tonic-gate 		goto parse_flag;
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	case oRhostsAuthentication:
4080Sstevel@tonic-gate 		intptr = &options->rhosts_authentication;
4090Sstevel@tonic-gate 		goto parse_flag;
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	case oPasswordAuthentication:
4120Sstevel@tonic-gate 		intptr = &options->password_authentication;
4130Sstevel@tonic-gate 		goto parse_flag;
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	case oKbdInteractiveAuthentication:
4160Sstevel@tonic-gate 		intptr = &options->kbd_interactive_authentication;
4170Sstevel@tonic-gate 		goto parse_flag;
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 	case oKbdInteractiveDevices:
4200Sstevel@tonic-gate 		charptr = &options->kbd_interactive_devices;
4210Sstevel@tonic-gate 		goto parse_string;
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	case oPubkeyAuthentication:
4240Sstevel@tonic-gate 		intptr = &options->pubkey_authentication;
4250Sstevel@tonic-gate 		goto parse_flag;
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	case oRSAAuthentication:
4280Sstevel@tonic-gate 		intptr = &options->rsa_authentication;
4290Sstevel@tonic-gate 		goto parse_flag;
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	case oRhostsRSAAuthentication:
4320Sstevel@tonic-gate 		intptr = &options->rhosts_rsa_authentication;
4330Sstevel@tonic-gate 		goto parse_flag;
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	case oHostbasedAuthentication:
4360Sstevel@tonic-gate 		intptr = &options->hostbased_authentication;
4370Sstevel@tonic-gate 		goto parse_flag;
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	case oChallengeResponseAuthentication:
4400Sstevel@tonic-gate 		intptr = &options->challenge_response_authentication;
4410Sstevel@tonic-gate 		goto parse_flag;
4420Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
4430Sstevel@tonic-gate 	case oKerberosAuthentication:
4440Sstevel@tonic-gate 		intptr = &options->kerberos_authentication;
4450Sstevel@tonic-gate 		goto parse_flag;
4460Sstevel@tonic-gate #endif
4470Sstevel@tonic-gate #ifdef GSSAPI
4480Sstevel@tonic-gate 	case oGssKeyEx:
4490Sstevel@tonic-gate 		intptr = &options->gss_keyex;
4500Sstevel@tonic-gate 		goto parse_flag;
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	case oGssAuthentication:
4530Sstevel@tonic-gate 		intptr = &options->gss_authentication;
4540Sstevel@tonic-gate 		goto parse_flag;
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	case oGssDelegateCreds:
4570Sstevel@tonic-gate 		intptr = &options->gss_deleg_creds;
4580Sstevel@tonic-gate 		goto parse_flag;
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate #ifdef GSI
4610Sstevel@tonic-gate 	case oGssGlobusDelegateLimitedCreds:
4620Sstevel@tonic-gate 		intptr = &options->gss_globus_deleg_limited_proxy;
4630Sstevel@tonic-gate 		goto parse_flag;
4640Sstevel@tonic-gate #endif /* GSI */
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate #endif /* GSSAPI */
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
4690Sstevel@tonic-gate 	case oKerberosTgtPassing:
4700Sstevel@tonic-gate 		intptr = &options->kerberos_tgt_passing;
4710Sstevel@tonic-gate 		goto parse_flag;
4720Sstevel@tonic-gate #endif
4730Sstevel@tonic-gate #ifdef AFS
4740Sstevel@tonic-gate 	case oAFSTokenPassing:
4750Sstevel@tonic-gate 		intptr = &options->afs_token_passing;
4760Sstevel@tonic-gate 		goto parse_flag;
4770Sstevel@tonic-gate #endif
4780Sstevel@tonic-gate 	case oFallBackToRsh:
4790Sstevel@tonic-gate 		intptr = &options->fallback_to_rsh;
4800Sstevel@tonic-gate 		goto parse_flag;
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 	case oUseRsh:
4830Sstevel@tonic-gate 		intptr = &options->use_rsh;
4840Sstevel@tonic-gate 		goto parse_flag;
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	case oBatchMode:
4870Sstevel@tonic-gate 		intptr = &options->batch_mode;
4880Sstevel@tonic-gate 		goto parse_flag;
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	case oCheckHostIP:
4910Sstevel@tonic-gate 		intptr = &options->check_host_ip;
4920Sstevel@tonic-gate 		goto parse_flag;
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	case oStrictHostKeyChecking:
4950Sstevel@tonic-gate 		intptr = &options->strict_host_key_checking;
4960Sstevel@tonic-gate 		arg = strdelim(&s);
4970Sstevel@tonic-gate 		if (!arg || *arg == '\0')
4980Sstevel@tonic-gate 			fatal("%.200s line %d: Missing yes/no/ask argument.",
4990Sstevel@tonic-gate 			    filename, linenum);
5000Sstevel@tonic-gate 		value = 0;	/* To avoid compiler warning... */
5010Sstevel@tonic-gate 		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
5020Sstevel@tonic-gate 			value = 1;
5030Sstevel@tonic-gate 		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
5040Sstevel@tonic-gate 			value = 0;
5050Sstevel@tonic-gate 		else if (strcmp(arg, "ask") == 0)
5060Sstevel@tonic-gate 			value = 2;
5070Sstevel@tonic-gate 		else
5080Sstevel@tonic-gate 			fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
5090Sstevel@tonic-gate 		if (*activep && *intptr == -1)
5100Sstevel@tonic-gate 			*intptr = value;
5110Sstevel@tonic-gate 		break;
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 	case oCompression:
5140Sstevel@tonic-gate 		intptr = &options->compression;
5150Sstevel@tonic-gate 		goto parse_flag;
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 	case oKeepAlives:
5180Sstevel@tonic-gate 		intptr = &options->keepalives;
5190Sstevel@tonic-gate 		goto parse_flag;
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	case oNoHostAuthenticationForLocalhost:
5220Sstevel@tonic-gate 		intptr = &options->no_host_authentication_for_localhost;
5230Sstevel@tonic-gate 		goto parse_flag;
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	case oNumberOfPasswordPrompts:
5260Sstevel@tonic-gate 		intptr = &options->number_of_password_prompts;
5270Sstevel@tonic-gate 		goto parse_int;
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	case oCompressionLevel:
5300Sstevel@tonic-gate 		intptr = &options->compression_level;
5310Sstevel@tonic-gate 		goto parse_int;
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	case oIdentityFile:
5340Sstevel@tonic-gate 		arg = strdelim(&s);
5350Sstevel@tonic-gate 		if (!arg || *arg == '\0')
5360Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
5370Sstevel@tonic-gate 		if (*activep) {
5380Sstevel@tonic-gate 			intptr = &options->num_identity_files;
5390Sstevel@tonic-gate 			if (*intptr >= SSH_MAX_IDENTITY_FILES)
5400Sstevel@tonic-gate 				fatal("%.200s line %d: Too many identity files specified (max %d).",
5410Sstevel@tonic-gate 				    filename, linenum, SSH_MAX_IDENTITY_FILES);
5420Sstevel@tonic-gate 			charptr =  &options->identity_files[*intptr];
5430Sstevel@tonic-gate 			*charptr = xstrdup(arg);
5440Sstevel@tonic-gate 			*intptr = *intptr + 1;
5450Sstevel@tonic-gate 		}
5460Sstevel@tonic-gate 		break;
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	case oXAuthLocation:
5490Sstevel@tonic-gate 		charptr=&options->xauth_location;
5500Sstevel@tonic-gate 		goto parse_string;
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	case oUser:
5530Sstevel@tonic-gate 		charptr = &options->user;
5540Sstevel@tonic-gate parse_string:
5550Sstevel@tonic-gate 		arg = strdelim(&s);
5560Sstevel@tonic-gate 		if (!arg || *arg == '\0')
5570Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
5580Sstevel@tonic-gate 		if (*activep && *charptr == NULL)
5590Sstevel@tonic-gate 			*charptr = xstrdup(arg);
5600Sstevel@tonic-gate 		break;
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 	case oGlobalKnownHostsFile:
5630Sstevel@tonic-gate 		charptr = &options->system_hostfile;
5640Sstevel@tonic-gate 		goto parse_string;
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 	case oUserKnownHostsFile:
5670Sstevel@tonic-gate 		charptr = &options->user_hostfile;
5680Sstevel@tonic-gate 		goto parse_string;
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 	case oGlobalKnownHostsFile2:
5710Sstevel@tonic-gate 		charptr = &options->system_hostfile2;
5720Sstevel@tonic-gate 		goto parse_string;
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	case oUserKnownHostsFile2:
5750Sstevel@tonic-gate 		charptr = &options->user_hostfile2;
5760Sstevel@tonic-gate 		goto parse_string;
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	case oHostName:
5790Sstevel@tonic-gate 		charptr = &options->hostname;
5800Sstevel@tonic-gate 		goto parse_string;
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	case oHostKeyAlias:
5830Sstevel@tonic-gate 		charptr = &options->host_key_alias;
5840Sstevel@tonic-gate 		goto parse_string;
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	case oPreferredAuthentications:
5870Sstevel@tonic-gate 		charptr = &options->preferred_authentications;
5880Sstevel@tonic-gate 		goto parse_string;
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	case oBindAddress:
5910Sstevel@tonic-gate 		charptr = &options->bind_address;
5920Sstevel@tonic-gate 		goto parse_string;
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	case oSmartcardDevice:
5950Sstevel@tonic-gate 		charptr = &options->smartcard_device;
5960Sstevel@tonic-gate 		goto parse_string;
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 	case oProxyCommand:
5990Sstevel@tonic-gate 		charptr = &options->proxy_command;
6000Sstevel@tonic-gate 		string = xstrdup("");
6010Sstevel@tonic-gate 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
6020Sstevel@tonic-gate 			string = xrealloc(string, strlen(string) + strlen(arg) + 2);
6030Sstevel@tonic-gate 			strcat(string, " ");
6040Sstevel@tonic-gate 			strcat(string, arg);
6050Sstevel@tonic-gate 		}
6060Sstevel@tonic-gate 		if (*activep && *charptr == NULL)
6070Sstevel@tonic-gate 			*charptr = string;
6080Sstevel@tonic-gate 		else
6090Sstevel@tonic-gate 			xfree(string);
6100Sstevel@tonic-gate 		return 0;
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 	case oPort:
6130Sstevel@tonic-gate 		intptr = &options->port;
6140Sstevel@tonic-gate parse_int:
6150Sstevel@tonic-gate 		arg = strdelim(&s);
6160Sstevel@tonic-gate 		if (!arg || *arg == '\0')
6170Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
6180Sstevel@tonic-gate 		if (arg[0] < '0' || arg[0] > '9')
6190Sstevel@tonic-gate 			fatal("%.200s line %d: Bad number.", filename, linenum);
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 		/* Octal, decimal, or hex format? */
6220Sstevel@tonic-gate 		value = strtol(arg, &endofnumber, 0);
6230Sstevel@tonic-gate 		if (arg == endofnumber)
6240Sstevel@tonic-gate 			fatal("%.200s line %d: Bad number.", filename, linenum);
6250Sstevel@tonic-gate 		if (*activep && *intptr == -1)
6260Sstevel@tonic-gate 			*intptr = value;
6270Sstevel@tonic-gate 		break;
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	case oConnectionAttempts:
6300Sstevel@tonic-gate 		intptr = &options->connection_attempts;
6310Sstevel@tonic-gate 		goto parse_int;
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	case oCipher:
6340Sstevel@tonic-gate 		intptr = &options->cipher;
6350Sstevel@tonic-gate 		arg = strdelim(&s);
6360Sstevel@tonic-gate 		if (!arg || *arg == '\0')
6370Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
6380Sstevel@tonic-gate 		value = cipher_number(arg);
6390Sstevel@tonic-gate 		if (value == -1)
6400Sstevel@tonic-gate 			fatal("%.200s line %d: Bad cipher '%s'.",
6410Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
6420Sstevel@tonic-gate 		if (*activep && *intptr == -1)
6430Sstevel@tonic-gate 			*intptr = value;
6440Sstevel@tonic-gate 		break;
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	case oCiphers:
6470Sstevel@tonic-gate 		arg = strdelim(&s);
6480Sstevel@tonic-gate 		if (!arg || *arg == '\0')
6490Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
6500Sstevel@tonic-gate 		if (!ciphers_valid(arg))
6510Sstevel@tonic-gate 			fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
6520Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
6530Sstevel@tonic-gate 		if (*activep && options->ciphers == NULL)
6540Sstevel@tonic-gate 			options->ciphers = xstrdup(arg);
6550Sstevel@tonic-gate 		break;
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	case oMacs:
6580Sstevel@tonic-gate 		arg = strdelim(&s);
6590Sstevel@tonic-gate 		if (!arg || *arg == '\0')
6600Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
6610Sstevel@tonic-gate 		if (!mac_valid(arg))
6620Sstevel@tonic-gate 			fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
6630Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
6640Sstevel@tonic-gate 		if (*activep && options->macs == NULL)
6650Sstevel@tonic-gate 			options->macs = xstrdup(arg);
6660Sstevel@tonic-gate 		break;
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 	case oHostKeyAlgorithms:
6690Sstevel@tonic-gate 		arg = strdelim(&s);
6700Sstevel@tonic-gate 		if (!arg || *arg == '\0')
6710Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
6720Sstevel@tonic-gate 		if (!key_names_valid2(arg))
6730Sstevel@tonic-gate 			fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
6740Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
6750Sstevel@tonic-gate 		if (*activep && options->hostkeyalgorithms == NULL)
6760Sstevel@tonic-gate 			options->hostkeyalgorithms = xstrdup(arg);
6770Sstevel@tonic-gate 		break;
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 	case oProtocol:
6800Sstevel@tonic-gate 		intptr = &options->protocol;
6810Sstevel@tonic-gate 		arg = strdelim(&s);
6820Sstevel@tonic-gate 		if (!arg || *arg == '\0')
6830Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
6840Sstevel@tonic-gate 		value = proto_spec(arg);
6850Sstevel@tonic-gate 		if (value == SSH_PROTO_UNKNOWN)
6860Sstevel@tonic-gate 			fatal("%.200s line %d: Bad protocol spec '%s'.",
6870Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
6880Sstevel@tonic-gate 		if (*activep && *intptr == SSH_PROTO_UNKNOWN)
6890Sstevel@tonic-gate 			*intptr = value;
6900Sstevel@tonic-gate 		break;
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	case oLogLevel:
6930Sstevel@tonic-gate 		intptr = (int *) &options->log_level;
6940Sstevel@tonic-gate 		arg = strdelim(&s);
6950Sstevel@tonic-gate 		value = log_level_number(arg);
6960Sstevel@tonic-gate 		if (value == SYSLOG_LEVEL_NOT_SET)
6970Sstevel@tonic-gate 			fatal("%.200s line %d: unsupported log level '%s'",
6980Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
6990Sstevel@tonic-gate 		if (*activep && (LogLevel) *intptr == SYSLOG_LEVEL_NOT_SET)
7000Sstevel@tonic-gate 			*intptr = (LogLevel) value;
7010Sstevel@tonic-gate 		break;
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	case oLocalForward:
7040Sstevel@tonic-gate 	case oRemoteForward:
7050Sstevel@tonic-gate 		arg = strdelim(&s);
706*5334Sjp161948 		if (arg == NULL || *arg == '\0')
7070Sstevel@tonic-gate 			fatal("%.200s line %d: Missing port argument.",
7080Sstevel@tonic-gate 			    filename, linenum);
709*5334Sjp161948 		arg2 = strdelim(&s);
710*5334Sjp161948 		if (arg2 == NULL || *arg2 == '\0')
711*5334Sjp161948 			fatal("%.200s line %d: Missing target argument.",
7120Sstevel@tonic-gate 			    filename, linenum);
713*5334Sjp161948 
714*5334Sjp161948 		/* construct a string for parse_forward */
715*5334Sjp161948 		snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
716*5334Sjp161948 
717*5334Sjp161948 		if (parse_forward(1, &fwd, fwdarg) == 0)
7180Sstevel@tonic-gate 			fatal("%.200s line %d: Bad forwarding specification.",
7190Sstevel@tonic-gate 			    filename, linenum);
720*5334Sjp161948 
7210Sstevel@tonic-gate 		if (*activep) {
7220Sstevel@tonic-gate 			if (opcode == oLocalForward)
723*5334Sjp161948 				add_local_forward(options, &fwd);
7240Sstevel@tonic-gate 			else if (opcode == oRemoteForward)
725*5334Sjp161948 				add_remote_forward(options, &fwd);
7260Sstevel@tonic-gate 		}
7270Sstevel@tonic-gate 		break;
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	case oDynamicForward:
7300Sstevel@tonic-gate 		arg = strdelim(&s);
7310Sstevel@tonic-gate 		if (!arg || *arg == '\0')
7320Sstevel@tonic-gate 			fatal("%.200s line %d: Missing port argument.",
7330Sstevel@tonic-gate 			    filename, linenum);
734*5334Sjp161948 
735*5334Sjp161948 		if (parse_forward(0, &fwd, arg) == 0) {
736*5334Sjp161948 			fatal("%.200s line %d: Bad dynamic forwarding specification.",
7370Sstevel@tonic-gate 			    filename, linenum);
738*5334Sjp161948 		}
739*5334Sjp161948 
740*5334Sjp161948 		if (*activep) {
741*5334Sjp161948 			fwd.connect_host = "socks";
742*5334Sjp161948 			add_local_forward(options, &fwd);
743*5334Sjp161948 		}
7440Sstevel@tonic-gate 		break;
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 	case oClearAllForwardings:
7470Sstevel@tonic-gate 		intptr = &options->clear_forwardings;
7480Sstevel@tonic-gate 		goto parse_flag;
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	case oHost:
7510Sstevel@tonic-gate 		*activep = 0;
7520Sstevel@tonic-gate 		while ((arg = strdelim(&s)) != NULL && *arg != '\0')
7530Sstevel@tonic-gate 			if (match_pattern(host, arg)) {
7540Sstevel@tonic-gate 				debug("Applying options for %.100s", arg);
7550Sstevel@tonic-gate 				*activep = 1;
7560Sstevel@tonic-gate 				break;
7570Sstevel@tonic-gate 			}
7580Sstevel@tonic-gate 		/* Avoid garbage check below, as strdelim is done. */
7590Sstevel@tonic-gate 		return 0;
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 	case oEscapeChar:
7620Sstevel@tonic-gate 		intptr = &options->escape_char;
7630Sstevel@tonic-gate 		arg = strdelim(&s);
7640Sstevel@tonic-gate 		if (!arg || *arg == '\0')
7650Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
7660Sstevel@tonic-gate 		if (arg[0] == '^' && arg[2] == 0 &&
7670Sstevel@tonic-gate 		    (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
7680Sstevel@tonic-gate 			value = (u_char) arg[1] & 31;
7690Sstevel@tonic-gate 		else if (strlen(arg) == 1)
7700Sstevel@tonic-gate 			value = (u_char) arg[0];
7710Sstevel@tonic-gate 		else if (strcmp(arg, "none") == 0)
7720Sstevel@tonic-gate 			value = SSH_ESCAPECHAR_NONE;
7730Sstevel@tonic-gate 		else {
7740Sstevel@tonic-gate 			fatal("%.200s line %d: Bad escape character.",
7750Sstevel@tonic-gate 			    filename, linenum);
7760Sstevel@tonic-gate 			/* NOTREACHED */
7770Sstevel@tonic-gate 			value = 0;	/* Avoid compiler warning. */
7780Sstevel@tonic-gate 		}
7790Sstevel@tonic-gate 		if (*activep && *intptr == -1)
7800Sstevel@tonic-gate 			*intptr = value;
7810Sstevel@tonic-gate 		break;
7820Sstevel@tonic-gate 
7834668Sjp161948 	case oServerAliveInterval:
7844668Sjp161948 		intptr = &options->server_alive_interval;
7854668Sjp161948 		goto parse_time;
7864668Sjp161948 
7874668Sjp161948 	case oServerAliveCountMax:
7884668Sjp161948 		intptr = &options->server_alive_count_max;
7894668Sjp161948 		goto parse_int;
7904668Sjp161948 
7915243Sjp161948 	case oHashKnownHosts:
7925243Sjp161948 		intptr = &options->hash_known_hosts;
7935243Sjp161948 		goto parse_flag;
7945243Sjp161948 
7954958Sjp161948 	case oDisableBanner:
7964958Sjp161948 		arg = strdelim(&s);
7974958Sjp161948 		if (get_yes_no_flag(&options->disable_banner, arg, filename,
7984958Sjp161948 		    linenum, *activep) == 1)
7994958Sjp161948 			break;
8004958Sjp161948 
8014958Sjp161948 		if (strcmp(arg, "in-exec-mode") == 0)
8024958Sjp161948 			options->disable_banner = SSH_NO_BANNER_IN_EXEC_MODE;
8034958Sjp161948 		else
8044958Sjp161948 			fatal("%.200s line %d: Bad yes/no/in-exec-mode "
8054958Sjp161948 			    "argument.", filename, linenum);
8064958Sjp161948 		break;
8074958Sjp161948 
8085266Sjp161948 	case oIgnoreIfUnknown:
8095266Sjp161948 		charptr = &options->ignore_if_unknown;
8105266Sjp161948 		goto parse_string;
8115266Sjp161948 
8120Sstevel@tonic-gate 	case oDeprecated:
8130Sstevel@tonic-gate 		debug("%s line %d: Deprecated option \"%s\"",
8140Sstevel@tonic-gate 		    filename, linenum, keyword);
8150Sstevel@tonic-gate 		return 0;
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 	default:
8180Sstevel@tonic-gate 		fatal("process_config_line: Unimplemented opcode %d", opcode);
8190Sstevel@tonic-gate 	}
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 	/* Check that there is no garbage at end of line. */
8220Sstevel@tonic-gate 	if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
8230Sstevel@tonic-gate 		fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
8240Sstevel@tonic-gate 		     filename, linenum, arg);
8250Sstevel@tonic-gate 	}
8260Sstevel@tonic-gate 	return 0;
8270Sstevel@tonic-gate }
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate /*
8310Sstevel@tonic-gate  * Reads the config file and modifies the options accordingly.  Options
8320Sstevel@tonic-gate  * should already be initialized before this call.  This never returns if
8330Sstevel@tonic-gate  * there is an error.  If the file does not exist, this returns 0.
8340Sstevel@tonic-gate  */
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate int
8370Sstevel@tonic-gate read_config_file(const char *filename, const char *host, Options *options)
8380Sstevel@tonic-gate {
8390Sstevel@tonic-gate 	FILE *f;
8400Sstevel@tonic-gate 	char line[1024];
8410Sstevel@tonic-gate 	int active, linenum;
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	/* Open the file. */
8440Sstevel@tonic-gate 	f = fopen(filename, "r");
8450Sstevel@tonic-gate 	if (!f)
8460Sstevel@tonic-gate 		return 0;
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	debug("Reading configuration data %.200s", filename);
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 	/*
8510Sstevel@tonic-gate 	 * Mark that we are now processing the options.  This flag is turned
8520Sstevel@tonic-gate 	 * on/off by Host specifications.
8530Sstevel@tonic-gate 	 */
8540Sstevel@tonic-gate 	active = 1;
8550Sstevel@tonic-gate 	linenum = 0;
8560Sstevel@tonic-gate 	while (fgets(line, sizeof(line), f)) {
8570Sstevel@tonic-gate 		/* Update line number counter. */
8580Sstevel@tonic-gate 		linenum++;
8595266Sjp161948 		process_config_line(options, host, line, filename, linenum, &active);
8600Sstevel@tonic-gate 	}
8610Sstevel@tonic-gate 	fclose(f);
8620Sstevel@tonic-gate 	return 1;
8630Sstevel@tonic-gate }
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate /*
8660Sstevel@tonic-gate  * Initializes options to special values that indicate that they have not yet
8670Sstevel@tonic-gate  * been set.  Read_config_file will only set options with this value. Options
8680Sstevel@tonic-gate  * are processed in the following order: command line, user config file,
8690Sstevel@tonic-gate  * system config file.  Last, fill_default_options is called.
8700Sstevel@tonic-gate  */
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate void
8730Sstevel@tonic-gate initialize_options(Options * options)
8740Sstevel@tonic-gate {
8750Sstevel@tonic-gate 	memset(options, 'X', sizeof(*options));
8760Sstevel@tonic-gate 	options->forward_agent = -1;
8770Sstevel@tonic-gate 	options->forward_x11 = -1;
8784907Sjp161948 	options->forward_x11_trusted = -1;
8790Sstevel@tonic-gate 	options->xauth_location = NULL;
8800Sstevel@tonic-gate 	options->gateway_ports = -1;
8810Sstevel@tonic-gate 	options->use_privileged_port = -1;
8820Sstevel@tonic-gate 	options->rhosts_authentication = -1;
8830Sstevel@tonic-gate 	options->rsa_authentication = -1;
8840Sstevel@tonic-gate 	options->pubkey_authentication = -1;
8850Sstevel@tonic-gate 	options->challenge_response_authentication = -1;
8860Sstevel@tonic-gate #ifdef GSSAPI
8870Sstevel@tonic-gate         options->gss_keyex = -1;
8880Sstevel@tonic-gate         options->gss_authentication = -1;
8890Sstevel@tonic-gate         options->gss_deleg_creds = -1;
8900Sstevel@tonic-gate #ifdef GSI
8910Sstevel@tonic-gate         options->gss_globus_deleg_limited_proxy = -1;
8920Sstevel@tonic-gate #endif /* GSI */
8930Sstevel@tonic-gate #endif /* GSSAPI */
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
8960Sstevel@tonic-gate 	options->kerberos_authentication = -1;
8970Sstevel@tonic-gate #endif
8980Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
8990Sstevel@tonic-gate 	options->kerberos_tgt_passing = -1;
9000Sstevel@tonic-gate #endif
9010Sstevel@tonic-gate #ifdef AFS
9020Sstevel@tonic-gate 	options->afs_token_passing = -1;
9030Sstevel@tonic-gate #endif
9040Sstevel@tonic-gate 	options->password_authentication = -1;
9050Sstevel@tonic-gate 	options->kbd_interactive_authentication = -1;
9060Sstevel@tonic-gate 	options->kbd_interactive_devices = NULL;
9070Sstevel@tonic-gate 	options->rhosts_rsa_authentication = -1;
9080Sstevel@tonic-gate 	options->hostbased_authentication = -1;
9090Sstevel@tonic-gate 	options->batch_mode = -1;
9100Sstevel@tonic-gate 	options->check_host_ip = -1;
9110Sstevel@tonic-gate 	options->strict_host_key_checking = -1;
9120Sstevel@tonic-gate 	options->compression = -1;
9130Sstevel@tonic-gate 	options->keepalives = -1;
9140Sstevel@tonic-gate 	options->compression_level = -1;
9150Sstevel@tonic-gate 	options->port = -1;
9160Sstevel@tonic-gate 	options->connection_attempts = -1;
9173946Sjp161948 	options->connection_timeout = -1;
9180Sstevel@tonic-gate 	options->number_of_password_prompts = -1;
9190Sstevel@tonic-gate 	options->cipher = -1;
9200Sstevel@tonic-gate 	options->ciphers = NULL;
9210Sstevel@tonic-gate 	options->macs = NULL;
9220Sstevel@tonic-gate 	options->hostkeyalgorithms = NULL;
9230Sstevel@tonic-gate 	options->protocol = SSH_PROTO_UNKNOWN;
9240Sstevel@tonic-gate 	options->num_identity_files = 0;
9250Sstevel@tonic-gate 	options->hostname = NULL;
9260Sstevel@tonic-gate 	options->host_key_alias = NULL;
9270Sstevel@tonic-gate 	options->proxy_command = NULL;
9280Sstevel@tonic-gate 	options->user = NULL;
9290Sstevel@tonic-gate 	options->escape_char = -1;
9300Sstevel@tonic-gate 	options->system_hostfile = NULL;
9310Sstevel@tonic-gate 	options->user_hostfile = NULL;
9320Sstevel@tonic-gate 	options->system_hostfile2 = NULL;
9330Sstevel@tonic-gate 	options->user_hostfile2 = NULL;
9340Sstevel@tonic-gate 	options->num_local_forwards = 0;
9350Sstevel@tonic-gate 	options->num_remote_forwards = 0;
9360Sstevel@tonic-gate 	options->clear_forwardings = -1;
9370Sstevel@tonic-gate 	options->log_level = SYSLOG_LEVEL_NOT_SET;
9380Sstevel@tonic-gate 	options->preferred_authentications = NULL;
9390Sstevel@tonic-gate 	options->bind_address = NULL;
9400Sstevel@tonic-gate 	options->smartcard_device = NULL;
9410Sstevel@tonic-gate 	options->no_host_authentication_for_localhost = - 1;
9420Sstevel@tonic-gate 	options->fallback_to_rsh = -1;
9430Sstevel@tonic-gate 	options->use_rsh = -1;
9444668Sjp161948 	options->server_alive_interval = -1;
9454668Sjp161948 	options->server_alive_count_max = -1;
9465243Sjp161948 	options->hash_known_hosts = -1;
9475266Sjp161948 	options->ignore_if_unknown = NULL;
9485266Sjp161948 	options->unknown_opts_num = 0;
9494958Sjp161948 	options->disable_banner = -1;
9500Sstevel@tonic-gate }
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate /*
9530Sstevel@tonic-gate  * Called after processing other sources of option data, this fills those
9540Sstevel@tonic-gate  * options for which no value has been specified with their default values.
9550Sstevel@tonic-gate  */
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate void
9580Sstevel@tonic-gate fill_default_options(Options * options)
9590Sstevel@tonic-gate {
9600Sstevel@tonic-gate 	int len;
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 	if (options->forward_agent == -1)
9630Sstevel@tonic-gate 		options->forward_agent = 0;
9640Sstevel@tonic-gate 	if (options->forward_x11 == -1)
9650Sstevel@tonic-gate 		options->forward_x11 = 0;
9664907Sjp161948 	/*
9674907Sjp161948 	 * Unlike OpenSSH, we keep backward compatibility for '-X' option
9684907Sjp161948 	 * which means that X11 forwarding is trusted by default.
9694907Sjp161948 	 */
9704907Sjp161948 	if (options->forward_x11_trusted == -1)
9714907Sjp161948 		options->forward_x11_trusted = 1;
9720Sstevel@tonic-gate 	if (options->xauth_location == NULL)
9730Sstevel@tonic-gate 		options->xauth_location = _PATH_XAUTH;
9740Sstevel@tonic-gate 	if (options->gateway_ports == -1)
9750Sstevel@tonic-gate 		options->gateway_ports = 0;
9760Sstevel@tonic-gate 	if (options->use_privileged_port == -1)
9770Sstevel@tonic-gate 		options->use_privileged_port = 0;
9780Sstevel@tonic-gate 	if (options->rhosts_authentication == -1)
9790Sstevel@tonic-gate 		options->rhosts_authentication = 0;
9800Sstevel@tonic-gate 	if (options->rsa_authentication == -1)
9810Sstevel@tonic-gate 		options->rsa_authentication = 1;
9820Sstevel@tonic-gate 	if (options->pubkey_authentication == -1)
9830Sstevel@tonic-gate 		options->pubkey_authentication = 1;
9840Sstevel@tonic-gate 	if (options->challenge_response_authentication == -1)
9850Sstevel@tonic-gate 		options->challenge_response_authentication = 1;
9860Sstevel@tonic-gate #ifdef GSSAPI
9870Sstevel@tonic-gate 	if (options->gss_keyex == -1)
9880Sstevel@tonic-gate 		options->gss_keyex = 1;
9890Sstevel@tonic-gate 	if (options->gss_authentication == -1)
9900Sstevel@tonic-gate 		options->gss_authentication = 1;
9910Sstevel@tonic-gate 	if (options->gss_deleg_creds == -1)
9920Sstevel@tonic-gate 		options->gss_deleg_creds = 0;
9930Sstevel@tonic-gate #ifdef GSI
9940Sstevel@tonic-gate 	if (options->gss_globus_deleg_limited_proxy == -1)
9950Sstevel@tonic-gate 		options->gss_globus_deleg_limited_proxy = 0;
9960Sstevel@tonic-gate #endif /* GSI */
9970Sstevel@tonic-gate #endif /* GSSAPI */
9980Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
9990Sstevel@tonic-gate 	if (options->kerberos_authentication == -1)
10000Sstevel@tonic-gate 		options->kerberos_authentication = 1;
10010Sstevel@tonic-gate #endif
10020Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
10030Sstevel@tonic-gate 	if (options->kerberos_tgt_passing == -1)
10040Sstevel@tonic-gate 		options->kerberos_tgt_passing = 1;
10050Sstevel@tonic-gate #endif
10060Sstevel@tonic-gate #ifdef AFS
10070Sstevel@tonic-gate 	if (options->afs_token_passing == -1)
10080Sstevel@tonic-gate 		options->afs_token_passing = 1;
10090Sstevel@tonic-gate #endif
10100Sstevel@tonic-gate 	if (options->password_authentication == -1)
10110Sstevel@tonic-gate 		options->password_authentication = 1;
10120Sstevel@tonic-gate 	if (options->kbd_interactive_authentication == -1)
10130Sstevel@tonic-gate 		options->kbd_interactive_authentication = 1;
10140Sstevel@tonic-gate 	if (options->rhosts_rsa_authentication == -1)
10150Sstevel@tonic-gate 		options->rhosts_rsa_authentication = 0;
10160Sstevel@tonic-gate 	if (options->hostbased_authentication == -1)
10170Sstevel@tonic-gate 		options->hostbased_authentication = 0;
10180Sstevel@tonic-gate 	if (options->batch_mode == -1)
10190Sstevel@tonic-gate 		options->batch_mode = 0;
10200Sstevel@tonic-gate 	if (options->check_host_ip == -1)
10210Sstevel@tonic-gate 		options->check_host_ip = 1;
10220Sstevel@tonic-gate 	if (options->strict_host_key_checking == -1)
10230Sstevel@tonic-gate 		options->strict_host_key_checking = 2;	/* 2 is default */
10240Sstevel@tonic-gate 	if (options->compression == -1)
10250Sstevel@tonic-gate 		options->compression = 0;
10260Sstevel@tonic-gate 	if (options->keepalives == -1)
10270Sstevel@tonic-gate 		options->keepalives = 1;
10280Sstevel@tonic-gate 	if (options->compression_level == -1)
10290Sstevel@tonic-gate 		options->compression_level = 6;
10300Sstevel@tonic-gate 	if (options->port == -1)
10310Sstevel@tonic-gate 		options->port = 0;	/* Filled in ssh_connect. */
10320Sstevel@tonic-gate 	if (options->connection_attempts == -1)
10330Sstevel@tonic-gate 		options->connection_attempts = 1;
10340Sstevel@tonic-gate 	if (options->number_of_password_prompts == -1)
10350Sstevel@tonic-gate 		options->number_of_password_prompts = 3;
10360Sstevel@tonic-gate 	/* Selected in ssh_login(). */
10370Sstevel@tonic-gate 	if (options->cipher == -1)
10380Sstevel@tonic-gate 		options->cipher = SSH_CIPHER_NOT_SET;
10390Sstevel@tonic-gate 	/* options->ciphers, default set in myproposals.h */
10400Sstevel@tonic-gate 	/* options->macs, default set in myproposals.h */
10410Sstevel@tonic-gate 	/* options->hostkeyalgorithms, default set in myproposals.h */
10420Sstevel@tonic-gate 	if (options->protocol == SSH_PROTO_UNKNOWN)
10430Sstevel@tonic-gate 		options->protocol = SSH_PROTO_1|SSH_PROTO_2;
10440Sstevel@tonic-gate 	if (options->num_identity_files == 0) {
10450Sstevel@tonic-gate 		if (options->protocol & SSH_PROTO_1) {
10460Sstevel@tonic-gate 			len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;
10470Sstevel@tonic-gate 			options->identity_files[options->num_identity_files] =
10480Sstevel@tonic-gate 			    xmalloc(len);
10490Sstevel@tonic-gate 			snprintf(options->identity_files[options->num_identity_files++],
10500Sstevel@tonic-gate 			    len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY);
10510Sstevel@tonic-gate 		}
10520Sstevel@tonic-gate 		if (options->protocol & SSH_PROTO_2) {
10530Sstevel@tonic-gate 			len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1;
10540Sstevel@tonic-gate 			options->identity_files[options->num_identity_files] =
10550Sstevel@tonic-gate 			    xmalloc(len);
10560Sstevel@tonic-gate 			snprintf(options->identity_files[options->num_identity_files++],
10570Sstevel@tonic-gate 			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA);
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate 			len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1;
10600Sstevel@tonic-gate 			options->identity_files[options->num_identity_files] =
10610Sstevel@tonic-gate 			    xmalloc(len);
10620Sstevel@tonic-gate 			snprintf(options->identity_files[options->num_identity_files++],
10630Sstevel@tonic-gate 			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA);
10640Sstevel@tonic-gate 		}
10650Sstevel@tonic-gate 	}
10660Sstevel@tonic-gate 	if (options->escape_char == -1)
10670Sstevel@tonic-gate 		options->escape_char = '~';
10680Sstevel@tonic-gate 	if (options->system_hostfile == NULL)
10690Sstevel@tonic-gate 		options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
10700Sstevel@tonic-gate 	if (options->user_hostfile == NULL)
10710Sstevel@tonic-gate 		options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
10720Sstevel@tonic-gate 	if (options->system_hostfile2 == NULL)
10730Sstevel@tonic-gate 		options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
10740Sstevel@tonic-gate 	if (options->user_hostfile2 == NULL)
10750Sstevel@tonic-gate 		options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
10760Sstevel@tonic-gate 	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
10770Sstevel@tonic-gate 		options->log_level = SYSLOG_LEVEL_INFO;
10780Sstevel@tonic-gate 	if (options->clear_forwardings == 1)
10790Sstevel@tonic-gate 		clear_forwardings(options);
10800Sstevel@tonic-gate 	if (options->no_host_authentication_for_localhost == - 1)
10810Sstevel@tonic-gate 		options->no_host_authentication_for_localhost = 0;
10820Sstevel@tonic-gate 	if (options->fallback_to_rsh == - 1)
10830Sstevel@tonic-gate 		options->fallback_to_rsh = 0;
10840Sstevel@tonic-gate 	if (options->use_rsh == - 1)
10850Sstevel@tonic-gate 		options->use_rsh = 0;
10864668Sjp161948 	if (options->server_alive_interval == -1)
10874668Sjp161948 		options->server_alive_interval = 0;
10884668Sjp161948 	if (options->server_alive_count_max == -1)
10894668Sjp161948 		options->server_alive_count_max = 3;
10905243Sjp161948 	if (options->hash_known_hosts == -1)
10915243Sjp161948 		options->hash_known_hosts = 0;
10924958Sjp161948 	if (options->disable_banner == -1)
10934958Sjp161948 		options->disable_banner = 0;
10940Sstevel@tonic-gate 	/* options->proxy_command should not be set by default */
10950Sstevel@tonic-gate 	/* options->user will be set in the main program if appropriate */
10960Sstevel@tonic-gate 	/* options->hostname will be set in the main program if appropriate */
10970Sstevel@tonic-gate 	/* options->host_key_alias should not be set by default */
10980Sstevel@tonic-gate 	/* options->preferred_authentications will be set in ssh */
10995266Sjp161948 	/* options->ignore_if_unknown should not be set by default */
11000Sstevel@tonic-gate }
11015266Sjp161948 
11025266Sjp161948 /*
1103*5334Sjp161948  * Parses a string containing a port forwarding specification of one of the
1104*5334Sjp161948  * two forms, short or long:
1105*5334Sjp161948  *
1106*5334Sjp161948  *	[listenhost:]listenport
1107*5334Sjp161948  *	[listenhost:]listenport:connecthost:connectport
1108*5334Sjp161948  *
1109*5334Sjp161948  * short forwarding specification is used for dynamic port forwarding and for
1110*5334Sjp161948  * port forwarding cancelation in process_cmdline(). The function returns number
1111*5334Sjp161948  * of arguments parsed or zero on any error.
1112*5334Sjp161948  */
1113*5334Sjp161948 int
1114*5334Sjp161948 parse_forward(int long_form, Forward *fwd, const char *fwdspec)
1115*5334Sjp161948 {
1116*5334Sjp161948 	int i;
1117*5334Sjp161948 	char *p, *cp, *fwdarg[5];
1118*5334Sjp161948 
1119*5334Sjp161948 	memset(fwd, '\0', sizeof(*fwd));
1120*5334Sjp161948 
1121*5334Sjp161948 	cp = p = xstrdup(fwdspec);
1122*5334Sjp161948 
1123*5334Sjp161948 	/* skip leading spaces */
1124*5334Sjp161948 	while (isspace(*cp))
1125*5334Sjp161948 		cp++;
1126*5334Sjp161948 
1127*5334Sjp161948 	for (i = 0; i < 5; ++i)
1128*5334Sjp161948 		if ((fwdarg[i] = hpdelim(&cp)) == NULL)
1129*5334Sjp161948 			break;
1130*5334Sjp161948 
1131*5334Sjp161948 	if ((long_form == 0 && i > 2) || (long_form == 1 && i < 3) || (i == 5))
1132*5334Sjp161948 		goto fail_free;
1133*5334Sjp161948 
1134*5334Sjp161948 	switch (i) {
1135*5334Sjp161948 	case 0:
1136*5334Sjp161948 		goto fail_free;
1137*5334Sjp161948 
1138*5334Sjp161948 	case 1:
1139*5334Sjp161948 		fwd->listen_host = NULL;
1140*5334Sjp161948 		fwd->listen_port = a2port(fwdarg[0]);
1141*5334Sjp161948 		break;
1142*5334Sjp161948 
1143*5334Sjp161948 	case 2:
1144*5334Sjp161948 		fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1145*5334Sjp161948 		fwd->listen_port = a2port(fwdarg[1]);
1146*5334Sjp161948 		break;
1147*5334Sjp161948 
1148*5334Sjp161948 	case 3:
1149*5334Sjp161948 		fwd->listen_host = NULL;
1150*5334Sjp161948 		fwd->listen_port = a2port(fwdarg[0]);
1151*5334Sjp161948 		fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
1152*5334Sjp161948 		fwd->connect_port = a2port(fwdarg[2]);
1153*5334Sjp161948 		break;
1154*5334Sjp161948 
1155*5334Sjp161948 	case 4:
1156*5334Sjp161948 		fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1157*5334Sjp161948 		fwd->listen_port = a2port(fwdarg[1]);
1158*5334Sjp161948 		fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
1159*5334Sjp161948 		fwd->connect_port = a2port(fwdarg[3]);
1160*5334Sjp161948 		break;
1161*5334Sjp161948 	}
1162*5334Sjp161948 
1163*5334Sjp161948 	xfree(p);
1164*5334Sjp161948 
1165*5334Sjp161948 	if (fwd->listen_port == 0 || (fwd->connect_port == 0 && i > 2))
1166*5334Sjp161948 		goto fail_free;
1167*5334Sjp161948 
1168*5334Sjp161948 	return (i);
1169*5334Sjp161948 
1170*5334Sjp161948  fail_free:
1171*5334Sjp161948 	if (p != NULL)
1172*5334Sjp161948 		xfree(p);
1173*5334Sjp161948 	if (fwd->connect_host != NULL)
1174*5334Sjp161948 		xfree(fwd->connect_host);
1175*5334Sjp161948 	if (fwd->listen_host != NULL)
1176*5334Sjp161948 		xfree(fwd->listen_host);
1177*5334Sjp161948 	return (0);
1178*5334Sjp161948 }
1179*5334Sjp161948 
1180*5334Sjp161948 /*
11815266Sjp161948  * Process previously stored unknown options. When this function is called we
11825266Sjp161948  * already have IgnoreIfUnknown set so finally we can decide whether each
11835266Sjp161948  * unknown option is to be ignored or not.
11845266Sjp161948  */
11855266Sjp161948 void
11865266Sjp161948 process_unknown_options(Options *options)
11875266Sjp161948 {
11885266Sjp161948 	StoredOption *so;
11895266Sjp161948 	int m, i, bad_options = 0;
11905266Sjp161948 
11915266Sjp161948 	/* if there is no unknown option we are done */
11925266Sjp161948 	if (options->unknown_opts_num == 0)
11935266Sjp161948 		return;
11945266Sjp161948 
11955266Sjp161948 	/*
11965266Sjp161948 	 * Now go through the list of unknown options and report any one that
11975266Sjp161948 	 * is not explicitly listed in IgnoreIfUnknown option. If at least one
11985266Sjp161948 	 * such as that is found it's a show stopper.
11995266Sjp161948 	 */
12005266Sjp161948 	for (i = 0; i < options->unknown_opts_num; ++i) {
12015266Sjp161948 		so = &options->unknown_opts[i];
12025266Sjp161948 		if (options->ignore_if_unknown == NULL)
12035266Sjp161948 			m = 0;
12045266Sjp161948 		else
12055266Sjp161948 			m = match_pattern_list(tolowercase(so->keyword),
12065266Sjp161948 			    options->ignore_if_unknown,
12075266Sjp161948 			    strlen(options->ignore_if_unknown), 1);
12085266Sjp161948 		if (m == 1) {
12095266Sjp161948 			debug("%s: line %d: ignoring unknown option: %s",
12105266Sjp161948 			    so->filename, so->linenum, so->keyword);
12115266Sjp161948 		}
12125266Sjp161948 		else {
12135266Sjp161948 			error("%s: line %d: unknown configuration option: %s",
12145266Sjp161948 			    so->filename, so->linenum, so->keyword);
12155266Sjp161948 			bad_options++;
12165266Sjp161948 		}
12175266Sjp161948 		xfree(so->keyword);
12185266Sjp161948 		xfree(so->filename);
12195266Sjp161948 	}
12205266Sjp161948 
12215266Sjp161948 	/* exit if we found at least one unignored unknown option */
12225266Sjp161948 	if (bad_options > 0)
12235266Sjp161948 		fatal("terminating, %d bad configuration option(s)",
12245266Sjp161948 		    bad_options);
12255266Sjp161948 }
1226