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,
132*5562Sjp161948 	oIgnoreIfUnknown, oRekeyLimit,
133*5562Sjp161948 	oDeprecated
1340Sstevel@tonic-gate } OpCodes;
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate /* Textual representations of the tokens. */
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate static struct {
1390Sstevel@tonic-gate 	const char *name;
1400Sstevel@tonic-gate 	OpCodes opcode;
1410Sstevel@tonic-gate } keywords[] = {
1420Sstevel@tonic-gate 	{ "forwardagent", oForwardAgent },
1430Sstevel@tonic-gate 	{ "forwardx11", oForwardX11 },
1444907Sjp161948 	{ "forwardx11trusted", oForwardX11Trusted },
1450Sstevel@tonic-gate 	{ "xauthlocation", oXAuthLocation },
1460Sstevel@tonic-gate 	{ "gatewayports", oGatewayPorts },
1470Sstevel@tonic-gate 	{ "useprivilegedport", oUsePrivilegedPort },
1480Sstevel@tonic-gate 	{ "rhostsauthentication", oRhostsAuthentication },
1490Sstevel@tonic-gate 	{ "passwordauthentication", oPasswordAuthentication },
1500Sstevel@tonic-gate 	{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
1510Sstevel@tonic-gate 	{ "kbdinteractivedevices", oKbdInteractiveDevices },
1520Sstevel@tonic-gate 	{ "rsaauthentication", oRSAAuthentication },
1530Sstevel@tonic-gate 	{ "pubkeyauthentication", oPubkeyAuthentication },
1540Sstevel@tonic-gate 	{ "dsaauthentication", oPubkeyAuthentication },		    /* alias */
1550Sstevel@tonic-gate 	{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
1560Sstevel@tonic-gate 	{ "hostbasedauthentication", oHostbasedAuthentication },
1570Sstevel@tonic-gate 	{ "challengeresponseauthentication", oChallengeResponseAuthentication },
1580Sstevel@tonic-gate 	{ "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
1590Sstevel@tonic-gate 	{ "tisauthentication", oChallengeResponseAuthentication },  /* alias */
1600Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
1610Sstevel@tonic-gate 	{ "kerberosauthentication", oKerberosAuthentication },
1620Sstevel@tonic-gate #endif
1630Sstevel@tonic-gate #ifdef GSSAPI
1640Sstevel@tonic-gate 	{ "gssapikeyexchange", oGssKeyEx },
1650Sstevel@tonic-gate 	{ "gssapiauthentication", oGssAuthentication },
1660Sstevel@tonic-gate 	{ "gssapidelegatecredentials", oGssDelegateCreds },
1670Sstevel@tonic-gate 	{ "gsskeyex", oGssKeyEx },				/* alias */
1680Sstevel@tonic-gate 	{ "gssauthentication", oGssAuthentication },		/* alias */
1690Sstevel@tonic-gate 	{ "gssdelegatecreds", oGssDelegateCreds },		/* alias */
1700Sstevel@tonic-gate #ifdef GSI
1710Sstevel@tonic-gate 	/* For backwards compatability with old 1.2.27 client code */
1720Sstevel@tonic-gate 	{ "forwardgssapiglobusproxy", oGssDelegateCreds }, /* alias */
1730Sstevel@tonic-gate 	{ "forwardgssapiglobuslimitedproxy", oGssGlobusDelegateLimitedCreds },
1740Sstevel@tonic-gate #endif /* GSI */
1750Sstevel@tonic-gate #endif /* GSSAPI */
1760Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
1770Sstevel@tonic-gate 	{ "kerberostgtpassing", oKerberosTgtPassing },
1780Sstevel@tonic-gate #endif
1790Sstevel@tonic-gate #ifdef AFS
1800Sstevel@tonic-gate 	{ "afstokenpassing", oAFSTokenPassing },
1810Sstevel@tonic-gate #endif
1820Sstevel@tonic-gate 	{ "fallbacktorsh", oFallBackToRsh },
1830Sstevel@tonic-gate 	{ "usersh", oUseRsh },
1840Sstevel@tonic-gate 	{ "identityfile", oIdentityFile },
1850Sstevel@tonic-gate 	{ "identityfile2", oIdentityFile },			/* alias */
1860Sstevel@tonic-gate 	{ "hostname", oHostName },
1870Sstevel@tonic-gate 	{ "hostkeyalias", oHostKeyAlias },
1880Sstevel@tonic-gate 	{ "proxycommand", oProxyCommand },
1890Sstevel@tonic-gate 	{ "port", oPort },
1900Sstevel@tonic-gate 	{ "cipher", oCipher },
1910Sstevel@tonic-gate 	{ "ciphers", oCiphers },
1920Sstevel@tonic-gate 	{ "macs", oMacs },
1930Sstevel@tonic-gate 	{ "protocol", oProtocol },
1940Sstevel@tonic-gate 	{ "remoteforward", oRemoteForward },
1950Sstevel@tonic-gate 	{ "localforward", oLocalForward },
1960Sstevel@tonic-gate 	{ "user", oUser },
1970Sstevel@tonic-gate 	{ "host", oHost },
1980Sstevel@tonic-gate 	{ "escapechar", oEscapeChar },
1990Sstevel@tonic-gate 	{ "globalknownhostsfile", oGlobalKnownHostsFile },
2000Sstevel@tonic-gate 	{ "userknownhostsfile", oUserKnownHostsFile },		/* obsolete */
2010Sstevel@tonic-gate 	{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },
2020Sstevel@tonic-gate 	{ "userknownhostsfile2", oUserKnownHostsFile2 },	/* obsolete */
2030Sstevel@tonic-gate 	{ "connectionattempts", oConnectionAttempts },
2040Sstevel@tonic-gate 	{ "batchmode", oBatchMode },
2050Sstevel@tonic-gate 	{ "checkhostip", oCheckHostIP },
2060Sstevel@tonic-gate 	{ "stricthostkeychecking", oStrictHostKeyChecking },
2070Sstevel@tonic-gate 	{ "compression", oCompression },
2080Sstevel@tonic-gate 	{ "compressionlevel", oCompressionLevel },
2090Sstevel@tonic-gate 	{ "keepalive", oKeepAlives },
2100Sstevel@tonic-gate 	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
2110Sstevel@tonic-gate 	{ "loglevel", oLogLevel },
2120Sstevel@tonic-gate 	{ "dynamicforward", oDynamicForward },
2130Sstevel@tonic-gate 	{ "preferredauthentications", oPreferredAuthentications },
2140Sstevel@tonic-gate 	{ "hostkeyalgorithms", oHostKeyAlgorithms },
2150Sstevel@tonic-gate 	{ "bindaddress", oBindAddress },
2160Sstevel@tonic-gate 	{ "smartcarddevice", oSmartcardDevice },
2170Sstevel@tonic-gate 	{ "clearallforwardings", oClearAllForwardings },
2180Sstevel@tonic-gate 	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
219*5562Sjp161948 	{ "rekeylimit", oRekeyLimit },
2203946Sjp161948 	{ "connecttimeout", oConnectTimeout },
2214668Sjp161948 	{ "serveraliveinterval", oServerAliveInterval },
2224668Sjp161948 	{ "serveralivecountmax", oServerAliveCountMax },
2234958Sjp161948 	{ "disablebanner", oDisableBanner },
2245243Sjp161948 	{ "hashknownhosts", oHashKnownHosts },
2255266Sjp161948 	{ "ignoreifunknown", oIgnoreIfUnknown },
2260Sstevel@tonic-gate 	{ NULL, oBadOption }
2270Sstevel@tonic-gate };
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate /*
2300Sstevel@tonic-gate  * Adds a local TCP/IP port forward to options.  Never returns if there is an
2310Sstevel@tonic-gate  * error.
2320Sstevel@tonic-gate  */
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate void
2355334Sjp161948 add_local_forward(Options *options, const Forward *newfwd)
2360Sstevel@tonic-gate {
2370Sstevel@tonic-gate 	Forward *fwd;
2380Sstevel@tonic-gate #ifndef NO_IPPORT_RESERVED_CONCEPT
2390Sstevel@tonic-gate 	extern uid_t original_real_uid;
2405334Sjp161948 	if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0)
2410Sstevel@tonic-gate 		fatal("Privileged ports can only be forwarded by root.");
2420Sstevel@tonic-gate #endif
2430Sstevel@tonic-gate 	if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
2440Sstevel@tonic-gate 		fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
2450Sstevel@tonic-gate 	fwd = &options->local_forwards[options->num_local_forwards++];
2465334Sjp161948 
2475334Sjp161948 	fwd->listen_host = (newfwd->listen_host == NULL) ?
2485334Sjp161948 	    NULL : xstrdup(newfwd->listen_host);
2495334Sjp161948 	fwd->listen_port = newfwd->listen_port;
2505334Sjp161948 	fwd->connect_host = xstrdup(newfwd->connect_host);
2515334Sjp161948 	fwd->connect_port = newfwd->connect_port;
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate /*
2550Sstevel@tonic-gate  * Adds a remote TCP/IP port forward to options.  Never returns if there is
2560Sstevel@tonic-gate  * an error.
2570Sstevel@tonic-gate  */
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate void
2605334Sjp161948 add_remote_forward(Options *options, const Forward *newfwd)
2610Sstevel@tonic-gate {
2620Sstevel@tonic-gate 	Forward *fwd;
2630Sstevel@tonic-gate 	if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
2640Sstevel@tonic-gate 		fatal("Too many remote forwards (max %d).",
2650Sstevel@tonic-gate 		    SSH_MAX_FORWARDS_PER_DIRECTION);
2660Sstevel@tonic-gate 	fwd = &options->remote_forwards[options->num_remote_forwards++];
2675334Sjp161948 
2685334Sjp161948 	fwd->listen_host = (newfwd->listen_host == NULL) ?
2695334Sjp161948 	    NULL : xstrdup(newfwd->listen_host);
2705334Sjp161948 	fwd->listen_port = newfwd->listen_port;
2715334Sjp161948 	fwd->connect_host = xstrdup(newfwd->connect_host);
2725334Sjp161948 	fwd->connect_port = newfwd->connect_port;
2730Sstevel@tonic-gate }
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate static void
2760Sstevel@tonic-gate clear_forwardings(Options *options)
2770Sstevel@tonic-gate {
2780Sstevel@tonic-gate 	int i;
2790Sstevel@tonic-gate 
2805334Sjp161948 	for (i = 0; i < options->num_local_forwards; i++) {
2815334Sjp161948 		if (options->local_forwards[i].listen_host != NULL)
2825334Sjp161948 			xfree(options->local_forwards[i].listen_host);
2835334Sjp161948 		xfree(options->local_forwards[i].connect_host);
2845334Sjp161948 	}
2850Sstevel@tonic-gate 	options->num_local_forwards = 0;
2865334Sjp161948 	for (i = 0; i < options->num_remote_forwards; i++) {
2875334Sjp161948 		if (options->remote_forwards[i].listen_host != NULL)
2885334Sjp161948 			xfree(options->remote_forwards[i].listen_host);
2895334Sjp161948 		xfree(options->remote_forwards[i].connect_host);
2905334Sjp161948 	}
2910Sstevel@tonic-gate 	options->num_remote_forwards = 0;
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate /*
2950Sstevel@tonic-gate  * Returns the number of the token pointed to by cp or oBadOption.
2960Sstevel@tonic-gate  */
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate static OpCodes
2990Sstevel@tonic-gate parse_token(const char *cp, const char *filename, int linenum)
3000Sstevel@tonic-gate {
3010Sstevel@tonic-gate 	u_int i;
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	for (i = 0; keywords[i].name; i++)
3040Sstevel@tonic-gate 		if (strcasecmp(cp, keywords[i].name) == 0)
3050Sstevel@tonic-gate 			return keywords[i].opcode;
3060Sstevel@tonic-gate 
3075266Sjp161948 	debug("%s: line %d: unknown configuration option: %s",
3080Sstevel@tonic-gate 	    filename, linenum, cp);
3090Sstevel@tonic-gate 	return oBadOption;
3100Sstevel@tonic-gate }
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate /*
3130Sstevel@tonic-gate  * Processes a single option line as used in the configuration files. This
3140Sstevel@tonic-gate  * only sets those values that have not already been set.
3150Sstevel@tonic-gate  */
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate int
3180Sstevel@tonic-gate process_config_line(Options *options, const char *host,
3190Sstevel@tonic-gate 		    char *line, const char *filename, int linenum,
3200Sstevel@tonic-gate 		    int *activep)
3210Sstevel@tonic-gate {
3225334Sjp161948 	char *s, *string, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256];
323*5562Sjp161948 	int opcode, *intptr, value, scale, i;
324*5562Sjp161948 	long long orig, val64;
3255266Sjp161948 	StoredOption *so;
3265334Sjp161948 	Forward fwd;
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	s = line;
3290Sstevel@tonic-gate 	/* Get the keyword. (Each line is supposed to begin with a keyword). */
3300Sstevel@tonic-gate 	keyword = strdelim(&s);
3310Sstevel@tonic-gate 	/* Ignore leading whitespace. */
3320Sstevel@tonic-gate 	if (*keyword == '\0')
3330Sstevel@tonic-gate 		keyword = strdelim(&s);
3340Sstevel@tonic-gate 	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
3350Sstevel@tonic-gate 		return 0;
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	opcode = parse_token(keyword, filename, linenum);
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	switch (opcode) {
3400Sstevel@tonic-gate 	case oBadOption:
3415266Sjp161948 		if (options->unknown_opts_num == MAX_UNKNOWN_OPTIONS) {
3425266Sjp161948 			error("we can't have more than %d unknown options:",
3435266Sjp161948 			    MAX_UNKNOWN_OPTIONS);
3445266Sjp161948 			for (i = 0; i < MAX_UNKNOWN_OPTIONS; ++i) {
3455266Sjp161948 				so = &options->unknown_opts[i];
3465266Sjp161948 				error("%s:%d:%s",
3475266Sjp161948 				    so->filename, so->linenum, so->keyword);
3485266Sjp161948 				xfree(so->keyword);
3495266Sjp161948 				xfree(so->filename);
3505266Sjp161948 			}
3515266Sjp161948 			fatal("too many unknown options found, can't continue");
3525266Sjp161948 		}
3535266Sjp161948 
3545266Sjp161948 		/* unknown options will be processed later */
3555266Sjp161948 		so = &options->unknown_opts[options->unknown_opts_num];
3565266Sjp161948 		so->keyword = xstrdup(keyword);
3575266Sjp161948 		so->filename = xstrdup(filename);
3585266Sjp161948 		so->linenum = linenum;
3595266Sjp161948 		options->unknown_opts_num++;
3605266Sjp161948 		return (0);
3615266Sjp161948 
3620Sstevel@tonic-gate 		/* NOTREACHED */
3633946Sjp161948 	case oConnectTimeout:
3643946Sjp161948 		intptr = &options->connection_timeout;
3653946Sjp161948 parse_time:
3663946Sjp161948 		arg = strdelim(&s);
3673946Sjp161948 		if (!arg || *arg == '\0')
3683946Sjp161948 			fatal("%s line %d: missing time value.",
3693946Sjp161948 			    filename, linenum);
3703946Sjp161948 		if ((value = convtime(arg)) == -1)
3713946Sjp161948 			fatal("%s line %d: invalid time value.",
3723946Sjp161948 			    filename, linenum);
3733984Sjp161948 		if (*activep && *intptr == -1)
3743946Sjp161948 			*intptr = value;
3753946Sjp161948 		break;
3763946Sjp161948 
3770Sstevel@tonic-gate 	case oForwardAgent:
3780Sstevel@tonic-gate 		intptr = &options->forward_agent;
3790Sstevel@tonic-gate parse_flag:
3800Sstevel@tonic-gate 		arg = strdelim(&s);
3810Sstevel@tonic-gate 		if (!arg || *arg == '\0')
3820Sstevel@tonic-gate 			fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
3830Sstevel@tonic-gate 		value = 0;	/* To avoid compiler warning... */
3840Sstevel@tonic-gate 		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
3850Sstevel@tonic-gate 			value = 1;
3860Sstevel@tonic-gate 		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
3870Sstevel@tonic-gate 			value = 0;
3880Sstevel@tonic-gate 		else
3890Sstevel@tonic-gate 			fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
3900Sstevel@tonic-gate 		if (*activep && *intptr == -1)
3910Sstevel@tonic-gate 			*intptr = value;
3920Sstevel@tonic-gate 		break;
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	case oForwardX11:
3950Sstevel@tonic-gate 		intptr = &options->forward_x11;
3960Sstevel@tonic-gate 		goto parse_flag;
3970Sstevel@tonic-gate 
3984907Sjp161948 	case oForwardX11Trusted:
3994907Sjp161948 		intptr = &options->forward_x11_trusted;
4004907Sjp161948 		goto parse_flag;
4014907Sjp161948 
4020Sstevel@tonic-gate 	case oGatewayPorts:
4030Sstevel@tonic-gate 		intptr = &options->gateway_ports;
4040Sstevel@tonic-gate 		goto parse_flag;
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	case oUsePrivilegedPort:
4070Sstevel@tonic-gate 		intptr = &options->use_privileged_port;
4080Sstevel@tonic-gate 		goto parse_flag;
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	case oRhostsAuthentication:
4110Sstevel@tonic-gate 		intptr = &options->rhosts_authentication;
4120Sstevel@tonic-gate 		goto parse_flag;
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	case oPasswordAuthentication:
4150Sstevel@tonic-gate 		intptr = &options->password_authentication;
4160Sstevel@tonic-gate 		goto parse_flag;
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	case oKbdInteractiveAuthentication:
4190Sstevel@tonic-gate 		intptr = &options->kbd_interactive_authentication;
4200Sstevel@tonic-gate 		goto parse_flag;
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	case oKbdInteractiveDevices:
4230Sstevel@tonic-gate 		charptr = &options->kbd_interactive_devices;
4240Sstevel@tonic-gate 		goto parse_string;
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	case oPubkeyAuthentication:
4270Sstevel@tonic-gate 		intptr = &options->pubkey_authentication;
4280Sstevel@tonic-gate 		goto parse_flag;
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	case oRSAAuthentication:
4310Sstevel@tonic-gate 		intptr = &options->rsa_authentication;
4320Sstevel@tonic-gate 		goto parse_flag;
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	case oRhostsRSAAuthentication:
4350Sstevel@tonic-gate 		intptr = &options->rhosts_rsa_authentication;
4360Sstevel@tonic-gate 		goto parse_flag;
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 	case oHostbasedAuthentication:
4390Sstevel@tonic-gate 		intptr = &options->hostbased_authentication;
4400Sstevel@tonic-gate 		goto parse_flag;
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	case oChallengeResponseAuthentication:
4430Sstevel@tonic-gate 		intptr = &options->challenge_response_authentication;
4440Sstevel@tonic-gate 		goto parse_flag;
4450Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
4460Sstevel@tonic-gate 	case oKerberosAuthentication:
4470Sstevel@tonic-gate 		intptr = &options->kerberos_authentication;
4480Sstevel@tonic-gate 		goto parse_flag;
4490Sstevel@tonic-gate #endif
4500Sstevel@tonic-gate #ifdef GSSAPI
4510Sstevel@tonic-gate 	case oGssKeyEx:
4520Sstevel@tonic-gate 		intptr = &options->gss_keyex;
4530Sstevel@tonic-gate 		goto parse_flag;
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	case oGssAuthentication:
4560Sstevel@tonic-gate 		intptr = &options->gss_authentication;
4570Sstevel@tonic-gate 		goto parse_flag;
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	case oGssDelegateCreds:
4600Sstevel@tonic-gate 		intptr = &options->gss_deleg_creds;
4610Sstevel@tonic-gate 		goto parse_flag;
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate #ifdef GSI
4640Sstevel@tonic-gate 	case oGssGlobusDelegateLimitedCreds:
4650Sstevel@tonic-gate 		intptr = &options->gss_globus_deleg_limited_proxy;
4660Sstevel@tonic-gate 		goto parse_flag;
4670Sstevel@tonic-gate #endif /* GSI */
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate #endif /* GSSAPI */
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
4720Sstevel@tonic-gate 	case oKerberosTgtPassing:
4730Sstevel@tonic-gate 		intptr = &options->kerberos_tgt_passing;
4740Sstevel@tonic-gate 		goto parse_flag;
4750Sstevel@tonic-gate #endif
4760Sstevel@tonic-gate #ifdef AFS
4770Sstevel@tonic-gate 	case oAFSTokenPassing:
4780Sstevel@tonic-gate 		intptr = &options->afs_token_passing;
4790Sstevel@tonic-gate 		goto parse_flag;
4800Sstevel@tonic-gate #endif
4810Sstevel@tonic-gate 	case oFallBackToRsh:
4820Sstevel@tonic-gate 		intptr = &options->fallback_to_rsh;
4830Sstevel@tonic-gate 		goto parse_flag;
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	case oUseRsh:
4860Sstevel@tonic-gate 		intptr = &options->use_rsh;
4870Sstevel@tonic-gate 		goto parse_flag;
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 	case oBatchMode:
4900Sstevel@tonic-gate 		intptr = &options->batch_mode;
4910Sstevel@tonic-gate 		goto parse_flag;
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	case oCheckHostIP:
4940Sstevel@tonic-gate 		intptr = &options->check_host_ip;
4950Sstevel@tonic-gate 		goto parse_flag;
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	case oStrictHostKeyChecking:
4980Sstevel@tonic-gate 		intptr = &options->strict_host_key_checking;
4990Sstevel@tonic-gate 		arg = strdelim(&s);
5000Sstevel@tonic-gate 		if (!arg || *arg == '\0')
5010Sstevel@tonic-gate 			fatal("%.200s line %d: Missing yes/no/ask argument.",
5020Sstevel@tonic-gate 			    filename, linenum);
5030Sstevel@tonic-gate 		value = 0;	/* To avoid compiler warning... */
5040Sstevel@tonic-gate 		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
5050Sstevel@tonic-gate 			value = 1;
5060Sstevel@tonic-gate 		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
5070Sstevel@tonic-gate 			value = 0;
5080Sstevel@tonic-gate 		else if (strcmp(arg, "ask") == 0)
5090Sstevel@tonic-gate 			value = 2;
5100Sstevel@tonic-gate 		else
5110Sstevel@tonic-gate 			fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
5120Sstevel@tonic-gate 		if (*activep && *intptr == -1)
5130Sstevel@tonic-gate 			*intptr = value;
5140Sstevel@tonic-gate 		break;
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	case oCompression:
5170Sstevel@tonic-gate 		intptr = &options->compression;
5180Sstevel@tonic-gate 		goto parse_flag;
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	case oKeepAlives:
5210Sstevel@tonic-gate 		intptr = &options->keepalives;
5220Sstevel@tonic-gate 		goto parse_flag;
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	case oNoHostAuthenticationForLocalhost:
5250Sstevel@tonic-gate 		intptr = &options->no_host_authentication_for_localhost;
5260Sstevel@tonic-gate 		goto parse_flag;
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	case oNumberOfPasswordPrompts:
5290Sstevel@tonic-gate 		intptr = &options->number_of_password_prompts;
5300Sstevel@tonic-gate 		goto parse_int;
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 	case oCompressionLevel:
5330Sstevel@tonic-gate 		intptr = &options->compression_level;
5340Sstevel@tonic-gate 		goto parse_int;
5350Sstevel@tonic-gate 
536*5562Sjp161948 	case oRekeyLimit:
537*5562Sjp161948 		arg = strdelim(&s);
538*5562Sjp161948 		if (!arg || *arg == '\0')
539*5562Sjp161948 			fatal("%.200s line %d: Missing argument.", filename, linenum);
540*5562Sjp161948 		if (arg[0] < '0' || arg[0] > '9')
541*5562Sjp161948 			fatal("%.200s line %d: Bad number.", filename, linenum);
542*5562Sjp161948 		orig = val64 = strtoll(arg, &endofnumber, 10);
543*5562Sjp161948 		if (arg == endofnumber)
544*5562Sjp161948 			fatal("%.200s line %d: Bad number.", filename, linenum);
545*5562Sjp161948 		switch (toupper(*endofnumber)) {
546*5562Sjp161948 		case '\0':
547*5562Sjp161948 			scale = 1;
548*5562Sjp161948 			break;
549*5562Sjp161948 		case 'K':
550*5562Sjp161948 			scale = 1<<10;
551*5562Sjp161948 			break;
552*5562Sjp161948 		case 'M':
553*5562Sjp161948 			scale = 1<<20;
554*5562Sjp161948 			break;
555*5562Sjp161948 		case 'G':
556*5562Sjp161948 			scale = 1<<30;
557*5562Sjp161948 			break;
558*5562Sjp161948 		default:
559*5562Sjp161948 			fatal("%.200s line %d: Invalid RekeyLimit suffix",
560*5562Sjp161948 			    filename, linenum);
561*5562Sjp161948 		}
562*5562Sjp161948 		val64 *= scale;
563*5562Sjp161948 		/* detect integer wrap and too-large limits */
564*5562Sjp161948 		if ((val64 / scale) != orig || val64 > UINT_MAX)
565*5562Sjp161948 			fatal("%.200s line %d: RekeyLimit too large",
566*5562Sjp161948 			    filename, linenum);
567*5562Sjp161948 		if (val64 < 16)
568*5562Sjp161948 			fatal("%.200s line %d: RekeyLimit too small",
569*5562Sjp161948 			    filename, linenum);
570*5562Sjp161948 		if (*activep && options->rekey_limit == -1)
571*5562Sjp161948 			options->rekey_limit = (u_int32_t)val64;
572*5562Sjp161948 		break;
573*5562Sjp161948 
5740Sstevel@tonic-gate 	case oIdentityFile:
5750Sstevel@tonic-gate 		arg = strdelim(&s);
5760Sstevel@tonic-gate 		if (!arg || *arg == '\0')
5770Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
5780Sstevel@tonic-gate 		if (*activep) {
5790Sstevel@tonic-gate 			intptr = &options->num_identity_files;
5800Sstevel@tonic-gate 			if (*intptr >= SSH_MAX_IDENTITY_FILES)
5810Sstevel@tonic-gate 				fatal("%.200s line %d: Too many identity files specified (max %d).",
5820Sstevel@tonic-gate 				    filename, linenum, SSH_MAX_IDENTITY_FILES);
5830Sstevel@tonic-gate 			charptr =  &options->identity_files[*intptr];
5840Sstevel@tonic-gate 			*charptr = xstrdup(arg);
5850Sstevel@tonic-gate 			*intptr = *intptr + 1;
5860Sstevel@tonic-gate 		}
5870Sstevel@tonic-gate 		break;
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	case oXAuthLocation:
5900Sstevel@tonic-gate 		charptr=&options->xauth_location;
5910Sstevel@tonic-gate 		goto parse_string;
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 	case oUser:
5940Sstevel@tonic-gate 		charptr = &options->user;
5950Sstevel@tonic-gate parse_string:
5960Sstevel@tonic-gate 		arg = strdelim(&s);
5970Sstevel@tonic-gate 		if (!arg || *arg == '\0')
5980Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
5990Sstevel@tonic-gate 		if (*activep && *charptr == NULL)
6000Sstevel@tonic-gate 			*charptr = xstrdup(arg);
6010Sstevel@tonic-gate 		break;
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	case oGlobalKnownHostsFile:
6040Sstevel@tonic-gate 		charptr = &options->system_hostfile;
6050Sstevel@tonic-gate 		goto parse_string;
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	case oUserKnownHostsFile:
6080Sstevel@tonic-gate 		charptr = &options->user_hostfile;
6090Sstevel@tonic-gate 		goto parse_string;
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	case oGlobalKnownHostsFile2:
6120Sstevel@tonic-gate 		charptr = &options->system_hostfile2;
6130Sstevel@tonic-gate 		goto parse_string;
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	case oUserKnownHostsFile2:
6160Sstevel@tonic-gate 		charptr = &options->user_hostfile2;
6170Sstevel@tonic-gate 		goto parse_string;
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	case oHostName:
6200Sstevel@tonic-gate 		charptr = &options->hostname;
6210Sstevel@tonic-gate 		goto parse_string;
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 	case oHostKeyAlias:
6240Sstevel@tonic-gate 		charptr = &options->host_key_alias;
6250Sstevel@tonic-gate 		goto parse_string;
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	case oPreferredAuthentications:
6280Sstevel@tonic-gate 		charptr = &options->preferred_authentications;
6290Sstevel@tonic-gate 		goto parse_string;
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	case oBindAddress:
6320Sstevel@tonic-gate 		charptr = &options->bind_address;
6330Sstevel@tonic-gate 		goto parse_string;
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 	case oSmartcardDevice:
6360Sstevel@tonic-gate 		charptr = &options->smartcard_device;
6370Sstevel@tonic-gate 		goto parse_string;
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 	case oProxyCommand:
6400Sstevel@tonic-gate 		charptr = &options->proxy_command;
6410Sstevel@tonic-gate 		string = xstrdup("");
6420Sstevel@tonic-gate 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
6430Sstevel@tonic-gate 			string = xrealloc(string, strlen(string) + strlen(arg) + 2);
6440Sstevel@tonic-gate 			strcat(string, " ");
6450Sstevel@tonic-gate 			strcat(string, arg);
6460Sstevel@tonic-gate 		}
6470Sstevel@tonic-gate 		if (*activep && *charptr == NULL)
6480Sstevel@tonic-gate 			*charptr = string;
6490Sstevel@tonic-gate 		else
6500Sstevel@tonic-gate 			xfree(string);
6510Sstevel@tonic-gate 		return 0;
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 	case oPort:
6540Sstevel@tonic-gate 		intptr = &options->port;
6550Sstevel@tonic-gate parse_int:
6560Sstevel@tonic-gate 		arg = strdelim(&s);
6570Sstevel@tonic-gate 		if (!arg || *arg == '\0')
6580Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
6590Sstevel@tonic-gate 		if (arg[0] < '0' || arg[0] > '9')
6600Sstevel@tonic-gate 			fatal("%.200s line %d: Bad number.", filename, linenum);
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 		/* Octal, decimal, or hex format? */
6630Sstevel@tonic-gate 		value = strtol(arg, &endofnumber, 0);
6640Sstevel@tonic-gate 		if (arg == endofnumber)
6650Sstevel@tonic-gate 			fatal("%.200s line %d: Bad number.", filename, linenum);
6660Sstevel@tonic-gate 		if (*activep && *intptr == -1)
6670Sstevel@tonic-gate 			*intptr = value;
6680Sstevel@tonic-gate 		break;
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 	case oConnectionAttempts:
6710Sstevel@tonic-gate 		intptr = &options->connection_attempts;
6720Sstevel@tonic-gate 		goto parse_int;
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 	case oCipher:
6750Sstevel@tonic-gate 		intptr = &options->cipher;
6760Sstevel@tonic-gate 		arg = strdelim(&s);
6770Sstevel@tonic-gate 		if (!arg || *arg == '\0')
6780Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
6790Sstevel@tonic-gate 		value = cipher_number(arg);
6800Sstevel@tonic-gate 		if (value == -1)
6810Sstevel@tonic-gate 			fatal("%.200s line %d: Bad cipher '%s'.",
6820Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
6830Sstevel@tonic-gate 		if (*activep && *intptr == -1)
6840Sstevel@tonic-gate 			*intptr = value;
6850Sstevel@tonic-gate 		break;
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 	case oCiphers:
6880Sstevel@tonic-gate 		arg = strdelim(&s);
6890Sstevel@tonic-gate 		if (!arg || *arg == '\0')
6900Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
6910Sstevel@tonic-gate 		if (!ciphers_valid(arg))
6920Sstevel@tonic-gate 			fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
6930Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
6940Sstevel@tonic-gate 		if (*activep && options->ciphers == NULL)
6950Sstevel@tonic-gate 			options->ciphers = xstrdup(arg);
6960Sstevel@tonic-gate 		break;
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	case oMacs:
6990Sstevel@tonic-gate 		arg = strdelim(&s);
7000Sstevel@tonic-gate 		if (!arg || *arg == '\0')
7010Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
7020Sstevel@tonic-gate 		if (!mac_valid(arg))
7030Sstevel@tonic-gate 			fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
7040Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
7050Sstevel@tonic-gate 		if (*activep && options->macs == NULL)
7060Sstevel@tonic-gate 			options->macs = xstrdup(arg);
7070Sstevel@tonic-gate 		break;
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 	case oHostKeyAlgorithms:
7100Sstevel@tonic-gate 		arg = strdelim(&s);
7110Sstevel@tonic-gate 		if (!arg || *arg == '\0')
7120Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
7130Sstevel@tonic-gate 		if (!key_names_valid2(arg))
7140Sstevel@tonic-gate 			fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
7150Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
7160Sstevel@tonic-gate 		if (*activep && options->hostkeyalgorithms == NULL)
7170Sstevel@tonic-gate 			options->hostkeyalgorithms = xstrdup(arg);
7180Sstevel@tonic-gate 		break;
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 	case oProtocol:
7210Sstevel@tonic-gate 		intptr = &options->protocol;
7220Sstevel@tonic-gate 		arg = strdelim(&s);
7230Sstevel@tonic-gate 		if (!arg || *arg == '\0')
7240Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
7250Sstevel@tonic-gate 		value = proto_spec(arg);
7260Sstevel@tonic-gate 		if (value == SSH_PROTO_UNKNOWN)
7270Sstevel@tonic-gate 			fatal("%.200s line %d: Bad protocol spec '%s'.",
7280Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
7290Sstevel@tonic-gate 		if (*activep && *intptr == SSH_PROTO_UNKNOWN)
7300Sstevel@tonic-gate 			*intptr = value;
7310Sstevel@tonic-gate 		break;
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 	case oLogLevel:
7340Sstevel@tonic-gate 		intptr = (int *) &options->log_level;
7350Sstevel@tonic-gate 		arg = strdelim(&s);
7360Sstevel@tonic-gate 		value = log_level_number(arg);
7370Sstevel@tonic-gate 		if (value == SYSLOG_LEVEL_NOT_SET)
7380Sstevel@tonic-gate 			fatal("%.200s line %d: unsupported log level '%s'",
7390Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
7400Sstevel@tonic-gate 		if (*activep && (LogLevel) *intptr == SYSLOG_LEVEL_NOT_SET)
7410Sstevel@tonic-gate 			*intptr = (LogLevel) value;
7420Sstevel@tonic-gate 		break;
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	case oLocalForward:
7450Sstevel@tonic-gate 	case oRemoteForward:
7460Sstevel@tonic-gate 		arg = strdelim(&s);
7475334Sjp161948 		if (arg == NULL || *arg == '\0')
7480Sstevel@tonic-gate 			fatal("%.200s line %d: Missing port argument.",
7490Sstevel@tonic-gate 			    filename, linenum);
7505334Sjp161948 		arg2 = strdelim(&s);
7515334Sjp161948 		if (arg2 == NULL || *arg2 == '\0')
7525334Sjp161948 			fatal("%.200s line %d: Missing target argument.",
7530Sstevel@tonic-gate 			    filename, linenum);
7545334Sjp161948 
7555334Sjp161948 		/* construct a string for parse_forward */
7565334Sjp161948 		snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
7575334Sjp161948 
7585334Sjp161948 		if (parse_forward(1, &fwd, fwdarg) == 0)
7590Sstevel@tonic-gate 			fatal("%.200s line %d: Bad forwarding specification.",
7600Sstevel@tonic-gate 			    filename, linenum);
7615334Sjp161948 
7620Sstevel@tonic-gate 		if (*activep) {
7630Sstevel@tonic-gate 			if (opcode == oLocalForward)
7645334Sjp161948 				add_local_forward(options, &fwd);
7650Sstevel@tonic-gate 			else if (opcode == oRemoteForward)
7665334Sjp161948 				add_remote_forward(options, &fwd);
7670Sstevel@tonic-gate 		}
7680Sstevel@tonic-gate 		break;
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	case oDynamicForward:
7710Sstevel@tonic-gate 		arg = strdelim(&s);
7720Sstevel@tonic-gate 		if (!arg || *arg == '\0')
7730Sstevel@tonic-gate 			fatal("%.200s line %d: Missing port argument.",
7740Sstevel@tonic-gate 			    filename, linenum);
7755334Sjp161948 
7765334Sjp161948 		if (parse_forward(0, &fwd, arg) == 0) {
7775334Sjp161948 			fatal("%.200s line %d: Bad dynamic forwarding specification.",
7780Sstevel@tonic-gate 			    filename, linenum);
7795334Sjp161948 		}
7805334Sjp161948 
7815334Sjp161948 		if (*activep) {
7825334Sjp161948 			fwd.connect_host = "socks";
7835334Sjp161948 			add_local_forward(options, &fwd);
7845334Sjp161948 		}
7850Sstevel@tonic-gate 		break;
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 	case oClearAllForwardings:
7880Sstevel@tonic-gate 		intptr = &options->clear_forwardings;
7890Sstevel@tonic-gate 		goto parse_flag;
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 	case oHost:
7920Sstevel@tonic-gate 		*activep = 0;
7930Sstevel@tonic-gate 		while ((arg = strdelim(&s)) != NULL && *arg != '\0')
7940Sstevel@tonic-gate 			if (match_pattern(host, arg)) {
7950Sstevel@tonic-gate 				debug("Applying options for %.100s", arg);
7960Sstevel@tonic-gate 				*activep = 1;
7970Sstevel@tonic-gate 				break;
7980Sstevel@tonic-gate 			}
7990Sstevel@tonic-gate 		/* Avoid garbage check below, as strdelim is done. */
8000Sstevel@tonic-gate 		return 0;
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 	case oEscapeChar:
8030Sstevel@tonic-gate 		intptr = &options->escape_char;
8040Sstevel@tonic-gate 		arg = strdelim(&s);
8050Sstevel@tonic-gate 		if (!arg || *arg == '\0')
8060Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
8070Sstevel@tonic-gate 		if (arg[0] == '^' && arg[2] == 0 &&
8080Sstevel@tonic-gate 		    (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
8090Sstevel@tonic-gate 			value = (u_char) arg[1] & 31;
8100Sstevel@tonic-gate 		else if (strlen(arg) == 1)
8110Sstevel@tonic-gate 			value = (u_char) arg[0];
8120Sstevel@tonic-gate 		else if (strcmp(arg, "none") == 0)
8130Sstevel@tonic-gate 			value = SSH_ESCAPECHAR_NONE;
8140Sstevel@tonic-gate 		else {
8150Sstevel@tonic-gate 			fatal("%.200s line %d: Bad escape character.",
8160Sstevel@tonic-gate 			    filename, linenum);
8170Sstevel@tonic-gate 			/* NOTREACHED */
8180Sstevel@tonic-gate 			value = 0;	/* Avoid compiler warning. */
8190Sstevel@tonic-gate 		}
8200Sstevel@tonic-gate 		if (*activep && *intptr == -1)
8210Sstevel@tonic-gate 			*intptr = value;
8220Sstevel@tonic-gate 		break;
8230Sstevel@tonic-gate 
8244668Sjp161948 	case oServerAliveInterval:
8254668Sjp161948 		intptr = &options->server_alive_interval;
8264668Sjp161948 		goto parse_time;
8274668Sjp161948 
8284668Sjp161948 	case oServerAliveCountMax:
8294668Sjp161948 		intptr = &options->server_alive_count_max;
8304668Sjp161948 		goto parse_int;
8314668Sjp161948 
8325243Sjp161948 	case oHashKnownHosts:
8335243Sjp161948 		intptr = &options->hash_known_hosts;
8345243Sjp161948 		goto parse_flag;
8355243Sjp161948 
8364958Sjp161948 	case oDisableBanner:
8374958Sjp161948 		arg = strdelim(&s);
8384958Sjp161948 		if (get_yes_no_flag(&options->disable_banner, arg, filename,
8394958Sjp161948 		    linenum, *activep) == 1)
8404958Sjp161948 			break;
8414958Sjp161948 
8424958Sjp161948 		if (strcmp(arg, "in-exec-mode") == 0)
8434958Sjp161948 			options->disable_banner = SSH_NO_BANNER_IN_EXEC_MODE;
8444958Sjp161948 		else
8454958Sjp161948 			fatal("%.200s line %d: Bad yes/no/in-exec-mode "
8464958Sjp161948 			    "argument.", filename, linenum);
8474958Sjp161948 		break;
8484958Sjp161948 
8495266Sjp161948 	case oIgnoreIfUnknown:
8505266Sjp161948 		charptr = &options->ignore_if_unknown;
8515266Sjp161948 		goto parse_string;
8525266Sjp161948 
8530Sstevel@tonic-gate 	case oDeprecated:
8540Sstevel@tonic-gate 		debug("%s line %d: Deprecated option \"%s\"",
8550Sstevel@tonic-gate 		    filename, linenum, keyword);
8560Sstevel@tonic-gate 		return 0;
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	default:
8590Sstevel@tonic-gate 		fatal("process_config_line: Unimplemented opcode %d", opcode);
8600Sstevel@tonic-gate 	}
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 	/* Check that there is no garbage at end of line. */
8630Sstevel@tonic-gate 	if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
8640Sstevel@tonic-gate 		fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
8650Sstevel@tonic-gate 		     filename, linenum, arg);
8660Sstevel@tonic-gate 	}
8670Sstevel@tonic-gate 	return 0;
8680Sstevel@tonic-gate }
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate /*
8720Sstevel@tonic-gate  * Reads the config file and modifies the options accordingly.  Options
8730Sstevel@tonic-gate  * should already be initialized before this call.  This never returns if
8740Sstevel@tonic-gate  * there is an error.  If the file does not exist, this returns 0.
8750Sstevel@tonic-gate  */
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate int
8780Sstevel@tonic-gate read_config_file(const char *filename, const char *host, Options *options)
8790Sstevel@tonic-gate {
8800Sstevel@tonic-gate 	FILE *f;
8810Sstevel@tonic-gate 	char line[1024];
8820Sstevel@tonic-gate 	int active, linenum;
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate 	/* Open the file. */
8850Sstevel@tonic-gate 	f = fopen(filename, "r");
8860Sstevel@tonic-gate 	if (!f)
8870Sstevel@tonic-gate 		return 0;
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 	debug("Reading configuration data %.200s", filename);
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	/*
8920Sstevel@tonic-gate 	 * Mark that we are now processing the options.  This flag is turned
8930Sstevel@tonic-gate 	 * on/off by Host specifications.
8940Sstevel@tonic-gate 	 */
8950Sstevel@tonic-gate 	active = 1;
8960Sstevel@tonic-gate 	linenum = 0;
8970Sstevel@tonic-gate 	while (fgets(line, sizeof(line), f)) {
8980Sstevel@tonic-gate 		/* Update line number counter. */
8990Sstevel@tonic-gate 		linenum++;
9005266Sjp161948 		process_config_line(options, host, line, filename, linenum, &active);
9010Sstevel@tonic-gate 	}
9020Sstevel@tonic-gate 	fclose(f);
9030Sstevel@tonic-gate 	return 1;
9040Sstevel@tonic-gate }
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate /*
9070Sstevel@tonic-gate  * Initializes options to special values that indicate that they have not yet
9080Sstevel@tonic-gate  * been set.  Read_config_file will only set options with this value. Options
9090Sstevel@tonic-gate  * are processed in the following order: command line, user config file,
9100Sstevel@tonic-gate  * system config file.  Last, fill_default_options is called.
9110Sstevel@tonic-gate  */
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate void
9140Sstevel@tonic-gate initialize_options(Options * options)
9150Sstevel@tonic-gate {
9160Sstevel@tonic-gate 	memset(options, 'X', sizeof(*options));
9170Sstevel@tonic-gate 	options->forward_agent = -1;
9180Sstevel@tonic-gate 	options->forward_x11 = -1;
9194907Sjp161948 	options->forward_x11_trusted = -1;
9200Sstevel@tonic-gate 	options->xauth_location = NULL;
9210Sstevel@tonic-gate 	options->gateway_ports = -1;
9220Sstevel@tonic-gate 	options->use_privileged_port = -1;
9230Sstevel@tonic-gate 	options->rhosts_authentication = -1;
9240Sstevel@tonic-gate 	options->rsa_authentication = -1;
9250Sstevel@tonic-gate 	options->pubkey_authentication = -1;
9260Sstevel@tonic-gate 	options->challenge_response_authentication = -1;
9270Sstevel@tonic-gate #ifdef GSSAPI
9280Sstevel@tonic-gate         options->gss_keyex = -1;
9290Sstevel@tonic-gate         options->gss_authentication = -1;
9300Sstevel@tonic-gate         options->gss_deleg_creds = -1;
9310Sstevel@tonic-gate #ifdef GSI
9320Sstevel@tonic-gate         options->gss_globus_deleg_limited_proxy = -1;
9330Sstevel@tonic-gate #endif /* GSI */
9340Sstevel@tonic-gate #endif /* GSSAPI */
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
9370Sstevel@tonic-gate 	options->kerberos_authentication = -1;
9380Sstevel@tonic-gate #endif
9390Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
9400Sstevel@tonic-gate 	options->kerberos_tgt_passing = -1;
9410Sstevel@tonic-gate #endif
9420Sstevel@tonic-gate #ifdef AFS
9430Sstevel@tonic-gate 	options->afs_token_passing = -1;
9440Sstevel@tonic-gate #endif
9450Sstevel@tonic-gate 	options->password_authentication = -1;
9460Sstevel@tonic-gate 	options->kbd_interactive_authentication = -1;
9470Sstevel@tonic-gate 	options->kbd_interactive_devices = NULL;
9480Sstevel@tonic-gate 	options->rhosts_rsa_authentication = -1;
9490Sstevel@tonic-gate 	options->hostbased_authentication = -1;
9500Sstevel@tonic-gate 	options->batch_mode = -1;
9510Sstevel@tonic-gate 	options->check_host_ip = -1;
9520Sstevel@tonic-gate 	options->strict_host_key_checking = -1;
9530Sstevel@tonic-gate 	options->compression = -1;
9540Sstevel@tonic-gate 	options->keepalives = -1;
9550Sstevel@tonic-gate 	options->compression_level = -1;
9560Sstevel@tonic-gate 	options->port = -1;
9570Sstevel@tonic-gate 	options->connection_attempts = -1;
9583946Sjp161948 	options->connection_timeout = -1;
9590Sstevel@tonic-gate 	options->number_of_password_prompts = -1;
9600Sstevel@tonic-gate 	options->cipher = -1;
9610Sstevel@tonic-gate 	options->ciphers = NULL;
9620Sstevel@tonic-gate 	options->macs = NULL;
9630Sstevel@tonic-gate 	options->hostkeyalgorithms = NULL;
9640Sstevel@tonic-gate 	options->protocol = SSH_PROTO_UNKNOWN;
9650Sstevel@tonic-gate 	options->num_identity_files = 0;
9660Sstevel@tonic-gate 	options->hostname = NULL;
9670Sstevel@tonic-gate 	options->host_key_alias = NULL;
9680Sstevel@tonic-gate 	options->proxy_command = NULL;
9690Sstevel@tonic-gate 	options->user = NULL;
9700Sstevel@tonic-gate 	options->escape_char = -1;
9710Sstevel@tonic-gate 	options->system_hostfile = NULL;
9720Sstevel@tonic-gate 	options->user_hostfile = NULL;
9730Sstevel@tonic-gate 	options->system_hostfile2 = NULL;
9740Sstevel@tonic-gate 	options->user_hostfile2 = NULL;
9750Sstevel@tonic-gate 	options->num_local_forwards = 0;
9760Sstevel@tonic-gate 	options->num_remote_forwards = 0;
9770Sstevel@tonic-gate 	options->clear_forwardings = -1;
9780Sstevel@tonic-gate 	options->log_level = SYSLOG_LEVEL_NOT_SET;
9790Sstevel@tonic-gate 	options->preferred_authentications = NULL;
9800Sstevel@tonic-gate 	options->bind_address = NULL;
9810Sstevel@tonic-gate 	options->smartcard_device = NULL;
982*5562Sjp161948 	options->no_host_authentication_for_localhost = -1;
983*5562Sjp161948 	options->rekey_limit = -1;
9840Sstevel@tonic-gate 	options->fallback_to_rsh = -1;
9850Sstevel@tonic-gate 	options->use_rsh = -1;
9864668Sjp161948 	options->server_alive_interval = -1;
9874668Sjp161948 	options->server_alive_count_max = -1;
9885243Sjp161948 	options->hash_known_hosts = -1;
9895266Sjp161948 	options->ignore_if_unknown = NULL;
9905266Sjp161948 	options->unknown_opts_num = 0;
9914958Sjp161948 	options->disable_banner = -1;
9920Sstevel@tonic-gate }
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate /*
9950Sstevel@tonic-gate  * Called after processing other sources of option data, this fills those
9960Sstevel@tonic-gate  * options for which no value has been specified with their default values.
9970Sstevel@tonic-gate  */
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate void
10000Sstevel@tonic-gate fill_default_options(Options * options)
10010Sstevel@tonic-gate {
10020Sstevel@tonic-gate 	int len;
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 	if (options->forward_agent == -1)
10050Sstevel@tonic-gate 		options->forward_agent = 0;
10060Sstevel@tonic-gate 	if (options->forward_x11 == -1)
10070Sstevel@tonic-gate 		options->forward_x11 = 0;
10084907Sjp161948 	/*
10094907Sjp161948 	 * Unlike OpenSSH, we keep backward compatibility for '-X' option
10104907Sjp161948 	 * which means that X11 forwarding is trusted by default.
10114907Sjp161948 	 */
10124907Sjp161948 	if (options->forward_x11_trusted == -1)
10134907Sjp161948 		options->forward_x11_trusted = 1;
10140Sstevel@tonic-gate 	if (options->xauth_location == NULL)
10150Sstevel@tonic-gate 		options->xauth_location = _PATH_XAUTH;
10160Sstevel@tonic-gate 	if (options->gateway_ports == -1)
10170Sstevel@tonic-gate 		options->gateway_ports = 0;
10180Sstevel@tonic-gate 	if (options->use_privileged_port == -1)
10190Sstevel@tonic-gate 		options->use_privileged_port = 0;
10200Sstevel@tonic-gate 	if (options->rhosts_authentication == -1)
10210Sstevel@tonic-gate 		options->rhosts_authentication = 0;
10220Sstevel@tonic-gate 	if (options->rsa_authentication == -1)
10230Sstevel@tonic-gate 		options->rsa_authentication = 1;
10240Sstevel@tonic-gate 	if (options->pubkey_authentication == -1)
10250Sstevel@tonic-gate 		options->pubkey_authentication = 1;
10260Sstevel@tonic-gate 	if (options->challenge_response_authentication == -1)
10270Sstevel@tonic-gate 		options->challenge_response_authentication = 1;
10280Sstevel@tonic-gate #ifdef GSSAPI
10290Sstevel@tonic-gate 	if (options->gss_keyex == -1)
10300Sstevel@tonic-gate 		options->gss_keyex = 1;
10310Sstevel@tonic-gate 	if (options->gss_authentication == -1)
10320Sstevel@tonic-gate 		options->gss_authentication = 1;
10330Sstevel@tonic-gate 	if (options->gss_deleg_creds == -1)
10340Sstevel@tonic-gate 		options->gss_deleg_creds = 0;
10350Sstevel@tonic-gate #ifdef GSI
10360Sstevel@tonic-gate 	if (options->gss_globus_deleg_limited_proxy == -1)
10370Sstevel@tonic-gate 		options->gss_globus_deleg_limited_proxy = 0;
10380Sstevel@tonic-gate #endif /* GSI */
10390Sstevel@tonic-gate #endif /* GSSAPI */
10400Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
10410Sstevel@tonic-gate 	if (options->kerberos_authentication == -1)
10420Sstevel@tonic-gate 		options->kerberos_authentication = 1;
10430Sstevel@tonic-gate #endif
10440Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
10450Sstevel@tonic-gate 	if (options->kerberos_tgt_passing == -1)
10460Sstevel@tonic-gate 		options->kerberos_tgt_passing = 1;
10470Sstevel@tonic-gate #endif
10480Sstevel@tonic-gate #ifdef AFS
10490Sstevel@tonic-gate 	if (options->afs_token_passing == -1)
10500Sstevel@tonic-gate 		options->afs_token_passing = 1;
10510Sstevel@tonic-gate #endif
10520Sstevel@tonic-gate 	if (options->password_authentication == -1)
10530Sstevel@tonic-gate 		options->password_authentication = 1;
10540Sstevel@tonic-gate 	if (options->kbd_interactive_authentication == -1)
10550Sstevel@tonic-gate 		options->kbd_interactive_authentication = 1;
10560Sstevel@tonic-gate 	if (options->rhosts_rsa_authentication == -1)
10570Sstevel@tonic-gate 		options->rhosts_rsa_authentication = 0;
10580Sstevel@tonic-gate 	if (options->hostbased_authentication == -1)
10590Sstevel@tonic-gate 		options->hostbased_authentication = 0;
10600Sstevel@tonic-gate 	if (options->batch_mode == -1)
10610Sstevel@tonic-gate 		options->batch_mode = 0;
10620Sstevel@tonic-gate 	if (options->check_host_ip == -1)
10630Sstevel@tonic-gate 		options->check_host_ip = 1;
10640Sstevel@tonic-gate 	if (options->strict_host_key_checking == -1)
10650Sstevel@tonic-gate 		options->strict_host_key_checking = 2;	/* 2 is default */
10660Sstevel@tonic-gate 	if (options->compression == -1)
10670Sstevel@tonic-gate 		options->compression = 0;
10680Sstevel@tonic-gate 	if (options->keepalives == -1)
10690Sstevel@tonic-gate 		options->keepalives = 1;
10700Sstevel@tonic-gate 	if (options->compression_level == -1)
10710Sstevel@tonic-gate 		options->compression_level = 6;
10720Sstevel@tonic-gate 	if (options->port == -1)
10730Sstevel@tonic-gate 		options->port = 0;	/* Filled in ssh_connect. */
10740Sstevel@tonic-gate 	if (options->connection_attempts == -1)
10750Sstevel@tonic-gate 		options->connection_attempts = 1;
10760Sstevel@tonic-gate 	if (options->number_of_password_prompts == -1)
10770Sstevel@tonic-gate 		options->number_of_password_prompts = 3;
10780Sstevel@tonic-gate 	/* Selected in ssh_login(). */
10790Sstevel@tonic-gate 	if (options->cipher == -1)
10800Sstevel@tonic-gate 		options->cipher = SSH_CIPHER_NOT_SET;
10810Sstevel@tonic-gate 	/* options->ciphers, default set in myproposals.h */
10820Sstevel@tonic-gate 	/* options->macs, default set in myproposals.h */
10830Sstevel@tonic-gate 	/* options->hostkeyalgorithms, default set in myproposals.h */
10840Sstevel@tonic-gate 	if (options->protocol == SSH_PROTO_UNKNOWN)
10850Sstevel@tonic-gate 		options->protocol = SSH_PROTO_1|SSH_PROTO_2;
10860Sstevel@tonic-gate 	if (options->num_identity_files == 0) {
10870Sstevel@tonic-gate 		if (options->protocol & SSH_PROTO_1) {
10880Sstevel@tonic-gate 			len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;
10890Sstevel@tonic-gate 			options->identity_files[options->num_identity_files] =
10900Sstevel@tonic-gate 			    xmalloc(len);
10910Sstevel@tonic-gate 			snprintf(options->identity_files[options->num_identity_files++],
10920Sstevel@tonic-gate 			    len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY);
10930Sstevel@tonic-gate 		}
10940Sstevel@tonic-gate 		if (options->protocol & SSH_PROTO_2) {
10950Sstevel@tonic-gate 			len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1;
10960Sstevel@tonic-gate 			options->identity_files[options->num_identity_files] =
10970Sstevel@tonic-gate 			    xmalloc(len);
10980Sstevel@tonic-gate 			snprintf(options->identity_files[options->num_identity_files++],
10990Sstevel@tonic-gate 			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA);
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 			len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1;
11020Sstevel@tonic-gate 			options->identity_files[options->num_identity_files] =
11030Sstevel@tonic-gate 			    xmalloc(len);
11040Sstevel@tonic-gate 			snprintf(options->identity_files[options->num_identity_files++],
11050Sstevel@tonic-gate 			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA);
11060Sstevel@tonic-gate 		}
11070Sstevel@tonic-gate 	}
11080Sstevel@tonic-gate 	if (options->escape_char == -1)
11090Sstevel@tonic-gate 		options->escape_char = '~';
11100Sstevel@tonic-gate 	if (options->system_hostfile == NULL)
11110Sstevel@tonic-gate 		options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
11120Sstevel@tonic-gate 	if (options->user_hostfile == NULL)
11130Sstevel@tonic-gate 		options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
11140Sstevel@tonic-gate 	if (options->system_hostfile2 == NULL)
11150Sstevel@tonic-gate 		options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
11160Sstevel@tonic-gate 	if (options->user_hostfile2 == NULL)
11170Sstevel@tonic-gate 		options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
11180Sstevel@tonic-gate 	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
11190Sstevel@tonic-gate 		options->log_level = SYSLOG_LEVEL_INFO;
11200Sstevel@tonic-gate 	if (options->clear_forwardings == 1)
11210Sstevel@tonic-gate 		clear_forwardings(options);
1122*5562Sjp161948 	if (options->no_host_authentication_for_localhost == -1)
11230Sstevel@tonic-gate 		options->no_host_authentication_for_localhost = 0;
1124*5562Sjp161948 	if (options->rekey_limit == -1)
1125*5562Sjp161948 		options->rekey_limit = 0;
1126*5562Sjp161948 	if (options->fallback_to_rsh == -1)
11270Sstevel@tonic-gate 		options->fallback_to_rsh = 0;
1128*5562Sjp161948 	if (options->use_rsh == -1)
11290Sstevel@tonic-gate 		options->use_rsh = 0;
11304668Sjp161948 	if (options->server_alive_interval == -1)
11314668Sjp161948 		options->server_alive_interval = 0;
11324668Sjp161948 	if (options->server_alive_count_max == -1)
11334668Sjp161948 		options->server_alive_count_max = 3;
11345243Sjp161948 	if (options->hash_known_hosts == -1)
11355243Sjp161948 		options->hash_known_hosts = 0;
11364958Sjp161948 	if (options->disable_banner == -1)
11374958Sjp161948 		options->disable_banner = 0;
11380Sstevel@tonic-gate 	/* options->proxy_command should not be set by default */
11390Sstevel@tonic-gate 	/* options->user will be set in the main program if appropriate */
11400Sstevel@tonic-gate 	/* options->hostname will be set in the main program if appropriate */
11410Sstevel@tonic-gate 	/* options->host_key_alias should not be set by default */
11420Sstevel@tonic-gate 	/* options->preferred_authentications will be set in ssh */
11435266Sjp161948 	/* options->ignore_if_unknown should not be set by default */
11440Sstevel@tonic-gate }
11455266Sjp161948 
11465266Sjp161948 /*
11475334Sjp161948  * Parses a string containing a port forwarding specification of one of the
11485334Sjp161948  * two forms, short or long:
11495334Sjp161948  *
11505334Sjp161948  *	[listenhost:]listenport
11515334Sjp161948  *	[listenhost:]listenport:connecthost:connectport
11525334Sjp161948  *
11535334Sjp161948  * short forwarding specification is used for dynamic port forwarding and for
11545334Sjp161948  * port forwarding cancelation in process_cmdline(). The function returns number
11555334Sjp161948  * of arguments parsed or zero on any error.
11565334Sjp161948  */
11575334Sjp161948 int
11585334Sjp161948 parse_forward(int long_form, Forward *fwd, const char *fwdspec)
11595334Sjp161948 {
11605334Sjp161948 	int i;
11615334Sjp161948 	char *p, *cp, *fwdarg[5];
11625334Sjp161948 
11635334Sjp161948 	memset(fwd, '\0', sizeof(*fwd));
11645334Sjp161948 
11655334Sjp161948 	cp = p = xstrdup(fwdspec);
11665334Sjp161948 
11675334Sjp161948 	/* skip leading spaces */
11685334Sjp161948 	while (isspace(*cp))
11695334Sjp161948 		cp++;
11705334Sjp161948 
11715334Sjp161948 	for (i = 0; i < 5; ++i)
11725334Sjp161948 		if ((fwdarg[i] = hpdelim(&cp)) == NULL)
11735334Sjp161948 			break;
11745334Sjp161948 
11755334Sjp161948 	if ((long_form == 0 && i > 2) || (long_form == 1 && i < 3) || (i == 5))
11765334Sjp161948 		goto fail_free;
11775334Sjp161948 
11785334Sjp161948 	switch (i) {
11795334Sjp161948 	case 0:
11805334Sjp161948 		goto fail_free;
11815334Sjp161948 
11825334Sjp161948 	case 1:
11835334Sjp161948 		fwd->listen_host = NULL;
11845334Sjp161948 		fwd->listen_port = a2port(fwdarg[0]);
11855334Sjp161948 		break;
11865334Sjp161948 
11875334Sjp161948 	case 2:
11885334Sjp161948 		fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
11895334Sjp161948 		fwd->listen_port = a2port(fwdarg[1]);
11905334Sjp161948 		break;
11915334Sjp161948 
11925334Sjp161948 	case 3:
11935334Sjp161948 		fwd->listen_host = NULL;
11945334Sjp161948 		fwd->listen_port = a2port(fwdarg[0]);
11955334Sjp161948 		fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
11965334Sjp161948 		fwd->connect_port = a2port(fwdarg[2]);
11975334Sjp161948 		break;
11985334Sjp161948 
11995334Sjp161948 	case 4:
12005334Sjp161948 		fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
12015334Sjp161948 		fwd->listen_port = a2port(fwdarg[1]);
12025334Sjp161948 		fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
12035334Sjp161948 		fwd->connect_port = a2port(fwdarg[3]);
12045334Sjp161948 		break;
12055334Sjp161948 	}
12065334Sjp161948 
12075334Sjp161948 	xfree(p);
12085334Sjp161948 
12095334Sjp161948 	if (fwd->listen_port == 0 || (fwd->connect_port == 0 && i > 2))
12105334Sjp161948 		goto fail_free;
12115334Sjp161948 
12125334Sjp161948 	return (i);
12135334Sjp161948 
12145334Sjp161948  fail_free:
12155334Sjp161948 	if (p != NULL)
12165334Sjp161948 		xfree(p);
12175334Sjp161948 	if (fwd->connect_host != NULL)
12185334Sjp161948 		xfree(fwd->connect_host);
12195334Sjp161948 	if (fwd->listen_host != NULL)
12205334Sjp161948 		xfree(fwd->listen_host);
12215334Sjp161948 	return (0);
12225334Sjp161948 }
12235334Sjp161948 
12245334Sjp161948 /*
12255266Sjp161948  * Process previously stored unknown options. When this function is called we
12265266Sjp161948  * already have IgnoreIfUnknown set so finally we can decide whether each
12275266Sjp161948  * unknown option is to be ignored or not.
12285266Sjp161948  */
12295266Sjp161948 void
12305266Sjp161948 process_unknown_options(Options *options)
12315266Sjp161948 {
12325266Sjp161948 	StoredOption *so;
12335266Sjp161948 	int m, i, bad_options = 0;
12345266Sjp161948 
12355266Sjp161948 	/* if there is no unknown option we are done */
12365266Sjp161948 	if (options->unknown_opts_num == 0)
12375266Sjp161948 		return;
12385266Sjp161948 
12395266Sjp161948 	/*
12405266Sjp161948 	 * Now go through the list of unknown options and report any one that
12415266Sjp161948 	 * is not explicitly listed in IgnoreIfUnknown option. If at least one
12425266Sjp161948 	 * such as that is found it's a show stopper.
12435266Sjp161948 	 */
12445266Sjp161948 	for (i = 0; i < options->unknown_opts_num; ++i) {
12455266Sjp161948 		so = &options->unknown_opts[i];
12465266Sjp161948 		if (options->ignore_if_unknown == NULL)
12475266Sjp161948 			m = 0;
12485266Sjp161948 		else
12495266Sjp161948 			m = match_pattern_list(tolowercase(so->keyword),
12505266Sjp161948 			    options->ignore_if_unknown,
12515266Sjp161948 			    strlen(options->ignore_if_unknown), 1);
12525266Sjp161948 		if (m == 1) {
12535266Sjp161948 			debug("%s: line %d: ignoring unknown option: %s",
12545266Sjp161948 			    so->filename, so->linenum, so->keyword);
12555266Sjp161948 		}
12565266Sjp161948 		else {
12575266Sjp161948 			error("%s: line %d: unknown configuration option: %s",
12585266Sjp161948 			    so->filename, so->linenum, so->keyword);
12595266Sjp161948 			bad_options++;
12605266Sjp161948 		}
12615266Sjp161948 		xfree(so->keyword);
12625266Sjp161948 		xfree(so->filename);
12635266Sjp161948 	}
12645266Sjp161948 
12655266Sjp161948 	/* exit if we found at least one unignored unknown option */
12665266Sjp161948 	if (bad_options > 0)
12675266Sjp161948 		fatal("terminating, %d bad configuration option(s)",
12685266Sjp161948 		    bad_options);
12695266Sjp161948 }
1270