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 /*
14*9845SJan.Pechanec@Sun.COM * Copyright 2009 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 #include "ssh.h"
220Sstevel@tonic-gate #include "xmalloc.h"
230Sstevel@tonic-gate #include "compat.h"
240Sstevel@tonic-gate #include "cipher.h"
250Sstevel@tonic-gate #include "pathnames.h"
260Sstevel@tonic-gate #include "log.h"
270Sstevel@tonic-gate #include "readconf.h"
280Sstevel@tonic-gate #include "match.h"
290Sstevel@tonic-gate #include "misc.h"
300Sstevel@tonic-gate #include "kex.h"
310Sstevel@tonic-gate #include "mac.h"
320Sstevel@tonic-gate
330Sstevel@tonic-gate /* Format of the configuration file:
340Sstevel@tonic-gate
350Sstevel@tonic-gate # Configuration data is parsed as follows:
360Sstevel@tonic-gate # 1. command line options
370Sstevel@tonic-gate # 2. user-specific file
380Sstevel@tonic-gate # 3. system-wide file
390Sstevel@tonic-gate # Any configuration value is only changed the first time it is set.
400Sstevel@tonic-gate # Thus, host-specific definitions should be at the beginning of the
410Sstevel@tonic-gate # configuration file, and defaults at the end.
420Sstevel@tonic-gate
430Sstevel@tonic-gate # Host-specific declarations. These may override anything above. A single
440Sstevel@tonic-gate # host may match multiple declarations; these are processed in the order
450Sstevel@tonic-gate # that they are given in.
460Sstevel@tonic-gate
470Sstevel@tonic-gate Host *.ngs.fi ngs.fi
480Sstevel@tonic-gate User foo
490Sstevel@tonic-gate
500Sstevel@tonic-gate Host fake.com
510Sstevel@tonic-gate HostName another.host.name.real.org
520Sstevel@tonic-gate User blaah
530Sstevel@tonic-gate Port 34289
540Sstevel@tonic-gate ForwardX11 no
550Sstevel@tonic-gate ForwardAgent no
560Sstevel@tonic-gate
570Sstevel@tonic-gate Host books.com
580Sstevel@tonic-gate RemoteForward 9999 shadows.cs.hut.fi:9999
590Sstevel@tonic-gate Cipher 3des
600Sstevel@tonic-gate
610Sstevel@tonic-gate Host fascist.blob.com
620Sstevel@tonic-gate Port 23123
630Sstevel@tonic-gate User tylonen
640Sstevel@tonic-gate RhostsAuthentication no
650Sstevel@tonic-gate PasswordAuthentication no
660Sstevel@tonic-gate
670Sstevel@tonic-gate Host puukko.hut.fi
680Sstevel@tonic-gate User t35124p
690Sstevel@tonic-gate ProxyCommand ssh-proxy %h %p
700Sstevel@tonic-gate
710Sstevel@tonic-gate Host *.fr
720Sstevel@tonic-gate PublicKeyAuthentication no
730Sstevel@tonic-gate
740Sstevel@tonic-gate Host *.su
750Sstevel@tonic-gate Cipher none
760Sstevel@tonic-gate PasswordAuthentication no
770Sstevel@tonic-gate
780Sstevel@tonic-gate # Defaults for various options
790Sstevel@tonic-gate Host *
800Sstevel@tonic-gate ForwardAgent no
810Sstevel@tonic-gate ForwardX11 no
820Sstevel@tonic-gate RhostsAuthentication yes
830Sstevel@tonic-gate PasswordAuthentication yes
840Sstevel@tonic-gate RSAAuthentication yes
850Sstevel@tonic-gate RhostsRSAAuthentication yes
860Sstevel@tonic-gate StrictHostKeyChecking yes
870Sstevel@tonic-gate KeepAlives no
880Sstevel@tonic-gate IdentityFile ~/.ssh/identity
890Sstevel@tonic-gate Port 22
900Sstevel@tonic-gate EscapeChar ~
910Sstevel@tonic-gate
920Sstevel@tonic-gate */
930Sstevel@tonic-gate
940Sstevel@tonic-gate /* Keyword tokens. */
950Sstevel@tonic-gate
960Sstevel@tonic-gate typedef enum {
970Sstevel@tonic-gate oBadOption,
984907Sjp161948 oForwardAgent, oForwardX11, oForwardX11Trusted, oGatewayPorts,
994907Sjp161948 oRhostsAuthentication,
1000Sstevel@tonic-gate oPasswordAuthentication, oRSAAuthentication,
1010Sstevel@tonic-gate oChallengeResponseAuthentication, oXAuthLocation,
1020Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
1030Sstevel@tonic-gate oKerberosAuthentication,
1040Sstevel@tonic-gate #endif
1050Sstevel@tonic-gate #ifdef GSSAPI
1060Sstevel@tonic-gate oGssKeyEx, oGssAuthentication, oGssDelegateCreds,
1070Sstevel@tonic-gate #ifdef GSI
1080Sstevel@tonic-gate oGssGlobusDelegateLimitedCreds,
1090Sstevel@tonic-gate #endif /* GSI */
1100Sstevel@tonic-gate #endif /* GSSAPI */
1110Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
1120Sstevel@tonic-gate oKerberosTgtPassing,
1130Sstevel@tonic-gate #endif
1140Sstevel@tonic-gate #ifdef AFS
1150Sstevel@tonic-gate oAFSTokenPassing,
1160Sstevel@tonic-gate #endif
1170Sstevel@tonic-gate oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
1180Sstevel@tonic-gate oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
1190Sstevel@tonic-gate oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
1200Sstevel@tonic-gate oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
1210Sstevel@tonic-gate oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts,
1220Sstevel@tonic-gate oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
1230Sstevel@tonic-gate oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
1240Sstevel@tonic-gate oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
1250Sstevel@tonic-gate oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
1260Sstevel@tonic-gate oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
1270Sstevel@tonic-gate oClearAllForwardings, oNoHostAuthenticationForLocalhost,
1285243Sjp161948 oFallBackToRsh, oUseRsh, oConnectTimeout, oHashKnownHosts,
1294958Sjp161948 oServerAliveInterval, oServerAliveCountMax, oDisableBanner,
1307574SJan.Pechanec@Sun.COM oIgnoreIfUnknown, oRekeyLimit, oUseOpenSSLEngine,
1315562Sjp161948 oDeprecated
1320Sstevel@tonic-gate } OpCodes;
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate /* Textual representations of the tokens. */
1350Sstevel@tonic-gate
1360Sstevel@tonic-gate static struct {
1370Sstevel@tonic-gate const char *name;
1380Sstevel@tonic-gate OpCodes opcode;
1390Sstevel@tonic-gate } keywords[] = {
1400Sstevel@tonic-gate { "forwardagent", oForwardAgent },
1410Sstevel@tonic-gate { "forwardx11", oForwardX11 },
1424907Sjp161948 { "forwardx11trusted", oForwardX11Trusted },
1430Sstevel@tonic-gate { "xauthlocation", oXAuthLocation },
1440Sstevel@tonic-gate { "gatewayports", oGatewayPorts },
1450Sstevel@tonic-gate { "useprivilegedport", oUsePrivilegedPort },
1460Sstevel@tonic-gate { "rhostsauthentication", oRhostsAuthentication },
1470Sstevel@tonic-gate { "passwordauthentication", oPasswordAuthentication },
1480Sstevel@tonic-gate { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
1490Sstevel@tonic-gate { "kbdinteractivedevices", oKbdInteractiveDevices },
1500Sstevel@tonic-gate { "rsaauthentication", oRSAAuthentication },
1510Sstevel@tonic-gate { "pubkeyauthentication", oPubkeyAuthentication },
1520Sstevel@tonic-gate { "dsaauthentication", oPubkeyAuthentication }, /* alias */
1530Sstevel@tonic-gate { "rhostsrsaauthentication", oRhostsRSAAuthentication },
1540Sstevel@tonic-gate { "hostbasedauthentication", oHostbasedAuthentication },
1550Sstevel@tonic-gate { "challengeresponseauthentication", oChallengeResponseAuthentication },
1560Sstevel@tonic-gate { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
1570Sstevel@tonic-gate { "tisauthentication", oChallengeResponseAuthentication }, /* alias */
1580Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
1590Sstevel@tonic-gate { "kerberosauthentication", oKerberosAuthentication },
1600Sstevel@tonic-gate #endif
1610Sstevel@tonic-gate #ifdef GSSAPI
1620Sstevel@tonic-gate { "gssapikeyexchange", oGssKeyEx },
1630Sstevel@tonic-gate { "gssapiauthentication", oGssAuthentication },
1640Sstevel@tonic-gate { "gssapidelegatecredentials", oGssDelegateCreds },
1650Sstevel@tonic-gate { "gsskeyex", oGssKeyEx }, /* alias */
1660Sstevel@tonic-gate { "gssauthentication", oGssAuthentication }, /* alias */
1670Sstevel@tonic-gate { "gssdelegatecreds", oGssDelegateCreds }, /* alias */
1680Sstevel@tonic-gate #ifdef GSI
1690Sstevel@tonic-gate /* For backwards compatability with old 1.2.27 client code */
1700Sstevel@tonic-gate { "forwardgssapiglobusproxy", oGssDelegateCreds }, /* alias */
1710Sstevel@tonic-gate { "forwardgssapiglobuslimitedproxy", oGssGlobusDelegateLimitedCreds },
1720Sstevel@tonic-gate #endif /* GSI */
1730Sstevel@tonic-gate #endif /* GSSAPI */
1740Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
1750Sstevel@tonic-gate { "kerberostgtpassing", oKerberosTgtPassing },
1760Sstevel@tonic-gate #endif
1770Sstevel@tonic-gate #ifdef AFS
1780Sstevel@tonic-gate { "afstokenpassing", oAFSTokenPassing },
1790Sstevel@tonic-gate #endif
1800Sstevel@tonic-gate { "fallbacktorsh", oFallBackToRsh },
1810Sstevel@tonic-gate { "usersh", oUseRsh },
1820Sstevel@tonic-gate { "identityfile", oIdentityFile },
1830Sstevel@tonic-gate { "identityfile2", oIdentityFile }, /* alias */
1840Sstevel@tonic-gate { "hostname", oHostName },
1850Sstevel@tonic-gate { "hostkeyalias", oHostKeyAlias },
1860Sstevel@tonic-gate { "proxycommand", oProxyCommand },
1870Sstevel@tonic-gate { "port", oPort },
1880Sstevel@tonic-gate { "cipher", oCipher },
1890Sstevel@tonic-gate { "ciphers", oCiphers },
1900Sstevel@tonic-gate { "macs", oMacs },
1910Sstevel@tonic-gate { "protocol", oProtocol },
1920Sstevel@tonic-gate { "remoteforward", oRemoteForward },
1930Sstevel@tonic-gate { "localforward", oLocalForward },
1940Sstevel@tonic-gate { "user", oUser },
1950Sstevel@tonic-gate { "host", oHost },
1960Sstevel@tonic-gate { "escapechar", oEscapeChar },
1970Sstevel@tonic-gate { "globalknownhostsfile", oGlobalKnownHostsFile },
1980Sstevel@tonic-gate { "userknownhostsfile", oUserKnownHostsFile }, /* obsolete */
1990Sstevel@tonic-gate { "globalknownhostsfile2", oGlobalKnownHostsFile2 },
2000Sstevel@tonic-gate { "userknownhostsfile2", oUserKnownHostsFile2 }, /* obsolete */
2010Sstevel@tonic-gate { "connectionattempts", oConnectionAttempts },
2020Sstevel@tonic-gate { "batchmode", oBatchMode },
2030Sstevel@tonic-gate { "checkhostip", oCheckHostIP },
2040Sstevel@tonic-gate { "stricthostkeychecking", oStrictHostKeyChecking },
2050Sstevel@tonic-gate { "compression", oCompression },
2060Sstevel@tonic-gate { "compressionlevel", oCompressionLevel },
2070Sstevel@tonic-gate { "keepalive", oKeepAlives },
2080Sstevel@tonic-gate { "numberofpasswordprompts", oNumberOfPasswordPrompts },
2090Sstevel@tonic-gate { "loglevel", oLogLevel },
2100Sstevel@tonic-gate { "dynamicforward", oDynamicForward },
2110Sstevel@tonic-gate { "preferredauthentications", oPreferredAuthentications },
2120Sstevel@tonic-gate { "hostkeyalgorithms", oHostKeyAlgorithms },
2130Sstevel@tonic-gate { "bindaddress", oBindAddress },
2140Sstevel@tonic-gate { "smartcarddevice", oSmartcardDevice },
2150Sstevel@tonic-gate { "clearallforwardings", oClearAllForwardings },
2160Sstevel@tonic-gate { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
2175562Sjp161948 { "rekeylimit", oRekeyLimit },
2183946Sjp161948 { "connecttimeout", oConnectTimeout },
2194668Sjp161948 { "serveraliveinterval", oServerAliveInterval },
2204668Sjp161948 { "serveralivecountmax", oServerAliveCountMax },
2214958Sjp161948 { "disablebanner", oDisableBanner },
2225243Sjp161948 { "hashknownhosts", oHashKnownHosts },
2235266Sjp161948 { "ignoreifunknown", oIgnoreIfUnknown },
2247574SJan.Pechanec@Sun.COM { "useopensslengine", oUseOpenSSLEngine },
2250Sstevel@tonic-gate { NULL, oBadOption }
2260Sstevel@tonic-gate };
2270Sstevel@tonic-gate
2280Sstevel@tonic-gate /*
2290Sstevel@tonic-gate * Adds a local TCP/IP port forward to options. Never returns if there is an
2300Sstevel@tonic-gate * error.
2310Sstevel@tonic-gate */
2320Sstevel@tonic-gate
2330Sstevel@tonic-gate void
add_local_forward(Options * options,const Forward * newfwd)2345334Sjp161948 add_local_forward(Options *options, const Forward *newfwd)
2350Sstevel@tonic-gate {
2360Sstevel@tonic-gate Forward *fwd;
2370Sstevel@tonic-gate #ifndef NO_IPPORT_RESERVED_CONCEPT
2380Sstevel@tonic-gate extern uid_t original_real_uid;
2395334Sjp161948 if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0)
2400Sstevel@tonic-gate fatal("Privileged ports can only be forwarded by root.");
2410Sstevel@tonic-gate #endif
2420Sstevel@tonic-gate if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
2430Sstevel@tonic-gate fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
2440Sstevel@tonic-gate fwd = &options->local_forwards[options->num_local_forwards++];
2455334Sjp161948
2465334Sjp161948 fwd->listen_host = (newfwd->listen_host == NULL) ?
2475334Sjp161948 NULL : xstrdup(newfwd->listen_host);
2485334Sjp161948 fwd->listen_port = newfwd->listen_port;
2495334Sjp161948 fwd->connect_host = xstrdup(newfwd->connect_host);
2505334Sjp161948 fwd->connect_port = newfwd->connect_port;
2510Sstevel@tonic-gate }
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate /*
2540Sstevel@tonic-gate * Adds a remote TCP/IP port forward to options. Never returns if there is
2550Sstevel@tonic-gate * an error.
2560Sstevel@tonic-gate */
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate void
add_remote_forward(Options * options,const Forward * newfwd)2595334Sjp161948 add_remote_forward(Options *options, const Forward *newfwd)
2600Sstevel@tonic-gate {
2610Sstevel@tonic-gate Forward *fwd;
2620Sstevel@tonic-gate if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
2630Sstevel@tonic-gate fatal("Too many remote forwards (max %d).",
2640Sstevel@tonic-gate SSH_MAX_FORWARDS_PER_DIRECTION);
2650Sstevel@tonic-gate fwd = &options->remote_forwards[options->num_remote_forwards++];
2665334Sjp161948
2675334Sjp161948 fwd->listen_host = (newfwd->listen_host == NULL) ?
2685334Sjp161948 NULL : xstrdup(newfwd->listen_host);
2695334Sjp161948 fwd->listen_port = newfwd->listen_port;
2705334Sjp161948 fwd->connect_host = xstrdup(newfwd->connect_host);
2715334Sjp161948 fwd->connect_port = newfwd->connect_port;
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate
2740Sstevel@tonic-gate static void
clear_forwardings(Options * options)2750Sstevel@tonic-gate clear_forwardings(Options *options)
2760Sstevel@tonic-gate {
2770Sstevel@tonic-gate int i;
2780Sstevel@tonic-gate
2795334Sjp161948 for (i = 0; i < options->num_local_forwards; i++) {
2805334Sjp161948 if (options->local_forwards[i].listen_host != NULL)
2815334Sjp161948 xfree(options->local_forwards[i].listen_host);
2825334Sjp161948 xfree(options->local_forwards[i].connect_host);
2835334Sjp161948 }
2840Sstevel@tonic-gate options->num_local_forwards = 0;
2855334Sjp161948 for (i = 0; i < options->num_remote_forwards; i++) {
2865334Sjp161948 if (options->remote_forwards[i].listen_host != NULL)
2875334Sjp161948 xfree(options->remote_forwards[i].listen_host);
2885334Sjp161948 xfree(options->remote_forwards[i].connect_host);
2895334Sjp161948 }
2900Sstevel@tonic-gate options->num_remote_forwards = 0;
2910Sstevel@tonic-gate }
2920Sstevel@tonic-gate
2930Sstevel@tonic-gate /*
2940Sstevel@tonic-gate * Returns the number of the token pointed to by cp or oBadOption.
2950Sstevel@tonic-gate */
2960Sstevel@tonic-gate
2970Sstevel@tonic-gate static OpCodes
parse_token(const char * cp,const char * filename,int linenum)2980Sstevel@tonic-gate parse_token(const char *cp, const char *filename, int linenum)
2990Sstevel@tonic-gate {
3000Sstevel@tonic-gate u_int i;
3010Sstevel@tonic-gate
3020Sstevel@tonic-gate for (i = 0; keywords[i].name; i++)
3030Sstevel@tonic-gate if (strcasecmp(cp, keywords[i].name) == 0)
3040Sstevel@tonic-gate return keywords[i].opcode;
3050Sstevel@tonic-gate
3065266Sjp161948 debug("%s: line %d: unknown configuration option: %s",
3070Sstevel@tonic-gate filename, linenum, cp);
3080Sstevel@tonic-gate return oBadOption;
3090Sstevel@tonic-gate }
3100Sstevel@tonic-gate
3110Sstevel@tonic-gate /*
3120Sstevel@tonic-gate * Processes a single option line as used in the configuration files. This
3130Sstevel@tonic-gate * only sets those values that have not already been set.
3140Sstevel@tonic-gate */
3150Sstevel@tonic-gate
3160Sstevel@tonic-gate int
process_config_line(Options * options,const char * host,char * line,const char * filename,int linenum,int * activep)3170Sstevel@tonic-gate process_config_line(Options *options, const char *host,
3180Sstevel@tonic-gate char *line, const char *filename, int linenum,
3190Sstevel@tonic-gate int *activep)
3200Sstevel@tonic-gate {
3215334Sjp161948 char *s, *string, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256];
3225562Sjp161948 int opcode, *intptr, value, scale, i;
3235562Sjp161948 long long orig, val64;
3245266Sjp161948 StoredOption *so;
3255334Sjp161948 Forward fwd;
3260Sstevel@tonic-gate
3270Sstevel@tonic-gate s = line;
3280Sstevel@tonic-gate /* Get the keyword. (Each line is supposed to begin with a keyword). */
3290Sstevel@tonic-gate keyword = strdelim(&s);
3300Sstevel@tonic-gate /* Ignore leading whitespace. */
3310Sstevel@tonic-gate if (*keyword == '\0')
3320Sstevel@tonic-gate keyword = strdelim(&s);
3330Sstevel@tonic-gate if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
3340Sstevel@tonic-gate return 0;
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate opcode = parse_token(keyword, filename, linenum);
3370Sstevel@tonic-gate
3380Sstevel@tonic-gate switch (opcode) {
3390Sstevel@tonic-gate case oBadOption:
3405266Sjp161948 if (options->unknown_opts_num == MAX_UNKNOWN_OPTIONS) {
3415266Sjp161948 error("we can't have more than %d unknown options:",
3425266Sjp161948 MAX_UNKNOWN_OPTIONS);
3435266Sjp161948 for (i = 0; i < MAX_UNKNOWN_OPTIONS; ++i) {
3445266Sjp161948 so = &options->unknown_opts[i];
3455266Sjp161948 error("%s:%d:%s",
3465266Sjp161948 so->filename, so->linenum, so->keyword);
3475266Sjp161948 xfree(so->keyword);
3485266Sjp161948 xfree(so->filename);
3495266Sjp161948 }
3505266Sjp161948 fatal("too many unknown options found, can't continue");
3515266Sjp161948 }
3525266Sjp161948
3535266Sjp161948 /* unknown options will be processed later */
3545266Sjp161948 so = &options->unknown_opts[options->unknown_opts_num];
3555266Sjp161948 so->keyword = xstrdup(keyword);
3565266Sjp161948 so->filename = xstrdup(filename);
3575266Sjp161948 so->linenum = linenum;
3585266Sjp161948 options->unknown_opts_num++;
3595266Sjp161948 return (0);
3605266Sjp161948
3610Sstevel@tonic-gate /* NOTREACHED */
3623946Sjp161948 case oConnectTimeout:
3633946Sjp161948 intptr = &options->connection_timeout;
3643946Sjp161948 parse_time:
3653946Sjp161948 arg = strdelim(&s);
3663946Sjp161948 if (!arg || *arg == '\0')
3673946Sjp161948 fatal("%s line %d: missing time value.",
3683946Sjp161948 filename, linenum);
3693946Sjp161948 if ((value = convtime(arg)) == -1)
3703946Sjp161948 fatal("%s line %d: invalid time value.",
3713946Sjp161948 filename, linenum);
3723984Sjp161948 if (*activep && *intptr == -1)
3733946Sjp161948 *intptr = value;
3743946Sjp161948 break;
3753946Sjp161948
3760Sstevel@tonic-gate case oForwardAgent:
3770Sstevel@tonic-gate intptr = &options->forward_agent;
3780Sstevel@tonic-gate parse_flag:
3790Sstevel@tonic-gate arg = strdelim(&s);
3800Sstevel@tonic-gate if (!arg || *arg == '\0')
3810Sstevel@tonic-gate fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
3820Sstevel@tonic-gate value = 0; /* To avoid compiler warning... */
3830Sstevel@tonic-gate if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
3840Sstevel@tonic-gate value = 1;
3850Sstevel@tonic-gate else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
3860Sstevel@tonic-gate value = 0;
3870Sstevel@tonic-gate else
3880Sstevel@tonic-gate fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
3890Sstevel@tonic-gate if (*activep && *intptr == -1)
3900Sstevel@tonic-gate *intptr = value;
3910Sstevel@tonic-gate break;
3920Sstevel@tonic-gate
3930Sstevel@tonic-gate case oForwardX11:
3940Sstevel@tonic-gate intptr = &options->forward_x11;
3950Sstevel@tonic-gate goto parse_flag;
3960Sstevel@tonic-gate
3974907Sjp161948 case oForwardX11Trusted:
3984907Sjp161948 intptr = &options->forward_x11_trusted;
3994907Sjp161948 goto parse_flag;
4004907Sjp161948
4010Sstevel@tonic-gate case oGatewayPorts:
4020Sstevel@tonic-gate intptr = &options->gateway_ports;
4030Sstevel@tonic-gate goto parse_flag;
4040Sstevel@tonic-gate
4050Sstevel@tonic-gate case oUsePrivilegedPort:
4060Sstevel@tonic-gate intptr = &options->use_privileged_port;
4070Sstevel@tonic-gate goto parse_flag;
4080Sstevel@tonic-gate
4090Sstevel@tonic-gate case oRhostsAuthentication:
4100Sstevel@tonic-gate intptr = &options->rhosts_authentication;
4110Sstevel@tonic-gate goto parse_flag;
4120Sstevel@tonic-gate
4130Sstevel@tonic-gate case oPasswordAuthentication:
4140Sstevel@tonic-gate intptr = &options->password_authentication;
4150Sstevel@tonic-gate goto parse_flag;
4160Sstevel@tonic-gate
4170Sstevel@tonic-gate case oKbdInteractiveAuthentication:
4180Sstevel@tonic-gate intptr = &options->kbd_interactive_authentication;
4190Sstevel@tonic-gate goto parse_flag;
4200Sstevel@tonic-gate
4210Sstevel@tonic-gate case oKbdInteractiveDevices:
4220Sstevel@tonic-gate charptr = &options->kbd_interactive_devices;
4230Sstevel@tonic-gate goto parse_string;
4240Sstevel@tonic-gate
4250Sstevel@tonic-gate case oPubkeyAuthentication:
4260Sstevel@tonic-gate intptr = &options->pubkey_authentication;
4270Sstevel@tonic-gate goto parse_flag;
4280Sstevel@tonic-gate
4290Sstevel@tonic-gate case oRSAAuthentication:
4300Sstevel@tonic-gate intptr = &options->rsa_authentication;
4310Sstevel@tonic-gate goto parse_flag;
4320Sstevel@tonic-gate
4330Sstevel@tonic-gate case oRhostsRSAAuthentication:
4340Sstevel@tonic-gate intptr = &options->rhosts_rsa_authentication;
4350Sstevel@tonic-gate goto parse_flag;
4360Sstevel@tonic-gate
4370Sstevel@tonic-gate case oHostbasedAuthentication:
4380Sstevel@tonic-gate intptr = &options->hostbased_authentication;
4390Sstevel@tonic-gate goto parse_flag;
4400Sstevel@tonic-gate
4410Sstevel@tonic-gate case oChallengeResponseAuthentication:
4420Sstevel@tonic-gate intptr = &options->challenge_response_authentication;
4430Sstevel@tonic-gate goto parse_flag;
4440Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
4450Sstevel@tonic-gate case oKerberosAuthentication:
4460Sstevel@tonic-gate intptr = &options->kerberos_authentication;
4470Sstevel@tonic-gate goto parse_flag;
4480Sstevel@tonic-gate #endif
4490Sstevel@tonic-gate #ifdef GSSAPI
4500Sstevel@tonic-gate case oGssKeyEx:
4510Sstevel@tonic-gate intptr = &options->gss_keyex;
4520Sstevel@tonic-gate goto parse_flag;
4530Sstevel@tonic-gate
4540Sstevel@tonic-gate case oGssAuthentication:
4550Sstevel@tonic-gate intptr = &options->gss_authentication;
4560Sstevel@tonic-gate goto parse_flag;
4570Sstevel@tonic-gate
4580Sstevel@tonic-gate case oGssDelegateCreds:
4590Sstevel@tonic-gate intptr = &options->gss_deleg_creds;
4600Sstevel@tonic-gate goto parse_flag;
4610Sstevel@tonic-gate
4620Sstevel@tonic-gate #ifdef GSI
4630Sstevel@tonic-gate case oGssGlobusDelegateLimitedCreds:
4640Sstevel@tonic-gate intptr = &options->gss_globus_deleg_limited_proxy;
4650Sstevel@tonic-gate goto parse_flag;
4660Sstevel@tonic-gate #endif /* GSI */
4670Sstevel@tonic-gate
4680Sstevel@tonic-gate #endif /* GSSAPI */
4690Sstevel@tonic-gate
4700Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
4710Sstevel@tonic-gate case oKerberosTgtPassing:
4720Sstevel@tonic-gate intptr = &options->kerberos_tgt_passing;
4730Sstevel@tonic-gate goto parse_flag;
4740Sstevel@tonic-gate #endif
4750Sstevel@tonic-gate #ifdef AFS
4760Sstevel@tonic-gate case oAFSTokenPassing:
4770Sstevel@tonic-gate intptr = &options->afs_token_passing;
4780Sstevel@tonic-gate goto parse_flag;
4790Sstevel@tonic-gate #endif
4800Sstevel@tonic-gate case oFallBackToRsh:
4810Sstevel@tonic-gate intptr = &options->fallback_to_rsh;
4820Sstevel@tonic-gate goto parse_flag;
4830Sstevel@tonic-gate
4840Sstevel@tonic-gate case oUseRsh:
4850Sstevel@tonic-gate intptr = &options->use_rsh;
4860Sstevel@tonic-gate goto parse_flag;
4870Sstevel@tonic-gate
4880Sstevel@tonic-gate case oBatchMode:
4890Sstevel@tonic-gate intptr = &options->batch_mode;
4900Sstevel@tonic-gate goto parse_flag;
4910Sstevel@tonic-gate
4920Sstevel@tonic-gate case oCheckHostIP:
4930Sstevel@tonic-gate intptr = &options->check_host_ip;
4940Sstevel@tonic-gate goto parse_flag;
4950Sstevel@tonic-gate
4960Sstevel@tonic-gate case oStrictHostKeyChecking:
4970Sstevel@tonic-gate intptr = &options->strict_host_key_checking;
4980Sstevel@tonic-gate arg = strdelim(&s);
4990Sstevel@tonic-gate if (!arg || *arg == '\0')
5000Sstevel@tonic-gate fatal("%.200s line %d: Missing yes/no/ask argument.",
5010Sstevel@tonic-gate filename, linenum);
5020Sstevel@tonic-gate value = 0; /* To avoid compiler warning... */
5030Sstevel@tonic-gate if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
5040Sstevel@tonic-gate value = 1;
5050Sstevel@tonic-gate else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
5060Sstevel@tonic-gate value = 0;
5070Sstevel@tonic-gate else if (strcmp(arg, "ask") == 0)
5080Sstevel@tonic-gate value = 2;
5090Sstevel@tonic-gate else
5100Sstevel@tonic-gate fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
5110Sstevel@tonic-gate if (*activep && *intptr == -1)
5120Sstevel@tonic-gate *intptr = value;
5130Sstevel@tonic-gate break;
5140Sstevel@tonic-gate
5150Sstevel@tonic-gate case oCompression:
5160Sstevel@tonic-gate intptr = &options->compression;
5170Sstevel@tonic-gate goto parse_flag;
5180Sstevel@tonic-gate
5190Sstevel@tonic-gate case oKeepAlives:
5200Sstevel@tonic-gate intptr = &options->keepalives;
5210Sstevel@tonic-gate goto parse_flag;
5220Sstevel@tonic-gate
5230Sstevel@tonic-gate case oNoHostAuthenticationForLocalhost:
5240Sstevel@tonic-gate intptr = &options->no_host_authentication_for_localhost;
5250Sstevel@tonic-gate goto parse_flag;
5260Sstevel@tonic-gate
5270Sstevel@tonic-gate case oNumberOfPasswordPrompts:
5280Sstevel@tonic-gate intptr = &options->number_of_password_prompts;
5290Sstevel@tonic-gate goto parse_int;
5300Sstevel@tonic-gate
5310Sstevel@tonic-gate case oCompressionLevel:
5320Sstevel@tonic-gate intptr = &options->compression_level;
5330Sstevel@tonic-gate goto parse_int;
5340Sstevel@tonic-gate
5355562Sjp161948 case oRekeyLimit:
5365562Sjp161948 arg = strdelim(&s);
5375562Sjp161948 if (!arg || *arg == '\0')
5385562Sjp161948 fatal("%.200s line %d: Missing argument.", filename, linenum);
5395562Sjp161948 if (arg[0] < '0' || arg[0] > '9')
5405562Sjp161948 fatal("%.200s line %d: Bad number.", filename, linenum);
5415562Sjp161948 orig = val64 = strtoll(arg, &endofnumber, 10);
5425562Sjp161948 if (arg == endofnumber)
5435562Sjp161948 fatal("%.200s line %d: Bad number.", filename, linenum);
5445562Sjp161948 switch (toupper(*endofnumber)) {
5455562Sjp161948 case '\0':
5465562Sjp161948 scale = 1;
5475562Sjp161948 break;
5485562Sjp161948 case 'K':
5495562Sjp161948 scale = 1<<10;
5505562Sjp161948 break;
5515562Sjp161948 case 'M':
5525562Sjp161948 scale = 1<<20;
5535562Sjp161948 break;
5545562Sjp161948 case 'G':
5555562Sjp161948 scale = 1<<30;
5565562Sjp161948 break;
5575562Sjp161948 default:
5585562Sjp161948 fatal("%.200s line %d: Invalid RekeyLimit suffix",
5595562Sjp161948 filename, linenum);
5605562Sjp161948 }
5615562Sjp161948 val64 *= scale;
5625562Sjp161948 /* detect integer wrap and too-large limits */
5635562Sjp161948 if ((val64 / scale) != orig || val64 > UINT_MAX)
5645562Sjp161948 fatal("%.200s line %d: RekeyLimit too large",
5655562Sjp161948 filename, linenum);
5665562Sjp161948 if (val64 < 16)
5675562Sjp161948 fatal("%.200s line %d: RekeyLimit too small",
5685562Sjp161948 filename, linenum);
5695562Sjp161948 if (*activep && options->rekey_limit == -1)
5705562Sjp161948 options->rekey_limit = (u_int32_t)val64;
5715562Sjp161948 break;
5725562Sjp161948
5730Sstevel@tonic-gate case oIdentityFile:
5740Sstevel@tonic-gate arg = strdelim(&s);
5750Sstevel@tonic-gate if (!arg || *arg == '\0')
5760Sstevel@tonic-gate fatal("%.200s line %d: Missing argument.", filename, linenum);
5770Sstevel@tonic-gate if (*activep) {
5780Sstevel@tonic-gate intptr = &options->num_identity_files;
5790Sstevel@tonic-gate if (*intptr >= SSH_MAX_IDENTITY_FILES)
5800Sstevel@tonic-gate fatal("%.200s line %d: Too many identity files specified (max %d).",
5810Sstevel@tonic-gate filename, linenum, SSH_MAX_IDENTITY_FILES);
5820Sstevel@tonic-gate charptr = &options->identity_files[*intptr];
5830Sstevel@tonic-gate *charptr = xstrdup(arg);
5840Sstevel@tonic-gate *intptr = *intptr + 1;
5850Sstevel@tonic-gate }
5860Sstevel@tonic-gate break;
5870Sstevel@tonic-gate
5880Sstevel@tonic-gate case oXAuthLocation:
5890Sstevel@tonic-gate charptr=&options->xauth_location;
5900Sstevel@tonic-gate goto parse_string;
5910Sstevel@tonic-gate
5920Sstevel@tonic-gate case oUser:
5930Sstevel@tonic-gate charptr = &options->user;
5940Sstevel@tonic-gate parse_string:
5950Sstevel@tonic-gate arg = strdelim(&s);
5960Sstevel@tonic-gate if (!arg || *arg == '\0')
5970Sstevel@tonic-gate fatal("%.200s line %d: Missing argument.", filename, linenum);
5980Sstevel@tonic-gate if (*activep && *charptr == NULL)
5990Sstevel@tonic-gate *charptr = xstrdup(arg);
6000Sstevel@tonic-gate break;
6010Sstevel@tonic-gate
6020Sstevel@tonic-gate case oGlobalKnownHostsFile:
6030Sstevel@tonic-gate charptr = &options->system_hostfile;
6040Sstevel@tonic-gate goto parse_string;
6050Sstevel@tonic-gate
6060Sstevel@tonic-gate case oUserKnownHostsFile:
6070Sstevel@tonic-gate charptr = &options->user_hostfile;
6080Sstevel@tonic-gate goto parse_string;
6090Sstevel@tonic-gate
6100Sstevel@tonic-gate case oGlobalKnownHostsFile2:
6110Sstevel@tonic-gate charptr = &options->system_hostfile2;
6120Sstevel@tonic-gate goto parse_string;
6130Sstevel@tonic-gate
6140Sstevel@tonic-gate case oUserKnownHostsFile2:
6150Sstevel@tonic-gate charptr = &options->user_hostfile2;
6160Sstevel@tonic-gate goto parse_string;
6170Sstevel@tonic-gate
6180Sstevel@tonic-gate case oHostName:
6190Sstevel@tonic-gate charptr = &options->hostname;
6200Sstevel@tonic-gate goto parse_string;
6210Sstevel@tonic-gate
6220Sstevel@tonic-gate case oHostKeyAlias:
6230Sstevel@tonic-gate charptr = &options->host_key_alias;
6240Sstevel@tonic-gate goto parse_string;
6250Sstevel@tonic-gate
6260Sstevel@tonic-gate case oPreferredAuthentications:
6270Sstevel@tonic-gate charptr = &options->preferred_authentications;
6280Sstevel@tonic-gate goto parse_string;
6290Sstevel@tonic-gate
6300Sstevel@tonic-gate case oBindAddress:
6310Sstevel@tonic-gate charptr = &options->bind_address;
6320Sstevel@tonic-gate goto parse_string;
6330Sstevel@tonic-gate
6340Sstevel@tonic-gate case oSmartcardDevice:
6350Sstevel@tonic-gate charptr = &options->smartcard_device;
6360Sstevel@tonic-gate goto parse_string;
6370Sstevel@tonic-gate
6380Sstevel@tonic-gate case oProxyCommand:
6390Sstevel@tonic-gate charptr = &options->proxy_command;
6400Sstevel@tonic-gate string = xstrdup("");
6410Sstevel@tonic-gate while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
6420Sstevel@tonic-gate string = xrealloc(string, strlen(string) + strlen(arg) + 2);
6430Sstevel@tonic-gate strcat(string, " ");
6440Sstevel@tonic-gate strcat(string, arg);
6450Sstevel@tonic-gate }
6460Sstevel@tonic-gate if (*activep && *charptr == NULL)
6470Sstevel@tonic-gate *charptr = string;
6480Sstevel@tonic-gate else
6490Sstevel@tonic-gate xfree(string);
6500Sstevel@tonic-gate return 0;
6510Sstevel@tonic-gate
6520Sstevel@tonic-gate case oPort:
6530Sstevel@tonic-gate intptr = &options->port;
6540Sstevel@tonic-gate parse_int:
6550Sstevel@tonic-gate arg = strdelim(&s);
6560Sstevel@tonic-gate if (!arg || *arg == '\0')
6570Sstevel@tonic-gate fatal("%.200s line %d: Missing argument.", filename, linenum);
6580Sstevel@tonic-gate if (arg[0] < '0' || arg[0] > '9')
6590Sstevel@tonic-gate fatal("%.200s line %d: Bad number.", filename, linenum);
6600Sstevel@tonic-gate
6610Sstevel@tonic-gate /* Octal, decimal, or hex format? */
6620Sstevel@tonic-gate value = strtol(arg, &endofnumber, 0);
6630Sstevel@tonic-gate if (arg == endofnumber)
6640Sstevel@tonic-gate fatal("%.200s line %d: Bad number.", filename, linenum);
6650Sstevel@tonic-gate if (*activep && *intptr == -1)
6660Sstevel@tonic-gate *intptr = value;
6670Sstevel@tonic-gate break;
6680Sstevel@tonic-gate
6690Sstevel@tonic-gate case oConnectionAttempts:
6700Sstevel@tonic-gate intptr = &options->connection_attempts;
6710Sstevel@tonic-gate goto parse_int;
6720Sstevel@tonic-gate
6730Sstevel@tonic-gate case oCipher:
6740Sstevel@tonic-gate intptr = &options->cipher;
6750Sstevel@tonic-gate arg = strdelim(&s);
6760Sstevel@tonic-gate if (!arg || *arg == '\0')
6770Sstevel@tonic-gate fatal("%.200s line %d: Missing argument.", filename, linenum);
6780Sstevel@tonic-gate value = cipher_number(arg);
6790Sstevel@tonic-gate if (value == -1)
6800Sstevel@tonic-gate fatal("%.200s line %d: Bad cipher '%s'.",
6810Sstevel@tonic-gate filename, linenum, arg ? arg : "<NONE>");
6820Sstevel@tonic-gate if (*activep && *intptr == -1)
6830Sstevel@tonic-gate *intptr = value;
6840Sstevel@tonic-gate break;
6850Sstevel@tonic-gate
6860Sstevel@tonic-gate case oCiphers:
6870Sstevel@tonic-gate arg = strdelim(&s);
6880Sstevel@tonic-gate if (!arg || *arg == '\0')
6890Sstevel@tonic-gate fatal("%.200s line %d: Missing argument.", filename, linenum);
6900Sstevel@tonic-gate if (!ciphers_valid(arg))
6910Sstevel@tonic-gate fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
6920Sstevel@tonic-gate filename, linenum, arg ? arg : "<NONE>");
6930Sstevel@tonic-gate if (*activep && options->ciphers == NULL)
6940Sstevel@tonic-gate options->ciphers = xstrdup(arg);
6950Sstevel@tonic-gate break;
6960Sstevel@tonic-gate
6970Sstevel@tonic-gate case oMacs:
6980Sstevel@tonic-gate arg = strdelim(&s);
6990Sstevel@tonic-gate if (!arg || *arg == '\0')
7000Sstevel@tonic-gate fatal("%.200s line %d: Missing argument.", filename, linenum);
7010Sstevel@tonic-gate if (!mac_valid(arg))
7020Sstevel@tonic-gate fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
7030Sstevel@tonic-gate filename, linenum, arg ? arg : "<NONE>");
7040Sstevel@tonic-gate if (*activep && options->macs == NULL)
7050Sstevel@tonic-gate options->macs = xstrdup(arg);
7060Sstevel@tonic-gate break;
7070Sstevel@tonic-gate
7080Sstevel@tonic-gate case oHostKeyAlgorithms:
7090Sstevel@tonic-gate arg = strdelim(&s);
7100Sstevel@tonic-gate if (!arg || *arg == '\0')
7110Sstevel@tonic-gate fatal("%.200s line %d: Missing argument.", filename, linenum);
7120Sstevel@tonic-gate if (!key_names_valid2(arg))
7130Sstevel@tonic-gate fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
7140Sstevel@tonic-gate filename, linenum, arg ? arg : "<NONE>");
7150Sstevel@tonic-gate if (*activep && options->hostkeyalgorithms == NULL)
7160Sstevel@tonic-gate options->hostkeyalgorithms = xstrdup(arg);
7170Sstevel@tonic-gate break;
7180Sstevel@tonic-gate
7190Sstevel@tonic-gate case oProtocol:
7200Sstevel@tonic-gate intptr = &options->protocol;
7210Sstevel@tonic-gate arg = strdelim(&s);
7220Sstevel@tonic-gate if (!arg || *arg == '\0')
7230Sstevel@tonic-gate fatal("%.200s line %d: Missing argument.", filename, linenum);
7240Sstevel@tonic-gate value = proto_spec(arg);
7250Sstevel@tonic-gate if (value == SSH_PROTO_UNKNOWN)
7260Sstevel@tonic-gate fatal("%.200s line %d: Bad protocol spec '%s'.",
7270Sstevel@tonic-gate filename, linenum, arg ? arg : "<NONE>");
7280Sstevel@tonic-gate if (*activep && *intptr == SSH_PROTO_UNKNOWN)
7290Sstevel@tonic-gate *intptr = value;
7300Sstevel@tonic-gate break;
7310Sstevel@tonic-gate
7320Sstevel@tonic-gate case oLogLevel:
7330Sstevel@tonic-gate intptr = (int *) &options->log_level;
7340Sstevel@tonic-gate arg = strdelim(&s);
7350Sstevel@tonic-gate value = log_level_number(arg);
7360Sstevel@tonic-gate if (value == SYSLOG_LEVEL_NOT_SET)
7370Sstevel@tonic-gate fatal("%.200s line %d: unsupported log level '%s'",
7380Sstevel@tonic-gate filename, linenum, arg ? arg : "<NONE>");
7390Sstevel@tonic-gate if (*activep && (LogLevel) *intptr == SYSLOG_LEVEL_NOT_SET)
7400Sstevel@tonic-gate *intptr = (LogLevel) value;
7410Sstevel@tonic-gate break;
7420Sstevel@tonic-gate
7430Sstevel@tonic-gate case oLocalForward:
7440Sstevel@tonic-gate case oRemoteForward:
7450Sstevel@tonic-gate arg = strdelim(&s);
7465334Sjp161948 if (arg == NULL || *arg == '\0')
7470Sstevel@tonic-gate fatal("%.200s line %d: Missing port argument.",
7480Sstevel@tonic-gate filename, linenum);
7495334Sjp161948 arg2 = strdelim(&s);
7505334Sjp161948 if (arg2 == NULL || *arg2 == '\0')
7515334Sjp161948 fatal("%.200s line %d: Missing target argument.",
7520Sstevel@tonic-gate filename, linenum);
7535334Sjp161948
7545334Sjp161948 /* construct a string for parse_forward */
7555334Sjp161948 snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
7565334Sjp161948
7575334Sjp161948 if (parse_forward(1, &fwd, fwdarg) == 0)
7580Sstevel@tonic-gate fatal("%.200s line %d: Bad forwarding specification.",
7590Sstevel@tonic-gate filename, linenum);
7605334Sjp161948
7610Sstevel@tonic-gate if (*activep) {
7620Sstevel@tonic-gate if (opcode == oLocalForward)
7635334Sjp161948 add_local_forward(options, &fwd);
7640Sstevel@tonic-gate else if (opcode == oRemoteForward)
7655334Sjp161948 add_remote_forward(options, &fwd);
7660Sstevel@tonic-gate }
7670Sstevel@tonic-gate break;
7680Sstevel@tonic-gate
7690Sstevel@tonic-gate case oDynamicForward:
7700Sstevel@tonic-gate arg = strdelim(&s);
7710Sstevel@tonic-gate if (!arg || *arg == '\0')
7720Sstevel@tonic-gate fatal("%.200s line %d: Missing port argument.",
7730Sstevel@tonic-gate filename, linenum);
7745334Sjp161948
7755334Sjp161948 if (parse_forward(0, &fwd, arg) == 0) {
7765334Sjp161948 fatal("%.200s line %d: Bad dynamic forwarding specification.",
7770Sstevel@tonic-gate filename, linenum);
7785334Sjp161948 }
7795334Sjp161948
7805334Sjp161948 if (*activep) {
7815334Sjp161948 fwd.connect_host = "socks";
7825334Sjp161948 add_local_forward(options, &fwd);
7835334Sjp161948 }
7840Sstevel@tonic-gate break;
7850Sstevel@tonic-gate
7860Sstevel@tonic-gate case oClearAllForwardings:
7870Sstevel@tonic-gate intptr = &options->clear_forwardings;
7880Sstevel@tonic-gate goto parse_flag;
7890Sstevel@tonic-gate
7900Sstevel@tonic-gate case oHost:
7910Sstevel@tonic-gate *activep = 0;
7920Sstevel@tonic-gate while ((arg = strdelim(&s)) != NULL && *arg != '\0')
7930Sstevel@tonic-gate if (match_pattern(host, arg)) {
7940Sstevel@tonic-gate debug("Applying options for %.100s", arg);
7950Sstevel@tonic-gate *activep = 1;
7960Sstevel@tonic-gate break;
7970Sstevel@tonic-gate }
7980Sstevel@tonic-gate /* Avoid garbage check below, as strdelim is done. */
7990Sstevel@tonic-gate return 0;
8000Sstevel@tonic-gate
8010Sstevel@tonic-gate case oEscapeChar:
8020Sstevel@tonic-gate intptr = &options->escape_char;
8030Sstevel@tonic-gate arg = strdelim(&s);
8040Sstevel@tonic-gate if (!arg || *arg == '\0')
8050Sstevel@tonic-gate fatal("%.200s line %d: Missing argument.", filename, linenum);
8060Sstevel@tonic-gate if (arg[0] == '^' && arg[2] == 0 &&
8070Sstevel@tonic-gate (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
8080Sstevel@tonic-gate value = (u_char) arg[1] & 31;
8090Sstevel@tonic-gate else if (strlen(arg) == 1)
8100Sstevel@tonic-gate value = (u_char) arg[0];
8110Sstevel@tonic-gate else if (strcmp(arg, "none") == 0)
8120Sstevel@tonic-gate value = SSH_ESCAPECHAR_NONE;
8130Sstevel@tonic-gate else {
8140Sstevel@tonic-gate fatal("%.200s line %d: Bad escape character.",
8150Sstevel@tonic-gate filename, linenum);
8160Sstevel@tonic-gate /* NOTREACHED */
8170Sstevel@tonic-gate value = 0; /* Avoid compiler warning. */
8180Sstevel@tonic-gate }
8190Sstevel@tonic-gate if (*activep && *intptr == -1)
8200Sstevel@tonic-gate *intptr = value;
8210Sstevel@tonic-gate break;
8220Sstevel@tonic-gate
8234668Sjp161948 case oServerAliveInterval:
8244668Sjp161948 intptr = &options->server_alive_interval;
8254668Sjp161948 goto parse_time;
8264668Sjp161948
8274668Sjp161948 case oServerAliveCountMax:
8284668Sjp161948 intptr = &options->server_alive_count_max;
8294668Sjp161948 goto parse_int;
8304668Sjp161948
8315243Sjp161948 case oHashKnownHosts:
8325243Sjp161948 intptr = &options->hash_known_hosts;
8335243Sjp161948 goto parse_flag;
8345243Sjp161948
8354958Sjp161948 case oDisableBanner:
8364958Sjp161948 arg = strdelim(&s);
8374958Sjp161948 if (get_yes_no_flag(&options->disable_banner, arg, filename,
8384958Sjp161948 linenum, *activep) == 1)
8394958Sjp161948 break;
8404958Sjp161948
8414958Sjp161948 if (strcmp(arg, "in-exec-mode") == 0)
8424958Sjp161948 options->disable_banner = SSH_NO_BANNER_IN_EXEC_MODE;
8434958Sjp161948 else
8444958Sjp161948 fatal("%.200s line %d: Bad yes/no/in-exec-mode "
8454958Sjp161948 "argument.", filename, linenum);
8464958Sjp161948 break;
8474958Sjp161948
8485266Sjp161948 case oIgnoreIfUnknown:
8495266Sjp161948 charptr = &options->ignore_if_unknown;
8505266Sjp161948 goto parse_string;
8515266Sjp161948
8527574SJan.Pechanec@Sun.COM case oUseOpenSSLEngine:
8537574SJan.Pechanec@Sun.COM intptr = &options->use_openssl_engine;
8547574SJan.Pechanec@Sun.COM goto parse_flag;
8557574SJan.Pechanec@Sun.COM
8560Sstevel@tonic-gate case oDeprecated:
8570Sstevel@tonic-gate debug("%s line %d: Deprecated option \"%s\"",
8580Sstevel@tonic-gate filename, linenum, keyword);
8590Sstevel@tonic-gate return 0;
8600Sstevel@tonic-gate
8610Sstevel@tonic-gate default:
8620Sstevel@tonic-gate fatal("process_config_line: Unimplemented opcode %d", opcode);
8630Sstevel@tonic-gate }
8640Sstevel@tonic-gate
8650Sstevel@tonic-gate /* Check that there is no garbage at end of line. */
8660Sstevel@tonic-gate if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
8670Sstevel@tonic-gate fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
8680Sstevel@tonic-gate filename, linenum, arg);
8690Sstevel@tonic-gate }
8700Sstevel@tonic-gate return 0;
8710Sstevel@tonic-gate }
8720Sstevel@tonic-gate
8730Sstevel@tonic-gate
8740Sstevel@tonic-gate /*
8750Sstevel@tonic-gate * Reads the config file and modifies the options accordingly. Options
8760Sstevel@tonic-gate * should already be initialized before this call. This never returns if
8770Sstevel@tonic-gate * there is an error. If the file does not exist, this returns 0.
8780Sstevel@tonic-gate */
8790Sstevel@tonic-gate
8800Sstevel@tonic-gate int
read_config_file(const char * filename,const char * host,Options * options)8810Sstevel@tonic-gate read_config_file(const char *filename, const char *host, Options *options)
8820Sstevel@tonic-gate {
8830Sstevel@tonic-gate FILE *f;
8840Sstevel@tonic-gate char line[1024];
8850Sstevel@tonic-gate int active, linenum;
8860Sstevel@tonic-gate
8870Sstevel@tonic-gate /* Open the file. */
8880Sstevel@tonic-gate f = fopen(filename, "r");
8890Sstevel@tonic-gate if (!f)
8900Sstevel@tonic-gate return 0;
8910Sstevel@tonic-gate
8920Sstevel@tonic-gate debug("Reading configuration data %.200s", filename);
8930Sstevel@tonic-gate
8940Sstevel@tonic-gate /*
8950Sstevel@tonic-gate * Mark that we are now processing the options. This flag is turned
8960Sstevel@tonic-gate * on/off by Host specifications.
8970Sstevel@tonic-gate */
8980Sstevel@tonic-gate active = 1;
8990Sstevel@tonic-gate linenum = 0;
9000Sstevel@tonic-gate while (fgets(line, sizeof(line), f)) {
9010Sstevel@tonic-gate /* Update line number counter. */
9020Sstevel@tonic-gate linenum++;
9035266Sjp161948 process_config_line(options, host, line, filename, linenum, &active);
9040Sstevel@tonic-gate }
9050Sstevel@tonic-gate fclose(f);
9060Sstevel@tonic-gate return 1;
9070Sstevel@tonic-gate }
9080Sstevel@tonic-gate
9090Sstevel@tonic-gate /*
9100Sstevel@tonic-gate * Initializes options to special values that indicate that they have not yet
9110Sstevel@tonic-gate * been set. Read_config_file will only set options with this value. Options
9120Sstevel@tonic-gate * are processed in the following order: command line, user config file,
9130Sstevel@tonic-gate * system config file. Last, fill_default_options is called.
9140Sstevel@tonic-gate */
9150Sstevel@tonic-gate
9160Sstevel@tonic-gate void
initialize_options(Options * options)9170Sstevel@tonic-gate initialize_options(Options * options)
9180Sstevel@tonic-gate {
9190Sstevel@tonic-gate memset(options, 'X', sizeof(*options));
9200Sstevel@tonic-gate options->forward_agent = -1;
9210Sstevel@tonic-gate options->forward_x11 = -1;
9224907Sjp161948 options->forward_x11_trusted = -1;
9230Sstevel@tonic-gate options->xauth_location = NULL;
9240Sstevel@tonic-gate options->gateway_ports = -1;
9250Sstevel@tonic-gate options->use_privileged_port = -1;
9260Sstevel@tonic-gate options->rhosts_authentication = -1;
9270Sstevel@tonic-gate options->rsa_authentication = -1;
9280Sstevel@tonic-gate options->pubkey_authentication = -1;
9290Sstevel@tonic-gate options->challenge_response_authentication = -1;
9300Sstevel@tonic-gate #ifdef GSSAPI
9310Sstevel@tonic-gate options->gss_keyex = -1;
9320Sstevel@tonic-gate options->gss_authentication = -1;
9330Sstevel@tonic-gate options->gss_deleg_creds = -1;
9340Sstevel@tonic-gate #ifdef GSI
9350Sstevel@tonic-gate options->gss_globus_deleg_limited_proxy = -1;
9360Sstevel@tonic-gate #endif /* GSI */
9370Sstevel@tonic-gate #endif /* GSSAPI */
9380Sstevel@tonic-gate
9390Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
9400Sstevel@tonic-gate options->kerberos_authentication = -1;
9410Sstevel@tonic-gate #endif
9420Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
9430Sstevel@tonic-gate options->kerberos_tgt_passing = -1;
9440Sstevel@tonic-gate #endif
9450Sstevel@tonic-gate #ifdef AFS
9460Sstevel@tonic-gate options->afs_token_passing = -1;
9470Sstevel@tonic-gate #endif
9480Sstevel@tonic-gate options->password_authentication = -1;
9490Sstevel@tonic-gate options->kbd_interactive_authentication = -1;
9500Sstevel@tonic-gate options->kbd_interactive_devices = NULL;
9510Sstevel@tonic-gate options->rhosts_rsa_authentication = -1;
9520Sstevel@tonic-gate options->hostbased_authentication = -1;
9530Sstevel@tonic-gate options->batch_mode = -1;
9540Sstevel@tonic-gate options->check_host_ip = -1;
9550Sstevel@tonic-gate options->strict_host_key_checking = -1;
9560Sstevel@tonic-gate options->compression = -1;
9570Sstevel@tonic-gate options->keepalives = -1;
9580Sstevel@tonic-gate options->compression_level = -1;
9590Sstevel@tonic-gate options->port = -1;
9600Sstevel@tonic-gate options->connection_attempts = -1;
9613946Sjp161948 options->connection_timeout = -1;
9620Sstevel@tonic-gate options->number_of_password_prompts = -1;
9630Sstevel@tonic-gate options->cipher = -1;
9640Sstevel@tonic-gate options->ciphers = NULL;
9650Sstevel@tonic-gate options->macs = NULL;
9660Sstevel@tonic-gate options->hostkeyalgorithms = NULL;
9670Sstevel@tonic-gate options->protocol = SSH_PROTO_UNKNOWN;
9680Sstevel@tonic-gate options->num_identity_files = 0;
9690Sstevel@tonic-gate options->hostname = NULL;
9700Sstevel@tonic-gate options->host_key_alias = NULL;
9710Sstevel@tonic-gate options->proxy_command = NULL;
9720Sstevel@tonic-gate options->user = NULL;
9730Sstevel@tonic-gate options->escape_char = -1;
9740Sstevel@tonic-gate options->system_hostfile = NULL;
9750Sstevel@tonic-gate options->user_hostfile = NULL;
9760Sstevel@tonic-gate options->system_hostfile2 = NULL;
9770Sstevel@tonic-gate options->user_hostfile2 = NULL;
9780Sstevel@tonic-gate options->num_local_forwards = 0;
9790Sstevel@tonic-gate options->num_remote_forwards = 0;
9800Sstevel@tonic-gate options->clear_forwardings = -1;
9810Sstevel@tonic-gate options->log_level = SYSLOG_LEVEL_NOT_SET;
9820Sstevel@tonic-gate options->preferred_authentications = NULL;
9830Sstevel@tonic-gate options->bind_address = NULL;
9840Sstevel@tonic-gate options->smartcard_device = NULL;
9855562Sjp161948 options->no_host_authentication_for_localhost = -1;
9865562Sjp161948 options->rekey_limit = -1;
9870Sstevel@tonic-gate options->fallback_to_rsh = -1;
9880Sstevel@tonic-gate options->use_rsh = -1;
9894668Sjp161948 options->server_alive_interval = -1;
9904668Sjp161948 options->server_alive_count_max = -1;
9915243Sjp161948 options->hash_known_hosts = -1;
9925266Sjp161948 options->ignore_if_unknown = NULL;
9935266Sjp161948 options->unknown_opts_num = 0;
9944958Sjp161948 options->disable_banner = -1;
9957574SJan.Pechanec@Sun.COM options->use_openssl_engine = -1;
9960Sstevel@tonic-gate }
9970Sstevel@tonic-gate
9980Sstevel@tonic-gate /*
9990Sstevel@tonic-gate * Called after processing other sources of option data, this fills those
10000Sstevel@tonic-gate * options for which no value has been specified with their default values.
10010Sstevel@tonic-gate */
10020Sstevel@tonic-gate
10030Sstevel@tonic-gate void
fill_default_options(Options * options)10040Sstevel@tonic-gate fill_default_options(Options * options)
10050Sstevel@tonic-gate {
10060Sstevel@tonic-gate int len;
10070Sstevel@tonic-gate
10080Sstevel@tonic-gate if (options->forward_agent == -1)
10090Sstevel@tonic-gate options->forward_agent = 0;
10100Sstevel@tonic-gate if (options->forward_x11 == -1)
10110Sstevel@tonic-gate options->forward_x11 = 0;
10124907Sjp161948 /*
10134907Sjp161948 * Unlike OpenSSH, we keep backward compatibility for '-X' option
10144907Sjp161948 * which means that X11 forwarding is trusted by default.
10154907Sjp161948 */
10164907Sjp161948 if (options->forward_x11_trusted == -1)
10174907Sjp161948 options->forward_x11_trusted = 1;
10180Sstevel@tonic-gate if (options->xauth_location == NULL)
10190Sstevel@tonic-gate options->xauth_location = _PATH_XAUTH;
10200Sstevel@tonic-gate if (options->gateway_ports == -1)
10210Sstevel@tonic-gate options->gateway_ports = 0;
10220Sstevel@tonic-gate if (options->use_privileged_port == -1)
10230Sstevel@tonic-gate options->use_privileged_port = 0;
10240Sstevel@tonic-gate if (options->rhosts_authentication == -1)
10250Sstevel@tonic-gate options->rhosts_authentication = 0;
10260Sstevel@tonic-gate if (options->rsa_authentication == -1)
10270Sstevel@tonic-gate options->rsa_authentication = 1;
10280Sstevel@tonic-gate if (options->pubkey_authentication == -1)
10290Sstevel@tonic-gate options->pubkey_authentication = 1;
10300Sstevel@tonic-gate if (options->challenge_response_authentication == -1)
10310Sstevel@tonic-gate options->challenge_response_authentication = 1;
10320Sstevel@tonic-gate #ifdef GSSAPI
10330Sstevel@tonic-gate if (options->gss_keyex == -1)
10340Sstevel@tonic-gate options->gss_keyex = 1;
10350Sstevel@tonic-gate if (options->gss_authentication == -1)
10360Sstevel@tonic-gate options->gss_authentication = 1;
10370Sstevel@tonic-gate if (options->gss_deleg_creds == -1)
10380Sstevel@tonic-gate options->gss_deleg_creds = 0;
10390Sstevel@tonic-gate #ifdef GSI
10400Sstevel@tonic-gate if (options->gss_globus_deleg_limited_proxy == -1)
10410Sstevel@tonic-gate options->gss_globus_deleg_limited_proxy = 0;
10420Sstevel@tonic-gate #endif /* GSI */
10430Sstevel@tonic-gate #endif /* GSSAPI */
10440Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
10450Sstevel@tonic-gate if (options->kerberos_authentication == -1)
10460Sstevel@tonic-gate options->kerberos_authentication = 1;
10470Sstevel@tonic-gate #endif
10480Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
10490Sstevel@tonic-gate if (options->kerberos_tgt_passing == -1)
10500Sstevel@tonic-gate options->kerberos_tgt_passing = 1;
10510Sstevel@tonic-gate #endif
10520Sstevel@tonic-gate #ifdef AFS
10530Sstevel@tonic-gate if (options->afs_token_passing == -1)
10540Sstevel@tonic-gate options->afs_token_passing = 1;
10550Sstevel@tonic-gate #endif
10560Sstevel@tonic-gate if (options->password_authentication == -1)
10570Sstevel@tonic-gate options->password_authentication = 1;
10580Sstevel@tonic-gate if (options->kbd_interactive_authentication == -1)
10590Sstevel@tonic-gate options->kbd_interactive_authentication = 1;
10600Sstevel@tonic-gate if (options->rhosts_rsa_authentication == -1)
10610Sstevel@tonic-gate options->rhosts_rsa_authentication = 0;
10620Sstevel@tonic-gate if (options->hostbased_authentication == -1)
10630Sstevel@tonic-gate options->hostbased_authentication = 0;
10640Sstevel@tonic-gate if (options->batch_mode == -1)
10650Sstevel@tonic-gate options->batch_mode = 0;
10660Sstevel@tonic-gate if (options->check_host_ip == -1)
10670Sstevel@tonic-gate options->check_host_ip = 1;
10680Sstevel@tonic-gate if (options->strict_host_key_checking == -1)
10690Sstevel@tonic-gate options->strict_host_key_checking = 2; /* 2 is default */
10700Sstevel@tonic-gate if (options->compression == -1)
10710Sstevel@tonic-gate options->compression = 0;
10720Sstevel@tonic-gate if (options->keepalives == -1)
10730Sstevel@tonic-gate options->keepalives = 1;
10740Sstevel@tonic-gate if (options->compression_level == -1)
10750Sstevel@tonic-gate options->compression_level = 6;
10760Sstevel@tonic-gate if (options->port == -1)
10770Sstevel@tonic-gate options->port = 0; /* Filled in ssh_connect. */
10780Sstevel@tonic-gate if (options->connection_attempts == -1)
10790Sstevel@tonic-gate options->connection_attempts = 1;
10800Sstevel@tonic-gate if (options->number_of_password_prompts == -1)
10810Sstevel@tonic-gate options->number_of_password_prompts = 3;
10820Sstevel@tonic-gate /* Selected in ssh_login(). */
10830Sstevel@tonic-gate if (options->cipher == -1)
10840Sstevel@tonic-gate options->cipher = SSH_CIPHER_NOT_SET;
10850Sstevel@tonic-gate /* options->ciphers, default set in myproposals.h */
10860Sstevel@tonic-gate /* options->macs, default set in myproposals.h */
10870Sstevel@tonic-gate /* options->hostkeyalgorithms, default set in myproposals.h */
10880Sstevel@tonic-gate if (options->protocol == SSH_PROTO_UNKNOWN)
10890Sstevel@tonic-gate options->protocol = SSH_PROTO_1|SSH_PROTO_2;
10900Sstevel@tonic-gate if (options->num_identity_files == 0) {
10910Sstevel@tonic-gate if (options->protocol & SSH_PROTO_1) {
10920Sstevel@tonic-gate len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;
10930Sstevel@tonic-gate options->identity_files[options->num_identity_files] =
10940Sstevel@tonic-gate xmalloc(len);
10950Sstevel@tonic-gate snprintf(options->identity_files[options->num_identity_files++],
10960Sstevel@tonic-gate len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY);
10970Sstevel@tonic-gate }
10980Sstevel@tonic-gate if (options->protocol & SSH_PROTO_2) {
10990Sstevel@tonic-gate len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1;
11000Sstevel@tonic-gate options->identity_files[options->num_identity_files] =
11010Sstevel@tonic-gate xmalloc(len);
11020Sstevel@tonic-gate snprintf(options->identity_files[options->num_identity_files++],
11030Sstevel@tonic-gate len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA);
11040Sstevel@tonic-gate
11050Sstevel@tonic-gate len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1;
11060Sstevel@tonic-gate options->identity_files[options->num_identity_files] =
11070Sstevel@tonic-gate xmalloc(len);
11080Sstevel@tonic-gate snprintf(options->identity_files[options->num_identity_files++],
11090Sstevel@tonic-gate len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA);
11100Sstevel@tonic-gate }
11110Sstevel@tonic-gate }
11120Sstevel@tonic-gate if (options->escape_char == -1)
11130Sstevel@tonic-gate options->escape_char = '~';
11140Sstevel@tonic-gate if (options->system_hostfile == NULL)
11150Sstevel@tonic-gate options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
11160Sstevel@tonic-gate if (options->user_hostfile == NULL)
11170Sstevel@tonic-gate options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
11180Sstevel@tonic-gate if (options->system_hostfile2 == NULL)
11190Sstevel@tonic-gate options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
11200Sstevel@tonic-gate if (options->user_hostfile2 == NULL)
11210Sstevel@tonic-gate options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
11220Sstevel@tonic-gate if (options->log_level == SYSLOG_LEVEL_NOT_SET)
11230Sstevel@tonic-gate options->log_level = SYSLOG_LEVEL_INFO;
11240Sstevel@tonic-gate if (options->clear_forwardings == 1)
11250Sstevel@tonic-gate clear_forwardings(options);
11265562Sjp161948 if (options->no_host_authentication_for_localhost == -1)
11270Sstevel@tonic-gate options->no_host_authentication_for_localhost = 0;
11285562Sjp161948 if (options->rekey_limit == -1)
11295562Sjp161948 options->rekey_limit = 0;
11305562Sjp161948 if (options->fallback_to_rsh == -1)
11310Sstevel@tonic-gate options->fallback_to_rsh = 0;
11325562Sjp161948 if (options->use_rsh == -1)
11330Sstevel@tonic-gate options->use_rsh = 0;
11344668Sjp161948 if (options->server_alive_interval == -1)
11354668Sjp161948 options->server_alive_interval = 0;
11364668Sjp161948 if (options->server_alive_count_max == -1)
11374668Sjp161948 options->server_alive_count_max = 3;
11385243Sjp161948 if (options->hash_known_hosts == -1)
11395243Sjp161948 options->hash_known_hosts = 0;
11404958Sjp161948 if (options->disable_banner == -1)
11414958Sjp161948 options->disable_banner = 0;
11427574SJan.Pechanec@Sun.COM if (options->use_openssl_engine == -1)
11437574SJan.Pechanec@Sun.COM options->use_openssl_engine = 1;
11440Sstevel@tonic-gate /* options->proxy_command should not be set by default */
11450Sstevel@tonic-gate /* options->user will be set in the main program if appropriate */
11460Sstevel@tonic-gate /* options->hostname will be set in the main program if appropriate */
11470Sstevel@tonic-gate /* options->host_key_alias should not be set by default */
11480Sstevel@tonic-gate /* options->preferred_authentications will be set in ssh */
11495266Sjp161948 /* options->ignore_if_unknown should not be set by default */
11500Sstevel@tonic-gate }
11515266Sjp161948
11525266Sjp161948 /*
11535334Sjp161948 * Parses a string containing a port forwarding specification of one of the
11545334Sjp161948 * two forms, short or long:
11555334Sjp161948 *
11565334Sjp161948 * [listenhost:]listenport
11575334Sjp161948 * [listenhost:]listenport:connecthost:connectport
11585334Sjp161948 *
11595334Sjp161948 * short forwarding specification is used for dynamic port forwarding and for
11605334Sjp161948 * port forwarding cancelation in process_cmdline(). The function returns number
11615334Sjp161948 * of arguments parsed or zero on any error.
11625334Sjp161948 */
11635334Sjp161948 int
parse_forward(int long_form,Forward * fwd,const char * fwdspec)11645334Sjp161948 parse_forward(int long_form, Forward *fwd, const char *fwdspec)
11655334Sjp161948 {
11665334Sjp161948 int i;
11675334Sjp161948 char *p, *cp, *fwdarg[5];
11685334Sjp161948
11695334Sjp161948 memset(fwd, '\0', sizeof(*fwd));
11705334Sjp161948
11715334Sjp161948 cp = p = xstrdup(fwdspec);
11725334Sjp161948
11735334Sjp161948 /* skip leading spaces */
11745334Sjp161948 while (isspace(*cp))
11755334Sjp161948 cp++;
11765334Sjp161948
11775334Sjp161948 for (i = 0; i < 5; ++i)
11785334Sjp161948 if ((fwdarg[i] = hpdelim(&cp)) == NULL)
11795334Sjp161948 break;
11805334Sjp161948
11815334Sjp161948 if ((long_form == 0 && i > 2) || (long_form == 1 && i < 3) || (i == 5))
11825334Sjp161948 goto fail_free;
11835334Sjp161948
11845334Sjp161948 switch (i) {
11855334Sjp161948 case 0:
11865334Sjp161948 goto fail_free;
11875334Sjp161948
11885334Sjp161948 case 1:
11895334Sjp161948 fwd->listen_host = NULL;
11905334Sjp161948 fwd->listen_port = a2port(fwdarg[0]);
11915334Sjp161948 break;
11925334Sjp161948
11935334Sjp161948 case 2:
11945334Sjp161948 fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
11955334Sjp161948 fwd->listen_port = a2port(fwdarg[1]);
11965334Sjp161948 break;
11975334Sjp161948
11985334Sjp161948 case 3:
11995334Sjp161948 fwd->listen_host = NULL;
12005334Sjp161948 fwd->listen_port = a2port(fwdarg[0]);
12015334Sjp161948 fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
12025334Sjp161948 fwd->connect_port = a2port(fwdarg[2]);
12035334Sjp161948 break;
12045334Sjp161948
12055334Sjp161948 case 4:
12065334Sjp161948 fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
12075334Sjp161948 fwd->listen_port = a2port(fwdarg[1]);
12085334Sjp161948 fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
12095334Sjp161948 fwd->connect_port = a2port(fwdarg[3]);
12105334Sjp161948 break;
12115334Sjp161948 }
12125334Sjp161948
12135334Sjp161948 if (fwd->listen_port == 0 || (fwd->connect_port == 0 && i > 2))
12145334Sjp161948 goto fail_free;
12155334Sjp161948
1216*9845SJan.Pechanec@Sun.COM xfree(p);
12175334Sjp161948 return (i);
12185334Sjp161948
1219*9845SJan.Pechanec@Sun.COM fail_free:
12205334Sjp161948 if (p != NULL)
12215334Sjp161948 xfree(p);
12225334Sjp161948 if (fwd->connect_host != NULL)
12235334Sjp161948 xfree(fwd->connect_host);
12245334Sjp161948 if (fwd->listen_host != NULL)
12255334Sjp161948 xfree(fwd->listen_host);
12265334Sjp161948 return (0);
12275334Sjp161948 }
12285334Sjp161948
12295334Sjp161948 /*
12305266Sjp161948 * Process previously stored unknown options. When this function is called we
12315266Sjp161948 * already have IgnoreIfUnknown set so finally we can decide whether each
12325266Sjp161948 * unknown option is to be ignored or not.
12335266Sjp161948 */
12345266Sjp161948 void
process_unknown_options(Options * options)12355266Sjp161948 process_unknown_options(Options *options)
12365266Sjp161948 {
12375266Sjp161948 StoredOption *so;
12385266Sjp161948 int m, i, bad_options = 0;
12395266Sjp161948
12405266Sjp161948 /* if there is no unknown option we are done */
12415266Sjp161948 if (options->unknown_opts_num == 0)
12425266Sjp161948 return;
12435266Sjp161948
12445266Sjp161948 /*
12455266Sjp161948 * Now go through the list of unknown options and report any one that
12465266Sjp161948 * is not explicitly listed in IgnoreIfUnknown option. If at least one
12475266Sjp161948 * such as that is found it's a show stopper.
12485266Sjp161948 */
12495266Sjp161948 for (i = 0; i < options->unknown_opts_num; ++i) {
12505266Sjp161948 so = &options->unknown_opts[i];
12515266Sjp161948 if (options->ignore_if_unknown == NULL)
12525266Sjp161948 m = 0;
12535266Sjp161948 else
12545266Sjp161948 m = match_pattern_list(tolowercase(so->keyword),
12555266Sjp161948 options->ignore_if_unknown,
12565266Sjp161948 strlen(options->ignore_if_unknown), 1);
12575266Sjp161948 if (m == 1) {
12585266Sjp161948 debug("%s: line %d: ignoring unknown option: %s",
12595266Sjp161948 so->filename, so->linenum, so->keyword);
12605266Sjp161948 }
12615266Sjp161948 else {
12625266Sjp161948 error("%s: line %d: unknown configuration option: %s",
12635266Sjp161948 so->filename, so->linenum, so->keyword);
12645266Sjp161948 bad_options++;
12655266Sjp161948 }
12665266Sjp161948 xfree(so->keyword);
12675266Sjp161948 xfree(so->filename);
12685266Sjp161948 }
12695266Sjp161948
12705266Sjp161948 /* exit if we found at least one unignored unknown option */
12715266Sjp161948 if (bad_options > 0)
12725266Sjp161948 fatal("terminating, %d bad configuration option(s)",
12735266Sjp161948 bad_options);
12745266Sjp161948 }
1275