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