1*1323ec57SEd Maste /* $OpenBSD: readconf.c,v 1.366 2022/02/08 08:59:12 dtucker Exp $ */ 2511b41d2SMark Murray /* 3511b41d2SMark Murray * Author: Tatu Ylonen <ylo@cs.hut.fi> 4511b41d2SMark Murray * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 5511b41d2SMark Murray * All rights reserved 6511b41d2SMark Murray * Functions for reading the configuration files. 7511b41d2SMark Murray * 8c2d3a559SKris Kennaway * As far as I am concerned, the code I have written for this software 9c2d3a559SKris Kennaway * can be used freely for any purpose. Any derived versions of this 10c2d3a559SKris Kennaway * software must be clearly marked as such, and if the derived work is 11c2d3a559SKris Kennaway * incompatible with the protocol description in the RFC file, it must be 12c2d3a559SKris Kennaway * called by a name other than "ssh" or "Secure Shell". 13511b41d2SMark Murray */ 14511b41d2SMark Murray 15511b41d2SMark Murray #include "includes.h" 16333ee039SDag-Erling Smørgrav __RCSID("$FreeBSD$"); 17511b41d2SMark Murray 18333ee039SDag-Erling Smørgrav #include <sys/types.h> 19333ee039SDag-Erling Smørgrav #include <sys/stat.h> 20333ee039SDag-Erling Smørgrav #include <sys/socket.h> 21f7167e0eSDag-Erling Smørgrav #include <sys/wait.h> 22a0ee8cc6SDag-Erling Smørgrav #include <sys/un.h> 23333ee039SDag-Erling Smørgrav 24333ee039SDag-Erling Smørgrav #include <netinet/in.h> 254a421b63SDag-Erling Smørgrav #include <netinet/in_systm.h> 264a421b63SDag-Erling Smørgrav #include <netinet/ip.h> 27b83788ffSDag-Erling Smørgrav #include <arpa/inet.h> 28333ee039SDag-Erling Smørgrav 29333ee039SDag-Erling Smørgrav #include <ctype.h> 30333ee039SDag-Erling Smørgrav #include <errno.h> 31f7167e0eSDag-Erling Smørgrav #include <fcntl.h> 32bc5531deSDag-Erling Smørgrav #include <limits.h> 33333ee039SDag-Erling Smørgrav #include <netdb.h> 34f7167e0eSDag-Erling Smørgrav #ifdef HAVE_PATHS_H 35f7167e0eSDag-Erling Smørgrav # include <paths.h> 36f7167e0eSDag-Erling Smørgrav #endif 37f7167e0eSDag-Erling Smørgrav #include <pwd.h> 38333ee039SDag-Erling Smørgrav #include <signal.h> 39333ee039SDag-Erling Smørgrav #include <stdio.h> 40333ee039SDag-Erling Smørgrav #include <string.h> 4119261079SEd Maste #include <stdarg.h> 42333ee039SDag-Erling Smørgrav #include <unistd.h> 43076ad2f8SDag-Erling Smørgrav #ifdef USE_SYSTEM_GLOB 44076ad2f8SDag-Erling Smørgrav # include <glob.h> 45076ad2f8SDag-Erling Smørgrav #else 46076ad2f8SDag-Erling Smørgrav # include "openbsd-compat/glob.h" 47076ad2f8SDag-Erling Smørgrav #endif 48e4a9863fSDag-Erling Smørgrav #ifdef HAVE_UTIL_H 49e4a9863fSDag-Erling Smørgrav #include <util.h> 50e4a9863fSDag-Erling Smørgrav #endif 51bc5531deSDag-Erling Smørgrav #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) 52bc5531deSDag-Erling Smørgrav # include <vis.h> 53bc5531deSDag-Erling Smørgrav #endif 54333ee039SDag-Erling Smørgrav 55511b41d2SMark Murray #include "xmalloc.h" 56333ee039SDag-Erling Smørgrav #include "ssh.h" 57190cef3dSDag-Erling Smørgrav #include "ssherr.h" 58e8aafc91SKris Kennaway #include "compat.h" 59ca3176e7SBrian Feldman #include "cipher.h" 60ca3176e7SBrian Feldman #include "pathnames.h" 61ca3176e7SBrian Feldman #include "log.h" 62bc5531deSDag-Erling Smørgrav #include "sshkey.h" 63a0ee8cc6SDag-Erling Smørgrav #include "misc.h" 64ca3176e7SBrian Feldman #include "readconf.h" 65ca3176e7SBrian Feldman #include "match.h" 66ca3176e7SBrian Feldman #include "kex.h" 67ca3176e7SBrian Feldman #include "mac.h" 68f7167e0eSDag-Erling Smørgrav #include "uidswap.h" 69bc5531deSDag-Erling Smørgrav #include "myproposal.h" 70bc5531deSDag-Erling Smørgrav #include "digest.h" 71cce7d346SDag-Erling Smørgrav #include "version.h" 72511b41d2SMark Murray 73511b41d2SMark Murray /* Format of the configuration file: 74511b41d2SMark Murray 75511b41d2SMark Murray # Configuration data is parsed as follows: 76511b41d2SMark Murray # 1. command line options 77511b41d2SMark Murray # 2. user-specific file 78511b41d2SMark Murray # 3. system-wide file 79511b41d2SMark Murray # Any configuration value is only changed the first time it is set. 80511b41d2SMark Murray # Thus, host-specific definitions should be at the beginning of the 81511b41d2SMark Murray # configuration file, and defaults at the end. 82511b41d2SMark Murray 83511b41d2SMark Murray # Host-specific declarations. These may override anything above. A single 84511b41d2SMark Murray # host may match multiple declarations; these are processed in the order 85511b41d2SMark Murray # that they are given in. 86511b41d2SMark Murray 87511b41d2SMark Murray Host *.ngs.fi ngs.fi 8880628bacSDag-Erling Smørgrav User foo 89511b41d2SMark Murray 90511b41d2SMark Murray Host fake.com 9119261079SEd Maste Hostname another.host.name.real.org 92511b41d2SMark Murray User blaah 93511b41d2SMark Murray Port 34289 94511b41d2SMark Murray ForwardX11 no 95511b41d2SMark Murray ForwardAgent no 96511b41d2SMark Murray 97511b41d2SMark Murray Host books.com 98511b41d2SMark Murray RemoteForward 9999 shadows.cs.hut.fi:9999 99d93a896eSDag-Erling Smørgrav Ciphers 3des-cbc 100511b41d2SMark Murray 101511b41d2SMark Murray Host fascist.blob.com 102511b41d2SMark Murray Port 23123 103511b41d2SMark Murray User tylonen 104511b41d2SMark Murray PasswordAuthentication no 105511b41d2SMark Murray 106511b41d2SMark Murray Host puukko.hut.fi 107511b41d2SMark Murray User t35124p 108511b41d2SMark Murray ProxyCommand ssh-proxy %h %p 109511b41d2SMark Murray 110511b41d2SMark Murray Host *.fr 11180628bacSDag-Erling Smørgrav PublicKeyAuthentication no 112511b41d2SMark Murray 113511b41d2SMark Murray Host *.su 114d93a896eSDag-Erling Smørgrav Ciphers aes128-ctr 115511b41d2SMark Murray PasswordAuthentication no 116511b41d2SMark Murray 117b74df5b2SDag-Erling Smørgrav Host vpn.fake.com 118b74df5b2SDag-Erling Smørgrav Tunnel yes 119b74df5b2SDag-Erling Smørgrav TunnelDevice 3 120b74df5b2SDag-Erling Smørgrav 121511b41d2SMark Murray # Defaults for various options 122511b41d2SMark Murray Host * 123511b41d2SMark Murray ForwardAgent no 124ca3176e7SBrian Feldman ForwardX11 no 125511b41d2SMark Murray PasswordAuthentication yes 126511b41d2SMark Murray StrictHostKeyChecking yes 1271ec0d754SDag-Erling Smørgrav TcpKeepAlive no 128511b41d2SMark Murray IdentityFile ~/.ssh/identity 129511b41d2SMark Murray Port 22 130511b41d2SMark Murray EscapeChar ~ 131511b41d2SMark Murray 132511b41d2SMark Murray */ 133511b41d2SMark Murray 134076ad2f8SDag-Erling Smørgrav static int read_config_file_depth(const char *filename, struct passwd *pw, 135076ad2f8SDag-Erling Smørgrav const char *host, const char *original_host, Options *options, 13619261079SEd Maste int flags, int *activep, int *want_final_pass, int depth); 137076ad2f8SDag-Erling Smørgrav static int process_config_line_depth(Options *options, struct passwd *pw, 138076ad2f8SDag-Erling Smørgrav const char *host, const char *original_host, char *line, 13919261079SEd Maste const char *filename, int linenum, int *activep, int flags, 14019261079SEd Maste int *want_final_pass, int depth); 141076ad2f8SDag-Erling Smørgrav 142511b41d2SMark Murray /* Keyword tokens. */ 143511b41d2SMark Murray 144511b41d2SMark Murray typedef enum { 145511b41d2SMark Murray oBadOption, 146eccfee6eSDag-Erling Smørgrav oVersionAddendum, 147076ad2f8SDag-Erling Smørgrav oHost, oMatch, oInclude, 148e2f6069cSDag-Erling Smørgrav oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout, 149e2f6069cSDag-Erling Smørgrav oGatewayPorts, oExitOnForwardFailure, 15019261079SEd Maste oPasswordAuthentication, 15119261079SEd Maste oXAuthLocation, 15219261079SEd Maste oIdentityFile, oHostname, oPort, oRemoteForward, oLocalForward, 15319261079SEd Maste oPermitRemoteOpen, 154076ad2f8SDag-Erling Smørgrav oCertificateFile, oAddKeysToAgent, oIdentityAgent, 15519261079SEd Maste oUser, oEscapeChar, oProxyCommand, 156511b41d2SMark Murray oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, 157511b41d2SMark Murray oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, 15819261079SEd Maste oTCPKeepAlive, oNumberOfPasswordPrompts, 15919261079SEd Maste oLogFacility, oLogLevel, oLogVerbose, oCiphers, oMacs, 160bc5531deSDag-Erling Smørgrav oPubkeyAuthentication, 161ca3176e7SBrian Feldman oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, 162ca3176e7SBrian Feldman oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, 16347dd1d1bSDag-Erling Smørgrav oHostKeyAlgorithms, oBindAddress, oBindInterface, oPKCS11Provider, 1649e2cbe04SDag-Erling Smørgrav oClearAllForwardings, oNoHostAuthenticationForLocalhost, 165cf2b5f3bSDag-Erling Smørgrav oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, 166cf2b5f3bSDag-Erling Smørgrav oAddressFamily, oGssAuthentication, oGssDelegateCreds, 1675962c0e9SDag-Erling Smørgrav oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, 168190cef3dSDag-Erling Smørgrav oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist, 169e2f6069cSDag-Erling Smørgrav oHashKnownHosts, 1704f52dfbbSDag-Erling Smørgrav oTunnel, oTunnelDevice, 1714f52dfbbSDag-Erling Smørgrav oLocalCommand, oPermitLocalCommand, oRemoteCommand, 172acc1a9efSDag-Erling Smørgrav oVisualHostKey, 17319261079SEd Maste oKexAlgorithms, oIPQoS, oRequestTTY, oSessionType, oStdinNull, 17419261079SEd Maste oForkAfterAuthentication, oIgnoreUnknown, oProxyUseFdpass, 175f7167e0eSDag-Erling Smørgrav oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, 176f7167e0eSDag-Erling Smørgrav oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, 177bc5531deSDag-Erling Smørgrav oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys, 17819261079SEd Maste oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms, 17919261079SEd Maste oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump, 18019261079SEd Maste oSecurityKeyProvider, oKnownHostsCommand, 1814f52dfbbSDag-Erling Smørgrav oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported 182511b41d2SMark Murray } OpCodes; 183511b41d2SMark Murray 184511b41d2SMark Murray /* Textual representations of the tokens. */ 185511b41d2SMark Murray 186511b41d2SMark Murray static struct { 187511b41d2SMark Murray const char *name; 188511b41d2SMark Murray OpCodes opcode; 189511b41d2SMark Murray } keywords[] = { 190d93a896eSDag-Erling Smørgrav /* Deprecated options */ 1914f52dfbbSDag-Erling Smørgrav { "protocol", oIgnore }, /* NB. silently ignored */ 1924f52dfbbSDag-Erling Smørgrav { "cipher", oDeprecated }, 193d93a896eSDag-Erling Smørgrav { "fallbacktorsh", oDeprecated }, 194d93a896eSDag-Erling Smørgrav { "globalknownhostsfile2", oDeprecated }, 195d93a896eSDag-Erling Smørgrav { "rhostsauthentication", oDeprecated }, 196d93a896eSDag-Erling Smørgrav { "userknownhostsfile2", oDeprecated }, 197d93a896eSDag-Erling Smørgrav { "useroaming", oDeprecated }, 198d93a896eSDag-Erling Smørgrav { "usersh", oDeprecated }, 199190cef3dSDag-Erling Smørgrav { "useprivilegedport", oDeprecated }, 200d93a896eSDag-Erling Smørgrav 201d93a896eSDag-Erling Smørgrav /* Unsupported options */ 202d93a896eSDag-Erling Smørgrav { "afstokenpassing", oUnsupported }, 203d93a896eSDag-Erling Smørgrav { "kerberosauthentication", oUnsupported }, 204d93a896eSDag-Erling Smørgrav { "kerberostgtpassing", oUnsupported }, 20519261079SEd Maste { "rsaauthentication", oUnsupported }, 20619261079SEd Maste { "rhostsrsaauthentication", oUnsupported }, 20719261079SEd Maste { "compressionlevel", oUnsupported }, 208d93a896eSDag-Erling Smørgrav 209d93a896eSDag-Erling Smørgrav /* Sometimes-unsupported options */ 210d93a896eSDag-Erling Smørgrav #if defined(GSSAPI) 211d93a896eSDag-Erling Smørgrav { "gssapiauthentication", oGssAuthentication }, 212d93a896eSDag-Erling Smørgrav { "gssapidelegatecredentials", oGssDelegateCreds }, 213d93a896eSDag-Erling Smørgrav # else 214d93a896eSDag-Erling Smørgrav { "gssapiauthentication", oUnsupported }, 215d93a896eSDag-Erling Smørgrav { "gssapidelegatecredentials", oUnsupported }, 216d93a896eSDag-Erling Smørgrav #endif 217d93a896eSDag-Erling Smørgrav #ifdef ENABLE_PKCS11 218d93a896eSDag-Erling Smørgrav { "pkcs11provider", oPKCS11Provider }, 21919261079SEd Maste { "smartcarddevice", oPKCS11Provider }, 220d93a896eSDag-Erling Smørgrav # else 221d93a896eSDag-Erling Smørgrav { "smartcarddevice", oUnsupported }, 222d93a896eSDag-Erling Smørgrav { "pkcs11provider", oUnsupported }, 223d93a896eSDag-Erling Smørgrav #endif 224d93a896eSDag-Erling Smørgrav 225511b41d2SMark Murray { "forwardagent", oForwardAgent }, 226511b41d2SMark Murray { "forwardx11", oForwardX11 }, 2271ec0d754SDag-Erling Smørgrav { "forwardx11trusted", oForwardX11Trusted }, 228e2f6069cSDag-Erling Smørgrav { "forwardx11timeout", oForwardX11Timeout }, 229333ee039SDag-Erling Smørgrav { "exitonforwardfailure", oExitOnForwardFailure }, 230c2d3a559SKris Kennaway { "xauthlocation", oXAuthLocation }, 231511b41d2SMark Murray { "gatewayports", oGatewayPorts }, 232511b41d2SMark Murray { "passwordauthentication", oPasswordAuthentication }, 23309958426SBrian Feldman { "kbdinteractiveauthentication", oKbdInteractiveAuthentication }, 23409958426SBrian Feldman { "kbdinteractivedevices", oKbdInteractiveDevices }, 23519261079SEd Maste { "challengeresponseauthentication", oKbdInteractiveAuthentication }, /* alias */ 23619261079SEd Maste { "skeyauthentication", oKbdInteractiveAuthentication }, /* alias */ 23719261079SEd Maste { "tisauthentication", oKbdInteractiveAuthentication }, /* alias */ 238ca3176e7SBrian Feldman { "pubkeyauthentication", oPubkeyAuthentication }, 239ca3176e7SBrian Feldman { "dsaauthentication", oPubkeyAuthentication }, /* alias */ 240ca3176e7SBrian Feldman { "hostbasedauthentication", oHostbasedAuthentication }, 241511b41d2SMark Murray { "identityfile", oIdentityFile }, 242cce7d346SDag-Erling Smørgrav { "identityfile2", oIdentityFile }, /* obsolete */ 2435962c0e9SDag-Erling Smørgrav { "identitiesonly", oIdentitiesOnly }, 244acc1a9efSDag-Erling Smørgrav { "certificatefile", oCertificateFile }, 245acc1a9efSDag-Erling Smørgrav { "addkeystoagent", oAddKeysToAgent }, 246076ad2f8SDag-Erling Smørgrav { "identityagent", oIdentityAgent }, 24719261079SEd Maste { "hostname", oHostname }, 248ca3176e7SBrian Feldman { "hostkeyalias", oHostKeyAlias }, 249511b41d2SMark Murray { "proxycommand", oProxyCommand }, 250511b41d2SMark Murray { "port", oPort }, 251e8aafc91SKris Kennaway { "ciphers", oCiphers }, 252ca3176e7SBrian Feldman { "macs", oMacs }, 253511b41d2SMark Murray { "remoteforward", oRemoteForward }, 254511b41d2SMark Murray { "localforward", oLocalForward }, 25519261079SEd Maste { "permitremoteopen", oPermitRemoteOpen }, 256511b41d2SMark Murray { "user", oUser }, 257511b41d2SMark Murray { "host", oHost }, 258f7167e0eSDag-Erling Smørgrav { "match", oMatch }, 259511b41d2SMark Murray { "escapechar", oEscapeChar }, 260511b41d2SMark Murray { "globalknownhostsfile", oGlobalKnownHostsFile }, 261cce7d346SDag-Erling Smørgrav { "userknownhostsfile", oUserKnownHostsFile }, 262511b41d2SMark Murray { "connectionattempts", oConnectionAttempts }, 263511b41d2SMark Murray { "batchmode", oBatchMode }, 264511b41d2SMark Murray { "checkhostip", oCheckHostIP }, 265511b41d2SMark Murray { "stricthostkeychecking", oStrictHostKeyChecking }, 266511b41d2SMark Murray { "compression", oCompression }, 2671ec0d754SDag-Erling Smørgrav { "tcpkeepalive", oTCPKeepAlive }, 2681ec0d754SDag-Erling Smørgrav { "keepalive", oTCPKeepAlive }, /* obsolete */ 269511b41d2SMark Murray { "numberofpasswordprompts", oNumberOfPasswordPrompts }, 2704f52dfbbSDag-Erling Smørgrav { "syslogfacility", oLogFacility }, 271511b41d2SMark Murray { "loglevel", oLogLevel }, 27219261079SEd Maste { "logverbose", oLogVerbose }, 273ca3176e7SBrian Feldman { "dynamicforward", oDynamicForward }, 274ca3176e7SBrian Feldman { "preferredauthentications", oPreferredAuthentications }, 275ca3176e7SBrian Feldman { "hostkeyalgorithms", oHostKeyAlgorithms }, 2762f513db7SEd Maste { "casignaturealgorithms", oCASignatureAlgorithms }, 277af12a3e7SDag-Erling Smørgrav { "bindaddress", oBindAddress }, 27847dd1d1bSDag-Erling Smørgrav { "bindinterface", oBindInterface }, 279af12a3e7SDag-Erling Smørgrav { "clearallforwardings", oClearAllForwardings }, 280e73e9afaSDag-Erling Smørgrav { "enablesshkeysign", oEnableSSHKeysign }, 281cf2b5f3bSDag-Erling Smørgrav { "verifyhostkeydns", oVerifyHostKeyDNS }, 282af12a3e7SDag-Erling Smørgrav { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost }, 283cf2b5f3bSDag-Erling Smørgrav { "rekeylimit", oRekeyLimit }, 284cf2b5f3bSDag-Erling Smørgrav { "connecttimeout", oConnectTimeout }, 285cf2b5f3bSDag-Erling Smørgrav { "addressfamily", oAddressFamily }, 2861ec0d754SDag-Erling Smørgrav { "serveraliveinterval", oServerAliveInterval }, 2871ec0d754SDag-Erling Smørgrav { "serveralivecountmax", oServerAliveCountMax }, 28821e764dfSDag-Erling Smørgrav { "sendenv", oSendEnv }, 289190cef3dSDag-Erling Smørgrav { "setenv", oSetEnv }, 29021e764dfSDag-Erling Smørgrav { "controlpath", oControlPath }, 29121e764dfSDag-Erling Smørgrav { "controlmaster", oControlMaster }, 292e2f6069cSDag-Erling Smørgrav { "controlpersist", oControlPersist }, 293aa49c926SDag-Erling Smørgrav { "hashknownhosts", oHashKnownHosts }, 294076ad2f8SDag-Erling Smørgrav { "include", oInclude }, 295b74df5b2SDag-Erling Smørgrav { "tunnel", oTunnel }, 296b74df5b2SDag-Erling Smørgrav { "tunneldevice", oTunnelDevice }, 297b74df5b2SDag-Erling Smørgrav { "localcommand", oLocalCommand }, 298b74df5b2SDag-Erling Smørgrav { "permitlocalcommand", oPermitLocalCommand }, 2994f52dfbbSDag-Erling Smørgrav { "remotecommand", oRemoteCommand }, 300d4af9e69SDag-Erling Smørgrav { "visualhostkey", oVisualHostKey }, 3014a421b63SDag-Erling Smørgrav { "kexalgorithms", oKexAlgorithms }, 3024a421b63SDag-Erling Smørgrav { "ipqos", oIPQoS }, 303e146993eSDag-Erling Smørgrav { "requesttty", oRequestTTY }, 30419261079SEd Maste { "sessiontype", oSessionType }, 30519261079SEd Maste { "stdinnull", oStdinNull }, 30619261079SEd Maste { "forkafterauthentication", oForkAfterAuthentication }, 307f7167e0eSDag-Erling Smørgrav { "proxyusefdpass", oProxyUseFdpass }, 308f7167e0eSDag-Erling Smørgrav { "canonicaldomains", oCanonicalDomains }, 309f7167e0eSDag-Erling Smørgrav { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal }, 310f7167e0eSDag-Erling Smørgrav { "canonicalizehostname", oCanonicalizeHostname }, 311f7167e0eSDag-Erling Smørgrav { "canonicalizemaxdots", oCanonicalizeMaxDots }, 312f7167e0eSDag-Erling Smørgrav { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs }, 313a0ee8cc6SDag-Erling Smørgrav { "streamlocalbindmask", oStreamLocalBindMask }, 314a0ee8cc6SDag-Erling Smørgrav { "streamlocalbindunlink", oStreamLocalBindUnlink }, 315bc5531deSDag-Erling Smørgrav { "revokedhostkeys", oRevokedHostKeys }, 316bc5531deSDag-Erling Smørgrav { "fingerprinthash", oFingerprintHash }, 317bc5531deSDag-Erling Smørgrav { "updatehostkeys", oUpdateHostkeys }, 31819261079SEd Maste { "hostbasedacceptedalgorithms", oHostbasedAcceptedAlgorithms }, 31919261079SEd Maste { "hostbasedkeytypes", oHostbasedAcceptedAlgorithms }, /* obsolete */ 32019261079SEd Maste { "pubkeyacceptedalgorithms", oPubkeyAcceptedAlgorithms }, 32119261079SEd Maste { "pubkeyacceptedkeytypes", oPubkeyAcceptedAlgorithms }, /* obsolete */ 322e4a9863fSDag-Erling Smørgrav { "ignoreunknown", oIgnoreUnknown }, 323076ad2f8SDag-Erling Smørgrav { "proxyjump", oProxyJump }, 32419261079SEd Maste { "securitykeyprovider", oSecurityKeyProvider }, 32519261079SEd Maste { "knownhostscommand", oKnownHostsCommand }, 326076ad2f8SDag-Erling Smørgrav 3279860d96eSDag-Erling Smørgrav { "hpndisabled", oDeprecated }, 3289860d96eSDag-Erling Smørgrav { "hpnbuffersize", oDeprecated }, 3299860d96eSDag-Erling Smørgrav { "tcprcvbufpoll", oDeprecated }, 3309860d96eSDag-Erling Smørgrav { "tcprcvbuf", oDeprecated }, 33163620802SDag-Erling Smørgrav { "noneenabled", oUnsupported }, 33263620802SDag-Erling Smørgrav { "noneswitch", oUnsupported }, 333975616f0SDag-Erling Smørgrav { "versionaddendum", oVersionAddendum }, 33435762f59SEd Schouten 335af12a3e7SDag-Erling Smørgrav { NULL, oBadOption } 336511b41d2SMark Murray }; 337511b41d2SMark Murray 33819261079SEd Maste static const char *lookup_opcode_name(OpCodes code); 33919261079SEd Maste 34019261079SEd Maste const char * 34119261079SEd Maste kex_default_pk_alg(void) 34219261079SEd Maste { 34319261079SEd Maste static char *pkalgs; 34419261079SEd Maste 34519261079SEd Maste if (pkalgs == NULL) { 34619261079SEd Maste char *all_key; 34719261079SEd Maste 34819261079SEd Maste all_key = sshkey_alg_list(0, 0, 1, ','); 34919261079SEd Maste pkalgs = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key); 35019261079SEd Maste free(all_key); 35119261079SEd Maste } 35219261079SEd Maste return pkalgs; 35319261079SEd Maste } 35419261079SEd Maste 35519261079SEd Maste char * 35619261079SEd Maste ssh_connection_hash(const char *thishost, const char *host, const char *portstr, 35719261079SEd Maste const char *user) 35819261079SEd Maste { 35919261079SEd Maste struct ssh_digest_ctx *md; 36019261079SEd Maste u_char conn_hash[SSH_DIGEST_MAX_LENGTH]; 36119261079SEd Maste 36219261079SEd Maste if ((md = ssh_digest_start(SSH_DIGEST_SHA1)) == NULL || 36319261079SEd Maste ssh_digest_update(md, thishost, strlen(thishost)) < 0 || 36419261079SEd Maste ssh_digest_update(md, host, strlen(host)) < 0 || 36519261079SEd Maste ssh_digest_update(md, portstr, strlen(portstr)) < 0 || 36619261079SEd Maste ssh_digest_update(md, user, strlen(user)) < 0 || 36719261079SEd Maste ssh_digest_final(md, conn_hash, sizeof(conn_hash)) < 0) 36819261079SEd Maste fatal_f("mux digest failed"); 36919261079SEd Maste ssh_digest_free(md); 37019261079SEd Maste return tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1)); 37119261079SEd Maste } 37219261079SEd Maste 373511b41d2SMark Murray /* 374511b41d2SMark Murray * Adds a local TCP/IP port forward to options. Never returns if there is an 375511b41d2SMark Murray * error. 376511b41d2SMark Murray */ 377511b41d2SMark Murray 378511b41d2SMark Murray void 379a0ee8cc6SDag-Erling Smørgrav add_local_forward(Options *options, const struct Forward *newfwd) 380511b41d2SMark Murray { 381a0ee8cc6SDag-Erling Smørgrav struct Forward *fwd; 3829e14b918SEd Maste int i; 38303f6c5cdSDag-Erling Smørgrav 384076ad2f8SDag-Erling Smørgrav /* Don't add duplicates */ 385076ad2f8SDag-Erling Smørgrav for (i = 0; i < options->num_local_forwards; i++) { 386076ad2f8SDag-Erling Smørgrav if (forward_equals(newfwd, options->local_forwards + i)) 387076ad2f8SDag-Erling Smørgrav return; 388076ad2f8SDag-Erling Smørgrav } 389557f75e5SDag-Erling Smørgrav options->local_forwards = xreallocarray(options->local_forwards, 390e2f6069cSDag-Erling Smørgrav options->num_local_forwards + 1, 391e2f6069cSDag-Erling Smørgrav sizeof(*options->local_forwards)); 392511b41d2SMark Murray fwd = &options->local_forwards[options->num_local_forwards++]; 393aa49c926SDag-Erling Smørgrav 394cce7d346SDag-Erling Smørgrav fwd->listen_host = newfwd->listen_host; 395aa49c926SDag-Erling Smørgrav fwd->listen_port = newfwd->listen_port; 396a0ee8cc6SDag-Erling Smørgrav fwd->listen_path = newfwd->listen_path; 397cce7d346SDag-Erling Smørgrav fwd->connect_host = newfwd->connect_host; 398aa49c926SDag-Erling Smørgrav fwd->connect_port = newfwd->connect_port; 399a0ee8cc6SDag-Erling Smørgrav fwd->connect_path = newfwd->connect_path; 400511b41d2SMark Murray } 401511b41d2SMark Murray 402511b41d2SMark Murray /* 403511b41d2SMark Murray * Adds a remote TCP/IP port forward to options. Never returns if there is 404511b41d2SMark Murray * an error. 405511b41d2SMark Murray */ 406511b41d2SMark Murray 407511b41d2SMark Murray void 408a0ee8cc6SDag-Erling Smørgrav add_remote_forward(Options *options, const struct Forward *newfwd) 409511b41d2SMark Murray { 410a0ee8cc6SDag-Erling Smørgrav struct Forward *fwd; 411076ad2f8SDag-Erling Smørgrav int i; 412e2f6069cSDag-Erling Smørgrav 413076ad2f8SDag-Erling Smørgrav /* Don't add duplicates */ 414076ad2f8SDag-Erling Smørgrav for (i = 0; i < options->num_remote_forwards; i++) { 415076ad2f8SDag-Erling Smørgrav if (forward_equals(newfwd, options->remote_forwards + i)) 416076ad2f8SDag-Erling Smørgrav return; 417076ad2f8SDag-Erling Smørgrav } 418557f75e5SDag-Erling Smørgrav options->remote_forwards = xreallocarray(options->remote_forwards, 419e2f6069cSDag-Erling Smørgrav options->num_remote_forwards + 1, 420e2f6069cSDag-Erling Smørgrav sizeof(*options->remote_forwards)); 421511b41d2SMark Murray fwd = &options->remote_forwards[options->num_remote_forwards++]; 422aa49c926SDag-Erling Smørgrav 423cce7d346SDag-Erling Smørgrav fwd->listen_host = newfwd->listen_host; 424aa49c926SDag-Erling Smørgrav fwd->listen_port = newfwd->listen_port; 425a0ee8cc6SDag-Erling Smørgrav fwd->listen_path = newfwd->listen_path; 426cce7d346SDag-Erling Smørgrav fwd->connect_host = newfwd->connect_host; 427aa49c926SDag-Erling Smørgrav fwd->connect_port = newfwd->connect_port; 428a0ee8cc6SDag-Erling Smørgrav fwd->connect_path = newfwd->connect_path; 429462c32cbSDag-Erling Smørgrav fwd->handle = newfwd->handle; 430e2f6069cSDag-Erling Smørgrav fwd->allocated_port = 0; 431511b41d2SMark Murray } 432511b41d2SMark Murray 433af12a3e7SDag-Erling Smørgrav static void 434af12a3e7SDag-Erling Smørgrav clear_forwardings(Options *options) 435af12a3e7SDag-Erling Smørgrav { 436af12a3e7SDag-Erling Smørgrav int i; 437af12a3e7SDag-Erling Smørgrav 438aa49c926SDag-Erling Smørgrav for (i = 0; i < options->num_local_forwards; i++) { 439e4a9863fSDag-Erling Smørgrav free(options->local_forwards[i].listen_host); 440a0ee8cc6SDag-Erling Smørgrav free(options->local_forwards[i].listen_path); 441e4a9863fSDag-Erling Smørgrav free(options->local_forwards[i].connect_host); 442a0ee8cc6SDag-Erling Smørgrav free(options->local_forwards[i].connect_path); 443aa49c926SDag-Erling Smørgrav } 444e2f6069cSDag-Erling Smørgrav if (options->num_local_forwards > 0) { 445e4a9863fSDag-Erling Smørgrav free(options->local_forwards); 446e2f6069cSDag-Erling Smørgrav options->local_forwards = NULL; 447e2f6069cSDag-Erling Smørgrav } 448af12a3e7SDag-Erling Smørgrav options->num_local_forwards = 0; 449aa49c926SDag-Erling Smørgrav for (i = 0; i < options->num_remote_forwards; i++) { 450e4a9863fSDag-Erling Smørgrav free(options->remote_forwards[i].listen_host); 451a0ee8cc6SDag-Erling Smørgrav free(options->remote_forwards[i].listen_path); 452e4a9863fSDag-Erling Smørgrav free(options->remote_forwards[i].connect_host); 453a0ee8cc6SDag-Erling Smørgrav free(options->remote_forwards[i].connect_path); 454aa49c926SDag-Erling Smørgrav } 455e2f6069cSDag-Erling Smørgrav if (options->num_remote_forwards > 0) { 456e4a9863fSDag-Erling Smørgrav free(options->remote_forwards); 457e2f6069cSDag-Erling Smørgrav options->remote_forwards = NULL; 458e2f6069cSDag-Erling Smørgrav } 459af12a3e7SDag-Erling Smørgrav options->num_remote_forwards = 0; 460b74df5b2SDag-Erling Smørgrav options->tun_open = SSH_TUNMODE_NO; 461af12a3e7SDag-Erling Smørgrav } 462af12a3e7SDag-Erling Smørgrav 463fa67e83cSDag-Erling Smørgrav void 464acc1a9efSDag-Erling Smørgrav add_certificate_file(Options *options, const char *path, int userprovided) 465acc1a9efSDag-Erling Smørgrav { 466acc1a9efSDag-Erling Smørgrav int i; 467acc1a9efSDag-Erling Smørgrav 468acc1a9efSDag-Erling Smørgrav if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES) 469acc1a9efSDag-Erling Smørgrav fatal("Too many certificate files specified (max %d)", 470acc1a9efSDag-Erling Smørgrav SSH_MAX_CERTIFICATE_FILES); 471acc1a9efSDag-Erling Smørgrav 472acc1a9efSDag-Erling Smørgrav /* Avoid registering duplicates */ 473acc1a9efSDag-Erling Smørgrav for (i = 0; i < options->num_certificate_files; i++) { 474acc1a9efSDag-Erling Smørgrav if (options->certificate_file_userprovided[i] == userprovided && 475acc1a9efSDag-Erling Smørgrav strcmp(options->certificate_files[i], path) == 0) { 47619261079SEd Maste debug2_f("ignoring duplicate key %s", path); 477acc1a9efSDag-Erling Smørgrav return; 478acc1a9efSDag-Erling Smørgrav } 479acc1a9efSDag-Erling Smørgrav } 480acc1a9efSDag-Erling Smørgrav 481acc1a9efSDag-Erling Smørgrav options->certificate_file_userprovided[options->num_certificate_files] = 482acc1a9efSDag-Erling Smørgrav userprovided; 483acc1a9efSDag-Erling Smørgrav options->certificate_files[options->num_certificate_files++] = 484acc1a9efSDag-Erling Smørgrav xstrdup(path); 485acc1a9efSDag-Erling Smørgrav } 486acc1a9efSDag-Erling Smørgrav 487acc1a9efSDag-Erling Smørgrav void 488fa67e83cSDag-Erling Smørgrav add_identity_file(Options *options, const char *dir, const char *filename, 489fa67e83cSDag-Erling Smørgrav int userprovided) 490fa67e83cSDag-Erling Smørgrav { 491fa67e83cSDag-Erling Smørgrav char *path; 492a0ee8cc6SDag-Erling Smørgrav int i; 493fa67e83cSDag-Erling Smørgrav 494fa67e83cSDag-Erling Smørgrav if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES) 495fa67e83cSDag-Erling Smørgrav fatal("Too many identity files specified (max %d)", 496fa67e83cSDag-Erling Smørgrav SSH_MAX_IDENTITY_FILES); 497fa67e83cSDag-Erling Smørgrav 498fa67e83cSDag-Erling Smørgrav if (dir == NULL) /* no dir, filename is absolute */ 499fa67e83cSDag-Erling Smørgrav path = xstrdup(filename); 5004f52dfbbSDag-Erling Smørgrav else if (xasprintf(&path, "%s%s", dir, filename) >= PATH_MAX) 5014f52dfbbSDag-Erling Smørgrav fatal("Identity file path %s too long", path); 502fa67e83cSDag-Erling Smørgrav 503a0ee8cc6SDag-Erling Smørgrav /* Avoid registering duplicates */ 504a0ee8cc6SDag-Erling Smørgrav for (i = 0; i < options->num_identity_files; i++) { 505a0ee8cc6SDag-Erling Smørgrav if (options->identity_file_userprovided[i] == userprovided && 506a0ee8cc6SDag-Erling Smørgrav strcmp(options->identity_files[i], path) == 0) { 50719261079SEd Maste debug2_f("ignoring duplicate key %s", path); 508a0ee8cc6SDag-Erling Smørgrav free(path); 509a0ee8cc6SDag-Erling Smørgrav return; 510a0ee8cc6SDag-Erling Smørgrav } 511a0ee8cc6SDag-Erling Smørgrav } 512a0ee8cc6SDag-Erling Smørgrav 513fa67e83cSDag-Erling Smørgrav options->identity_file_userprovided[options->num_identity_files] = 514fa67e83cSDag-Erling Smørgrav userprovided; 515fa67e83cSDag-Erling Smørgrav options->identity_files[options->num_identity_files++] = path; 516fa67e83cSDag-Erling Smørgrav } 517fa67e83cSDag-Erling Smørgrav 518f7167e0eSDag-Erling Smørgrav int 519f7167e0eSDag-Erling Smørgrav default_ssh_port(void) 520f7167e0eSDag-Erling Smørgrav { 521f7167e0eSDag-Erling Smørgrav static int port; 522f7167e0eSDag-Erling Smørgrav struct servent *sp; 523f7167e0eSDag-Erling Smørgrav 524f7167e0eSDag-Erling Smørgrav if (port == 0) { 525f7167e0eSDag-Erling Smørgrav sp = getservbyname(SSH_SERVICE_NAME, "tcp"); 526f7167e0eSDag-Erling Smørgrav port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT; 527f7167e0eSDag-Erling Smørgrav } 528f7167e0eSDag-Erling Smørgrav return port; 529f7167e0eSDag-Erling Smørgrav } 530f7167e0eSDag-Erling Smørgrav 531f7167e0eSDag-Erling Smørgrav /* 532f7167e0eSDag-Erling Smørgrav * Execute a command in a shell. 533f7167e0eSDag-Erling Smørgrav * Return its exit status or -1 on abnormal exit. 534f7167e0eSDag-Erling Smørgrav */ 535f7167e0eSDag-Erling Smørgrav static int 536f7167e0eSDag-Erling Smørgrav execute_in_shell(const char *cmd) 537f7167e0eSDag-Erling Smørgrav { 538acc1a9efSDag-Erling Smørgrav char *shell; 539f7167e0eSDag-Erling Smørgrav pid_t pid; 54019261079SEd Maste int status; 541f7167e0eSDag-Erling Smørgrav 542f7167e0eSDag-Erling Smørgrav if ((shell = getenv("SHELL")) == NULL) 543f7167e0eSDag-Erling Smørgrav shell = _PATH_BSHELL; 544f7167e0eSDag-Erling Smørgrav 54519261079SEd Maste if (access(shell, X_OK) == -1) { 54619261079SEd Maste fatal("Shell \"%s\" is not executable: %s", 54719261079SEd Maste shell, strerror(errno)); 54819261079SEd Maste } 549f7167e0eSDag-Erling Smørgrav 550f7167e0eSDag-Erling Smørgrav debug("Executing command: '%.500s'", cmd); 551f7167e0eSDag-Erling Smørgrav 552f7167e0eSDag-Erling Smørgrav /* Fork and execute the command. */ 553f7167e0eSDag-Erling Smørgrav if ((pid = fork()) == 0) { 554f7167e0eSDag-Erling Smørgrav char *argv[4]; 555f7167e0eSDag-Erling Smørgrav 55619261079SEd Maste if (stdfd_devnull(1, 1, 0) == -1) 55719261079SEd Maste fatal_f("stdfd_devnull failed"); 558f7167e0eSDag-Erling Smørgrav closefrom(STDERR_FILENO + 1); 559f7167e0eSDag-Erling Smørgrav 560f7167e0eSDag-Erling Smørgrav argv[0] = shell; 561f7167e0eSDag-Erling Smørgrav argv[1] = "-c"; 562acc1a9efSDag-Erling Smørgrav argv[2] = xstrdup(cmd); 563f7167e0eSDag-Erling Smørgrav argv[3] = NULL; 564f7167e0eSDag-Erling Smørgrav 565f7167e0eSDag-Erling Smørgrav execv(argv[0], argv); 566f7167e0eSDag-Erling Smørgrav error("Unable to execute '%.100s': %s", cmd, strerror(errno)); 567f7167e0eSDag-Erling Smørgrav /* Die with signal to make this error apparent to parent. */ 56819261079SEd Maste ssh_signal(SIGTERM, SIG_DFL); 569f7167e0eSDag-Erling Smørgrav kill(getpid(), SIGTERM); 570f7167e0eSDag-Erling Smørgrav _exit(1); 571f7167e0eSDag-Erling Smørgrav } 572f7167e0eSDag-Erling Smørgrav /* Parent. */ 57319261079SEd Maste if (pid == -1) 57419261079SEd Maste fatal_f("fork: %.100s", strerror(errno)); 575f7167e0eSDag-Erling Smørgrav 576f7167e0eSDag-Erling Smørgrav while (waitpid(pid, &status, 0) == -1) { 577f7167e0eSDag-Erling Smørgrav if (errno != EINTR && errno != EAGAIN) 57819261079SEd Maste fatal_f("waitpid: %s", strerror(errno)); 579f7167e0eSDag-Erling Smørgrav } 580f7167e0eSDag-Erling Smørgrav if (!WIFEXITED(status)) { 581f7167e0eSDag-Erling Smørgrav error("command '%.100s' exited abnormally", cmd); 582f7167e0eSDag-Erling Smørgrav return -1; 583f7167e0eSDag-Erling Smørgrav } 584f7167e0eSDag-Erling Smørgrav debug3("command returned status %d", WEXITSTATUS(status)); 585f7167e0eSDag-Erling Smørgrav return WEXITSTATUS(status); 586f7167e0eSDag-Erling Smørgrav } 587f7167e0eSDag-Erling Smørgrav 588f7167e0eSDag-Erling Smørgrav /* 589f7167e0eSDag-Erling Smørgrav * Parse and execute a Match directive. 590f7167e0eSDag-Erling Smørgrav */ 591f7167e0eSDag-Erling Smørgrav static int 592f7167e0eSDag-Erling Smørgrav match_cfg_line(Options *options, char **condition, struct passwd *pw, 59319261079SEd Maste const char *host_arg, const char *original_host, int final_pass, 59419261079SEd Maste int *want_final_pass, const char *filename, int linenum) 595f7167e0eSDag-Erling Smørgrav { 596bc5531deSDag-Erling Smørgrav char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria; 597f7167e0eSDag-Erling Smørgrav const char *ruser; 598bc5531deSDag-Erling Smørgrav int r, port, this_result, result = 1, attributes = 0, negate; 599f7167e0eSDag-Erling Smørgrav char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; 600190cef3dSDag-Erling Smørgrav char uidstr[32]; 601f7167e0eSDag-Erling Smørgrav 602f7167e0eSDag-Erling Smørgrav /* 603f7167e0eSDag-Erling Smørgrav * Configuration is likely to be incomplete at this point so we 604f7167e0eSDag-Erling Smørgrav * must be prepared to use default values. 605f7167e0eSDag-Erling Smørgrav */ 606f7167e0eSDag-Erling Smørgrav port = options->port <= 0 ? default_ssh_port() : options->port; 607f7167e0eSDag-Erling Smørgrav ruser = options->user == NULL ? pw->pw_name : options->user; 60819261079SEd Maste if (final_pass) { 609acc1a9efSDag-Erling Smørgrav host = xstrdup(options->hostname); 610acc1a9efSDag-Erling Smørgrav } else if (options->hostname != NULL) { 611f7167e0eSDag-Erling Smørgrav /* NB. Please keep in sync with ssh.c:main() */ 612f7167e0eSDag-Erling Smørgrav host = percent_expand(options->hostname, 613f7167e0eSDag-Erling Smørgrav "h", host_arg, (char *)NULL); 614acc1a9efSDag-Erling Smørgrav } else { 615f7167e0eSDag-Erling Smørgrav host = xstrdup(host_arg); 616acc1a9efSDag-Erling Smørgrav } 617f7167e0eSDag-Erling Smørgrav 618bc5531deSDag-Erling Smørgrav debug2("checking match for '%s' host %s originally %s", 619bc5531deSDag-Erling Smørgrav cp, host, original_host); 620bc5531deSDag-Erling Smørgrav while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') { 62119261079SEd Maste /* Terminate on comment */ 62219261079SEd Maste if (*attrib == '#') { 62319261079SEd Maste cp = NULL; /* mark all arguments consumed */ 62419261079SEd Maste break; 62519261079SEd Maste } 62619261079SEd Maste arg = criteria = NULL; 627bc5531deSDag-Erling Smørgrav this_result = 1; 628bc5531deSDag-Erling Smørgrav if ((negate = attrib[0] == '!')) 629bc5531deSDag-Erling Smørgrav attrib++; 63019261079SEd Maste /* Criterion "all" has no argument and must appear alone */ 631f7167e0eSDag-Erling Smørgrav if (strcasecmp(attrib, "all") == 0) { 63219261079SEd Maste if (attributes > 1 || ((arg = strdelim(&cp)) != NULL && 63319261079SEd Maste *arg != '\0' && *arg != '#')) { 634bc5531deSDag-Erling Smørgrav error("%.200s line %d: '%s' cannot be combined " 635bc5531deSDag-Erling Smørgrav "with other Match attributes", 636bc5531deSDag-Erling Smørgrav filename, linenum, oattrib); 637f7167e0eSDag-Erling Smørgrav result = -1; 638f7167e0eSDag-Erling Smørgrav goto out; 639f7167e0eSDag-Erling Smørgrav } 64019261079SEd Maste if (arg != NULL && *arg == '#') 64119261079SEd Maste cp = NULL; /* mark all arguments consumed */ 642bc5531deSDag-Erling Smørgrav if (result) 643bc5531deSDag-Erling Smørgrav result = negate ? 0 : 1; 644f7167e0eSDag-Erling Smørgrav goto out; 645f7167e0eSDag-Erling Smørgrav } 646bc5531deSDag-Erling Smørgrav attributes++; 64719261079SEd Maste /* criteria "final" and "canonical" have no argument */ 64819261079SEd Maste if (strcasecmp(attrib, "canonical") == 0 || 64919261079SEd Maste strcasecmp(attrib, "final") == 0) { 65019261079SEd Maste /* 65119261079SEd Maste * If the config requests "Match final" then remember 65219261079SEd Maste * this so we can perform a second pass later. 65319261079SEd Maste */ 65419261079SEd Maste if (strcasecmp(attrib, "final") == 0 && 65519261079SEd Maste want_final_pass != NULL) 65619261079SEd Maste *want_final_pass = 1; 65719261079SEd Maste r = !!final_pass; /* force bitmask member to boolean */ 658bc5531deSDag-Erling Smørgrav if (r == (negate ? 1 : 0)) 659bc5531deSDag-Erling Smørgrav this_result = result = 0; 660bc5531deSDag-Erling Smørgrav debug3("%.200s line %d: %smatched '%s'", 661bc5531deSDag-Erling Smørgrav filename, linenum, 662bc5531deSDag-Erling Smørgrav this_result ? "" : "not ", oattrib); 663bc5531deSDag-Erling Smørgrav continue; 664bc5531deSDag-Erling Smørgrav } 665bc5531deSDag-Erling Smørgrav /* All other criteria require an argument */ 66619261079SEd Maste if ((arg = strdelim(&cp)) == NULL || 66719261079SEd Maste *arg == '\0' || *arg == '#') { 668f7167e0eSDag-Erling Smørgrav error("Missing Match criteria for %s", attrib); 669f7167e0eSDag-Erling Smørgrav result = -1; 670f7167e0eSDag-Erling Smørgrav goto out; 671f7167e0eSDag-Erling Smørgrav } 672f7167e0eSDag-Erling Smørgrav if (strcasecmp(attrib, "host") == 0) { 673bc5531deSDag-Erling Smørgrav criteria = xstrdup(host); 674557f75e5SDag-Erling Smørgrav r = match_hostname(host, arg) == 1; 675bc5531deSDag-Erling Smørgrav if (r == (negate ? 1 : 0)) 676bc5531deSDag-Erling Smørgrav this_result = result = 0; 677f7167e0eSDag-Erling Smørgrav } else if (strcasecmp(attrib, "originalhost") == 0) { 678bc5531deSDag-Erling Smørgrav criteria = xstrdup(original_host); 679557f75e5SDag-Erling Smørgrav r = match_hostname(original_host, arg) == 1; 680bc5531deSDag-Erling Smørgrav if (r == (negate ? 1 : 0)) 681bc5531deSDag-Erling Smørgrav this_result = result = 0; 682f7167e0eSDag-Erling Smørgrav } else if (strcasecmp(attrib, "user") == 0) { 683bc5531deSDag-Erling Smørgrav criteria = xstrdup(ruser); 684557f75e5SDag-Erling Smørgrav r = match_pattern_list(ruser, arg, 0) == 1; 685bc5531deSDag-Erling Smørgrav if (r == (negate ? 1 : 0)) 686bc5531deSDag-Erling Smørgrav this_result = result = 0; 687f7167e0eSDag-Erling Smørgrav } else if (strcasecmp(attrib, "localuser") == 0) { 688bc5531deSDag-Erling Smørgrav criteria = xstrdup(pw->pw_name); 689557f75e5SDag-Erling Smørgrav r = match_pattern_list(pw->pw_name, arg, 0) == 1; 690bc5531deSDag-Erling Smørgrav if (r == (negate ? 1 : 0)) 691bc5531deSDag-Erling Smørgrav this_result = result = 0; 692f7167e0eSDag-Erling Smørgrav } else if (strcasecmp(attrib, "exec") == 0) { 69319261079SEd Maste char *conn_hash_hex, *keyalias; 69419261079SEd Maste 695f7167e0eSDag-Erling Smørgrav if (gethostname(thishost, sizeof(thishost)) == -1) 696f7167e0eSDag-Erling Smørgrav fatal("gethostname: %s", strerror(errno)); 697f7167e0eSDag-Erling Smørgrav strlcpy(shorthost, thishost, sizeof(shorthost)); 698f7167e0eSDag-Erling Smørgrav shorthost[strcspn(thishost, ".")] = '\0'; 699f7167e0eSDag-Erling Smørgrav snprintf(portstr, sizeof(portstr), "%d", port); 700190cef3dSDag-Erling Smørgrav snprintf(uidstr, sizeof(uidstr), "%llu", 701190cef3dSDag-Erling Smørgrav (unsigned long long)pw->pw_uid); 70219261079SEd Maste conn_hash_hex = ssh_connection_hash(thishost, host, 70319261079SEd Maste portstr, ruser); 70419261079SEd Maste keyalias = options->host_key_alias ? 70519261079SEd Maste options->host_key_alias : host; 706f7167e0eSDag-Erling Smørgrav 707f7167e0eSDag-Erling Smørgrav cmd = percent_expand(arg, 70819261079SEd Maste "C", conn_hash_hex, 709f7167e0eSDag-Erling Smørgrav "L", shorthost, 710f7167e0eSDag-Erling Smørgrav "d", pw->pw_dir, 711f7167e0eSDag-Erling Smørgrav "h", host, 71219261079SEd Maste "k", keyalias, 713f7167e0eSDag-Erling Smørgrav "l", thishost, 714bc5531deSDag-Erling Smørgrav "n", original_host, 715f7167e0eSDag-Erling Smørgrav "p", portstr, 716f7167e0eSDag-Erling Smørgrav "r", ruser, 717f7167e0eSDag-Erling Smørgrav "u", pw->pw_name, 718190cef3dSDag-Erling Smørgrav "i", uidstr, 719f7167e0eSDag-Erling Smørgrav (char *)NULL); 72019261079SEd Maste free(conn_hash_hex); 721b83788ffSDag-Erling Smørgrav if (result != 1) { 722b83788ffSDag-Erling Smørgrav /* skip execution if prior predicate failed */ 723bc5531deSDag-Erling Smørgrav debug3("%.200s line %d: skipped exec " 724bc5531deSDag-Erling Smørgrav "\"%.100s\"", filename, linenum, cmd); 725bc5531deSDag-Erling Smørgrav free(cmd); 726bc5531deSDag-Erling Smørgrav continue; 727bc5531deSDag-Erling Smørgrav } 728f7167e0eSDag-Erling Smørgrav r = execute_in_shell(cmd); 729f7167e0eSDag-Erling Smørgrav if (r == -1) { 730b83788ffSDag-Erling Smørgrav fatal("%.200s line %d: match exec " 731b83788ffSDag-Erling Smørgrav "'%.100s' error", filename, 732b83788ffSDag-Erling Smørgrav linenum, cmd); 733b83788ffSDag-Erling Smørgrav } 734bc5531deSDag-Erling Smørgrav criteria = xstrdup(cmd); 735f7167e0eSDag-Erling Smørgrav free(cmd); 736bc5531deSDag-Erling Smørgrav /* Force exit status to boolean */ 737bc5531deSDag-Erling Smørgrav r = r == 0; 738bc5531deSDag-Erling Smørgrav if (r == (negate ? 1 : 0)) 739bc5531deSDag-Erling Smørgrav this_result = result = 0; 740f7167e0eSDag-Erling Smørgrav } else { 741f7167e0eSDag-Erling Smørgrav error("Unsupported Match attribute %s", attrib); 742f7167e0eSDag-Erling Smørgrav result = -1; 743f7167e0eSDag-Erling Smørgrav goto out; 744f7167e0eSDag-Erling Smørgrav } 745bc5531deSDag-Erling Smørgrav debug3("%.200s line %d: %smatched '%s \"%.100s\"' ", 746bc5531deSDag-Erling Smørgrav filename, linenum, this_result ? "": "not ", 747bc5531deSDag-Erling Smørgrav oattrib, criteria); 748bc5531deSDag-Erling Smørgrav free(criteria); 749f7167e0eSDag-Erling Smørgrav } 750f7167e0eSDag-Erling Smørgrav if (attributes == 0) { 751f7167e0eSDag-Erling Smørgrav error("One or more attributes required for Match"); 752f7167e0eSDag-Erling Smørgrav result = -1; 753f7167e0eSDag-Erling Smørgrav goto out; 754f7167e0eSDag-Erling Smørgrav } 755f7167e0eSDag-Erling Smørgrav out: 756bc5531deSDag-Erling Smørgrav if (result != -1) 757bc5531deSDag-Erling Smørgrav debug2("match %sfound", result ? "" : "not "); 758bc5531deSDag-Erling Smørgrav *condition = cp; 759f7167e0eSDag-Erling Smørgrav free(host); 760f7167e0eSDag-Erling Smørgrav return result; 761f7167e0eSDag-Erling Smørgrav } 762f7167e0eSDag-Erling Smørgrav 763190cef3dSDag-Erling Smørgrav /* Remove environment variable by pattern */ 764190cef3dSDag-Erling Smørgrav static void 765190cef3dSDag-Erling Smørgrav rm_env(Options *options, const char *arg, const char *filename, int linenum) 766190cef3dSDag-Erling Smørgrav { 76719261079SEd Maste int i, j, onum_send_env = options->num_send_env; 768190cef3dSDag-Erling Smørgrav char *cp; 769190cef3dSDag-Erling Smørgrav 770190cef3dSDag-Erling Smørgrav /* Remove an environment variable */ 771190cef3dSDag-Erling Smørgrav for (i = 0; i < options->num_send_env; ) { 772190cef3dSDag-Erling Smørgrav cp = xstrdup(options->send_env[i]); 773190cef3dSDag-Erling Smørgrav if (!match_pattern(cp, arg + 1)) { 774190cef3dSDag-Erling Smørgrav free(cp); 775190cef3dSDag-Erling Smørgrav i++; 776190cef3dSDag-Erling Smørgrav continue; 777190cef3dSDag-Erling Smørgrav } 778190cef3dSDag-Erling Smørgrav debug3("%s line %d: removing environment %s", 779190cef3dSDag-Erling Smørgrav filename, linenum, cp); 780190cef3dSDag-Erling Smørgrav free(cp); 781190cef3dSDag-Erling Smørgrav free(options->send_env[i]); 782190cef3dSDag-Erling Smørgrav options->send_env[i] = NULL; 783190cef3dSDag-Erling Smørgrav for (j = i; j < options->num_send_env - 1; j++) { 784190cef3dSDag-Erling Smørgrav options->send_env[j] = options->send_env[j + 1]; 785190cef3dSDag-Erling Smørgrav options->send_env[j + 1] = NULL; 786190cef3dSDag-Erling Smørgrav } 787190cef3dSDag-Erling Smørgrav options->num_send_env--; 788190cef3dSDag-Erling Smørgrav /* NB. don't increment i */ 789190cef3dSDag-Erling Smørgrav } 79019261079SEd Maste if (onum_send_env != options->num_send_env) { 79119261079SEd Maste options->send_env = xrecallocarray(options->send_env, 79219261079SEd Maste onum_send_env, options->num_send_env, 79319261079SEd Maste sizeof(*options->send_env)); 79419261079SEd Maste } 795190cef3dSDag-Erling Smørgrav } 796190cef3dSDag-Erling Smørgrav 797511b41d2SMark Murray /* 798ca3176e7SBrian Feldman * Returns the number of the token pointed to by cp or oBadOption. 799511b41d2SMark Murray */ 800511b41d2SMark Murray static OpCodes 801e4a9863fSDag-Erling Smørgrav parse_token(const char *cp, const char *filename, int linenum, 802e4a9863fSDag-Erling Smørgrav const char *ignored_unknown) 803511b41d2SMark Murray { 804e4a9863fSDag-Erling Smørgrav int i; 805511b41d2SMark Murray 806511b41d2SMark Murray for (i = 0; keywords[i].name; i++) 807e4a9863fSDag-Erling Smørgrav if (strcmp(cp, keywords[i].name) == 0) 808511b41d2SMark Murray return keywords[i].opcode; 809557f75e5SDag-Erling Smørgrav if (ignored_unknown != NULL && 810557f75e5SDag-Erling Smørgrav match_pattern_list(cp, ignored_unknown, 1) == 1) 811e4a9863fSDag-Erling Smørgrav return oIgnoredUnknownOption; 812ca3176e7SBrian Feldman error("%s: line %d: Bad configuration option: %s", 813511b41d2SMark Murray filename, linenum, cp); 814511b41d2SMark Murray return oBadOption; 815511b41d2SMark Murray } 816511b41d2SMark Murray 817f7167e0eSDag-Erling Smørgrav /* Multistate option parsing */ 818f7167e0eSDag-Erling Smørgrav struct multistate { 819f7167e0eSDag-Erling Smørgrav char *key; 820f7167e0eSDag-Erling Smørgrav int value; 821f7167e0eSDag-Erling Smørgrav }; 822f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_flag[] = { 823f7167e0eSDag-Erling Smørgrav { "true", 1 }, 824f7167e0eSDag-Erling Smørgrav { "false", 0 }, 825f7167e0eSDag-Erling Smørgrav { "yes", 1 }, 826f7167e0eSDag-Erling Smørgrav { "no", 0 }, 827f7167e0eSDag-Erling Smørgrav { NULL, -1 } 828f7167e0eSDag-Erling Smørgrav }; 829f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_yesnoask[] = { 830f7167e0eSDag-Erling Smørgrav { "true", 1 }, 831f7167e0eSDag-Erling Smørgrav { "false", 0 }, 832f7167e0eSDag-Erling Smørgrav { "yes", 1 }, 833f7167e0eSDag-Erling Smørgrav { "no", 0 }, 834f7167e0eSDag-Erling Smørgrav { "ask", 2 }, 835f7167e0eSDag-Erling Smørgrav { NULL, -1 } 836f7167e0eSDag-Erling Smørgrav }; 8374f52dfbbSDag-Erling Smørgrav static const struct multistate multistate_strict_hostkey[] = { 8384f52dfbbSDag-Erling Smørgrav { "true", SSH_STRICT_HOSTKEY_YES }, 8394f52dfbbSDag-Erling Smørgrav { "false", SSH_STRICT_HOSTKEY_OFF }, 8404f52dfbbSDag-Erling Smørgrav { "yes", SSH_STRICT_HOSTKEY_YES }, 8414f52dfbbSDag-Erling Smørgrav { "no", SSH_STRICT_HOSTKEY_OFF }, 8424f52dfbbSDag-Erling Smørgrav { "ask", SSH_STRICT_HOSTKEY_ASK }, 8434f52dfbbSDag-Erling Smørgrav { "off", SSH_STRICT_HOSTKEY_OFF }, 8444f52dfbbSDag-Erling Smørgrav { "accept-new", SSH_STRICT_HOSTKEY_NEW }, 8454f52dfbbSDag-Erling Smørgrav { NULL, -1 } 8464f52dfbbSDag-Erling Smørgrav }; 847acc1a9efSDag-Erling Smørgrav static const struct multistate multistate_yesnoaskconfirm[] = { 848acc1a9efSDag-Erling Smørgrav { "true", 1 }, 849acc1a9efSDag-Erling Smørgrav { "false", 0 }, 850acc1a9efSDag-Erling Smørgrav { "yes", 1 }, 851acc1a9efSDag-Erling Smørgrav { "no", 0 }, 852acc1a9efSDag-Erling Smørgrav { "ask", 2 }, 853acc1a9efSDag-Erling Smørgrav { "confirm", 3 }, 854acc1a9efSDag-Erling Smørgrav { NULL, -1 } 855acc1a9efSDag-Erling Smørgrav }; 856f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_addressfamily[] = { 857f7167e0eSDag-Erling Smørgrav { "inet", AF_INET }, 858f7167e0eSDag-Erling Smørgrav { "inet6", AF_INET6 }, 859f7167e0eSDag-Erling Smørgrav { "any", AF_UNSPEC }, 860f7167e0eSDag-Erling Smørgrav { NULL, -1 } 861f7167e0eSDag-Erling Smørgrav }; 862f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_controlmaster[] = { 863f7167e0eSDag-Erling Smørgrav { "true", SSHCTL_MASTER_YES }, 864f7167e0eSDag-Erling Smørgrav { "yes", SSHCTL_MASTER_YES }, 865f7167e0eSDag-Erling Smørgrav { "false", SSHCTL_MASTER_NO }, 866f7167e0eSDag-Erling Smørgrav { "no", SSHCTL_MASTER_NO }, 867f7167e0eSDag-Erling Smørgrav { "auto", SSHCTL_MASTER_AUTO }, 868f7167e0eSDag-Erling Smørgrav { "ask", SSHCTL_MASTER_ASK }, 869f7167e0eSDag-Erling Smørgrav { "autoask", SSHCTL_MASTER_AUTO_ASK }, 870f7167e0eSDag-Erling Smørgrav { NULL, -1 } 871f7167e0eSDag-Erling Smørgrav }; 872f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_tunnel[] = { 873f7167e0eSDag-Erling Smørgrav { "ethernet", SSH_TUNMODE_ETHERNET }, 874f7167e0eSDag-Erling Smørgrav { "point-to-point", SSH_TUNMODE_POINTOPOINT }, 875f7167e0eSDag-Erling Smørgrav { "true", SSH_TUNMODE_DEFAULT }, 876f7167e0eSDag-Erling Smørgrav { "yes", SSH_TUNMODE_DEFAULT }, 877f7167e0eSDag-Erling Smørgrav { "false", SSH_TUNMODE_NO }, 878f7167e0eSDag-Erling Smørgrav { "no", SSH_TUNMODE_NO }, 879f7167e0eSDag-Erling Smørgrav { NULL, -1 } 880f7167e0eSDag-Erling Smørgrav }; 881f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_requesttty[] = { 882f7167e0eSDag-Erling Smørgrav { "true", REQUEST_TTY_YES }, 883f7167e0eSDag-Erling Smørgrav { "yes", REQUEST_TTY_YES }, 884f7167e0eSDag-Erling Smørgrav { "false", REQUEST_TTY_NO }, 885f7167e0eSDag-Erling Smørgrav { "no", REQUEST_TTY_NO }, 886f7167e0eSDag-Erling Smørgrav { "force", REQUEST_TTY_FORCE }, 887f7167e0eSDag-Erling Smørgrav { "auto", REQUEST_TTY_AUTO }, 888f7167e0eSDag-Erling Smørgrav { NULL, -1 } 889f7167e0eSDag-Erling Smørgrav }; 89019261079SEd Maste static const struct multistate multistate_sessiontype[] = { 89119261079SEd Maste { "none", SESSION_TYPE_NONE }, 89219261079SEd Maste { "subsystem", SESSION_TYPE_SUBSYSTEM }, 89319261079SEd Maste { "default", SESSION_TYPE_DEFAULT }, 89419261079SEd Maste { NULL, -1 } 89519261079SEd Maste }; 896f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_canonicalizehostname[] = { 897f7167e0eSDag-Erling Smørgrav { "true", SSH_CANONICALISE_YES }, 898f7167e0eSDag-Erling Smørgrav { "false", SSH_CANONICALISE_NO }, 899f7167e0eSDag-Erling Smørgrav { "yes", SSH_CANONICALISE_YES }, 900f7167e0eSDag-Erling Smørgrav { "no", SSH_CANONICALISE_NO }, 901f7167e0eSDag-Erling Smørgrav { "always", SSH_CANONICALISE_ALWAYS }, 902f7167e0eSDag-Erling Smørgrav { NULL, -1 } 903f7167e0eSDag-Erling Smørgrav }; 904*1323ec57SEd Maste static const struct multistate multistate_pubkey_auth[] = { 905*1323ec57SEd Maste { "true", SSH_PUBKEY_AUTH_ALL }, 906*1323ec57SEd Maste { "false", SSH_PUBKEY_AUTH_NO }, 907*1323ec57SEd Maste { "yes", SSH_PUBKEY_AUTH_ALL }, 908*1323ec57SEd Maste { "no", SSH_PUBKEY_AUTH_NO }, 909*1323ec57SEd Maste { "unbound", SSH_PUBKEY_AUTH_UNBOUND }, 910*1323ec57SEd Maste { "host-bound", SSH_PUBKEY_AUTH_HBOUND }, 911*1323ec57SEd Maste { NULL, -1 } 912*1323ec57SEd Maste }; 91319261079SEd Maste static const struct multistate multistate_compression[] = { 91419261079SEd Maste #ifdef WITH_ZLIB 91519261079SEd Maste { "yes", COMP_ZLIB }, 91619261079SEd Maste #endif 91719261079SEd Maste { "no", COMP_NONE }, 91819261079SEd Maste { NULL, -1 } 91919261079SEd Maste }; 92019261079SEd Maste 92119261079SEd Maste static int 92219261079SEd Maste parse_multistate_value(const char *arg, const char *filename, int linenum, 92319261079SEd Maste const struct multistate *multistate_ptr) 92419261079SEd Maste { 92519261079SEd Maste int i; 92619261079SEd Maste 92719261079SEd Maste if (!arg || *arg == '\0') { 92819261079SEd Maste error("%s line %d: missing argument.", filename, linenum); 92919261079SEd Maste return -1; 93019261079SEd Maste } 93119261079SEd Maste for (i = 0; multistate_ptr[i].key != NULL; i++) { 93219261079SEd Maste if (strcasecmp(arg, multistate_ptr[i].key) == 0) 93319261079SEd Maste return multistate_ptr[i].value; 93419261079SEd Maste } 93519261079SEd Maste return -1; 93619261079SEd Maste } 937f7167e0eSDag-Erling Smørgrav 938511b41d2SMark Murray /* 939511b41d2SMark Murray * Processes a single option line as used in the configuration files. This 940511b41d2SMark Murray * only sets those values that have not already been set. 941511b41d2SMark Murray */ 942511b41d2SMark Murray int 943f7167e0eSDag-Erling Smørgrav process_config_line(Options *options, struct passwd *pw, const char *host, 944bc5531deSDag-Erling Smørgrav const char *original_host, char *line, const char *filename, 945bc5531deSDag-Erling Smørgrav int linenum, int *activep, int flags) 946511b41d2SMark Murray { 947076ad2f8SDag-Erling Smørgrav return process_config_line_depth(options, pw, host, original_host, 94819261079SEd Maste line, filename, linenum, activep, flags, NULL, 0); 949076ad2f8SDag-Erling Smørgrav } 950076ad2f8SDag-Erling Smørgrav 951076ad2f8SDag-Erling Smørgrav #define WHITESPACE " \t\r\n" 952076ad2f8SDag-Erling Smørgrav static int 953076ad2f8SDag-Erling Smørgrav process_config_line_depth(Options *options, struct passwd *pw, const char *host, 954076ad2f8SDag-Erling Smørgrav const char *original_host, char *line, const char *filename, 95519261079SEd Maste int linenum, int *activep, int flags, int *want_final_pass, int depth) 956076ad2f8SDag-Erling Smørgrav { 957*1323ec57SEd Maste char *str, **charptr, *endofnumber, *keyword, *arg, *arg2, *p; 95819261079SEd Maste char **cpptr, ***cppptr, fwdarg[256]; 95919261079SEd Maste u_int i, *uintptr, uvalue, max_entries = 0; 960076ad2f8SDag-Erling Smørgrav int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0; 9614f52dfbbSDag-Erling Smørgrav int remotefwd, dynamicfwd; 962d4af9e69SDag-Erling Smørgrav LogLevel *log_level_ptr; 9634f52dfbbSDag-Erling Smørgrav SyslogFacility *log_facility_ptr; 964e4a9863fSDag-Erling Smørgrav long long val64; 965e73e9afaSDag-Erling Smørgrav size_t len; 966a0ee8cc6SDag-Erling Smørgrav struct Forward fwd; 967f7167e0eSDag-Erling Smørgrav const struct multistate *multistate_ptr; 968f7167e0eSDag-Erling Smørgrav struct allowed_cname *cname; 969076ad2f8SDag-Erling Smørgrav glob_t gl; 97047dd1d1bSDag-Erling Smørgrav const char *errstr; 97119261079SEd Maste char **oav = NULL, **av; 97219261079SEd Maste int oac = 0, ac; 97319261079SEd Maste int ret = -1; 974f7167e0eSDag-Erling Smørgrav 975f7167e0eSDag-Erling Smørgrav if (activep == NULL) { /* We are processing a command line directive */ 976f7167e0eSDag-Erling Smørgrav cmdline = 1; 977f7167e0eSDag-Erling Smørgrav activep = &cmdline; 978f7167e0eSDag-Erling Smørgrav } 979511b41d2SMark Murray 980d93a896eSDag-Erling Smørgrav /* Strip trailing whitespace. Allow \f (form feed) at EOL only */ 981557f75e5SDag-Erling Smørgrav if ((len = strlen(line)) == 0) 982557f75e5SDag-Erling Smørgrav return 0; 983557f75e5SDag-Erling Smørgrav for (len--; len > 0; len--) { 984d93a896eSDag-Erling Smørgrav if (strchr(WHITESPACE "\f", line[len]) == NULL) 985cf2b5f3bSDag-Erling Smørgrav break; 986cf2b5f3bSDag-Erling Smørgrav line[len] = '\0'; 987cf2b5f3bSDag-Erling Smørgrav } 988cf2b5f3bSDag-Erling Smørgrav 98919261079SEd Maste str = line; 990c2d3a559SKris Kennaway /* Get the keyword. (Each line is supposed to begin with a keyword). */ 99119261079SEd Maste if ((keyword = strdelim(&str)) == NULL) 992333ee039SDag-Erling Smørgrav return 0; 993c2d3a559SKris Kennaway /* Ignore leading whitespace. */ 994c2d3a559SKris Kennaway if (*keyword == '\0') 99519261079SEd Maste keyword = strdelim(&str); 996ca3176e7SBrian Feldman if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#') 997511b41d2SMark Murray return 0; 998e4a9863fSDag-Erling Smørgrav /* Match lowercase keyword */ 999f7167e0eSDag-Erling Smørgrav lowercase(keyword); 1000511b41d2SMark Murray 100119261079SEd Maste /* Prepare to parse remainder of line */ 100219261079SEd Maste if (str != NULL) 100319261079SEd Maste str += strspn(str, WHITESPACE); 100419261079SEd Maste if (str == NULL || *str == '\0') { 100519261079SEd Maste error("%s line %d: no argument after keyword \"%s\"", 100619261079SEd Maste filename, linenum, keyword); 100719261079SEd Maste return -1; 100819261079SEd Maste } 1009e4a9863fSDag-Erling Smørgrav opcode = parse_token(keyword, filename, linenum, 1010e4a9863fSDag-Erling Smørgrav options->ignored_unknown); 101119261079SEd Maste if (argv_split(str, &oac, &oav, 1) != 0) { 101219261079SEd Maste error("%s line %d: invalid quotes", filename, linenum); 101319261079SEd Maste return -1; 101419261079SEd Maste } 101519261079SEd Maste ac = oac; 101619261079SEd Maste av = oav; 1017511b41d2SMark Murray 1018511b41d2SMark Murray switch (opcode) { 1019511b41d2SMark Murray case oBadOption: 1020511b41d2SMark Murray /* don't panic, but count bad options */ 102119261079SEd Maste goto out; 10224f52dfbbSDag-Erling Smørgrav case oIgnore: 102319261079SEd Maste argv_consume(&ac); 102419261079SEd Maste break; 1025e4a9863fSDag-Erling Smørgrav case oIgnoredUnknownOption: 1026e4a9863fSDag-Erling Smørgrav debug("%s line %d: Ignored unknown option \"%s\"", 1027e4a9863fSDag-Erling Smørgrav filename, linenum, keyword); 102819261079SEd Maste argv_consume(&ac); 102919261079SEd Maste break; 1030cf2b5f3bSDag-Erling Smørgrav case oConnectTimeout: 1031cf2b5f3bSDag-Erling Smørgrav intptr = &options->connection_timeout; 10321ec0d754SDag-Erling Smørgrav parse_time: 103319261079SEd Maste arg = argv_next(&ac, &av); 103419261079SEd Maste if (!arg || *arg == '\0') { 103519261079SEd Maste error("%s line %d: missing time value.", 1036cf2b5f3bSDag-Erling Smørgrav filename, linenum); 103719261079SEd Maste goto out; 103819261079SEd Maste } 1039bc5531deSDag-Erling Smørgrav if (strcmp(arg, "none") == 0) 1040bc5531deSDag-Erling Smørgrav value = -1; 104119261079SEd Maste else if ((value = convtime(arg)) == -1) { 104219261079SEd Maste error("%s line %d: invalid time value.", 1043cf2b5f3bSDag-Erling Smørgrav filename, linenum); 104419261079SEd Maste goto out; 104519261079SEd Maste } 1046d4af9e69SDag-Erling Smørgrav if (*activep && *intptr == -1) 1047cf2b5f3bSDag-Erling Smørgrav *intptr = value; 1048cf2b5f3bSDag-Erling Smørgrav break; 1049cf2b5f3bSDag-Erling Smørgrav 1050511b41d2SMark Murray case oForwardAgent: 1051511b41d2SMark Murray intptr = &options->forward_agent; 105219261079SEd Maste 105319261079SEd Maste arg = argv_next(&ac, &av); 105419261079SEd Maste if (!arg || *arg == '\0') { 105519261079SEd Maste error("%s line %d: missing argument.", 1056f7167e0eSDag-Erling Smørgrav filename, linenum); 105719261079SEd Maste goto out; 105819261079SEd Maste } 105919261079SEd Maste 1060f7167e0eSDag-Erling Smørgrav value = -1; 106119261079SEd Maste multistate_ptr = multistate_flag; 1062f7167e0eSDag-Erling Smørgrav for (i = 0; multistate_ptr[i].key != NULL; i++) { 1063f7167e0eSDag-Erling Smørgrav if (strcasecmp(arg, multistate_ptr[i].key) == 0) { 1064f7167e0eSDag-Erling Smørgrav value = multistate_ptr[i].value; 1065f7167e0eSDag-Erling Smørgrav break; 1066f7167e0eSDag-Erling Smørgrav } 1067f7167e0eSDag-Erling Smørgrav } 106819261079SEd Maste if (value != -1) { 1069511b41d2SMark Murray if (*activep && *intptr == -1) 1070511b41d2SMark Murray *intptr = value; 1071511b41d2SMark Murray break; 107219261079SEd Maste } 107319261079SEd Maste /* ForwardAgent wasn't 'yes' or 'no', assume a path */ 107419261079SEd Maste if (*activep && *intptr == -1) 107519261079SEd Maste *intptr = 1; 107619261079SEd Maste 107719261079SEd Maste charptr = &options->forward_agent_sock_path; 107819261079SEd Maste goto parse_agent_path; 1079511b41d2SMark Murray 1080511b41d2SMark Murray case oForwardX11: 1081511b41d2SMark Murray intptr = &options->forward_x11; 108219261079SEd Maste parse_flag: 108319261079SEd Maste multistate_ptr = multistate_flag; 108419261079SEd Maste parse_multistate: 108519261079SEd Maste arg = argv_next(&ac, &av); 108619261079SEd Maste if ((value = parse_multistate_value(arg, filename, linenum, 108719261079SEd Maste multistate_ptr)) == -1) { 108819261079SEd Maste error("%s line %d: unsupported option \"%s\".", 108919261079SEd Maste filename, linenum, arg); 109019261079SEd Maste goto out; 109119261079SEd Maste } 109219261079SEd Maste if (*activep && *intptr == -1) 109319261079SEd Maste *intptr = value; 109419261079SEd Maste break; 1095511b41d2SMark Murray 10961ec0d754SDag-Erling Smørgrav case oForwardX11Trusted: 10971ec0d754SDag-Erling Smørgrav intptr = &options->forward_x11_trusted; 10981ec0d754SDag-Erling Smørgrav goto parse_flag; 10991ec0d754SDag-Erling Smørgrav 1100e2f6069cSDag-Erling Smørgrav case oForwardX11Timeout: 1101e2f6069cSDag-Erling Smørgrav intptr = &options->forward_x11_timeout; 1102e2f6069cSDag-Erling Smørgrav goto parse_time; 1103e2f6069cSDag-Erling Smørgrav 1104511b41d2SMark Murray case oGatewayPorts: 1105a0ee8cc6SDag-Erling Smørgrav intptr = &options->fwd_opts.gateway_ports; 1106511b41d2SMark Murray goto parse_flag; 1107511b41d2SMark Murray 1108333ee039SDag-Erling Smørgrav case oExitOnForwardFailure: 1109333ee039SDag-Erling Smørgrav intptr = &options->exit_on_forward_failure; 1110333ee039SDag-Erling Smørgrav goto parse_flag; 1111333ee039SDag-Erling Smørgrav 1112511b41d2SMark Murray case oPasswordAuthentication: 1113511b41d2SMark Murray intptr = &options->password_authentication; 1114511b41d2SMark Murray goto parse_flag; 1115511b41d2SMark Murray 111609958426SBrian Feldman case oKbdInteractiveAuthentication: 111709958426SBrian Feldman intptr = &options->kbd_interactive_authentication; 111809958426SBrian Feldman goto parse_flag; 111909958426SBrian Feldman 112009958426SBrian Feldman case oKbdInteractiveDevices: 112109958426SBrian Feldman charptr = &options->kbd_interactive_devices; 112209958426SBrian Feldman goto parse_string; 112309958426SBrian Feldman 1124ca3176e7SBrian Feldman case oPubkeyAuthentication: 1125*1323ec57SEd Maste multistate_ptr = multistate_pubkey_auth; 1126ca3176e7SBrian Feldman intptr = &options->pubkey_authentication; 1127*1323ec57SEd Maste goto parse_multistate; 1128e8aafc91SKris Kennaway 1129ca3176e7SBrian Feldman case oHostbasedAuthentication: 1130ca3176e7SBrian Feldman intptr = &options->hostbased_authentication; 1131511b41d2SMark Murray goto parse_flag; 1132511b41d2SMark Murray 1133cf2b5f3bSDag-Erling Smørgrav case oGssAuthentication: 1134cf2b5f3bSDag-Erling Smørgrav intptr = &options->gss_authentication; 1135511b41d2SMark Murray goto parse_flag; 1136cf2b5f3bSDag-Erling Smørgrav 1137cf2b5f3bSDag-Erling Smørgrav case oGssDelegateCreds: 1138cf2b5f3bSDag-Erling Smørgrav intptr = &options->gss_deleg_creds; 1139ca3176e7SBrian Feldman goto parse_flag; 1140cf2b5f3bSDag-Erling Smørgrav 1141511b41d2SMark Murray case oBatchMode: 1142511b41d2SMark Murray intptr = &options->batch_mode; 1143511b41d2SMark Murray goto parse_flag; 1144511b41d2SMark Murray 1145511b41d2SMark Murray case oCheckHostIP: 1146511b41d2SMark Murray intptr = &options->check_host_ip; 1147511b41d2SMark Murray goto parse_flag; 1148511b41d2SMark Murray 1149cf2b5f3bSDag-Erling Smørgrav case oVerifyHostKeyDNS: 1150cf2b5f3bSDag-Erling Smørgrav intptr = &options->verify_host_key_dns; 1151f7167e0eSDag-Erling Smørgrav multistate_ptr = multistate_yesnoask; 1152f7167e0eSDag-Erling Smørgrav goto parse_multistate; 1153cf2b5f3bSDag-Erling Smørgrav 1154511b41d2SMark Murray case oStrictHostKeyChecking: 1155511b41d2SMark Murray intptr = &options->strict_host_key_checking; 11564f52dfbbSDag-Erling Smørgrav multistate_ptr = multistate_strict_hostkey; 1157f7167e0eSDag-Erling Smørgrav goto parse_multistate; 1158511b41d2SMark Murray 1159511b41d2SMark Murray case oCompression: 1160511b41d2SMark Murray intptr = &options->compression; 116119261079SEd Maste multistate_ptr = multistate_compression; 116219261079SEd Maste goto parse_multistate; 1163511b41d2SMark Murray 11641ec0d754SDag-Erling Smørgrav case oTCPKeepAlive: 11651ec0d754SDag-Erling Smørgrav intptr = &options->tcp_keep_alive; 1166511b41d2SMark Murray goto parse_flag; 1167511b41d2SMark Murray 1168af12a3e7SDag-Erling Smørgrav case oNoHostAuthenticationForLocalhost: 1169af12a3e7SDag-Erling Smørgrav intptr = &options->no_host_authentication_for_localhost; 1170af12a3e7SDag-Erling Smørgrav goto parse_flag; 1171af12a3e7SDag-Erling Smørgrav 1172511b41d2SMark Murray case oNumberOfPasswordPrompts: 1173511b41d2SMark Murray intptr = &options->number_of_password_prompts; 1174511b41d2SMark Murray goto parse_int; 1175511b41d2SMark Murray 1176cf2b5f3bSDag-Erling Smørgrav case oRekeyLimit: 117719261079SEd Maste arg = argv_next(&ac, &av); 117819261079SEd Maste if (!arg || *arg == '\0') { 117919261079SEd Maste error("%.200s line %d: Missing argument.", filename, 1180e4a9863fSDag-Erling Smørgrav linenum); 118119261079SEd Maste goto out; 118219261079SEd Maste } 1183e4a9863fSDag-Erling Smørgrav if (strcmp(arg, "default") == 0) { 1184e4a9863fSDag-Erling Smørgrav val64 = 0; 1185e4a9863fSDag-Erling Smørgrav } else { 118619261079SEd Maste if (scan_scaled(arg, &val64) == -1) { 118719261079SEd Maste error("%.200s line %d: Bad number '%s': %s", 1188e4a9863fSDag-Erling Smørgrav filename, linenum, arg, strerror(errno)); 118919261079SEd Maste goto out; 119019261079SEd Maste } 119119261079SEd Maste if (val64 != 0 && val64 < 16) { 119219261079SEd Maste error("%.200s line %d: RekeyLimit too small", 1193333ee039SDag-Erling Smørgrav filename, linenum); 119419261079SEd Maste goto out; 119519261079SEd Maste } 1196e4a9863fSDag-Erling Smørgrav } 1197d4af9e69SDag-Erling Smørgrav if (*activep && options->rekey_limit == -1) 1198acc1a9efSDag-Erling Smørgrav options->rekey_limit = val64; 119919261079SEd Maste if (ac != 0) { /* optional rekey interval present */ 120019261079SEd Maste if (strcmp(av[0], "none") == 0) { 120119261079SEd Maste (void)argv_next(&ac, &av); /* discard */ 1202e4a9863fSDag-Erling Smørgrav break; 1203e4a9863fSDag-Erling Smørgrav } 1204e4a9863fSDag-Erling Smørgrav intptr = &options->rekey_interval; 1205e4a9863fSDag-Erling Smørgrav goto parse_time; 1206e4a9863fSDag-Erling Smørgrav } 1207cf2b5f3bSDag-Erling Smørgrav break; 1208cf2b5f3bSDag-Erling Smørgrav 1209511b41d2SMark Murray case oIdentityFile: 121019261079SEd Maste arg = argv_next(&ac, &av); 121119261079SEd Maste if (!arg || *arg == '\0') { 121219261079SEd Maste error("%.200s line %d: Missing argument.", 121319261079SEd Maste filename, linenum); 121419261079SEd Maste goto out; 121519261079SEd Maste } 1216511b41d2SMark Murray if (*activep) { 1217ca3176e7SBrian Feldman intptr = &options->num_identity_files; 121819261079SEd Maste if (*intptr >= SSH_MAX_IDENTITY_FILES) { 121919261079SEd Maste error("%.200s line %d: Too many identity files " 122019261079SEd Maste "specified (max %d).", filename, linenum, 122119261079SEd Maste SSH_MAX_IDENTITY_FILES); 122219261079SEd Maste goto out; 122319261079SEd Maste } 1224bc5531deSDag-Erling Smørgrav add_identity_file(options, NULL, 1225bc5531deSDag-Erling Smørgrav arg, flags & SSHCONF_USERCONF); 1226511b41d2SMark Murray } 1227511b41d2SMark Murray break; 1228511b41d2SMark Murray 1229acc1a9efSDag-Erling Smørgrav case oCertificateFile: 123019261079SEd Maste arg = argv_next(&ac, &av); 123119261079SEd Maste if (!arg || *arg == '\0') { 123219261079SEd Maste error("%.200s line %d: Missing argument.", 1233acc1a9efSDag-Erling Smørgrav filename, linenum); 123419261079SEd Maste goto out; 123519261079SEd Maste } 1236acc1a9efSDag-Erling Smørgrav if (*activep) { 1237acc1a9efSDag-Erling Smørgrav intptr = &options->num_certificate_files; 1238acc1a9efSDag-Erling Smørgrav if (*intptr >= SSH_MAX_CERTIFICATE_FILES) { 123919261079SEd Maste error("%.200s line %d: Too many certificate " 1240acc1a9efSDag-Erling Smørgrav "files specified (max %d).", 1241acc1a9efSDag-Erling Smørgrav filename, linenum, 1242acc1a9efSDag-Erling Smørgrav SSH_MAX_CERTIFICATE_FILES); 124319261079SEd Maste goto out; 1244acc1a9efSDag-Erling Smørgrav } 1245acc1a9efSDag-Erling Smørgrav add_certificate_file(options, arg, 1246acc1a9efSDag-Erling Smørgrav flags & SSHCONF_USERCONF); 1247acc1a9efSDag-Erling Smørgrav } 1248acc1a9efSDag-Erling Smørgrav break; 1249acc1a9efSDag-Erling Smørgrav 1250c2d3a559SKris Kennaway case oXAuthLocation: 1251c2d3a559SKris Kennaway charptr=&options->xauth_location; 1252c2d3a559SKris Kennaway goto parse_string; 1253c2d3a559SKris Kennaway 1254511b41d2SMark Murray case oUser: 1255511b41d2SMark Murray charptr = &options->user; 1256511b41d2SMark Murray parse_string: 125719261079SEd Maste arg = argv_next(&ac, &av); 125819261079SEd Maste if (!arg || *arg == '\0') { 125919261079SEd Maste error("%.200s line %d: Missing argument.", 1260e146993eSDag-Erling Smørgrav filename, linenum); 126119261079SEd Maste goto out; 126219261079SEd Maste } 1263511b41d2SMark Murray if (*activep && *charptr == NULL) 1264c2d3a559SKris Kennaway *charptr = xstrdup(arg); 1265511b41d2SMark Murray break; 1266511b41d2SMark Murray 1267511b41d2SMark Murray case oGlobalKnownHostsFile: 1268e146993eSDag-Erling Smørgrav cpptr = (char **)&options->system_hostfiles; 1269e146993eSDag-Erling Smørgrav uintptr = &options->num_system_hostfiles; 1270e146993eSDag-Erling Smørgrav max_entries = SSH_MAX_HOSTS_FILES; 1271e146993eSDag-Erling Smørgrav parse_char_array: 127219261079SEd Maste i = 0; 127319261079SEd Maste value = *uintptr == 0; /* was array empty when we started? */ 127419261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) { 127519261079SEd Maste if (*arg == '\0') { 127619261079SEd Maste error("%s line %d: keyword %s empty argument", 127719261079SEd Maste filename, linenum, keyword); 127819261079SEd Maste goto out; 127919261079SEd Maste } 128019261079SEd Maste /* Allow "none" only in first position */ 128119261079SEd Maste if (strcasecmp(arg, "none") == 0) { 128219261079SEd Maste if (i > 0 || ac > 0) { 128319261079SEd Maste error("%s line %d: keyword %s \"none\" " 128419261079SEd Maste "argument must appear alone.", 128519261079SEd Maste filename, linenum, keyword); 128619261079SEd Maste goto out; 128719261079SEd Maste } 128819261079SEd Maste } 128919261079SEd Maste i++; 129019261079SEd Maste if (*activep && value) { 129119261079SEd Maste if ((*uintptr) >= max_entries) { 129219261079SEd Maste error("%s line %d: too many %s " 129319261079SEd Maste "entries.", filename, linenum, 129419261079SEd Maste keyword); 129519261079SEd Maste goto out; 129619261079SEd Maste } 1297e146993eSDag-Erling Smørgrav cpptr[(*uintptr)++] = xstrdup(arg); 1298e146993eSDag-Erling Smørgrav } 1299e146993eSDag-Erling Smørgrav } 130019261079SEd Maste break; 1301511b41d2SMark Murray 1302511b41d2SMark Murray case oUserKnownHostsFile: 1303e146993eSDag-Erling Smørgrav cpptr = (char **)&options->user_hostfiles; 1304e146993eSDag-Erling Smørgrav uintptr = &options->num_user_hostfiles; 1305e146993eSDag-Erling Smørgrav max_entries = SSH_MAX_HOSTS_FILES; 1306e146993eSDag-Erling Smørgrav goto parse_char_array; 1307e8aafc91SKris Kennaway 130819261079SEd Maste case oHostname: 1309511b41d2SMark Murray charptr = &options->hostname; 1310511b41d2SMark Murray goto parse_string; 1311511b41d2SMark Murray 1312ca3176e7SBrian Feldman case oHostKeyAlias: 1313ca3176e7SBrian Feldman charptr = &options->host_key_alias; 1314ca3176e7SBrian Feldman goto parse_string; 1315ca3176e7SBrian Feldman 1316ca3176e7SBrian Feldman case oPreferredAuthentications: 1317ca3176e7SBrian Feldman charptr = &options->preferred_authentications; 1318ca3176e7SBrian Feldman goto parse_string; 1319ca3176e7SBrian Feldman 1320af12a3e7SDag-Erling Smørgrav case oBindAddress: 1321af12a3e7SDag-Erling Smørgrav charptr = &options->bind_address; 1322af12a3e7SDag-Erling Smørgrav goto parse_string; 1323af12a3e7SDag-Erling Smørgrav 132447dd1d1bSDag-Erling Smørgrav case oBindInterface: 132547dd1d1bSDag-Erling Smørgrav charptr = &options->bind_interface; 132647dd1d1bSDag-Erling Smørgrav goto parse_string; 132747dd1d1bSDag-Erling Smørgrav 1328b15c8340SDag-Erling Smørgrav case oPKCS11Provider: 1329b15c8340SDag-Erling Smørgrav charptr = &options->pkcs11_provider; 1330af12a3e7SDag-Erling Smørgrav goto parse_string; 1331af12a3e7SDag-Erling Smørgrav 133219261079SEd Maste case oSecurityKeyProvider: 133319261079SEd Maste charptr = &options->sk_provider; 133419261079SEd Maste goto parse_string; 133519261079SEd Maste 133619261079SEd Maste case oKnownHostsCommand: 133719261079SEd Maste charptr = &options->known_hosts_command; 133819261079SEd Maste goto parse_command; 133919261079SEd Maste 1340511b41d2SMark Murray case oProxyCommand: 1341b74df5b2SDag-Erling Smørgrav charptr = &options->proxy_command; 1342076ad2f8SDag-Erling Smørgrav /* Ignore ProxyCommand if ProxyJump already specified */ 1343076ad2f8SDag-Erling Smørgrav if (options->jump_host != NULL) 1344076ad2f8SDag-Erling Smørgrav charptr = &options->jump_host; /* Skip below */ 1345b74df5b2SDag-Erling Smørgrav parse_command: 134619261079SEd Maste if (str == NULL) { 134719261079SEd Maste error("%.200s line %d: Missing argument.", 134819261079SEd Maste filename, linenum); 134919261079SEd Maste goto out; 135019261079SEd Maste } 135119261079SEd Maste len = strspn(str, WHITESPACE "="); 1352511b41d2SMark Murray if (*activep && *charptr == NULL) 135319261079SEd Maste *charptr = xstrdup(str + len); 135419261079SEd Maste argv_consume(&ac); 135519261079SEd Maste break; 1356511b41d2SMark Murray 1357076ad2f8SDag-Erling Smørgrav case oProxyJump: 135819261079SEd Maste if (str == NULL) { 135919261079SEd Maste error("%.200s line %d: Missing argument.", 1360076ad2f8SDag-Erling Smørgrav filename, linenum); 136119261079SEd Maste goto out; 1362076ad2f8SDag-Erling Smørgrav } 136319261079SEd Maste len = strspn(str, WHITESPACE "="); 136419261079SEd Maste /* XXX use argv? */ 136519261079SEd Maste if (parse_jump(str + len, options, *activep) == -1) { 136619261079SEd Maste error("%.200s line %d: Invalid ProxyJump \"%s\"", 136719261079SEd Maste filename, linenum, str + len); 136819261079SEd Maste goto out; 1369076ad2f8SDag-Erling Smørgrav } 137019261079SEd Maste argv_consume(&ac); 137119261079SEd Maste break; 1372076ad2f8SDag-Erling Smørgrav 1373511b41d2SMark Murray case oPort: 137419261079SEd Maste arg = argv_next(&ac, &av); 137519261079SEd Maste if (!arg || *arg == '\0') { 137619261079SEd Maste error("%.200s line %d: Missing argument.", 13772f513db7SEd Maste filename, linenum); 137819261079SEd Maste goto out; 137919261079SEd Maste } 13802f513db7SEd Maste value = a2port(arg); 138119261079SEd Maste if (value <= 0) { 138219261079SEd Maste error("%.200s line %d: Bad port '%s'.", 13832f513db7SEd Maste filename, linenum, arg); 138419261079SEd Maste goto out; 138519261079SEd Maste } 13862f513db7SEd Maste if (*activep && options->port == -1) 13872f513db7SEd Maste options->port = value; 13882f513db7SEd Maste break; 13892f513db7SEd Maste 13902f513db7SEd Maste case oConnectionAttempts: 13912f513db7SEd Maste intptr = &options->connection_attempts; 1392511b41d2SMark Murray parse_int: 139319261079SEd Maste arg = argv_next(&ac, &av); 139419261079SEd Maste if ((errstr = atoi_err(arg, &value)) != NULL) { 139519261079SEd Maste error("%s line %d: integer value %s.", 139647dd1d1bSDag-Erling Smørgrav filename, linenum, errstr); 139719261079SEd Maste goto out; 139819261079SEd Maste } 1399511b41d2SMark Murray if (*activep && *intptr == -1) 1400511b41d2SMark Murray *intptr = value; 1401511b41d2SMark Murray break; 1402511b41d2SMark Murray 1403e8aafc91SKris Kennaway case oCiphers: 140419261079SEd Maste arg = argv_next(&ac, &av); 140519261079SEd Maste if (!arg || *arg == '\0') { 140619261079SEd Maste error("%.200s line %d: Missing argument.", 140719261079SEd Maste filename, linenum); 140819261079SEd Maste goto out; 140919261079SEd Maste } 141019261079SEd Maste if (*arg != '-' && 141119261079SEd Maste !ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)){ 141219261079SEd Maste error("%.200s line %d: Bad SSH2 cipher spec '%s'.", 1413c2d3a559SKris Kennaway filename, linenum, arg ? arg : "<NONE>"); 141419261079SEd Maste goto out; 141519261079SEd Maste } 1416e8aafc91SKris Kennaway if (*activep && options->ciphers == NULL) 1417c2d3a559SKris Kennaway options->ciphers = xstrdup(arg); 1418e8aafc91SKris Kennaway break; 1419e8aafc91SKris Kennaway 1420ca3176e7SBrian Feldman case oMacs: 142119261079SEd Maste arg = argv_next(&ac, &av); 142219261079SEd Maste if (!arg || *arg == '\0') { 142319261079SEd Maste error("%.200s line %d: Missing argument.", 142419261079SEd Maste filename, linenum); 142519261079SEd Maste goto out; 142619261079SEd Maste } 142719261079SEd Maste if (*arg != '-' && 142819261079SEd Maste !mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)) { 142919261079SEd Maste error("%.200s line %d: Bad SSH2 MAC spec '%s'.", 1430ca3176e7SBrian Feldman filename, linenum, arg ? arg : "<NONE>"); 143119261079SEd Maste goto out; 143219261079SEd Maste } 1433ca3176e7SBrian Feldman if (*activep && options->macs == NULL) 1434ca3176e7SBrian Feldman options->macs = xstrdup(arg); 1435ca3176e7SBrian Feldman break; 1436ca3176e7SBrian Feldman 14374a421b63SDag-Erling Smørgrav case oKexAlgorithms: 143819261079SEd Maste arg = argv_next(&ac, &av); 143919261079SEd Maste if (!arg || *arg == '\0') { 144019261079SEd Maste error("%.200s line %d: Missing argument.", 14414a421b63SDag-Erling Smørgrav filename, linenum); 144219261079SEd Maste goto out; 144319261079SEd Maste } 1444d93a896eSDag-Erling Smørgrav if (*arg != '-' && 144519261079SEd Maste !kex_names_valid(*arg == '+' || *arg == '^' ? 144619261079SEd Maste arg + 1 : arg)) { 144719261079SEd Maste error("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.", 14484a421b63SDag-Erling Smørgrav filename, linenum, arg ? arg : "<NONE>"); 144919261079SEd Maste goto out; 145019261079SEd Maste } 14514a421b63SDag-Erling Smørgrav if (*activep && options->kex_algorithms == NULL) 14524a421b63SDag-Erling Smørgrav options->kex_algorithms = xstrdup(arg); 14534a421b63SDag-Erling Smørgrav break; 14544a421b63SDag-Erling Smørgrav 1455ca3176e7SBrian Feldman case oHostKeyAlgorithms: 1456eccfee6eSDag-Erling Smørgrav charptr = &options->hostkeyalgorithms; 145719261079SEd Maste parse_pubkey_algos: 145819261079SEd Maste arg = argv_next(&ac, &av); 145919261079SEd Maste if (!arg || *arg == '\0') { 146019261079SEd Maste error("%.200s line %d: Missing argument.", 1461eccfee6eSDag-Erling Smørgrav filename, linenum); 146219261079SEd Maste goto out; 146319261079SEd Maste } 1464d93a896eSDag-Erling Smørgrav if (*arg != '-' && 146519261079SEd Maste !sshkey_names_valid2(*arg == '+' || *arg == '^' ? 146619261079SEd Maste arg + 1 : arg, 1)) { 146719261079SEd Maste error("%s line %d: Bad key types '%s'.", 1468ca3176e7SBrian Feldman filename, linenum, arg ? arg : "<NONE>"); 146919261079SEd Maste goto out; 147019261079SEd Maste } 1471eccfee6eSDag-Erling Smørgrav if (*activep && *charptr == NULL) 1472eccfee6eSDag-Erling Smørgrav *charptr = xstrdup(arg); 1473ca3176e7SBrian Feldman break; 1474ca3176e7SBrian Feldman 14752f513db7SEd Maste case oCASignatureAlgorithms: 14762f513db7SEd Maste charptr = &options->ca_sign_algorithms; 147719261079SEd Maste goto parse_pubkey_algos; 14782f513db7SEd Maste 1479511b41d2SMark Murray case oLogLevel: 1480d4af9e69SDag-Erling Smørgrav log_level_ptr = &options->log_level; 148119261079SEd Maste arg = argv_next(&ac, &av); 1482c2d3a559SKris Kennaway value = log_level_number(arg); 148319261079SEd Maste if (value == SYSLOG_LEVEL_NOT_SET) { 148419261079SEd Maste error("%.200s line %d: unsupported log level '%s'", 1485c2d3a559SKris Kennaway filename, linenum, arg ? arg : "<NONE>"); 148619261079SEd Maste goto out; 148719261079SEd Maste } 1488d4af9e69SDag-Erling Smørgrav if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET) 1489d4af9e69SDag-Erling Smørgrav *log_level_ptr = (LogLevel) value; 1490511b41d2SMark Murray break; 1491511b41d2SMark Murray 14924f52dfbbSDag-Erling Smørgrav case oLogFacility: 14934f52dfbbSDag-Erling Smørgrav log_facility_ptr = &options->log_facility; 149419261079SEd Maste arg = argv_next(&ac, &av); 14954f52dfbbSDag-Erling Smørgrav value = log_facility_number(arg); 149619261079SEd Maste if (value == SYSLOG_FACILITY_NOT_SET) { 149719261079SEd Maste error("%.200s line %d: unsupported log facility '%s'", 14984f52dfbbSDag-Erling Smørgrav filename, linenum, arg ? arg : "<NONE>"); 149919261079SEd Maste goto out; 150019261079SEd Maste } 15014f52dfbbSDag-Erling Smørgrav if (*log_facility_ptr == -1) 15024f52dfbbSDag-Erling Smørgrav *log_facility_ptr = (SyslogFacility) value; 15034f52dfbbSDag-Erling Smørgrav break; 15044f52dfbbSDag-Erling Smørgrav 150519261079SEd Maste case oLogVerbose: 150619261079SEd Maste cppptr = &options->log_verbose; 150719261079SEd Maste uintptr = &options->num_log_verbose; 150819261079SEd Maste i = 0; 150919261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) { 151019261079SEd Maste if (*arg == '\0') { 151119261079SEd Maste error("%s line %d: keyword %s empty argument", 151219261079SEd Maste filename, linenum, keyword); 151319261079SEd Maste goto out; 151419261079SEd Maste } 151519261079SEd Maste /* Allow "none" only in first position */ 151619261079SEd Maste if (strcasecmp(arg, "none") == 0) { 151719261079SEd Maste if (i > 0 || ac > 0) { 151819261079SEd Maste error("%s line %d: keyword %s \"none\" " 151919261079SEd Maste "argument must appear alone.", 152019261079SEd Maste filename, linenum, keyword); 152119261079SEd Maste goto out; 152219261079SEd Maste } 152319261079SEd Maste } 152419261079SEd Maste i++; 152519261079SEd Maste if (*activep && *uintptr == 0) { 152619261079SEd Maste *cppptr = xrecallocarray(*cppptr, *uintptr, 152719261079SEd Maste *uintptr + 1, sizeof(**cppptr)); 152819261079SEd Maste (*cppptr)[(*uintptr)++] = xstrdup(arg); 152919261079SEd Maste } 153019261079SEd Maste } 153119261079SEd Maste break; 153219261079SEd Maste 1533af12a3e7SDag-Erling Smørgrav case oLocalForward: 1534511b41d2SMark Murray case oRemoteForward: 1535cce7d346SDag-Erling Smørgrav case oDynamicForward: 153619261079SEd Maste arg = argv_next(&ac, &av); 153719261079SEd Maste if (!arg || *arg == '\0') { 153819261079SEd Maste error("%.200s line %d: Missing argument.", 1539af12a3e7SDag-Erling Smørgrav filename, linenum); 154019261079SEd Maste goto out; 154119261079SEd Maste } 1542cce7d346SDag-Erling Smørgrav 15434f52dfbbSDag-Erling Smørgrav remotefwd = (opcode == oRemoteForward); 15444f52dfbbSDag-Erling Smørgrav dynamicfwd = (opcode == oDynamicForward); 15454f52dfbbSDag-Erling Smørgrav 15464f52dfbbSDag-Erling Smørgrav if (!dynamicfwd) { 154719261079SEd Maste arg2 = argv_next(&ac, &av); 15484f52dfbbSDag-Erling Smørgrav if (arg2 == NULL || *arg2 == '\0') { 15494f52dfbbSDag-Erling Smørgrav if (remotefwd) 15504f52dfbbSDag-Erling Smørgrav dynamicfwd = 1; 155119261079SEd Maste else { 155219261079SEd Maste error("%.200s line %d: Missing target " 15534f52dfbbSDag-Erling Smørgrav "argument.", filename, linenum); 155419261079SEd Maste goto out; 155519261079SEd Maste } 15564f52dfbbSDag-Erling Smørgrav } else { 1557aa49c926SDag-Erling Smørgrav /* construct a string for parse_forward */ 15584f52dfbbSDag-Erling Smørgrav snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, 15594f52dfbbSDag-Erling Smørgrav arg2); 1560cce7d346SDag-Erling Smørgrav } 15614f52dfbbSDag-Erling Smørgrav } 15624f52dfbbSDag-Erling Smørgrav if (dynamicfwd) 15634f52dfbbSDag-Erling Smørgrav strlcpy(fwdarg, arg, sizeof(fwdarg)); 1564aa49c926SDag-Erling Smørgrav 156519261079SEd Maste if (parse_forward(&fwd, fwdarg, dynamicfwd, remotefwd) == 0) { 156619261079SEd Maste error("%.200s line %d: Bad forwarding specification.", 1567511b41d2SMark Murray filename, linenum); 156819261079SEd Maste goto out; 156919261079SEd Maste } 1570aa49c926SDag-Erling Smørgrav 1571af12a3e7SDag-Erling Smørgrav if (*activep) { 15724f52dfbbSDag-Erling Smørgrav if (remotefwd) { 1573aa49c926SDag-Erling Smørgrav add_remote_forward(options, &fwd); 15744f52dfbbSDag-Erling Smørgrav } else { 15754f52dfbbSDag-Erling Smørgrav add_local_forward(options, &fwd); 15764f52dfbbSDag-Erling Smørgrav } 1577af12a3e7SDag-Erling Smørgrav } 1578511b41d2SMark Murray break; 1579511b41d2SMark Murray 158019261079SEd Maste case oPermitRemoteOpen: 158119261079SEd Maste uintptr = &options->num_permitted_remote_opens; 158219261079SEd Maste cppptr = &options->permitted_remote_opens; 158319261079SEd Maste arg = argv_next(&ac, &av); 158419261079SEd Maste if (!arg || *arg == '\0') 158519261079SEd Maste fatal("%s line %d: missing %s specification", 158619261079SEd Maste filename, linenum, lookup_opcode_name(opcode)); 158719261079SEd Maste uvalue = *uintptr; /* modified later */ 158819261079SEd Maste if (strcmp(arg, "any") == 0 || strcmp(arg, "none") == 0) { 158919261079SEd Maste if (*activep && uvalue == 0) { 159019261079SEd Maste *uintptr = 1; 159119261079SEd Maste *cppptr = xcalloc(1, sizeof(**cppptr)); 159219261079SEd Maste (*cppptr)[0] = xstrdup(arg); 159319261079SEd Maste } 159419261079SEd Maste break; 159519261079SEd Maste } 159619261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) { 159719261079SEd Maste arg2 = xstrdup(arg); 1598*1323ec57SEd Maste p = hpdelim(&arg); 1599*1323ec57SEd Maste if (p == NULL) { 160019261079SEd Maste fatal("%s line %d: missing host in %s", 160119261079SEd Maste filename, linenum, 160219261079SEd Maste lookup_opcode_name(opcode)); 160319261079SEd Maste } 160419261079SEd Maste p = cleanhostname(p); 160519261079SEd Maste /* 160619261079SEd Maste * don't want to use permitopen_port to avoid 160719261079SEd Maste * dependency on channels.[ch] here. 160819261079SEd Maste */ 160919261079SEd Maste if (arg == NULL || 161019261079SEd Maste (strcmp(arg, "*") != 0 && a2port(arg) <= 0)) { 161119261079SEd Maste fatal("%s line %d: bad port number in %s", 161219261079SEd Maste filename, linenum, 161319261079SEd Maste lookup_opcode_name(opcode)); 161419261079SEd Maste } 161519261079SEd Maste if (*activep && uvalue == 0) { 161619261079SEd Maste opt_array_append(filename, linenum, 161719261079SEd Maste lookup_opcode_name(opcode), 161819261079SEd Maste cppptr, uintptr, arg2); 161919261079SEd Maste } 162019261079SEd Maste free(arg2); 162119261079SEd Maste } 162219261079SEd Maste break; 162319261079SEd Maste 1624af12a3e7SDag-Erling Smørgrav case oClearAllForwardings: 1625af12a3e7SDag-Erling Smørgrav intptr = &options->clear_forwardings; 1626af12a3e7SDag-Erling Smørgrav goto parse_flag; 1627af12a3e7SDag-Erling Smørgrav 1628511b41d2SMark Murray case oHost: 162919261079SEd Maste if (cmdline) { 163019261079SEd Maste error("Host directive not supported as a command-line " 1631f7167e0eSDag-Erling Smørgrav "option"); 163219261079SEd Maste goto out; 163319261079SEd Maste } 1634511b41d2SMark Murray *activep = 0; 1635e146993eSDag-Erling Smørgrav arg2 = NULL; 163619261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) { 163719261079SEd Maste if (*arg == '\0') { 163819261079SEd Maste error("%s line %d: keyword %s empty argument", 163919261079SEd Maste filename, linenum, keyword); 164019261079SEd Maste goto out; 164119261079SEd Maste } 164219261079SEd Maste if ((flags & SSHCONF_NEVERMATCH) != 0) { 164319261079SEd Maste argv_consume(&ac); 1644076ad2f8SDag-Erling Smørgrav break; 164519261079SEd Maste } 1646e146993eSDag-Erling Smørgrav negated = *arg == '!'; 1647e146993eSDag-Erling Smørgrav if (negated) 1648e146993eSDag-Erling Smørgrav arg++; 1649c2d3a559SKris Kennaway if (match_pattern(host, arg)) { 1650e146993eSDag-Erling Smørgrav if (negated) { 1651e146993eSDag-Erling Smørgrav debug("%.200s line %d: Skipping Host " 1652e146993eSDag-Erling Smørgrav "block because of negated match " 1653e146993eSDag-Erling Smørgrav "for %.100s", filename, linenum, 1654e146993eSDag-Erling Smørgrav arg); 1655e146993eSDag-Erling Smørgrav *activep = 0; 165619261079SEd Maste argv_consume(&ac); 1657511b41d2SMark Murray break; 1658511b41d2SMark Murray } 1659e146993eSDag-Erling Smørgrav if (!*activep) 1660e146993eSDag-Erling Smørgrav arg2 = arg; /* logged below */ 1661e146993eSDag-Erling Smørgrav *activep = 1; 1662e146993eSDag-Erling Smørgrav } 1663e146993eSDag-Erling Smørgrav } 1664e146993eSDag-Erling Smørgrav if (*activep) 1665e146993eSDag-Erling Smørgrav debug("%.200s line %d: Applying options for %.100s", 1666e146993eSDag-Erling Smørgrav filename, linenum, arg2); 166719261079SEd Maste break; 1668511b41d2SMark Murray 1669f7167e0eSDag-Erling Smørgrav case oMatch: 167019261079SEd Maste if (cmdline) { 167119261079SEd Maste error("Host directive not supported as a command-line " 1672f7167e0eSDag-Erling Smørgrav "option"); 167319261079SEd Maste goto out; 167419261079SEd Maste } 167519261079SEd Maste value = match_cfg_line(options, &str, pw, host, original_host, 167619261079SEd Maste flags & SSHCONF_FINAL, want_final_pass, 167719261079SEd Maste filename, linenum); 167819261079SEd Maste if (value < 0) { 167919261079SEd Maste error("%.200s line %d: Bad Match condition", filename, 1680f7167e0eSDag-Erling Smørgrav linenum); 168119261079SEd Maste goto out; 168219261079SEd Maste } 1683076ad2f8SDag-Erling Smørgrav *activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value; 168419261079SEd Maste /* 168519261079SEd Maste * If match_cfg_line() didn't consume all its arguments then 168619261079SEd Maste * arrange for the extra arguments check below to fail. 168719261079SEd Maste */ 168819261079SEd Maste 168919261079SEd Maste if (str == NULL || *str == '\0') 169019261079SEd Maste argv_consume(&ac); 1691f7167e0eSDag-Erling Smørgrav break; 1692f7167e0eSDag-Erling Smørgrav 1693511b41d2SMark Murray case oEscapeChar: 1694511b41d2SMark Murray intptr = &options->escape_char; 169519261079SEd Maste arg = argv_next(&ac, &av); 169619261079SEd Maste if (!arg || *arg == '\0') { 169719261079SEd Maste error("%.200s line %d: Missing argument.", 169819261079SEd Maste filename, linenum); 169919261079SEd Maste goto out; 170019261079SEd Maste } 1701557f75e5SDag-Erling Smørgrav if (strcmp(arg, "none") == 0) 1702557f75e5SDag-Erling Smørgrav value = SSH_ESCAPECHAR_NONE; 1703557f75e5SDag-Erling Smørgrav else if (arg[1] == '\0') 1704557f75e5SDag-Erling Smørgrav value = (u_char) arg[0]; 1705557f75e5SDag-Erling Smørgrav else if (arg[0] == '^' && arg[2] == 0 && 1706ca3176e7SBrian Feldman (u_char) arg[1] >= 64 && (u_char) arg[1] < 128) 1707ca3176e7SBrian Feldman value = (u_char) arg[1] & 31; 1708511b41d2SMark Murray else { 170919261079SEd Maste error("%.200s line %d: Bad escape character.", 1710511b41d2SMark Murray filename, linenum); 171119261079SEd Maste goto out; 1712511b41d2SMark Murray } 1713511b41d2SMark Murray if (*activep && *intptr == -1) 1714511b41d2SMark Murray *intptr = value; 1715511b41d2SMark Murray break; 1716511b41d2SMark Murray 1717cf2b5f3bSDag-Erling Smørgrav case oAddressFamily: 1718cf2b5f3bSDag-Erling Smørgrav intptr = &options->address_family; 1719f7167e0eSDag-Erling Smørgrav multistate_ptr = multistate_addressfamily; 1720f7167e0eSDag-Erling Smørgrav goto parse_multistate; 1721cf2b5f3bSDag-Erling Smørgrav 1722e73e9afaSDag-Erling Smørgrav case oEnableSSHKeysign: 1723e73e9afaSDag-Erling Smørgrav intptr = &options->enable_ssh_keysign; 1724e73e9afaSDag-Erling Smørgrav goto parse_flag; 1725e73e9afaSDag-Erling Smørgrav 17265962c0e9SDag-Erling Smørgrav case oIdentitiesOnly: 17275962c0e9SDag-Erling Smørgrav intptr = &options->identities_only; 17285962c0e9SDag-Erling Smørgrav goto parse_flag; 17295962c0e9SDag-Erling Smørgrav 17301ec0d754SDag-Erling Smørgrav case oServerAliveInterval: 17311ec0d754SDag-Erling Smørgrav intptr = &options->server_alive_interval; 17321ec0d754SDag-Erling Smørgrav goto parse_time; 17331ec0d754SDag-Erling Smørgrav 17341ec0d754SDag-Erling Smørgrav case oServerAliveCountMax: 17351ec0d754SDag-Erling Smørgrav intptr = &options->server_alive_count_max; 17361ec0d754SDag-Erling Smørgrav goto parse_int; 17371ec0d754SDag-Erling Smørgrav 173821e764dfSDag-Erling Smørgrav case oSendEnv: 173919261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) { 174019261079SEd Maste if (*arg == '\0' || strchr(arg, '=') != NULL) { 174119261079SEd Maste error("%s line %d: Invalid environment name.", 174221e764dfSDag-Erling Smørgrav filename, linenum); 174319261079SEd Maste goto out; 174419261079SEd Maste } 1745aa49c926SDag-Erling Smørgrav if (!*activep) 1746aa49c926SDag-Erling Smørgrav continue; 1747190cef3dSDag-Erling Smørgrav if (*arg == '-') { 1748190cef3dSDag-Erling Smørgrav /* Removing an env var */ 1749190cef3dSDag-Erling Smørgrav rm_env(options, arg, filename, linenum); 1750190cef3dSDag-Erling Smørgrav continue; 1751190cef3dSDag-Erling Smørgrav } else { 1752190cef3dSDag-Erling Smørgrav /* Adding an env var */ 175319261079SEd Maste if (options->num_send_env >= INT_MAX) { 175419261079SEd Maste error("%s line %d: too many send env.", 175521e764dfSDag-Erling Smørgrav filename, linenum); 175619261079SEd Maste goto out; 175719261079SEd Maste } 1758190cef3dSDag-Erling Smørgrav options->send_env = xrecallocarray( 1759190cef3dSDag-Erling Smørgrav options->send_env, options->num_send_env, 1760190cef3dSDag-Erling Smørgrav options->num_send_env + 1, 1761190cef3dSDag-Erling Smørgrav sizeof(*options->send_env)); 176221e764dfSDag-Erling Smørgrav options->send_env[options->num_send_env++] = 176321e764dfSDag-Erling Smørgrav xstrdup(arg); 176421e764dfSDag-Erling Smørgrav } 1765190cef3dSDag-Erling Smørgrav } 1766190cef3dSDag-Erling Smørgrav break; 1767190cef3dSDag-Erling Smørgrav 1768190cef3dSDag-Erling Smørgrav case oSetEnv: 1769190cef3dSDag-Erling Smørgrav value = options->num_setenv; 177019261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) { 177119261079SEd Maste if (strchr(arg, '=') == NULL) { 177219261079SEd Maste error("%s line %d: Invalid SetEnv.", 1773190cef3dSDag-Erling Smørgrav filename, linenum); 177419261079SEd Maste goto out; 177519261079SEd Maste } 1776190cef3dSDag-Erling Smørgrav if (!*activep || value != 0) 1777190cef3dSDag-Erling Smørgrav continue; 1778190cef3dSDag-Erling Smørgrav /* Adding a setenv var */ 177919261079SEd Maste if (options->num_setenv >= INT_MAX) { 178019261079SEd Maste error("%s line %d: too many SetEnv.", 1781190cef3dSDag-Erling Smørgrav filename, linenum); 178219261079SEd Maste goto out; 178319261079SEd Maste } 1784190cef3dSDag-Erling Smørgrav options->setenv = xrecallocarray( 1785190cef3dSDag-Erling Smørgrav options->setenv, options->num_setenv, 1786190cef3dSDag-Erling Smørgrav options->num_setenv + 1, sizeof(*options->setenv)); 1787190cef3dSDag-Erling Smørgrav options->setenv[options->num_setenv++] = xstrdup(arg); 1788190cef3dSDag-Erling Smørgrav } 178921e764dfSDag-Erling Smørgrav break; 179021e764dfSDag-Erling Smørgrav 179121e764dfSDag-Erling Smørgrav case oControlPath: 179221e764dfSDag-Erling Smørgrav charptr = &options->control_path; 179321e764dfSDag-Erling Smørgrav goto parse_string; 179421e764dfSDag-Erling Smørgrav 179521e764dfSDag-Erling Smørgrav case oControlMaster: 179621e764dfSDag-Erling Smørgrav intptr = &options->control_master; 1797f7167e0eSDag-Erling Smørgrav multistate_ptr = multistate_controlmaster; 1798f7167e0eSDag-Erling Smørgrav goto parse_multistate; 179921e764dfSDag-Erling Smørgrav 1800e2f6069cSDag-Erling Smørgrav case oControlPersist: 1801e2f6069cSDag-Erling Smørgrav /* no/false/yes/true, or a time spec */ 1802e2f6069cSDag-Erling Smørgrav intptr = &options->control_persist; 180319261079SEd Maste arg = argv_next(&ac, &av); 180419261079SEd Maste if (!arg || *arg == '\0') { 180519261079SEd Maste error("%.200s line %d: Missing ControlPersist" 1806e2f6069cSDag-Erling Smørgrav " argument.", filename, linenum); 180719261079SEd Maste goto out; 180819261079SEd Maste } 1809e2f6069cSDag-Erling Smørgrav value = 0; 1810e2f6069cSDag-Erling Smørgrav value2 = 0; /* timeout */ 1811e2f6069cSDag-Erling Smørgrav if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) 1812e2f6069cSDag-Erling Smørgrav value = 0; 1813e2f6069cSDag-Erling Smørgrav else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) 1814e2f6069cSDag-Erling Smørgrav value = 1; 1815e2f6069cSDag-Erling Smørgrav else if ((value2 = convtime(arg)) >= 0) 1816e2f6069cSDag-Erling Smørgrav value = 1; 181719261079SEd Maste else { 181819261079SEd Maste error("%.200s line %d: Bad ControlPersist argument.", 1819e2f6069cSDag-Erling Smørgrav filename, linenum); 182019261079SEd Maste goto out; 182119261079SEd Maste } 1822e2f6069cSDag-Erling Smørgrav if (*activep && *intptr == -1) { 1823e2f6069cSDag-Erling Smørgrav *intptr = value; 1824e2f6069cSDag-Erling Smørgrav options->control_persist_timeout = value2; 1825e2f6069cSDag-Erling Smørgrav } 1826e2f6069cSDag-Erling Smørgrav break; 1827e2f6069cSDag-Erling Smørgrav 1828aa49c926SDag-Erling Smørgrav case oHashKnownHosts: 1829aa49c926SDag-Erling Smørgrav intptr = &options->hash_known_hosts; 1830aa49c926SDag-Erling Smørgrav goto parse_flag; 1831aa49c926SDag-Erling Smørgrav 1832b74df5b2SDag-Erling Smørgrav case oTunnel: 1833b74df5b2SDag-Erling Smørgrav intptr = &options->tun_open; 1834f7167e0eSDag-Erling Smørgrav multistate_ptr = multistate_tunnel; 1835f7167e0eSDag-Erling Smørgrav goto parse_multistate; 1836b74df5b2SDag-Erling Smørgrav 1837b74df5b2SDag-Erling Smørgrav case oTunnelDevice: 183819261079SEd Maste arg = argv_next(&ac, &av); 183919261079SEd Maste if (!arg || *arg == '\0') { 184019261079SEd Maste error("%.200s line %d: Missing argument.", 184119261079SEd Maste filename, linenum); 184219261079SEd Maste goto out; 184319261079SEd Maste } 1844b74df5b2SDag-Erling Smørgrav value = a2tun(arg, &value2); 184519261079SEd Maste if (value == SSH_TUNID_ERR) { 184619261079SEd Maste error("%.200s line %d: Bad tun device.", 184719261079SEd Maste filename, linenum); 184819261079SEd Maste goto out; 184919261079SEd Maste } 185019261079SEd Maste if (*activep && options->tun_local == -1) { 1851b74df5b2SDag-Erling Smørgrav options->tun_local = value; 1852b74df5b2SDag-Erling Smørgrav options->tun_remote = value2; 1853b74df5b2SDag-Erling Smørgrav } 1854b74df5b2SDag-Erling Smørgrav break; 1855b74df5b2SDag-Erling Smørgrav 1856b74df5b2SDag-Erling Smørgrav case oLocalCommand: 1857b74df5b2SDag-Erling Smørgrav charptr = &options->local_command; 1858b74df5b2SDag-Erling Smørgrav goto parse_command; 1859b74df5b2SDag-Erling Smørgrav 1860b74df5b2SDag-Erling Smørgrav case oPermitLocalCommand: 1861b74df5b2SDag-Erling Smørgrav intptr = &options->permit_local_command; 1862b74df5b2SDag-Erling Smørgrav goto parse_flag; 1863b74df5b2SDag-Erling Smørgrav 18644f52dfbbSDag-Erling Smørgrav case oRemoteCommand: 18654f52dfbbSDag-Erling Smørgrav charptr = &options->remote_command; 18664f52dfbbSDag-Erling Smørgrav goto parse_command; 18674f52dfbbSDag-Erling Smørgrav 1868d4af9e69SDag-Erling Smørgrav case oVisualHostKey: 1869d4af9e69SDag-Erling Smørgrav intptr = &options->visual_host_key; 1870d4af9e69SDag-Erling Smørgrav goto parse_flag; 1871d4af9e69SDag-Erling Smørgrav 1872076ad2f8SDag-Erling Smørgrav case oInclude: 187319261079SEd Maste if (cmdline) { 187419261079SEd Maste error("Include directive not supported as a " 1875076ad2f8SDag-Erling Smørgrav "command-line option"); 187619261079SEd Maste goto out; 187719261079SEd Maste } 1878076ad2f8SDag-Erling Smørgrav value = 0; 187919261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) { 188019261079SEd Maste if (*arg == '\0') { 188119261079SEd Maste error("%s line %d: keyword %s empty argument", 188219261079SEd Maste filename, linenum, keyword); 188319261079SEd Maste goto out; 188419261079SEd Maste } 1885076ad2f8SDag-Erling Smørgrav /* 1886076ad2f8SDag-Erling Smørgrav * Ensure all paths are anchored. User configuration 1887076ad2f8SDag-Erling Smørgrav * files may begin with '~/' but system configurations 1888076ad2f8SDag-Erling Smørgrav * must not. If the path is relative, then treat it 1889076ad2f8SDag-Erling Smørgrav * as living in ~/.ssh for user configurations or 1890076ad2f8SDag-Erling Smørgrav * /etc/ssh for system ones. 1891076ad2f8SDag-Erling Smørgrav */ 189219261079SEd Maste if (*arg == '~' && (flags & SSHCONF_USERCONF) == 0) { 189319261079SEd Maste error("%.200s line %d: bad include path %s.", 1894076ad2f8SDag-Erling Smørgrav filename, linenum, arg); 189519261079SEd Maste goto out; 189619261079SEd Maste } 189719261079SEd Maste if (!path_absolute(arg) && *arg != '~') { 1898076ad2f8SDag-Erling Smørgrav xasprintf(&arg2, "%s/%s", 1899076ad2f8SDag-Erling Smørgrav (flags & SSHCONF_USERCONF) ? 1900076ad2f8SDag-Erling Smørgrav "~/" _PATH_SSH_USER_DIR : SSHDIR, arg); 1901076ad2f8SDag-Erling Smørgrav } else 1902076ad2f8SDag-Erling Smørgrav arg2 = xstrdup(arg); 1903076ad2f8SDag-Erling Smørgrav memset(&gl, 0, sizeof(gl)); 1904076ad2f8SDag-Erling Smørgrav r = glob(arg2, GLOB_TILDE, NULL, &gl); 1905076ad2f8SDag-Erling Smørgrav if (r == GLOB_NOMATCH) { 1906076ad2f8SDag-Erling Smørgrav debug("%.200s line %d: include %s matched no " 1907076ad2f8SDag-Erling Smørgrav "files",filename, linenum, arg2); 1908d93a896eSDag-Erling Smørgrav free(arg2); 1909076ad2f8SDag-Erling Smørgrav continue; 191019261079SEd Maste } else if (r != 0) { 191119261079SEd Maste error("%.200s line %d: glob failed for %s.", 1912076ad2f8SDag-Erling Smørgrav filename, linenum, arg2); 191319261079SEd Maste goto out; 191419261079SEd Maste } 1915076ad2f8SDag-Erling Smørgrav free(arg2); 1916076ad2f8SDag-Erling Smørgrav oactive = *activep; 191719261079SEd Maste for (i = 0; i < gl.gl_pathc; i++) { 1918076ad2f8SDag-Erling Smørgrav debug3("%.200s line %d: Including file %s " 1919076ad2f8SDag-Erling Smørgrav "depth %d%s", filename, linenum, 1920076ad2f8SDag-Erling Smørgrav gl.gl_pathv[i], depth, 1921076ad2f8SDag-Erling Smørgrav oactive ? "" : " (parse only)"); 1922076ad2f8SDag-Erling Smørgrav r = read_config_file_depth(gl.gl_pathv[i], 1923076ad2f8SDag-Erling Smørgrav pw, host, original_host, options, 1924076ad2f8SDag-Erling Smørgrav flags | SSHCONF_CHECKPERM | 1925076ad2f8SDag-Erling Smørgrav (oactive ? 0 : SSHCONF_NEVERMATCH), 192619261079SEd Maste activep, want_final_pass, depth + 1); 1927d93a896eSDag-Erling Smørgrav if (r != 1 && errno != ENOENT) { 192819261079SEd Maste error("Can't open user config file " 1929d93a896eSDag-Erling Smørgrav "%.100s: %.100s", gl.gl_pathv[i], 1930d93a896eSDag-Erling Smørgrav strerror(errno)); 193119261079SEd Maste globfree(&gl); 193219261079SEd Maste goto out; 1933d93a896eSDag-Erling Smørgrav } 1934076ad2f8SDag-Erling Smørgrav /* 1935076ad2f8SDag-Erling Smørgrav * don't let Match in includes clobber the 1936076ad2f8SDag-Erling Smørgrav * containing file's Match state. 1937076ad2f8SDag-Erling Smørgrav */ 1938076ad2f8SDag-Erling Smørgrav *activep = oactive; 1939076ad2f8SDag-Erling Smørgrav if (r != 1) 1940076ad2f8SDag-Erling Smørgrav value = -1; 1941076ad2f8SDag-Erling Smørgrav } 1942076ad2f8SDag-Erling Smørgrav globfree(&gl); 1943076ad2f8SDag-Erling Smørgrav } 1944076ad2f8SDag-Erling Smørgrav if (value != 0) 194519261079SEd Maste ret = value; 1946076ad2f8SDag-Erling Smørgrav break; 1947076ad2f8SDag-Erling Smørgrav 19484a421b63SDag-Erling Smørgrav case oIPQoS: 194919261079SEd Maste arg = argv_next(&ac, &av); 195019261079SEd Maste if ((value = parse_ipqos(arg)) == -1) { 195119261079SEd Maste error("%s line %d: Bad IPQoS value: %s", 19524a421b63SDag-Erling Smørgrav filename, linenum, arg); 195319261079SEd Maste goto out; 195419261079SEd Maste } 195519261079SEd Maste arg = argv_next(&ac, &av); 19564a421b63SDag-Erling Smørgrav if (arg == NULL) 19574a421b63SDag-Erling Smørgrav value2 = value; 195819261079SEd Maste else if ((value2 = parse_ipqos(arg)) == -1) { 195919261079SEd Maste error("%s line %d: Bad IPQoS value: %s", 19604a421b63SDag-Erling Smørgrav filename, linenum, arg); 196119261079SEd Maste goto out; 196219261079SEd Maste } 196319261079SEd Maste if (*activep && options->ip_qos_interactive == -1) { 19644a421b63SDag-Erling Smørgrav options->ip_qos_interactive = value; 19654a421b63SDag-Erling Smørgrav options->ip_qos_bulk = value2; 19664a421b63SDag-Erling Smørgrav } 19674a421b63SDag-Erling Smørgrav break; 19684a421b63SDag-Erling Smørgrav 1969e146993eSDag-Erling Smørgrav case oRequestTTY: 1970e146993eSDag-Erling Smørgrav intptr = &options->request_tty; 1971f7167e0eSDag-Erling Smørgrav multistate_ptr = multistate_requesttty; 1972f7167e0eSDag-Erling Smørgrav goto parse_multistate; 1973975616f0SDag-Erling Smørgrav 197419261079SEd Maste case oSessionType: 197519261079SEd Maste intptr = &options->session_type; 197619261079SEd Maste multistate_ptr = multistate_sessiontype; 197719261079SEd Maste goto parse_multistate; 197819261079SEd Maste 197919261079SEd Maste case oStdinNull: 198019261079SEd Maste intptr = &options->stdin_null; 198119261079SEd Maste goto parse_flag; 198219261079SEd Maste 198319261079SEd Maste case oForkAfterAuthentication: 198419261079SEd Maste intptr = &options->fork_after_authentication; 198519261079SEd Maste goto parse_flag; 198619261079SEd Maste 1987e146993eSDag-Erling Smørgrav case oVersionAddendum: 198819261079SEd Maste if (str == NULL) 1989462c32cbSDag-Erling Smørgrav fatal("%.200s line %d: Missing argument.", filename, 1990462c32cbSDag-Erling Smørgrav linenum); 199119261079SEd Maste len = strspn(str, WHITESPACE); 1992462c32cbSDag-Erling Smørgrav if (*activep && options->version_addendum == NULL) { 199319261079SEd Maste if (strcasecmp(str + len, "none") == 0) 1994462c32cbSDag-Erling Smørgrav options->version_addendum = xstrdup(""); 199519261079SEd Maste else if (strchr(str + len, '\r') != NULL) 1996462c32cbSDag-Erling Smørgrav fatal("%.200s line %d: Invalid argument", 1997462c32cbSDag-Erling Smørgrav filename, linenum); 1998462c32cbSDag-Erling Smørgrav else 199919261079SEd Maste options->version_addendum = xstrdup(str + len); 2000462c32cbSDag-Erling Smørgrav } 2001462c32cbSDag-Erling Smørgrav return 0; 2002e146993eSDag-Erling Smørgrav 2003e4a9863fSDag-Erling Smørgrav case oIgnoreUnknown: 2004e4a9863fSDag-Erling Smørgrav charptr = &options->ignored_unknown; 2005e4a9863fSDag-Erling Smørgrav goto parse_string; 2006e4a9863fSDag-Erling Smørgrav 2007f7167e0eSDag-Erling Smørgrav case oProxyUseFdpass: 2008f7167e0eSDag-Erling Smørgrav intptr = &options->proxy_use_fdpass; 2009f7167e0eSDag-Erling Smørgrav goto parse_flag; 2010f7167e0eSDag-Erling Smørgrav 2011f7167e0eSDag-Erling Smørgrav case oCanonicalDomains: 2012f7167e0eSDag-Erling Smørgrav value = options->num_canonical_domains != 0; 201319261079SEd Maste i = 0; 201419261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) { 201519261079SEd Maste if (*arg == '\0') { 201619261079SEd Maste error("%s line %d: keyword %s empty argument", 201719261079SEd Maste filename, linenum, keyword); 201819261079SEd Maste goto out; 201919261079SEd Maste } 202019261079SEd Maste /* Allow "none" only in first position */ 202119261079SEd Maste if (strcasecmp(arg, "none") == 0) { 202219261079SEd Maste if (i > 0 || ac > 0) { 202319261079SEd Maste error("%s line %d: keyword %s \"none\" " 202419261079SEd Maste "argument must appear alone.", 202519261079SEd Maste filename, linenum, keyword); 202619261079SEd Maste goto out; 202719261079SEd Maste } 202819261079SEd Maste } 202919261079SEd Maste i++; 203047dd1d1bSDag-Erling Smørgrav if (!valid_domain(arg, 1, &errstr)) { 203119261079SEd Maste error("%s line %d: %s", filename, linenum, 203247dd1d1bSDag-Erling Smørgrav errstr); 203319261079SEd Maste goto out; 203447dd1d1bSDag-Erling Smørgrav } 2035f7167e0eSDag-Erling Smørgrav if (!*activep || value) 2036f7167e0eSDag-Erling Smørgrav continue; 203719261079SEd Maste if (options->num_canonical_domains >= 203819261079SEd Maste MAX_CANON_DOMAINS) { 203919261079SEd Maste error("%s line %d: too many hostname suffixes.", 2040f7167e0eSDag-Erling Smørgrav filename, linenum); 204119261079SEd Maste goto out; 204219261079SEd Maste } 2043f7167e0eSDag-Erling Smørgrav options->canonical_domains[ 2044f7167e0eSDag-Erling Smørgrav options->num_canonical_domains++] = xstrdup(arg); 2045f7167e0eSDag-Erling Smørgrav } 2046f7167e0eSDag-Erling Smørgrav break; 2047f7167e0eSDag-Erling Smørgrav 2048f7167e0eSDag-Erling Smørgrav case oCanonicalizePermittedCNAMEs: 2049f7167e0eSDag-Erling Smørgrav value = options->num_permitted_cnames != 0; 2050e9e8876aSEd Maste i = 0; 205119261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) { 2052e9e8876aSEd Maste /* 2053e9e8876aSEd Maste * Either 'none' (only in first position), '*' for 2054e9e8876aSEd Maste * everything or 'list:list' 2055e9e8876aSEd Maste */ 2056e9e8876aSEd Maste if (strcasecmp(arg, "none") == 0) { 2057e9e8876aSEd Maste if (i > 0 || ac > 0) { 2058e9e8876aSEd Maste error("%s line %d: keyword %s \"none\" " 2059e9e8876aSEd Maste "argument must appear alone.", 2060e9e8876aSEd Maste filename, linenum, keyword); 2061e9e8876aSEd Maste goto out; 2062e9e8876aSEd Maste } 2063e9e8876aSEd Maste arg2 = ""; 2064e9e8876aSEd Maste } else if (strcmp(arg, "*") == 0) { 2065f7167e0eSDag-Erling Smørgrav arg2 = arg; 2066e9e8876aSEd Maste } else { 2067f7167e0eSDag-Erling Smørgrav lowercase(arg); 2068f7167e0eSDag-Erling Smørgrav if ((arg2 = strchr(arg, ':')) == NULL || 2069f7167e0eSDag-Erling Smørgrav arg2[1] == '\0') { 207019261079SEd Maste error("%s line %d: " 2071f7167e0eSDag-Erling Smørgrav "Invalid permitted CNAME \"%s\"", 2072f7167e0eSDag-Erling Smørgrav filename, linenum, arg); 207319261079SEd Maste goto out; 2074f7167e0eSDag-Erling Smørgrav } 2075f7167e0eSDag-Erling Smørgrav *arg2 = '\0'; 2076f7167e0eSDag-Erling Smørgrav arg2++; 2077f7167e0eSDag-Erling Smørgrav } 2078e9e8876aSEd Maste i++; 2079f7167e0eSDag-Erling Smørgrav if (!*activep || value) 2080f7167e0eSDag-Erling Smørgrav continue; 208119261079SEd Maste if (options->num_permitted_cnames >= 208219261079SEd Maste MAX_CANON_DOMAINS) { 208319261079SEd Maste error("%s line %d: too many permitted CNAMEs.", 2084f7167e0eSDag-Erling Smørgrav filename, linenum); 208519261079SEd Maste goto out; 208619261079SEd Maste } 2087f7167e0eSDag-Erling Smørgrav cname = options->permitted_cnames + 2088f7167e0eSDag-Erling Smørgrav options->num_permitted_cnames++; 2089f7167e0eSDag-Erling Smørgrav cname->source_list = xstrdup(arg); 2090f7167e0eSDag-Erling Smørgrav cname->target_list = xstrdup(arg2); 2091f7167e0eSDag-Erling Smørgrav } 2092f7167e0eSDag-Erling Smørgrav break; 2093f7167e0eSDag-Erling Smørgrav 2094f7167e0eSDag-Erling Smørgrav case oCanonicalizeHostname: 2095f7167e0eSDag-Erling Smørgrav intptr = &options->canonicalize_hostname; 2096f7167e0eSDag-Erling Smørgrav multistate_ptr = multistate_canonicalizehostname; 2097f7167e0eSDag-Erling Smørgrav goto parse_multistate; 2098f7167e0eSDag-Erling Smørgrav 2099f7167e0eSDag-Erling Smørgrav case oCanonicalizeMaxDots: 2100f7167e0eSDag-Erling Smørgrav intptr = &options->canonicalize_max_dots; 2101f7167e0eSDag-Erling Smørgrav goto parse_int; 2102f7167e0eSDag-Erling Smørgrav 2103f7167e0eSDag-Erling Smørgrav case oCanonicalizeFallbackLocal: 2104f7167e0eSDag-Erling Smørgrav intptr = &options->canonicalize_fallback_local; 2105f7167e0eSDag-Erling Smørgrav goto parse_flag; 2106f7167e0eSDag-Erling Smørgrav 2107a0ee8cc6SDag-Erling Smørgrav case oStreamLocalBindMask: 210819261079SEd Maste arg = argv_next(&ac, &av); 210919261079SEd Maste if (!arg || *arg == '\0') { 211019261079SEd Maste error("%.200s line %d: Missing StreamLocalBindMask " 211119261079SEd Maste "argument.", filename, linenum); 211219261079SEd Maste goto out; 211319261079SEd Maste } 2114a0ee8cc6SDag-Erling Smørgrav /* Parse mode in octal format */ 2115a0ee8cc6SDag-Erling Smørgrav value = strtol(arg, &endofnumber, 8); 211619261079SEd Maste if (arg == endofnumber || value < 0 || value > 0777) { 211719261079SEd Maste error("%.200s line %d: Bad mask.", filename, linenum); 211819261079SEd Maste goto out; 211919261079SEd Maste } 2120a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_mask = (mode_t)value; 2121a0ee8cc6SDag-Erling Smørgrav break; 2122a0ee8cc6SDag-Erling Smørgrav 2123a0ee8cc6SDag-Erling Smørgrav case oStreamLocalBindUnlink: 2124a0ee8cc6SDag-Erling Smørgrav intptr = &options->fwd_opts.streamlocal_bind_unlink; 2125a0ee8cc6SDag-Erling Smørgrav goto parse_flag; 2126a0ee8cc6SDag-Erling Smørgrav 2127bc5531deSDag-Erling Smørgrav case oRevokedHostKeys: 2128bc5531deSDag-Erling Smørgrav charptr = &options->revoked_host_keys; 2129bc5531deSDag-Erling Smørgrav goto parse_string; 2130bc5531deSDag-Erling Smørgrav 2131bc5531deSDag-Erling Smørgrav case oFingerprintHash: 2132bc5531deSDag-Erling Smørgrav intptr = &options->fingerprint_hash; 213319261079SEd Maste arg = argv_next(&ac, &av); 213419261079SEd Maste if (!arg || *arg == '\0') { 213519261079SEd Maste error("%.200s line %d: Missing argument.", 2136bc5531deSDag-Erling Smørgrav filename, linenum); 213719261079SEd Maste goto out; 213819261079SEd Maste } 213919261079SEd Maste if ((value = ssh_digest_alg_by_name(arg)) == -1) { 214019261079SEd Maste error("%.200s line %d: Invalid hash algorithm \"%s\".", 2141bc5531deSDag-Erling Smørgrav filename, linenum, arg); 214219261079SEd Maste goto out; 214319261079SEd Maste } 2144bc5531deSDag-Erling Smørgrav if (*activep && *intptr == -1) 2145bc5531deSDag-Erling Smørgrav *intptr = value; 2146bc5531deSDag-Erling Smørgrav break; 2147bc5531deSDag-Erling Smørgrav 2148bc5531deSDag-Erling Smørgrav case oUpdateHostkeys: 2149bc5531deSDag-Erling Smørgrav intptr = &options->update_hostkeys; 2150bc5531deSDag-Erling Smørgrav multistate_ptr = multistate_yesnoask; 2151bc5531deSDag-Erling Smørgrav goto parse_multistate; 2152bc5531deSDag-Erling Smørgrav 215319261079SEd Maste case oHostbasedAcceptedAlgorithms: 215419261079SEd Maste charptr = &options->hostbased_accepted_algos; 215519261079SEd Maste goto parse_pubkey_algos; 2156eccfee6eSDag-Erling Smørgrav 215719261079SEd Maste case oPubkeyAcceptedAlgorithms: 215819261079SEd Maste charptr = &options->pubkey_accepted_algos; 215919261079SEd Maste goto parse_pubkey_algos; 2160bc5531deSDag-Erling Smørgrav 2161acc1a9efSDag-Erling Smørgrav case oAddKeysToAgent: 216219261079SEd Maste arg = argv_next(&ac, &av); 216319261079SEd Maste arg2 = argv_next(&ac, &av); 216419261079SEd Maste value = parse_multistate_value(arg, filename, linenum, 216519261079SEd Maste multistate_yesnoaskconfirm); 216619261079SEd Maste value2 = 0; /* unlimited lifespan by default */ 216719261079SEd Maste if (value == 3 && arg2 != NULL) { 216819261079SEd Maste /* allow "AddKeysToAgent confirm 5m" */ 216919261079SEd Maste if ((value2 = convtime(arg2)) == -1 || 217019261079SEd Maste value2 > INT_MAX) { 217119261079SEd Maste error("%s line %d: invalid time value.", 217219261079SEd Maste filename, linenum); 217319261079SEd Maste goto out; 217419261079SEd Maste } 217519261079SEd Maste } else if (value == -1 && arg2 == NULL) { 217619261079SEd Maste if ((value2 = convtime(arg)) == -1 || 217719261079SEd Maste value2 > INT_MAX) { 217819261079SEd Maste error("%s line %d: unsupported option", 217919261079SEd Maste filename, linenum); 218019261079SEd Maste goto out; 218119261079SEd Maste } 218219261079SEd Maste value = 1; /* yes */ 218319261079SEd Maste } else if (value == -1 || arg2 != NULL) { 218419261079SEd Maste error("%s line %d: unsupported option", 218519261079SEd Maste filename, linenum); 218619261079SEd Maste goto out; 218719261079SEd Maste } 218819261079SEd Maste if (*activep && options->add_keys_to_agent == -1) { 218919261079SEd Maste options->add_keys_to_agent = value; 219019261079SEd Maste options->add_keys_to_agent_lifespan = value2; 219119261079SEd Maste } 219219261079SEd Maste break; 2193acc1a9efSDag-Erling Smørgrav 2194076ad2f8SDag-Erling Smørgrav case oIdentityAgent: 2195076ad2f8SDag-Erling Smørgrav charptr = &options->identity_agent; 219619261079SEd Maste arg = argv_next(&ac, &av); 219719261079SEd Maste if (!arg || *arg == '\0') { 219819261079SEd Maste error("%.200s line %d: Missing argument.", 21992f513db7SEd Maste filename, linenum); 220019261079SEd Maste goto out; 220119261079SEd Maste } 220219261079SEd Maste parse_agent_path: 22032f513db7SEd Maste /* Extra validation if the string represents an env var. */ 220419261079SEd Maste if ((arg2 = dollar_expand(&r, arg)) == NULL || r) { 220519261079SEd Maste error("%.200s line %d: Invalid environment expansion " 220619261079SEd Maste "%s.", filename, linenum, arg); 220719261079SEd Maste goto out; 220819261079SEd Maste } 220919261079SEd Maste free(arg2); 221019261079SEd Maste /* check for legacy environment format */ 221119261079SEd Maste if (arg[0] == '$' && arg[1] != '{' && 221219261079SEd Maste !valid_env_name(arg + 1)) { 221319261079SEd Maste error("%.200s line %d: Invalid environment name %s.", 22142f513db7SEd Maste filename, linenum, arg); 221519261079SEd Maste goto out; 22162f513db7SEd Maste } 22172f513db7SEd Maste if (*activep && *charptr == NULL) 22182f513db7SEd Maste *charptr = xstrdup(arg); 22192f513db7SEd Maste break; 2220076ad2f8SDag-Erling Smørgrav 222180628bacSDag-Erling Smørgrav case oDeprecated: 222280628bacSDag-Erling Smørgrav debug("%s line %d: Deprecated option \"%s\"", 222380628bacSDag-Erling Smørgrav filename, linenum, keyword); 222419261079SEd Maste argv_consume(&ac); 222519261079SEd Maste break; 222680628bacSDag-Erling Smørgrav 2227cf2b5f3bSDag-Erling Smørgrav case oUnsupported: 2228cf2b5f3bSDag-Erling Smørgrav error("%s line %d: Unsupported option \"%s\"", 2229cf2b5f3bSDag-Erling Smørgrav filename, linenum, keyword); 223019261079SEd Maste argv_consume(&ac); 223119261079SEd Maste break; 2232cf2b5f3bSDag-Erling Smørgrav 2233511b41d2SMark Murray default: 223419261079SEd Maste error("%s line %d: Unimplemented opcode %d", 223519261079SEd Maste filename, linenum, opcode); 223619261079SEd Maste goto out; 2237511b41d2SMark Murray } 2238511b41d2SMark Murray 2239511b41d2SMark Murray /* Check that there is no garbage at end of line. */ 224019261079SEd Maste if (ac > 0) { 224119261079SEd Maste error("%.200s line %d: keyword %s extra arguments " 224219261079SEd Maste "at end of line", filename, linenum, keyword); 224319261079SEd Maste goto out; 2244c2d3a559SKris Kennaway } 224519261079SEd Maste 224619261079SEd Maste /* success */ 224719261079SEd Maste ret = 0; 224819261079SEd Maste out: 224919261079SEd Maste argv_free(oav, oac); 225019261079SEd Maste return ret; 2251511b41d2SMark Murray } 2252511b41d2SMark Murray 2253511b41d2SMark Murray /* 2254511b41d2SMark Murray * Reads the config file and modifies the options accordingly. Options 2255511b41d2SMark Murray * should already be initialized before this call. This never returns if 2256af12a3e7SDag-Erling Smørgrav * there is an error. If the file does not exist, this returns 0. 2257511b41d2SMark Murray */ 2258af12a3e7SDag-Erling Smørgrav int 2259f7167e0eSDag-Erling Smørgrav read_config_file(const char *filename, struct passwd *pw, const char *host, 226019261079SEd Maste const char *original_host, Options *options, int flags, 226119261079SEd Maste int *want_final_pass) 2262511b41d2SMark Murray { 2263076ad2f8SDag-Erling Smørgrav int active = 1; 2264076ad2f8SDag-Erling Smørgrav 2265076ad2f8SDag-Erling Smørgrav return read_config_file_depth(filename, pw, host, original_host, 226619261079SEd Maste options, flags, &active, want_final_pass, 0); 2267076ad2f8SDag-Erling Smørgrav } 2268076ad2f8SDag-Erling Smørgrav 2269076ad2f8SDag-Erling Smørgrav #define READCONF_MAX_DEPTH 16 2270076ad2f8SDag-Erling Smørgrav static int 2271076ad2f8SDag-Erling Smørgrav read_config_file_depth(const char *filename, struct passwd *pw, 2272076ad2f8SDag-Erling Smørgrav const char *host, const char *original_host, Options *options, 227319261079SEd Maste int flags, int *activep, int *want_final_pass, int depth) 2274076ad2f8SDag-Erling Smørgrav { 2275511b41d2SMark Murray FILE *f; 2276190cef3dSDag-Erling Smørgrav char *line = NULL; 2277190cef3dSDag-Erling Smørgrav size_t linesize = 0; 2278076ad2f8SDag-Erling Smørgrav int linenum; 2279511b41d2SMark Murray int bad_options = 0; 2280511b41d2SMark Murray 2281076ad2f8SDag-Erling Smørgrav if (depth < 0 || depth > READCONF_MAX_DEPTH) 2282076ad2f8SDag-Erling Smørgrav fatal("Too many recursive configuration includes"); 2283076ad2f8SDag-Erling Smørgrav 228421e764dfSDag-Erling Smørgrav if ((f = fopen(filename, "r")) == NULL) 2285af12a3e7SDag-Erling Smørgrav return 0; 2286511b41d2SMark Murray 228773370613SDag-Erling Smørgrav if (flags & SSHCONF_CHECKPERM) { 228821e764dfSDag-Erling Smørgrav struct stat sb; 228921e764dfSDag-Erling Smørgrav 229021e764dfSDag-Erling Smørgrav if (fstat(fileno(f), &sb) == -1) 229121e764dfSDag-Erling Smørgrav fatal("fstat %s: %s", filename, strerror(errno)); 229221e764dfSDag-Erling Smørgrav if (((sb.st_uid != 0 && sb.st_uid != getuid()) || 229321e764dfSDag-Erling Smørgrav (sb.st_mode & 022) != 0)) 229421e764dfSDag-Erling Smørgrav fatal("Bad owner or permissions on %s", filename); 229521e764dfSDag-Erling Smørgrav } 229621e764dfSDag-Erling Smørgrav 2297511b41d2SMark Murray debug("Reading configuration data %.200s", filename); 2298511b41d2SMark Murray 2299511b41d2SMark Murray /* 2300511b41d2SMark Murray * Mark that we are now processing the options. This flag is turned 2301511b41d2SMark Murray * on/off by Host specifications. 2302511b41d2SMark Murray */ 2303511b41d2SMark Murray linenum = 0; 2304190cef3dSDag-Erling Smørgrav while (getline(&line, &linesize, f) != -1) { 2305511b41d2SMark Murray /* Update line number counter. */ 2306511b41d2SMark Murray linenum++; 230719261079SEd Maste /* 230819261079SEd Maste * Trim out comments and strip whitespace. 230919261079SEd Maste * NB - preserve newlines, they are needed to reproduce 231019261079SEd Maste * line numbers later for error messages. 231119261079SEd Maste */ 2312076ad2f8SDag-Erling Smørgrav if (process_config_line_depth(options, pw, host, original_host, 231319261079SEd Maste line, filename, linenum, activep, flags, want_final_pass, 231419261079SEd Maste depth) != 0) 2315511b41d2SMark Murray bad_options++; 2316511b41d2SMark Murray } 2317190cef3dSDag-Erling Smørgrav free(line); 2318511b41d2SMark Murray fclose(f); 2319511b41d2SMark Murray if (bad_options > 0) 2320ca3176e7SBrian Feldman fatal("%s: terminating, %d bad configuration options", 2321511b41d2SMark Murray filename, bad_options); 2322af12a3e7SDag-Erling Smørgrav return 1; 2323511b41d2SMark Murray } 2324511b41d2SMark Murray 2325b83788ffSDag-Erling Smørgrav /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ 2326b83788ffSDag-Erling Smørgrav int 2327b83788ffSDag-Erling Smørgrav option_clear_or_none(const char *o) 2328b83788ffSDag-Erling Smørgrav { 2329b83788ffSDag-Erling Smørgrav return o == NULL || strcasecmp(o, "none") == 0; 2330b83788ffSDag-Erling Smørgrav } 2331b83788ffSDag-Erling Smørgrav 2332511b41d2SMark Murray /* 2333e9e8876aSEd Maste * Returns 1 if CanonicalizePermittedCNAMEs have been specified, 0 otherwise. 2334e9e8876aSEd Maste * Allowed to be called on non-final configuration. 2335e9e8876aSEd Maste */ 2336e9e8876aSEd Maste int 2337e9e8876aSEd Maste config_has_permitted_cnames(Options *options) 2338e9e8876aSEd Maste { 2339e9e8876aSEd Maste if (options->num_permitted_cnames == 1 && 2340e9e8876aSEd Maste strcasecmp(options->permitted_cnames[0].source_list, "none") == 0 && 2341e9e8876aSEd Maste strcmp(options->permitted_cnames[0].target_list, "") == 0) 2342e9e8876aSEd Maste return 0; 2343e9e8876aSEd Maste return options->num_permitted_cnames > 0; 2344e9e8876aSEd Maste } 2345e9e8876aSEd Maste 2346e9e8876aSEd Maste /* 2347511b41d2SMark Murray * Initializes options to special values that indicate that they have not yet 2348511b41d2SMark Murray * been set. Read_config_file will only set options with this value. Options 2349511b41d2SMark Murray * are processed in the following order: command line, user config file, 2350511b41d2SMark Murray * system config file. Last, fill_default_options is called. 2351511b41d2SMark Murray */ 2352511b41d2SMark Murray 2353511b41d2SMark Murray void 2354511b41d2SMark Murray initialize_options(Options * options) 2355511b41d2SMark Murray { 2356511b41d2SMark Murray memset(options, 'X', sizeof(*options)); 2357eccfee6eSDag-Erling Smørgrav options->version_addendum = NULL; 2358511b41d2SMark Murray options->forward_agent = -1; 235919261079SEd Maste options->forward_agent_sock_path = NULL; 2360511b41d2SMark Murray options->forward_x11 = -1; 23611ec0d754SDag-Erling Smørgrav options->forward_x11_trusted = -1; 2362e2f6069cSDag-Erling Smørgrav options->forward_x11_timeout = -1; 2363076ad2f8SDag-Erling Smørgrav options->stdio_forward_host = NULL; 2364076ad2f8SDag-Erling Smørgrav options->stdio_forward_port = 0; 2365076ad2f8SDag-Erling Smørgrav options->clear_forwardings = -1; 2366333ee039SDag-Erling Smørgrav options->exit_on_forward_failure = -1; 2367c2d3a559SKris Kennaway options->xauth_location = NULL; 2368a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.gateway_ports = -1; 2369a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_mask = (mode_t)-1; 2370a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_unlink = -1; 2371ca3176e7SBrian Feldman options->pubkey_authentication = -1; 2372cf2b5f3bSDag-Erling Smørgrav options->gss_authentication = -1; 2373cf2b5f3bSDag-Erling Smørgrav options->gss_deleg_creds = -1; 2374511b41d2SMark Murray options->password_authentication = -1; 237509958426SBrian Feldman options->kbd_interactive_authentication = -1; 237609958426SBrian Feldman options->kbd_interactive_devices = NULL; 2377ca3176e7SBrian Feldman options->hostbased_authentication = -1; 2378511b41d2SMark Murray options->batch_mode = -1; 2379511b41d2SMark Murray options->check_host_ip = -1; 2380511b41d2SMark Murray options->strict_host_key_checking = -1; 2381511b41d2SMark Murray options->compression = -1; 23821ec0d754SDag-Erling Smørgrav options->tcp_keep_alive = -1; 2383511b41d2SMark Murray options->port = -1; 2384cf2b5f3bSDag-Erling Smørgrav options->address_family = -1; 2385511b41d2SMark Murray options->connection_attempts = -1; 2386cf2b5f3bSDag-Erling Smørgrav options->connection_timeout = -1; 2387511b41d2SMark Murray options->number_of_password_prompts = -1; 2388e8aafc91SKris Kennaway options->ciphers = NULL; 2389ca3176e7SBrian Feldman options->macs = NULL; 23904a421b63SDag-Erling Smørgrav options->kex_algorithms = NULL; 2391ca3176e7SBrian Feldman options->hostkeyalgorithms = NULL; 23922f513db7SEd Maste options->ca_sign_algorithms = NULL; 2393511b41d2SMark Murray options->num_identity_files = 0; 239419261079SEd Maste memset(options->identity_keys, 0, sizeof(options->identity_keys)); 2395acc1a9efSDag-Erling Smørgrav options->num_certificate_files = 0; 239619261079SEd Maste memset(options->certificates, 0, sizeof(options->certificates)); 2397511b41d2SMark Murray options->hostname = NULL; 2398ca3176e7SBrian Feldman options->host_key_alias = NULL; 2399511b41d2SMark Murray options->proxy_command = NULL; 2400076ad2f8SDag-Erling Smørgrav options->jump_user = NULL; 2401076ad2f8SDag-Erling Smørgrav options->jump_host = NULL; 2402076ad2f8SDag-Erling Smørgrav options->jump_port = -1; 2403076ad2f8SDag-Erling Smørgrav options->jump_extra = NULL; 2404511b41d2SMark Murray options->user = NULL; 2405511b41d2SMark Murray options->escape_char = -1; 2406e146993eSDag-Erling Smørgrav options->num_system_hostfiles = 0; 2407e146993eSDag-Erling Smørgrav options->num_user_hostfiles = 0; 2408e2f6069cSDag-Erling Smørgrav options->local_forwards = NULL; 2409511b41d2SMark Murray options->num_local_forwards = 0; 2410e2f6069cSDag-Erling Smørgrav options->remote_forwards = NULL; 2411511b41d2SMark Murray options->num_remote_forwards = 0; 241219261079SEd Maste options->permitted_remote_opens = NULL; 241319261079SEd Maste options->num_permitted_remote_opens = 0; 24144f52dfbbSDag-Erling Smørgrav options->log_facility = SYSLOG_FACILITY_NOT_SET; 2415af12a3e7SDag-Erling Smørgrav options->log_level = SYSLOG_LEVEL_NOT_SET; 241619261079SEd Maste options->num_log_verbose = 0; 241719261079SEd Maste options->log_verbose = NULL; 2418ca3176e7SBrian Feldman options->preferred_authentications = NULL; 2419af12a3e7SDag-Erling Smørgrav options->bind_address = NULL; 242047dd1d1bSDag-Erling Smørgrav options->bind_interface = NULL; 2421b15c8340SDag-Erling Smørgrav options->pkcs11_provider = NULL; 242219261079SEd Maste options->sk_provider = NULL; 2423e73e9afaSDag-Erling Smørgrav options->enable_ssh_keysign = - 1; 2424af12a3e7SDag-Erling Smørgrav options->no_host_authentication_for_localhost = - 1; 24255962c0e9SDag-Erling Smørgrav options->identities_only = - 1; 2426cf2b5f3bSDag-Erling Smørgrav options->rekey_limit = - 1; 2427e4a9863fSDag-Erling Smørgrav options->rekey_interval = -1; 2428cf2b5f3bSDag-Erling Smørgrav options->verify_host_key_dns = -1; 24291ec0d754SDag-Erling Smørgrav options->server_alive_interval = -1; 24301ec0d754SDag-Erling Smørgrav options->server_alive_count_max = -1; 2431190cef3dSDag-Erling Smørgrav options->send_env = NULL; 243221e764dfSDag-Erling Smørgrav options->num_send_env = 0; 2433190cef3dSDag-Erling Smørgrav options->setenv = NULL; 2434190cef3dSDag-Erling Smørgrav options->num_setenv = 0; 243521e764dfSDag-Erling Smørgrav options->control_path = NULL; 243621e764dfSDag-Erling Smørgrav options->control_master = -1; 2437e2f6069cSDag-Erling Smørgrav options->control_persist = -1; 2438e2f6069cSDag-Erling Smørgrav options->control_persist_timeout = 0; 2439aa49c926SDag-Erling Smørgrav options->hash_known_hosts = -1; 2440b74df5b2SDag-Erling Smørgrav options->tun_open = -1; 2441b74df5b2SDag-Erling Smørgrav options->tun_local = -1; 2442b74df5b2SDag-Erling Smørgrav options->tun_remote = -1; 2443b74df5b2SDag-Erling Smørgrav options->local_command = NULL; 2444b74df5b2SDag-Erling Smørgrav options->permit_local_command = -1; 24454f52dfbbSDag-Erling Smørgrav options->remote_command = NULL; 2446acc1a9efSDag-Erling Smørgrav options->add_keys_to_agent = -1; 244719261079SEd Maste options->add_keys_to_agent_lifespan = -1; 2448076ad2f8SDag-Erling Smørgrav options->identity_agent = NULL; 2449d4af9e69SDag-Erling Smørgrav options->visual_host_key = -1; 24504a421b63SDag-Erling Smørgrav options->ip_qos_interactive = -1; 24514a421b63SDag-Erling Smørgrav options->ip_qos_bulk = -1; 2452e146993eSDag-Erling Smørgrav options->request_tty = -1; 245319261079SEd Maste options->session_type = -1; 245419261079SEd Maste options->stdin_null = -1; 245519261079SEd Maste options->fork_after_authentication = -1; 2456f7167e0eSDag-Erling Smørgrav options->proxy_use_fdpass = -1; 2457e4a9863fSDag-Erling Smørgrav options->ignored_unknown = NULL; 2458f7167e0eSDag-Erling Smørgrav options->num_canonical_domains = 0; 2459f7167e0eSDag-Erling Smørgrav options->num_permitted_cnames = 0; 2460f7167e0eSDag-Erling Smørgrav options->canonicalize_max_dots = -1; 2461f7167e0eSDag-Erling Smørgrav options->canonicalize_fallback_local = -1; 2462f7167e0eSDag-Erling Smørgrav options->canonicalize_hostname = -1; 2463bc5531deSDag-Erling Smørgrav options->revoked_host_keys = NULL; 2464bc5531deSDag-Erling Smørgrav options->fingerprint_hash = -1; 2465bc5531deSDag-Erling Smørgrav options->update_hostkeys = -1; 246619261079SEd Maste options->hostbased_accepted_algos = NULL; 246719261079SEd Maste options->pubkey_accepted_algos = NULL; 246819261079SEd Maste options->known_hosts_command = NULL; 2469511b41d2SMark Murray } 2470511b41d2SMark Murray 2471511b41d2SMark Murray /* 2472b83788ffSDag-Erling Smørgrav * A petite version of fill_default_options() that just fills the options 2473b83788ffSDag-Erling Smørgrav * needed for hostname canonicalization to proceed. 2474b83788ffSDag-Erling Smørgrav */ 2475b83788ffSDag-Erling Smørgrav void 2476b83788ffSDag-Erling Smørgrav fill_default_options_for_canonicalization(Options *options) 2477b83788ffSDag-Erling Smørgrav { 2478b83788ffSDag-Erling Smørgrav if (options->canonicalize_max_dots == -1) 2479b83788ffSDag-Erling Smørgrav options->canonicalize_max_dots = 1; 2480b83788ffSDag-Erling Smørgrav if (options->canonicalize_fallback_local == -1) 2481b83788ffSDag-Erling Smørgrav options->canonicalize_fallback_local = 1; 2482b83788ffSDag-Erling Smørgrav if (options->canonicalize_hostname == -1) 2483b83788ffSDag-Erling Smørgrav options->canonicalize_hostname = SSH_CANONICALISE_NO; 2484b83788ffSDag-Erling Smørgrav } 2485b83788ffSDag-Erling Smørgrav 2486b83788ffSDag-Erling Smørgrav /* 2487511b41d2SMark Murray * Called after processing other sources of option data, this fills those 2488511b41d2SMark Murray * options for which no value has been specified with their default values. 2489511b41d2SMark Murray */ 249019261079SEd Maste int 2491511b41d2SMark Murray fill_default_options(Options * options) 2492511b41d2SMark Murray { 24932f513db7SEd Maste char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig; 249419261079SEd Maste char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig; 249519261079SEd Maste int ret = 0, r; 2496190cef3dSDag-Erling Smørgrav 2497511b41d2SMark Murray if (options->forward_agent == -1) 2498db1cb46cSKris Kennaway options->forward_agent = 0; 2499511b41d2SMark Murray if (options->forward_x11 == -1) 25005dc73ebeSBrian Feldman options->forward_x11 = 0; 25011ec0d754SDag-Erling Smørgrav if (options->forward_x11_trusted == -1) 25021ec0d754SDag-Erling Smørgrav options->forward_x11_trusted = 0; 2503e2f6069cSDag-Erling Smørgrav if (options->forward_x11_timeout == -1) 2504e2f6069cSDag-Erling Smørgrav options->forward_x11_timeout = 1200; 2505076ad2f8SDag-Erling Smørgrav /* 2506076ad2f8SDag-Erling Smørgrav * stdio forwarding (-W) changes the default for these but we defer 2507076ad2f8SDag-Erling Smørgrav * setting the values so they can be overridden. 2508076ad2f8SDag-Erling Smørgrav */ 2509333ee039SDag-Erling Smørgrav if (options->exit_on_forward_failure == -1) 2510076ad2f8SDag-Erling Smørgrav options->exit_on_forward_failure = 2511076ad2f8SDag-Erling Smørgrav options->stdio_forward_host != NULL ? 1 : 0; 2512076ad2f8SDag-Erling Smørgrav if (options->clear_forwardings == -1) 2513076ad2f8SDag-Erling Smørgrav options->clear_forwardings = 2514076ad2f8SDag-Erling Smørgrav options->stdio_forward_host != NULL ? 1 : 0; 2515076ad2f8SDag-Erling Smørgrav if (options->clear_forwardings == 1) 2516076ad2f8SDag-Erling Smørgrav clear_forwardings(options); 2517076ad2f8SDag-Erling Smørgrav 2518c2d3a559SKris Kennaway if (options->xauth_location == NULL) 251919261079SEd Maste options->xauth_location = xstrdup(_PATH_XAUTH); 2520a0ee8cc6SDag-Erling Smørgrav if (options->fwd_opts.gateway_ports == -1) 2521a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.gateway_ports = 0; 2522a0ee8cc6SDag-Erling Smørgrav if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1) 2523a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_mask = 0177; 2524a0ee8cc6SDag-Erling Smørgrav if (options->fwd_opts.streamlocal_bind_unlink == -1) 2525a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_unlink = 0; 2526ca3176e7SBrian Feldman if (options->pubkey_authentication == -1) 2527*1323ec57SEd Maste options->pubkey_authentication = SSH_PUBKEY_AUTH_ALL; 2528cf2b5f3bSDag-Erling Smørgrav if (options->gss_authentication == -1) 25291ec0d754SDag-Erling Smørgrav options->gss_authentication = 0; 2530cf2b5f3bSDag-Erling Smørgrav if (options->gss_deleg_creds == -1) 2531cf2b5f3bSDag-Erling Smørgrav options->gss_deleg_creds = 0; 2532511b41d2SMark Murray if (options->password_authentication == -1) 2533511b41d2SMark Murray options->password_authentication = 1; 253409958426SBrian Feldman if (options->kbd_interactive_authentication == -1) 2535ca3176e7SBrian Feldman options->kbd_interactive_authentication = 1; 2536ca3176e7SBrian Feldman if (options->hostbased_authentication == -1) 2537ca3176e7SBrian Feldman options->hostbased_authentication = 0; 2538511b41d2SMark Murray if (options->batch_mode == -1) 2539511b41d2SMark Murray options->batch_mode = 0; 2540511b41d2SMark Murray if (options->check_host_ip == -1) 2541975616f0SDag-Erling Smørgrav options->check_host_ip = 0; 2542511b41d2SMark Murray if (options->strict_host_key_checking == -1) 25434f52dfbbSDag-Erling Smørgrav options->strict_host_key_checking = SSH_STRICT_HOSTKEY_ASK; 2544511b41d2SMark Murray if (options->compression == -1) 2545511b41d2SMark Murray options->compression = 0; 25461ec0d754SDag-Erling Smørgrav if (options->tcp_keep_alive == -1) 25471ec0d754SDag-Erling Smørgrav options->tcp_keep_alive = 1; 2548511b41d2SMark Murray if (options->port == -1) 2549511b41d2SMark Murray options->port = 0; /* Filled in ssh_connect. */ 2550cf2b5f3bSDag-Erling Smørgrav if (options->address_family == -1) 2551cf2b5f3bSDag-Erling Smørgrav options->address_family = AF_UNSPEC; 2552511b41d2SMark Murray if (options->connection_attempts == -1) 2553af12a3e7SDag-Erling Smørgrav options->connection_attempts = 1; 2554511b41d2SMark Murray if (options->number_of_password_prompts == -1) 2555511b41d2SMark Murray options->number_of_password_prompts = 3; 2556ca3176e7SBrian Feldman /* options->hostkeyalgorithms, default set in myproposals.h */ 255719261079SEd Maste if (options->add_keys_to_agent == -1) { 2558acc1a9efSDag-Erling Smørgrav options->add_keys_to_agent = 0; 255919261079SEd Maste options->add_keys_to_agent_lifespan = 0; 256019261079SEd Maste } 2561511b41d2SMark Murray if (options->num_identity_files == 0) { 25624f52dfbbSDag-Erling Smørgrav add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_RSA, 0); 25634a421b63SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC 25644f52dfbbSDag-Erling Smørgrav add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0); 256519261079SEd Maste add_identity_file(options, "~/", 256619261079SEd Maste _PATH_SSH_CLIENT_ID_ECDSA_SK, 0); 25674a421b63SDag-Erling Smørgrav #endif 2568f7167e0eSDag-Erling Smørgrav add_identity_file(options, "~/", 2569f7167e0eSDag-Erling Smørgrav _PATH_SSH_CLIENT_ID_ED25519, 0); 257019261079SEd Maste add_identity_file(options, "~/", 257119261079SEd Maste _PATH_SSH_CLIENT_ID_ED25519_SK, 0); 257247dd1d1bSDag-Erling Smørgrav add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_XMSS, 0); 2573*1323ec57SEd Maste add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0); 2574ca3176e7SBrian Feldman } 2575511b41d2SMark Murray if (options->escape_char == -1) 2576511b41d2SMark Murray options->escape_char = '~'; 2577e146993eSDag-Erling Smørgrav if (options->num_system_hostfiles == 0) { 2578e146993eSDag-Erling Smørgrav options->system_hostfiles[options->num_system_hostfiles++] = 2579e146993eSDag-Erling Smørgrav xstrdup(_PATH_SSH_SYSTEM_HOSTFILE); 2580e146993eSDag-Erling Smørgrav options->system_hostfiles[options->num_system_hostfiles++] = 2581e146993eSDag-Erling Smørgrav xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2); 2582e146993eSDag-Erling Smørgrav } 258319261079SEd Maste if (options->update_hostkeys == -1) { 258419261079SEd Maste if (options->verify_host_key_dns <= 0 && 258519261079SEd Maste (options->num_user_hostfiles == 0 || 258619261079SEd Maste (options->num_user_hostfiles == 1 && strcmp(options-> 258719261079SEd Maste user_hostfiles[0], _PATH_SSH_USER_HOSTFILE) == 0))) 258819261079SEd Maste options->update_hostkeys = SSH_UPDATE_HOSTKEYS_YES; 258919261079SEd Maste else 259019261079SEd Maste options->update_hostkeys = SSH_UPDATE_HOSTKEYS_NO; 259119261079SEd Maste } 2592e146993eSDag-Erling Smørgrav if (options->num_user_hostfiles == 0) { 2593e146993eSDag-Erling Smørgrav options->user_hostfiles[options->num_user_hostfiles++] = 2594e146993eSDag-Erling Smørgrav xstrdup(_PATH_SSH_USER_HOSTFILE); 2595e146993eSDag-Erling Smørgrav options->user_hostfiles[options->num_user_hostfiles++] = 2596e146993eSDag-Erling Smørgrav xstrdup(_PATH_SSH_USER_HOSTFILE2); 2597e146993eSDag-Erling Smørgrav } 2598af12a3e7SDag-Erling Smørgrav if (options->log_level == SYSLOG_LEVEL_NOT_SET) 2599511b41d2SMark Murray options->log_level = SYSLOG_LEVEL_INFO; 26004f52dfbbSDag-Erling Smørgrav if (options->log_facility == SYSLOG_FACILITY_NOT_SET) 26014f52dfbbSDag-Erling Smørgrav options->log_facility = SYSLOG_FACILITY_USER; 2602af12a3e7SDag-Erling Smørgrav if (options->no_host_authentication_for_localhost == - 1) 2603af12a3e7SDag-Erling Smørgrav options->no_host_authentication_for_localhost = 0; 26045962c0e9SDag-Erling Smørgrav if (options->identities_only == -1) 26055962c0e9SDag-Erling Smørgrav options->identities_only = 0; 2606e73e9afaSDag-Erling Smørgrav if (options->enable_ssh_keysign == -1) 2607e73e9afaSDag-Erling Smørgrav options->enable_ssh_keysign = 0; 2608cf2b5f3bSDag-Erling Smørgrav if (options->rekey_limit == -1) 2609cf2b5f3bSDag-Erling Smørgrav options->rekey_limit = 0; 2610e4a9863fSDag-Erling Smørgrav if (options->rekey_interval == -1) 2611e4a9863fSDag-Erling Smørgrav options->rekey_interval = 0; 261283c6a524SDag-Erling Smørgrav #if HAVE_LDNS 261383c6a524SDag-Erling Smørgrav if (options->verify_host_key_dns == -1) 261483c6a524SDag-Erling Smørgrav /* automatically trust a verified SSHFP record */ 261583c6a524SDag-Erling Smørgrav options->verify_host_key_dns = 1; 261683c6a524SDag-Erling Smørgrav #else 2617cf2b5f3bSDag-Erling Smørgrav if (options->verify_host_key_dns == -1) 2618cf2b5f3bSDag-Erling Smørgrav options->verify_host_key_dns = 0; 261983c6a524SDag-Erling Smørgrav #endif 26201ec0d754SDag-Erling Smørgrav if (options->server_alive_interval == -1) 26211ec0d754SDag-Erling Smørgrav options->server_alive_interval = 0; 26221ec0d754SDag-Erling Smørgrav if (options->server_alive_count_max == -1) 26231ec0d754SDag-Erling Smørgrav options->server_alive_count_max = 3; 262421e764dfSDag-Erling Smørgrav if (options->control_master == -1) 262521e764dfSDag-Erling Smørgrav options->control_master = 0; 2626e2f6069cSDag-Erling Smørgrav if (options->control_persist == -1) { 2627e2f6069cSDag-Erling Smørgrav options->control_persist = 0; 2628e2f6069cSDag-Erling Smørgrav options->control_persist_timeout = 0; 2629e2f6069cSDag-Erling Smørgrav } 2630aa49c926SDag-Erling Smørgrav if (options->hash_known_hosts == -1) 2631aa49c926SDag-Erling Smørgrav options->hash_known_hosts = 0; 2632b74df5b2SDag-Erling Smørgrav if (options->tun_open == -1) 2633b74df5b2SDag-Erling Smørgrav options->tun_open = SSH_TUNMODE_NO; 2634b74df5b2SDag-Erling Smørgrav if (options->tun_local == -1) 2635b74df5b2SDag-Erling Smørgrav options->tun_local = SSH_TUNID_ANY; 2636b74df5b2SDag-Erling Smørgrav if (options->tun_remote == -1) 2637b74df5b2SDag-Erling Smørgrav options->tun_remote = SSH_TUNID_ANY; 2638b74df5b2SDag-Erling Smørgrav if (options->permit_local_command == -1) 2639b74df5b2SDag-Erling Smørgrav options->permit_local_command = 0; 2640d4af9e69SDag-Erling Smørgrav if (options->visual_host_key == -1) 2641d4af9e69SDag-Erling Smørgrav options->visual_host_key = 0; 26424a421b63SDag-Erling Smørgrav if (options->ip_qos_interactive == -1) 2643190cef3dSDag-Erling Smørgrav options->ip_qos_interactive = IPTOS_DSCP_AF21; 26444a421b63SDag-Erling Smørgrav if (options->ip_qos_bulk == -1) 2645190cef3dSDag-Erling Smørgrav options->ip_qos_bulk = IPTOS_DSCP_CS1; 2646e146993eSDag-Erling Smørgrav if (options->request_tty == -1) 2647e146993eSDag-Erling Smørgrav options->request_tty = REQUEST_TTY_AUTO; 264819261079SEd Maste if (options->session_type == -1) 264919261079SEd Maste options->session_type = SESSION_TYPE_DEFAULT; 265019261079SEd Maste if (options->stdin_null == -1) 265119261079SEd Maste options->stdin_null = 0; 265219261079SEd Maste if (options->fork_after_authentication == -1) 265319261079SEd Maste options->fork_after_authentication = 0; 2654f7167e0eSDag-Erling Smørgrav if (options->proxy_use_fdpass == -1) 2655f7167e0eSDag-Erling Smørgrav options->proxy_use_fdpass = 0; 2656f7167e0eSDag-Erling Smørgrav if (options->canonicalize_max_dots == -1) 2657f7167e0eSDag-Erling Smørgrav options->canonicalize_max_dots = 1; 2658f7167e0eSDag-Erling Smørgrav if (options->canonicalize_fallback_local == -1) 2659f7167e0eSDag-Erling Smørgrav options->canonicalize_fallback_local = 1; 2660f7167e0eSDag-Erling Smørgrav if (options->canonicalize_hostname == -1) 2661f7167e0eSDag-Erling Smørgrav options->canonicalize_hostname = SSH_CANONICALISE_NO; 2662bc5531deSDag-Erling Smørgrav if (options->fingerprint_hash == -1) 2663bc5531deSDag-Erling Smørgrav options->fingerprint_hash = SSH_FP_HASH_DEFAULT; 266419261079SEd Maste #ifdef ENABLE_SK_INTERNAL 266519261079SEd Maste if (options->sk_provider == NULL) 266619261079SEd Maste options->sk_provider = xstrdup("internal"); 266719261079SEd Maste #else 266819261079SEd Maste if (options->sk_provider == NULL) 266919261079SEd Maste options->sk_provider = xstrdup("$SSH_SK_PROVIDER"); 267019261079SEd Maste #endif 2671190cef3dSDag-Erling Smørgrav 2672190cef3dSDag-Erling Smørgrav /* Expand KEX name lists */ 2673190cef3dSDag-Erling Smørgrav all_cipher = cipher_alg_list(',', 0); 2674190cef3dSDag-Erling Smørgrav all_mac = mac_alg_list(','); 2675190cef3dSDag-Erling Smørgrav all_kex = kex_alg_list(','); 2676190cef3dSDag-Erling Smørgrav all_key = sshkey_alg_list(0, 0, 1, ','); 26772f513db7SEd Maste all_sig = sshkey_alg_list(0, 1, 1, ','); 267819261079SEd Maste /* remove unsupported algos from default lists */ 267919261079SEd Maste def_cipher = match_filter_allowlist(KEX_CLIENT_ENCRYPT, all_cipher); 268019261079SEd Maste def_mac = match_filter_allowlist(KEX_CLIENT_MAC, all_mac); 268119261079SEd Maste def_kex = match_filter_allowlist(KEX_CLIENT_KEX, all_kex); 268219261079SEd Maste def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key); 268319261079SEd Maste def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig); 2684190cef3dSDag-Erling Smørgrav #define ASSEMBLE(what, defaults, all) \ 2685190cef3dSDag-Erling Smørgrav do { \ 2686190cef3dSDag-Erling Smørgrav if ((r = kex_assemble_names(&options->what, \ 268719261079SEd Maste defaults, all)) != 0) { \ 268819261079SEd Maste error_fr(r, "%s", #what); \ 268919261079SEd Maste goto fail; \ 269019261079SEd Maste } \ 2691190cef3dSDag-Erling Smørgrav } while (0) 269219261079SEd Maste ASSEMBLE(ciphers, def_cipher, all_cipher); 269319261079SEd Maste ASSEMBLE(macs, def_mac, all_mac); 269419261079SEd Maste ASSEMBLE(kex_algorithms, def_kex, all_kex); 269519261079SEd Maste ASSEMBLE(hostbased_accepted_algos, def_key, all_key); 269619261079SEd Maste ASSEMBLE(pubkey_accepted_algos, def_key, all_key); 269719261079SEd Maste ASSEMBLE(ca_sign_algorithms, def_sig, all_sig); 2698190cef3dSDag-Erling Smørgrav #undef ASSEMBLE 2699bc5531deSDag-Erling Smørgrav 2700f7167e0eSDag-Erling Smørgrav #define CLEAR_ON_NONE(v) \ 2701f7167e0eSDag-Erling Smørgrav do { \ 2702b83788ffSDag-Erling Smørgrav if (option_clear_or_none(v)) { \ 2703f7167e0eSDag-Erling Smørgrav free(v); \ 2704f7167e0eSDag-Erling Smørgrav v = NULL; \ 2705f7167e0eSDag-Erling Smørgrav } \ 2706f7167e0eSDag-Erling Smørgrav } while(0) 2707f7167e0eSDag-Erling Smørgrav CLEAR_ON_NONE(options->local_command); 27084f52dfbbSDag-Erling Smørgrav CLEAR_ON_NONE(options->remote_command); 2709f7167e0eSDag-Erling Smørgrav CLEAR_ON_NONE(options->proxy_command); 2710f7167e0eSDag-Erling Smørgrav CLEAR_ON_NONE(options->control_path); 2711bc5531deSDag-Erling Smørgrav CLEAR_ON_NONE(options->revoked_host_keys); 271219261079SEd Maste CLEAR_ON_NONE(options->pkcs11_provider); 271319261079SEd Maste CLEAR_ON_NONE(options->sk_provider); 271419261079SEd Maste CLEAR_ON_NONE(options->known_hosts_command); 2715190cef3dSDag-Erling Smørgrav if (options->jump_host != NULL && 2716190cef3dSDag-Erling Smørgrav strcmp(options->jump_host, "none") == 0 && 2717190cef3dSDag-Erling Smørgrav options->jump_port == 0 && options->jump_user == NULL) { 2718190cef3dSDag-Erling Smørgrav free(options->jump_host); 2719190cef3dSDag-Erling Smørgrav options->jump_host = NULL; 2720190cef3dSDag-Erling Smørgrav } 2721e9e8876aSEd Maste if (options->num_permitted_cnames == 1 && 2722e9e8876aSEd Maste !config_has_permitted_cnames(options)) { 2723e9e8876aSEd Maste /* clean up CanonicalizePermittedCNAMEs=none */ 2724e9e8876aSEd Maste free(options->permitted_cnames[0].source_list); 2725e9e8876aSEd Maste free(options->permitted_cnames[0].target_list); 2726e9e8876aSEd Maste memset(options->permitted_cnames, '\0', 2727e9e8876aSEd Maste sizeof(*options->permitted_cnames)); 2728e9e8876aSEd Maste options->num_permitted_cnames = 0; 2729e9e8876aSEd Maste } 2730076ad2f8SDag-Erling Smørgrav /* options->identity_agent distinguishes NULL from 'none' */ 2731511b41d2SMark Murray /* options->user will be set in the main program if appropriate */ 2732511b41d2SMark Murray /* options->hostname will be set in the main program if appropriate */ 2733ca3176e7SBrian Feldman /* options->host_key_alias should not be set by default */ 2734ca3176e7SBrian Feldman /* options->preferred_authentications will be set in ssh */ 2735462c32cbSDag-Erling Smørgrav if (options->version_addendum == NULL) 2736462c32cbSDag-Erling Smørgrav options->version_addendum = xstrdup(SSH_VERSION_FREEBSD); 273719261079SEd Maste 273819261079SEd Maste /* success */ 273919261079SEd Maste ret = 0; 274019261079SEd Maste fail: 274119261079SEd Maste free(all_cipher); 274219261079SEd Maste free(all_mac); 274319261079SEd Maste free(all_kex); 274419261079SEd Maste free(all_key); 274519261079SEd Maste free(all_sig); 274619261079SEd Maste free(def_cipher); 274719261079SEd Maste free(def_mac); 274819261079SEd Maste free(def_kex); 274919261079SEd Maste free(def_key); 275019261079SEd Maste free(def_sig); 275119261079SEd Maste return ret; 275219261079SEd Maste } 275319261079SEd Maste 275419261079SEd Maste void 275519261079SEd Maste free_options(Options *o) 275619261079SEd Maste { 275719261079SEd Maste int i; 275819261079SEd Maste 275919261079SEd Maste if (o == NULL) 276019261079SEd Maste return; 276119261079SEd Maste 276219261079SEd Maste #define FREE_ARRAY(type, n, a) \ 276319261079SEd Maste do { \ 276419261079SEd Maste type _i; \ 276519261079SEd Maste for (_i = 0; _i < (n); _i++) \ 276619261079SEd Maste free((a)[_i]); \ 276719261079SEd Maste } while (0) 276819261079SEd Maste 276919261079SEd Maste free(o->forward_agent_sock_path); 277019261079SEd Maste free(o->xauth_location); 277119261079SEd Maste FREE_ARRAY(u_int, o->num_log_verbose, o->log_verbose); 277219261079SEd Maste free(o->log_verbose); 277319261079SEd Maste free(o->ciphers); 277419261079SEd Maste free(o->macs); 277519261079SEd Maste free(o->hostkeyalgorithms); 277619261079SEd Maste free(o->kex_algorithms); 277719261079SEd Maste free(o->ca_sign_algorithms); 277819261079SEd Maste free(o->hostname); 277919261079SEd Maste free(o->host_key_alias); 278019261079SEd Maste free(o->proxy_command); 278119261079SEd Maste free(o->user); 278219261079SEd Maste FREE_ARRAY(u_int, o->num_system_hostfiles, o->system_hostfiles); 278319261079SEd Maste FREE_ARRAY(u_int, o->num_user_hostfiles, o->user_hostfiles); 278419261079SEd Maste free(o->preferred_authentications); 278519261079SEd Maste free(o->bind_address); 278619261079SEd Maste free(o->bind_interface); 278719261079SEd Maste free(o->pkcs11_provider); 278819261079SEd Maste free(o->sk_provider); 278919261079SEd Maste for (i = 0; i < o->num_identity_files; i++) { 279019261079SEd Maste free(o->identity_files[i]); 279119261079SEd Maste sshkey_free(o->identity_keys[i]); 279219261079SEd Maste } 279319261079SEd Maste for (i = 0; i < o->num_certificate_files; i++) { 279419261079SEd Maste free(o->certificate_files[i]); 279519261079SEd Maste sshkey_free(o->certificates[i]); 279619261079SEd Maste } 279719261079SEd Maste free(o->identity_agent); 279819261079SEd Maste for (i = 0; i < o->num_local_forwards; i++) { 279919261079SEd Maste free(o->local_forwards[i].listen_host); 280019261079SEd Maste free(o->local_forwards[i].listen_path); 280119261079SEd Maste free(o->local_forwards[i].connect_host); 280219261079SEd Maste free(o->local_forwards[i].connect_path); 280319261079SEd Maste } 280419261079SEd Maste free(o->local_forwards); 280519261079SEd Maste for (i = 0; i < o->num_remote_forwards; i++) { 280619261079SEd Maste free(o->remote_forwards[i].listen_host); 280719261079SEd Maste free(o->remote_forwards[i].listen_path); 280819261079SEd Maste free(o->remote_forwards[i].connect_host); 280919261079SEd Maste free(o->remote_forwards[i].connect_path); 281019261079SEd Maste } 281119261079SEd Maste free(o->remote_forwards); 281219261079SEd Maste free(o->stdio_forward_host); 281319261079SEd Maste FREE_ARRAY(int, o->num_send_env, o->send_env); 281419261079SEd Maste free(o->send_env); 281519261079SEd Maste FREE_ARRAY(int, o->num_setenv, o->setenv); 281619261079SEd Maste free(o->setenv); 281719261079SEd Maste free(o->control_path); 281819261079SEd Maste free(o->local_command); 281919261079SEd Maste free(o->remote_command); 282019261079SEd Maste FREE_ARRAY(int, o->num_canonical_domains, o->canonical_domains); 282119261079SEd Maste for (i = 0; i < o->num_permitted_cnames; i++) { 282219261079SEd Maste free(o->permitted_cnames[i].source_list); 282319261079SEd Maste free(o->permitted_cnames[i].target_list); 282419261079SEd Maste } 282519261079SEd Maste free(o->revoked_host_keys); 282619261079SEd Maste free(o->hostbased_accepted_algos); 282719261079SEd Maste free(o->pubkey_accepted_algos); 282819261079SEd Maste free(o->jump_user); 282919261079SEd Maste free(o->jump_host); 283019261079SEd Maste free(o->jump_extra); 283119261079SEd Maste free(o->ignored_unknown); 283219261079SEd Maste explicit_bzero(o, sizeof(*o)); 283319261079SEd Maste #undef FREE_ARRAY 2834511b41d2SMark Murray } 2835aa49c926SDag-Erling Smørgrav 2836a0ee8cc6SDag-Erling Smørgrav struct fwdarg { 2837a0ee8cc6SDag-Erling Smørgrav char *arg; 2838a0ee8cc6SDag-Erling Smørgrav int ispath; 2839a0ee8cc6SDag-Erling Smørgrav }; 2840a0ee8cc6SDag-Erling Smørgrav 2841a0ee8cc6SDag-Erling Smørgrav /* 2842a0ee8cc6SDag-Erling Smørgrav * parse_fwd_field 2843a0ee8cc6SDag-Erling Smørgrav * parses the next field in a port forwarding specification. 2844a0ee8cc6SDag-Erling Smørgrav * sets fwd to the parsed field and advances p past the colon 2845a0ee8cc6SDag-Erling Smørgrav * or sets it to NULL at end of string. 2846a0ee8cc6SDag-Erling Smørgrav * returns 0 on success, else non-zero. 2847a0ee8cc6SDag-Erling Smørgrav */ 2848a0ee8cc6SDag-Erling Smørgrav static int 2849a0ee8cc6SDag-Erling Smørgrav parse_fwd_field(char **p, struct fwdarg *fwd) 2850a0ee8cc6SDag-Erling Smørgrav { 2851a0ee8cc6SDag-Erling Smørgrav char *ep, *cp = *p; 2852a0ee8cc6SDag-Erling Smørgrav int ispath = 0; 2853a0ee8cc6SDag-Erling Smørgrav 2854a0ee8cc6SDag-Erling Smørgrav if (*cp == '\0') { 2855a0ee8cc6SDag-Erling Smørgrav *p = NULL; 2856a0ee8cc6SDag-Erling Smørgrav return -1; /* end of string */ 2857a0ee8cc6SDag-Erling Smørgrav } 2858a0ee8cc6SDag-Erling Smørgrav 2859a0ee8cc6SDag-Erling Smørgrav /* 2860a0ee8cc6SDag-Erling Smørgrav * A field escaped with square brackets is used literally. 2861a0ee8cc6SDag-Erling Smørgrav * XXX - allow ']' to be escaped via backslash? 2862a0ee8cc6SDag-Erling Smørgrav */ 2863a0ee8cc6SDag-Erling Smørgrav if (*cp == '[') { 2864a0ee8cc6SDag-Erling Smørgrav /* find matching ']' */ 2865a0ee8cc6SDag-Erling Smørgrav for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) { 2866a0ee8cc6SDag-Erling Smørgrav if (*ep == '/') 2867a0ee8cc6SDag-Erling Smørgrav ispath = 1; 2868a0ee8cc6SDag-Erling Smørgrav } 2869a0ee8cc6SDag-Erling Smørgrav /* no matching ']' or not at end of field. */ 2870a0ee8cc6SDag-Erling Smørgrav if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0')) 2871a0ee8cc6SDag-Erling Smørgrav return -1; 2872a0ee8cc6SDag-Erling Smørgrav /* NUL terminate the field and advance p past the colon */ 2873a0ee8cc6SDag-Erling Smørgrav *ep++ = '\0'; 2874a0ee8cc6SDag-Erling Smørgrav if (*ep != '\0') 2875a0ee8cc6SDag-Erling Smørgrav *ep++ = '\0'; 2876a0ee8cc6SDag-Erling Smørgrav fwd->arg = cp + 1; 2877a0ee8cc6SDag-Erling Smørgrav fwd->ispath = ispath; 2878a0ee8cc6SDag-Erling Smørgrav *p = ep; 2879a0ee8cc6SDag-Erling Smørgrav return 0; 2880a0ee8cc6SDag-Erling Smørgrav } 2881a0ee8cc6SDag-Erling Smørgrav 2882a0ee8cc6SDag-Erling Smørgrav for (cp = *p; *cp != '\0'; cp++) { 2883a0ee8cc6SDag-Erling Smørgrav switch (*cp) { 2884a0ee8cc6SDag-Erling Smørgrav case '\\': 2885a0ee8cc6SDag-Erling Smørgrav memmove(cp, cp + 1, strlen(cp + 1) + 1); 2886557f75e5SDag-Erling Smørgrav if (*cp == '\0') 2887557f75e5SDag-Erling Smørgrav return -1; 2888a0ee8cc6SDag-Erling Smørgrav break; 2889a0ee8cc6SDag-Erling Smørgrav case '/': 2890a0ee8cc6SDag-Erling Smørgrav ispath = 1; 2891a0ee8cc6SDag-Erling Smørgrav break; 2892a0ee8cc6SDag-Erling Smørgrav case ':': 2893a0ee8cc6SDag-Erling Smørgrav *cp++ = '\0'; 2894a0ee8cc6SDag-Erling Smørgrav goto done; 2895a0ee8cc6SDag-Erling Smørgrav } 2896a0ee8cc6SDag-Erling Smørgrav } 2897a0ee8cc6SDag-Erling Smørgrav done: 2898a0ee8cc6SDag-Erling Smørgrav fwd->arg = *p; 2899a0ee8cc6SDag-Erling Smørgrav fwd->ispath = ispath; 2900a0ee8cc6SDag-Erling Smørgrav *p = cp; 2901a0ee8cc6SDag-Erling Smørgrav return 0; 2902a0ee8cc6SDag-Erling Smørgrav } 2903a0ee8cc6SDag-Erling Smørgrav 2904aa49c926SDag-Erling Smørgrav /* 2905aa49c926SDag-Erling Smørgrav * parse_forward 2906aa49c926SDag-Erling Smørgrav * parses a string containing a port forwarding specification of the form: 2907cce7d346SDag-Erling Smørgrav * dynamicfwd == 0 2908a0ee8cc6SDag-Erling Smørgrav * [listenhost:]listenport|listenpath:connecthost:connectport|connectpath 2909a0ee8cc6SDag-Erling Smørgrav * listenpath:connectpath 2910cce7d346SDag-Erling Smørgrav * dynamicfwd == 1 2911cce7d346SDag-Erling Smørgrav * [listenhost:]listenport 2912aa49c926SDag-Erling Smørgrav * returns number of arguments parsed or zero on error 2913aa49c926SDag-Erling Smørgrav */ 2914aa49c926SDag-Erling Smørgrav int 2915a0ee8cc6SDag-Erling Smørgrav parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd) 2916aa49c926SDag-Erling Smørgrav { 2917a0ee8cc6SDag-Erling Smørgrav struct fwdarg fwdargs[4]; 2918a0ee8cc6SDag-Erling Smørgrav char *p, *cp; 291919261079SEd Maste int i, err; 2920aa49c926SDag-Erling Smørgrav 2921a0ee8cc6SDag-Erling Smørgrav memset(fwd, 0, sizeof(*fwd)); 2922a0ee8cc6SDag-Erling Smørgrav memset(fwdargs, 0, sizeof(fwdargs)); 2923aa49c926SDag-Erling Smørgrav 292419261079SEd Maste /* 292519261079SEd Maste * We expand environment variables before checking if we think they're 292619261079SEd Maste * paths so that if ${VAR} expands to a fully qualified path it is 292719261079SEd Maste * treated as a path. 292819261079SEd Maste */ 292919261079SEd Maste cp = p = dollar_expand(&err, fwdspec); 293019261079SEd Maste if (p == NULL || err) 293119261079SEd Maste return 0; 2932aa49c926SDag-Erling Smørgrav 2933aa49c926SDag-Erling Smørgrav /* skip leading spaces */ 2934f7167e0eSDag-Erling Smørgrav while (isspace((u_char)*cp)) 2935aa49c926SDag-Erling Smørgrav cp++; 2936aa49c926SDag-Erling Smørgrav 2937a0ee8cc6SDag-Erling Smørgrav for (i = 0; i < 4; ++i) { 2938a0ee8cc6SDag-Erling Smørgrav if (parse_fwd_field(&cp, &fwdargs[i]) != 0) 2939aa49c926SDag-Erling Smørgrav break; 2940a0ee8cc6SDag-Erling Smørgrav } 2941aa49c926SDag-Erling Smørgrav 2942cce7d346SDag-Erling Smørgrav /* Check for trailing garbage */ 2943a0ee8cc6SDag-Erling Smørgrav if (cp != NULL && *cp != '\0') { 2944aa49c926SDag-Erling Smørgrav i = 0; /* failure */ 2945a0ee8cc6SDag-Erling Smørgrav } 2946aa49c926SDag-Erling Smørgrav 2947aa49c926SDag-Erling Smørgrav switch (i) { 2948cce7d346SDag-Erling Smørgrav case 1: 2949a0ee8cc6SDag-Erling Smørgrav if (fwdargs[0].ispath) { 2950a0ee8cc6SDag-Erling Smørgrav fwd->listen_path = xstrdup(fwdargs[0].arg); 2951a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = PORT_STREAMLOCAL; 2952a0ee8cc6SDag-Erling Smørgrav } else { 2953cce7d346SDag-Erling Smørgrav fwd->listen_host = NULL; 2954a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = a2port(fwdargs[0].arg); 2955a0ee8cc6SDag-Erling Smørgrav } 2956cce7d346SDag-Erling Smørgrav fwd->connect_host = xstrdup("socks"); 2957cce7d346SDag-Erling Smørgrav break; 2958cce7d346SDag-Erling Smørgrav 2959cce7d346SDag-Erling Smørgrav case 2: 2960a0ee8cc6SDag-Erling Smørgrav if (fwdargs[0].ispath && fwdargs[1].ispath) { 2961a0ee8cc6SDag-Erling Smørgrav fwd->listen_path = xstrdup(fwdargs[0].arg); 2962a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = PORT_STREAMLOCAL; 2963a0ee8cc6SDag-Erling Smørgrav fwd->connect_path = xstrdup(fwdargs[1].arg); 2964a0ee8cc6SDag-Erling Smørgrav fwd->connect_port = PORT_STREAMLOCAL; 2965a0ee8cc6SDag-Erling Smørgrav } else if (fwdargs[1].ispath) { 2966a0ee8cc6SDag-Erling Smørgrav fwd->listen_host = NULL; 2967a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = a2port(fwdargs[0].arg); 2968a0ee8cc6SDag-Erling Smørgrav fwd->connect_path = xstrdup(fwdargs[1].arg); 2969a0ee8cc6SDag-Erling Smørgrav fwd->connect_port = PORT_STREAMLOCAL; 2970a0ee8cc6SDag-Erling Smørgrav } else { 2971a0ee8cc6SDag-Erling Smørgrav fwd->listen_host = xstrdup(fwdargs[0].arg); 2972a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = a2port(fwdargs[1].arg); 2973cce7d346SDag-Erling Smørgrav fwd->connect_host = xstrdup("socks"); 2974a0ee8cc6SDag-Erling Smørgrav } 2975cce7d346SDag-Erling Smørgrav break; 2976cce7d346SDag-Erling Smørgrav 2977aa49c926SDag-Erling Smørgrav case 3: 2978a0ee8cc6SDag-Erling Smørgrav if (fwdargs[0].ispath) { 2979a0ee8cc6SDag-Erling Smørgrav fwd->listen_path = xstrdup(fwdargs[0].arg); 2980a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = PORT_STREAMLOCAL; 2981a0ee8cc6SDag-Erling Smørgrav fwd->connect_host = xstrdup(fwdargs[1].arg); 2982a0ee8cc6SDag-Erling Smørgrav fwd->connect_port = a2port(fwdargs[2].arg); 2983a0ee8cc6SDag-Erling Smørgrav } else if (fwdargs[2].ispath) { 2984a0ee8cc6SDag-Erling Smørgrav fwd->listen_host = xstrdup(fwdargs[0].arg); 2985a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = a2port(fwdargs[1].arg); 2986a0ee8cc6SDag-Erling Smørgrav fwd->connect_path = xstrdup(fwdargs[2].arg); 2987a0ee8cc6SDag-Erling Smørgrav fwd->connect_port = PORT_STREAMLOCAL; 2988a0ee8cc6SDag-Erling Smørgrav } else { 2989aa49c926SDag-Erling Smørgrav fwd->listen_host = NULL; 2990a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = a2port(fwdargs[0].arg); 2991a0ee8cc6SDag-Erling Smørgrav fwd->connect_host = xstrdup(fwdargs[1].arg); 2992a0ee8cc6SDag-Erling Smørgrav fwd->connect_port = a2port(fwdargs[2].arg); 2993a0ee8cc6SDag-Erling Smørgrav } 2994aa49c926SDag-Erling Smørgrav break; 2995aa49c926SDag-Erling Smørgrav 2996aa49c926SDag-Erling Smørgrav case 4: 2997a0ee8cc6SDag-Erling Smørgrav fwd->listen_host = xstrdup(fwdargs[0].arg); 2998a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = a2port(fwdargs[1].arg); 2999a0ee8cc6SDag-Erling Smørgrav fwd->connect_host = xstrdup(fwdargs[2].arg); 3000a0ee8cc6SDag-Erling Smørgrav fwd->connect_port = a2port(fwdargs[3].arg); 3001aa49c926SDag-Erling Smørgrav break; 3002aa49c926SDag-Erling Smørgrav default: 3003aa49c926SDag-Erling Smørgrav i = 0; /* failure */ 3004aa49c926SDag-Erling Smørgrav } 3005aa49c926SDag-Erling Smørgrav 3006e4a9863fSDag-Erling Smørgrav free(p); 3007aa49c926SDag-Erling Smørgrav 3008cce7d346SDag-Erling Smørgrav if (dynamicfwd) { 3009cce7d346SDag-Erling Smørgrav if (!(i == 1 || i == 2)) 3010cce7d346SDag-Erling Smørgrav goto fail_free; 3011cce7d346SDag-Erling Smørgrav } else { 3012a0ee8cc6SDag-Erling Smørgrav if (!(i == 3 || i == 4)) { 3013a0ee8cc6SDag-Erling Smørgrav if (fwd->connect_path == NULL && 3014a0ee8cc6SDag-Erling Smørgrav fwd->listen_path == NULL) 3015cce7d346SDag-Erling Smørgrav goto fail_free; 3016a0ee8cc6SDag-Erling Smørgrav } 3017a0ee8cc6SDag-Erling Smørgrav if (fwd->connect_port <= 0 && fwd->connect_path == NULL) 3018cce7d346SDag-Erling Smørgrav goto fail_free; 3019cce7d346SDag-Erling Smørgrav } 3020cce7d346SDag-Erling Smørgrav 3021a0ee8cc6SDag-Erling Smørgrav if ((fwd->listen_port < 0 && fwd->listen_path == NULL) || 3022a0ee8cc6SDag-Erling Smørgrav (!remotefwd && fwd->listen_port == 0)) 3023aa49c926SDag-Erling Smørgrav goto fail_free; 3024aa49c926SDag-Erling Smørgrav if (fwd->connect_host != NULL && 3025aa49c926SDag-Erling Smørgrav strlen(fwd->connect_host) >= NI_MAXHOST) 3026aa49c926SDag-Erling Smørgrav goto fail_free; 302719261079SEd Maste /* 302819261079SEd Maste * XXX - if connecting to a remote socket, max sun len may not 302919261079SEd Maste * match this host 303019261079SEd Maste */ 3031a0ee8cc6SDag-Erling Smørgrav if (fwd->connect_path != NULL && 3032a0ee8cc6SDag-Erling Smørgrav strlen(fwd->connect_path) >= PATH_MAX_SUN) 3033a0ee8cc6SDag-Erling Smørgrav goto fail_free; 3034cce7d346SDag-Erling Smørgrav if (fwd->listen_host != NULL && 3035cce7d346SDag-Erling Smørgrav strlen(fwd->listen_host) >= NI_MAXHOST) 3036cce7d346SDag-Erling Smørgrav goto fail_free; 3037a0ee8cc6SDag-Erling Smørgrav if (fwd->listen_path != NULL && 3038a0ee8cc6SDag-Erling Smørgrav strlen(fwd->listen_path) >= PATH_MAX_SUN) 3039a0ee8cc6SDag-Erling Smørgrav goto fail_free; 3040aa49c926SDag-Erling Smørgrav 3041aa49c926SDag-Erling Smørgrav return (i); 3042aa49c926SDag-Erling Smørgrav 3043aa49c926SDag-Erling Smørgrav fail_free: 3044e4a9863fSDag-Erling Smørgrav free(fwd->connect_host); 3045cce7d346SDag-Erling Smørgrav fwd->connect_host = NULL; 3046a0ee8cc6SDag-Erling Smørgrav free(fwd->connect_path); 3047a0ee8cc6SDag-Erling Smørgrav fwd->connect_path = NULL; 3048e4a9863fSDag-Erling Smørgrav free(fwd->listen_host); 3049cce7d346SDag-Erling Smørgrav fwd->listen_host = NULL; 3050a0ee8cc6SDag-Erling Smørgrav free(fwd->listen_path); 3051a0ee8cc6SDag-Erling Smørgrav fwd->listen_path = NULL; 3052aa49c926SDag-Erling Smørgrav return (0); 3053aa49c926SDag-Erling Smørgrav } 3054bc5531deSDag-Erling Smørgrav 3055076ad2f8SDag-Erling Smørgrav int 3056076ad2f8SDag-Erling Smørgrav parse_jump(const char *s, Options *o, int active) 3057076ad2f8SDag-Erling Smørgrav { 3058076ad2f8SDag-Erling Smørgrav char *orig, *sdup, *cp; 3059076ad2f8SDag-Erling Smørgrav char *host = NULL, *user = NULL; 306019261079SEd Maste int r, ret = -1, port = -1, first; 3061076ad2f8SDag-Erling Smørgrav 3062076ad2f8SDag-Erling Smørgrav active &= o->proxy_command == NULL && o->jump_host == NULL; 3063076ad2f8SDag-Erling Smørgrav 3064076ad2f8SDag-Erling Smørgrav orig = sdup = xstrdup(s); 306519261079SEd Maste 306619261079SEd Maste /* Remove comment and trailing whitespace */ 306719261079SEd Maste if ((cp = strchr(orig, '#')) != NULL) 306819261079SEd Maste *cp = '\0'; 306919261079SEd Maste rtrim(orig); 307019261079SEd Maste 3071076ad2f8SDag-Erling Smørgrav first = active; 3072076ad2f8SDag-Erling Smørgrav do { 3073190cef3dSDag-Erling Smørgrav if (strcasecmp(s, "none") == 0) 3074190cef3dSDag-Erling Smørgrav break; 3075076ad2f8SDag-Erling Smørgrav if ((cp = strrchr(sdup, ',')) == NULL) 3076076ad2f8SDag-Erling Smørgrav cp = sdup; /* last */ 3077076ad2f8SDag-Erling Smørgrav else 3078076ad2f8SDag-Erling Smørgrav *cp++ = '\0'; 3079076ad2f8SDag-Erling Smørgrav 3080076ad2f8SDag-Erling Smørgrav if (first) { 3081076ad2f8SDag-Erling Smørgrav /* First argument and configuration is active */ 308219261079SEd Maste r = parse_ssh_uri(cp, &user, &host, &port); 308319261079SEd Maste if (r == -1 || (r == 1 && 308419261079SEd Maste parse_user_host_port(cp, &user, &host, &port) != 0)) 3085076ad2f8SDag-Erling Smørgrav goto out; 3086076ad2f8SDag-Erling Smørgrav } else { 3087076ad2f8SDag-Erling Smørgrav /* Subsequent argument or inactive configuration */ 308819261079SEd Maste r = parse_ssh_uri(cp, NULL, NULL, NULL); 308919261079SEd Maste if (r == -1 || (r == 1 && 309019261079SEd Maste parse_user_host_port(cp, NULL, NULL, NULL) != 0)) 3091076ad2f8SDag-Erling Smørgrav goto out; 3092076ad2f8SDag-Erling Smørgrav } 3093076ad2f8SDag-Erling Smørgrav first = 0; /* only check syntax for subsequent hosts */ 3094076ad2f8SDag-Erling Smørgrav } while (cp != sdup); 3095076ad2f8SDag-Erling Smørgrav /* success */ 3096076ad2f8SDag-Erling Smørgrav if (active) { 3097190cef3dSDag-Erling Smørgrav if (strcasecmp(s, "none") == 0) { 3098190cef3dSDag-Erling Smørgrav o->jump_host = xstrdup("none"); 3099190cef3dSDag-Erling Smørgrav o->jump_port = 0; 3100190cef3dSDag-Erling Smørgrav } else { 3101076ad2f8SDag-Erling Smørgrav o->jump_user = user; 3102076ad2f8SDag-Erling Smørgrav o->jump_host = host; 3103076ad2f8SDag-Erling Smørgrav o->jump_port = port; 3104076ad2f8SDag-Erling Smørgrav o->proxy_command = xstrdup("none"); 3105076ad2f8SDag-Erling Smørgrav user = host = NULL; 3106076ad2f8SDag-Erling Smørgrav if ((cp = strrchr(s, ',')) != NULL && cp != s) { 3107076ad2f8SDag-Erling Smørgrav o->jump_extra = xstrdup(s); 3108076ad2f8SDag-Erling Smørgrav o->jump_extra[cp - s] = '\0'; 3109076ad2f8SDag-Erling Smørgrav } 3110076ad2f8SDag-Erling Smørgrav } 3111190cef3dSDag-Erling Smørgrav } 3112076ad2f8SDag-Erling Smørgrav ret = 0; 3113076ad2f8SDag-Erling Smørgrav out: 3114076ad2f8SDag-Erling Smørgrav free(orig); 3115076ad2f8SDag-Erling Smørgrav free(user); 3116076ad2f8SDag-Erling Smørgrav free(host); 3117076ad2f8SDag-Erling Smørgrav return ret; 3118076ad2f8SDag-Erling Smørgrav } 3119076ad2f8SDag-Erling Smørgrav 312047dd1d1bSDag-Erling Smørgrav int 312147dd1d1bSDag-Erling Smørgrav parse_ssh_uri(const char *uri, char **userp, char **hostp, int *portp) 312247dd1d1bSDag-Erling Smørgrav { 312319261079SEd Maste char *user = NULL, *host = NULL, *path = NULL; 312419261079SEd Maste int r, port; 312547dd1d1bSDag-Erling Smørgrav 312619261079SEd Maste r = parse_uri("ssh", uri, &user, &host, &port, &path); 312747dd1d1bSDag-Erling Smørgrav if (r == 0 && path != NULL) 312847dd1d1bSDag-Erling Smørgrav r = -1; /* path not allowed */ 312919261079SEd Maste if (r == 0) { 313019261079SEd Maste if (userp != NULL) { 313119261079SEd Maste *userp = user; 313219261079SEd Maste user = NULL; 313319261079SEd Maste } 313419261079SEd Maste if (hostp != NULL) { 313519261079SEd Maste *hostp = host; 313619261079SEd Maste host = NULL; 313719261079SEd Maste } 313819261079SEd Maste if (portp != NULL) 313919261079SEd Maste *portp = port; 314019261079SEd Maste } 314119261079SEd Maste free(user); 314219261079SEd Maste free(host); 314319261079SEd Maste free(path); 314447dd1d1bSDag-Erling Smørgrav return r; 314547dd1d1bSDag-Erling Smørgrav } 314647dd1d1bSDag-Erling Smørgrav 3147bc5531deSDag-Erling Smørgrav /* XXX the following is a near-vebatim copy from servconf.c; refactor */ 3148bc5531deSDag-Erling Smørgrav static const char * 3149bc5531deSDag-Erling Smørgrav fmt_multistate_int(int val, const struct multistate *m) 3150bc5531deSDag-Erling Smørgrav { 3151bc5531deSDag-Erling Smørgrav u_int i; 3152bc5531deSDag-Erling Smørgrav 3153bc5531deSDag-Erling Smørgrav for (i = 0; m[i].key != NULL; i++) { 3154bc5531deSDag-Erling Smørgrav if (m[i].value == val) 3155bc5531deSDag-Erling Smørgrav return m[i].key; 3156bc5531deSDag-Erling Smørgrav } 3157bc5531deSDag-Erling Smørgrav return "UNKNOWN"; 3158bc5531deSDag-Erling Smørgrav } 3159bc5531deSDag-Erling Smørgrav 3160bc5531deSDag-Erling Smørgrav static const char * 3161bc5531deSDag-Erling Smørgrav fmt_intarg(OpCodes code, int val) 3162bc5531deSDag-Erling Smørgrav { 3163bc5531deSDag-Erling Smørgrav if (val == -1) 3164bc5531deSDag-Erling Smørgrav return "unset"; 3165bc5531deSDag-Erling Smørgrav switch (code) { 3166bc5531deSDag-Erling Smørgrav case oAddressFamily: 3167bc5531deSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_addressfamily); 3168bc5531deSDag-Erling Smørgrav case oVerifyHostKeyDNS: 3169bc5531deSDag-Erling Smørgrav case oUpdateHostkeys: 3170bc5531deSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_yesnoask); 31714f52dfbbSDag-Erling Smørgrav case oStrictHostKeyChecking: 31724f52dfbbSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_strict_hostkey); 3173bc5531deSDag-Erling Smørgrav case oControlMaster: 3174bc5531deSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_controlmaster); 3175bc5531deSDag-Erling Smørgrav case oTunnel: 3176bc5531deSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_tunnel); 3177bc5531deSDag-Erling Smørgrav case oRequestTTY: 3178bc5531deSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_requesttty); 317919261079SEd Maste case oSessionType: 318019261079SEd Maste return fmt_multistate_int(val, multistate_sessiontype); 3181bc5531deSDag-Erling Smørgrav case oCanonicalizeHostname: 3182bc5531deSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_canonicalizehostname); 3183190cef3dSDag-Erling Smørgrav case oAddKeysToAgent: 3184190cef3dSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_yesnoaskconfirm); 3185*1323ec57SEd Maste case oPubkeyAuthentication: 3186*1323ec57SEd Maste return fmt_multistate_int(val, multistate_pubkey_auth); 3187bc5531deSDag-Erling Smørgrav case oFingerprintHash: 3188bc5531deSDag-Erling Smørgrav return ssh_digest_alg_name(val); 3189bc5531deSDag-Erling Smørgrav default: 3190bc5531deSDag-Erling Smørgrav switch (val) { 3191bc5531deSDag-Erling Smørgrav case 0: 3192bc5531deSDag-Erling Smørgrav return "no"; 3193bc5531deSDag-Erling Smørgrav case 1: 3194bc5531deSDag-Erling Smørgrav return "yes"; 3195bc5531deSDag-Erling Smørgrav default: 3196bc5531deSDag-Erling Smørgrav return "UNKNOWN"; 3197bc5531deSDag-Erling Smørgrav } 3198bc5531deSDag-Erling Smørgrav } 3199bc5531deSDag-Erling Smørgrav } 3200bc5531deSDag-Erling Smørgrav 3201bc5531deSDag-Erling Smørgrav static const char * 3202bc5531deSDag-Erling Smørgrav lookup_opcode_name(OpCodes code) 3203bc5531deSDag-Erling Smørgrav { 3204bc5531deSDag-Erling Smørgrav u_int i; 3205bc5531deSDag-Erling Smørgrav 3206bc5531deSDag-Erling Smørgrav for (i = 0; keywords[i].name != NULL; i++) 3207bc5531deSDag-Erling Smørgrav if (keywords[i].opcode == code) 3208bc5531deSDag-Erling Smørgrav return(keywords[i].name); 3209bc5531deSDag-Erling Smørgrav return "UNKNOWN"; 3210bc5531deSDag-Erling Smørgrav } 3211bc5531deSDag-Erling Smørgrav 3212bc5531deSDag-Erling Smørgrav static void 3213bc5531deSDag-Erling Smørgrav dump_cfg_int(OpCodes code, int val) 3214bc5531deSDag-Erling Smørgrav { 3215bc5531deSDag-Erling Smørgrav printf("%s %d\n", lookup_opcode_name(code), val); 3216bc5531deSDag-Erling Smørgrav } 3217bc5531deSDag-Erling Smørgrav 3218bc5531deSDag-Erling Smørgrav static void 3219bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(OpCodes code, int val) 3220bc5531deSDag-Erling Smørgrav { 3221bc5531deSDag-Erling Smørgrav printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val)); 3222bc5531deSDag-Erling Smørgrav } 3223bc5531deSDag-Erling Smørgrav 3224bc5531deSDag-Erling Smørgrav static void 3225bc5531deSDag-Erling Smørgrav dump_cfg_string(OpCodes code, const char *val) 3226bc5531deSDag-Erling Smørgrav { 3227bc5531deSDag-Erling Smørgrav if (val == NULL) 3228bc5531deSDag-Erling Smørgrav return; 3229bc5531deSDag-Erling Smørgrav printf("%s %s\n", lookup_opcode_name(code), val); 3230bc5531deSDag-Erling Smørgrav } 3231bc5531deSDag-Erling Smørgrav 3232bc5531deSDag-Erling Smørgrav static void 3233bc5531deSDag-Erling Smørgrav dump_cfg_strarray(OpCodes code, u_int count, char **vals) 3234bc5531deSDag-Erling Smørgrav { 3235bc5531deSDag-Erling Smørgrav u_int i; 3236bc5531deSDag-Erling Smørgrav 3237bc5531deSDag-Erling Smørgrav for (i = 0; i < count; i++) 3238bc5531deSDag-Erling Smørgrav printf("%s %s\n", lookup_opcode_name(code), vals[i]); 3239bc5531deSDag-Erling Smørgrav } 3240bc5531deSDag-Erling Smørgrav 3241bc5531deSDag-Erling Smørgrav static void 3242bc5531deSDag-Erling Smørgrav dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals) 3243bc5531deSDag-Erling Smørgrav { 3244bc5531deSDag-Erling Smørgrav u_int i; 3245bc5531deSDag-Erling Smørgrav 3246bc5531deSDag-Erling Smørgrav printf("%s", lookup_opcode_name(code)); 324719261079SEd Maste if (count == 0) 324819261079SEd Maste printf(" none"); 3249bc5531deSDag-Erling Smørgrav for (i = 0; i < count; i++) 3250bc5531deSDag-Erling Smørgrav printf(" %s", vals[i]); 3251bc5531deSDag-Erling Smørgrav printf("\n"); 3252bc5531deSDag-Erling Smørgrav } 3253bc5531deSDag-Erling Smørgrav 3254bc5531deSDag-Erling Smørgrav static void 3255bc5531deSDag-Erling Smørgrav dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds) 3256bc5531deSDag-Erling Smørgrav { 3257bc5531deSDag-Erling Smørgrav const struct Forward *fwd; 3258bc5531deSDag-Erling Smørgrav u_int i; 3259bc5531deSDag-Erling Smørgrav 3260bc5531deSDag-Erling Smørgrav /* oDynamicForward */ 3261bc5531deSDag-Erling Smørgrav for (i = 0; i < count; i++) { 3262bc5531deSDag-Erling Smørgrav fwd = &fwds[i]; 3263d93a896eSDag-Erling Smørgrav if (code == oDynamicForward && fwd->connect_host != NULL && 3264bc5531deSDag-Erling Smørgrav strcmp(fwd->connect_host, "socks") != 0) 3265bc5531deSDag-Erling Smørgrav continue; 3266d93a896eSDag-Erling Smørgrav if (code == oLocalForward && fwd->connect_host != NULL && 3267bc5531deSDag-Erling Smørgrav strcmp(fwd->connect_host, "socks") == 0) 3268bc5531deSDag-Erling Smørgrav continue; 3269bc5531deSDag-Erling Smørgrav printf("%s", lookup_opcode_name(code)); 3270bc5531deSDag-Erling Smørgrav if (fwd->listen_port == PORT_STREAMLOCAL) 3271bc5531deSDag-Erling Smørgrav printf(" %s", fwd->listen_path); 3272bc5531deSDag-Erling Smørgrav else if (fwd->listen_host == NULL) 3273bc5531deSDag-Erling Smørgrav printf(" %d", fwd->listen_port); 3274bc5531deSDag-Erling Smørgrav else { 3275bc5531deSDag-Erling Smørgrav printf(" [%s]:%d", 3276bc5531deSDag-Erling Smørgrav fwd->listen_host, fwd->listen_port); 3277bc5531deSDag-Erling Smørgrav } 3278bc5531deSDag-Erling Smørgrav if (code != oDynamicForward) { 3279bc5531deSDag-Erling Smørgrav if (fwd->connect_port == PORT_STREAMLOCAL) 3280bc5531deSDag-Erling Smørgrav printf(" %s", fwd->connect_path); 3281bc5531deSDag-Erling Smørgrav else if (fwd->connect_host == NULL) 3282bc5531deSDag-Erling Smørgrav printf(" %d", fwd->connect_port); 3283bc5531deSDag-Erling Smørgrav else { 3284bc5531deSDag-Erling Smørgrav printf(" [%s]:%d", 3285bc5531deSDag-Erling Smørgrav fwd->connect_host, fwd->connect_port); 3286bc5531deSDag-Erling Smørgrav } 3287bc5531deSDag-Erling Smørgrav } 3288bc5531deSDag-Erling Smørgrav printf("\n"); 3289bc5531deSDag-Erling Smørgrav } 3290bc5531deSDag-Erling Smørgrav } 3291bc5531deSDag-Erling Smørgrav 3292bc5531deSDag-Erling Smørgrav void 3293bc5531deSDag-Erling Smørgrav dump_client_config(Options *o, const char *host) 3294bc5531deSDag-Erling Smørgrav { 329519261079SEd Maste int i, r; 3296190cef3dSDag-Erling Smørgrav char buf[8], *all_key; 3297bc5531deSDag-Erling Smørgrav 329819261079SEd Maste /* 329919261079SEd Maste * Expand HostKeyAlgorithms name lists. This isn't handled in 330019261079SEd Maste * fill_default_options() like the other algorithm lists because 330119261079SEd Maste * the host key algorithms are by default dynamically chosen based 330219261079SEd Maste * on the host's keys found in known_hosts. 330319261079SEd Maste */ 3304190cef3dSDag-Erling Smørgrav all_key = sshkey_alg_list(0, 0, 1, ','); 330519261079SEd Maste if ((r = kex_assemble_names(&o->hostkeyalgorithms, kex_default_pk_alg(), 330619261079SEd Maste all_key)) != 0) 330719261079SEd Maste fatal_fr(r, "expand HostKeyAlgorithms"); 3308190cef3dSDag-Erling Smørgrav free(all_key); 3309acc1a9efSDag-Erling Smørgrav 3310bc5531deSDag-Erling Smørgrav /* Most interesting options first: user, host, port */ 3311bc5531deSDag-Erling Smørgrav dump_cfg_string(oUser, o->user); 331219261079SEd Maste dump_cfg_string(oHostname, host); 3313bc5531deSDag-Erling Smørgrav dump_cfg_int(oPort, o->port); 3314bc5531deSDag-Erling Smørgrav 3315bc5531deSDag-Erling Smørgrav /* Flag options */ 3316bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oAddressFamily, o->address_family); 3317bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oBatchMode, o->batch_mode); 3318bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local); 3319bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname); 3320bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oCheckHostIP, o->check_host_ip); 3321bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oCompression, o->compression); 3322bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oControlMaster, o->control_master); 3323bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign); 3324076ad2f8SDag-Erling Smørgrav dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings); 3325bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure); 3326bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash); 3327bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oForwardX11, o->forward_x11); 3328bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted); 3329bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports); 3330bc5531deSDag-Erling Smørgrav #ifdef GSSAPI 3331bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oGssAuthentication, o->gss_authentication); 3332bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds); 3333bc5531deSDag-Erling Smørgrav #endif /* GSSAPI */ 3334bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts); 3335bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication); 3336bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oIdentitiesOnly, o->identities_only); 3337bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication); 3338bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost); 3339bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication); 3340bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command); 3341bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass); 3342bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication); 3343bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oRequestTTY, o->request_tty); 334419261079SEd Maste dump_cfg_fmtint(oSessionType, o->session_type); 334519261079SEd Maste dump_cfg_fmtint(oStdinNull, o->stdin_null); 334619261079SEd Maste dump_cfg_fmtint(oForkAfterAuthentication, o->fork_after_authentication); 3347bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); 3348bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking); 3349bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive); 3350bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oTunnel, o->tun_open); 3351bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns); 3352bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oVisualHostKey, o->visual_host_key); 3353bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys); 3354bc5531deSDag-Erling Smørgrav 3355bc5531deSDag-Erling Smørgrav /* Integer options */ 3356bc5531deSDag-Erling Smørgrav dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots); 3357bc5531deSDag-Erling Smørgrav dump_cfg_int(oConnectionAttempts, o->connection_attempts); 3358bc5531deSDag-Erling Smørgrav dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout); 3359bc5531deSDag-Erling Smørgrav dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts); 3360bc5531deSDag-Erling Smørgrav dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max); 3361bc5531deSDag-Erling Smørgrav dump_cfg_int(oServerAliveInterval, o->server_alive_interval); 3362bc5531deSDag-Erling Smørgrav 3363bc5531deSDag-Erling Smørgrav /* String options */ 3364bc5531deSDag-Erling Smørgrav dump_cfg_string(oBindAddress, o->bind_address); 336547dd1d1bSDag-Erling Smørgrav dump_cfg_string(oBindInterface, o->bind_interface); 336619261079SEd Maste dump_cfg_string(oCiphers, o->ciphers); 3367bc5531deSDag-Erling Smørgrav dump_cfg_string(oControlPath, o->control_path); 3368acc1a9efSDag-Erling Smørgrav dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms); 3369bc5531deSDag-Erling Smørgrav dump_cfg_string(oHostKeyAlias, o->host_key_alias); 337019261079SEd Maste dump_cfg_string(oHostbasedAcceptedAlgorithms, o->hostbased_accepted_algos); 3371076ad2f8SDag-Erling Smørgrav dump_cfg_string(oIdentityAgent, o->identity_agent); 3372190cef3dSDag-Erling Smørgrav dump_cfg_string(oIgnoreUnknown, o->ignored_unknown); 3373bc5531deSDag-Erling Smørgrav dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices); 337419261079SEd Maste dump_cfg_string(oKexAlgorithms, o->kex_algorithms); 337519261079SEd Maste dump_cfg_string(oCASignatureAlgorithms, o->ca_sign_algorithms); 3376bc5531deSDag-Erling Smørgrav dump_cfg_string(oLocalCommand, o->local_command); 33774f52dfbbSDag-Erling Smørgrav dump_cfg_string(oRemoteCommand, o->remote_command); 3378bc5531deSDag-Erling Smørgrav dump_cfg_string(oLogLevel, log_level_name(o->log_level)); 337919261079SEd Maste dump_cfg_string(oMacs, o->macs); 3380d93a896eSDag-Erling Smørgrav #ifdef ENABLE_PKCS11 3381bc5531deSDag-Erling Smørgrav dump_cfg_string(oPKCS11Provider, o->pkcs11_provider); 3382d93a896eSDag-Erling Smørgrav #endif 338319261079SEd Maste dump_cfg_string(oSecurityKeyProvider, o->sk_provider); 3384bc5531deSDag-Erling Smørgrav dump_cfg_string(oPreferredAuthentications, o->preferred_authentications); 338519261079SEd Maste dump_cfg_string(oPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos); 3386bc5531deSDag-Erling Smørgrav dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys); 3387bc5531deSDag-Erling Smørgrav dump_cfg_string(oXAuthLocation, o->xauth_location); 338819261079SEd Maste dump_cfg_string(oKnownHostsCommand, o->known_hosts_command); 3389bc5531deSDag-Erling Smørgrav 3390bc5531deSDag-Erling Smørgrav /* Forwards */ 3391bc5531deSDag-Erling Smørgrav dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards); 3392bc5531deSDag-Erling Smørgrav dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards); 3393bc5531deSDag-Erling Smørgrav dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards); 3394bc5531deSDag-Erling Smørgrav 3395bc5531deSDag-Erling Smørgrav /* String array options */ 3396bc5531deSDag-Erling Smørgrav dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files); 3397bc5531deSDag-Erling Smørgrav dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains); 3398190cef3dSDag-Erling Smørgrav dump_cfg_strarray(oCertificateFile, o->num_certificate_files, o->certificate_files); 3399bc5531deSDag-Erling Smørgrav dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles); 3400bc5531deSDag-Erling Smørgrav dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles); 3401bc5531deSDag-Erling Smørgrav dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env); 3402190cef3dSDag-Erling Smørgrav dump_cfg_strarray(oSetEnv, o->num_setenv, o->setenv); 340319261079SEd Maste dump_cfg_strarray_oneline(oLogVerbose, 340419261079SEd Maste o->num_log_verbose, o->log_verbose); 3405bc5531deSDag-Erling Smørgrav 3406bc5531deSDag-Erling Smørgrav /* Special cases */ 3407bc5531deSDag-Erling Smørgrav 340819261079SEd Maste /* PermitRemoteOpen */ 340919261079SEd Maste if (o->num_permitted_remote_opens == 0) 341019261079SEd Maste printf("%s any\n", lookup_opcode_name(oPermitRemoteOpen)); 341119261079SEd Maste else 341219261079SEd Maste dump_cfg_strarray_oneline(oPermitRemoteOpen, 341319261079SEd Maste o->num_permitted_remote_opens, o->permitted_remote_opens); 341419261079SEd Maste 341519261079SEd Maste /* AddKeysToAgent */ 341619261079SEd Maste if (o->add_keys_to_agent_lifespan <= 0) 341719261079SEd Maste dump_cfg_fmtint(oAddKeysToAgent, o->add_keys_to_agent); 341819261079SEd Maste else { 341919261079SEd Maste printf("addkeystoagent%s %d\n", 342019261079SEd Maste o->add_keys_to_agent == 3 ? " confirm" : "", 342119261079SEd Maste o->add_keys_to_agent_lifespan); 342219261079SEd Maste } 342319261079SEd Maste 342419261079SEd Maste /* oForwardAgent */ 342519261079SEd Maste if (o->forward_agent_sock_path == NULL) 342619261079SEd Maste dump_cfg_fmtint(oForwardAgent, o->forward_agent); 342719261079SEd Maste else 342819261079SEd Maste dump_cfg_string(oForwardAgent, o->forward_agent_sock_path); 342919261079SEd Maste 3430bc5531deSDag-Erling Smørgrav /* oConnectTimeout */ 3431bc5531deSDag-Erling Smørgrav if (o->connection_timeout == -1) 3432bc5531deSDag-Erling Smørgrav printf("connecttimeout none\n"); 3433bc5531deSDag-Erling Smørgrav else 3434bc5531deSDag-Erling Smørgrav dump_cfg_int(oConnectTimeout, o->connection_timeout); 3435bc5531deSDag-Erling Smørgrav 3436bc5531deSDag-Erling Smørgrav /* oTunnelDevice */ 3437bc5531deSDag-Erling Smørgrav printf("tunneldevice"); 3438bc5531deSDag-Erling Smørgrav if (o->tun_local == SSH_TUNID_ANY) 3439bc5531deSDag-Erling Smørgrav printf(" any"); 3440bc5531deSDag-Erling Smørgrav else 3441bc5531deSDag-Erling Smørgrav printf(" %d", o->tun_local); 3442bc5531deSDag-Erling Smørgrav if (o->tun_remote == SSH_TUNID_ANY) 3443bc5531deSDag-Erling Smørgrav printf(":any"); 3444bc5531deSDag-Erling Smørgrav else 3445bc5531deSDag-Erling Smørgrav printf(":%d", o->tun_remote); 3446bc5531deSDag-Erling Smørgrav printf("\n"); 3447bc5531deSDag-Erling Smørgrav 3448bc5531deSDag-Erling Smørgrav /* oCanonicalizePermittedCNAMEs */ 3449bc5531deSDag-Erling Smørgrav printf("canonicalizePermittedcnames"); 3450e9e8876aSEd Maste if (o->num_permitted_cnames == 0) 3451e9e8876aSEd Maste printf(" none"); 3452bc5531deSDag-Erling Smørgrav for (i = 0; i < o->num_permitted_cnames; i++) { 3453bc5531deSDag-Erling Smørgrav printf(" %s:%s", o->permitted_cnames[i].source_list, 3454bc5531deSDag-Erling Smørgrav o->permitted_cnames[i].target_list); 3455bc5531deSDag-Erling Smørgrav } 3456bc5531deSDag-Erling Smørgrav printf("\n"); 3457bc5531deSDag-Erling Smørgrav 3458bc5531deSDag-Erling Smørgrav /* oControlPersist */ 3459bc5531deSDag-Erling Smørgrav if (o->control_persist == 0 || o->control_persist_timeout == 0) 3460bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oControlPersist, o->control_persist); 3461bc5531deSDag-Erling Smørgrav else 3462bc5531deSDag-Erling Smørgrav dump_cfg_int(oControlPersist, o->control_persist_timeout); 3463bc5531deSDag-Erling Smørgrav 3464bc5531deSDag-Erling Smørgrav /* oEscapeChar */ 3465bc5531deSDag-Erling Smørgrav if (o->escape_char == SSH_ESCAPECHAR_NONE) 3466bc5531deSDag-Erling Smørgrav printf("escapechar none\n"); 3467bc5531deSDag-Erling Smørgrav else { 3468076ad2f8SDag-Erling Smørgrav vis(buf, o->escape_char, VIS_WHITE, 0); 3469076ad2f8SDag-Erling Smørgrav printf("escapechar %s\n", buf); 3470bc5531deSDag-Erling Smørgrav } 3471bc5531deSDag-Erling Smørgrav 3472bc5531deSDag-Erling Smørgrav /* oIPQoS */ 3473bc5531deSDag-Erling Smørgrav printf("ipqos %s ", iptos2str(o->ip_qos_interactive)); 3474bc5531deSDag-Erling Smørgrav printf("%s\n", iptos2str(o->ip_qos_bulk)); 3475bc5531deSDag-Erling Smørgrav 3476bc5531deSDag-Erling Smørgrav /* oRekeyLimit */ 3477acc1a9efSDag-Erling Smørgrav printf("rekeylimit %llu %d\n", 3478acc1a9efSDag-Erling Smørgrav (unsigned long long)o->rekey_limit, o->rekey_interval); 3479bc5531deSDag-Erling Smørgrav 3480bc5531deSDag-Erling Smørgrav /* oStreamLocalBindMask */ 3481bc5531deSDag-Erling Smørgrav printf("streamlocalbindmask 0%o\n", 3482bc5531deSDag-Erling Smørgrav o->fwd_opts.streamlocal_bind_mask); 3483076ad2f8SDag-Erling Smørgrav 3484190cef3dSDag-Erling Smørgrav /* oLogFacility */ 3485190cef3dSDag-Erling Smørgrav printf("syslogfacility %s\n", log_facility_name(o->log_facility)); 3486190cef3dSDag-Erling Smørgrav 3487076ad2f8SDag-Erling Smørgrav /* oProxyCommand / oProxyJump */ 3488076ad2f8SDag-Erling Smørgrav if (o->jump_host == NULL) 3489076ad2f8SDag-Erling Smørgrav dump_cfg_string(oProxyCommand, o->proxy_command); 3490076ad2f8SDag-Erling Smørgrav else { 3491076ad2f8SDag-Erling Smørgrav /* Check for numeric addresses */ 3492076ad2f8SDag-Erling Smørgrav i = strchr(o->jump_host, ':') != NULL || 3493076ad2f8SDag-Erling Smørgrav strspn(o->jump_host, "1234567890.") == strlen(o->jump_host); 3494076ad2f8SDag-Erling Smørgrav snprintf(buf, sizeof(buf), "%d", o->jump_port); 3495076ad2f8SDag-Erling Smørgrav printf("proxyjump %s%s%s%s%s%s%s%s%s\n", 3496076ad2f8SDag-Erling Smørgrav /* optional additional jump spec */ 3497076ad2f8SDag-Erling Smørgrav o->jump_extra == NULL ? "" : o->jump_extra, 3498076ad2f8SDag-Erling Smørgrav o->jump_extra == NULL ? "" : ",", 3499076ad2f8SDag-Erling Smørgrav /* optional user */ 3500076ad2f8SDag-Erling Smørgrav o->jump_user == NULL ? "" : o->jump_user, 3501076ad2f8SDag-Erling Smørgrav o->jump_user == NULL ? "" : "@", 3502076ad2f8SDag-Erling Smørgrav /* opening [ if hostname is numeric */ 3503076ad2f8SDag-Erling Smørgrav i ? "[" : "", 3504076ad2f8SDag-Erling Smørgrav /* mandatory hostname */ 3505076ad2f8SDag-Erling Smørgrav o->jump_host, 3506076ad2f8SDag-Erling Smørgrav /* closing ] if hostname is numeric */ 3507076ad2f8SDag-Erling Smørgrav i ? "]" : "", 3508076ad2f8SDag-Erling Smørgrav /* optional port number */ 3509076ad2f8SDag-Erling Smørgrav o->jump_port <= 0 ? "" : ":", 3510076ad2f8SDag-Erling Smørgrav o->jump_port <= 0 ? "" : buf); 3511076ad2f8SDag-Erling Smørgrav } 3512bc5531deSDag-Erling Smørgrav } 3513