12f513db7SEd Maste /* $OpenBSD: readconf.c,v 1.300 2018/10/05 14:26:09 naddy 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> 1977c2fe20SDag-Erling Smørgrav #ifdef VMWARE_GUEST_WORKAROUND 2077c2fe20SDag-Erling Smørgrav #include <sys/sysctl.h> 2177c2fe20SDag-Erling Smørgrav #endif 22333ee039SDag-Erling Smørgrav #include <sys/stat.h> 23333ee039SDag-Erling Smørgrav #include <sys/socket.h> 24f7167e0eSDag-Erling Smørgrav #include <sys/wait.h> 25a0ee8cc6SDag-Erling Smørgrav #include <sys/un.h> 26333ee039SDag-Erling Smørgrav 27333ee039SDag-Erling Smørgrav #include <netinet/in.h> 284a421b63SDag-Erling Smørgrav #include <netinet/in_systm.h> 294a421b63SDag-Erling Smørgrav #include <netinet/ip.h> 30b83788ffSDag-Erling Smørgrav #include <arpa/inet.h> 31333ee039SDag-Erling Smørgrav 32333ee039SDag-Erling Smørgrav #include <ctype.h> 33333ee039SDag-Erling Smørgrav #include <errno.h> 34f7167e0eSDag-Erling Smørgrav #include <fcntl.h> 35bc5531deSDag-Erling Smørgrav #include <limits.h> 36333ee039SDag-Erling Smørgrav #include <netdb.h> 37f7167e0eSDag-Erling Smørgrav #ifdef HAVE_PATHS_H 38f7167e0eSDag-Erling Smørgrav # include <paths.h> 39f7167e0eSDag-Erling Smørgrav #endif 40f7167e0eSDag-Erling Smørgrav #include <pwd.h> 41333ee039SDag-Erling Smørgrav #include <signal.h> 42333ee039SDag-Erling Smørgrav #include <stdarg.h> 43333ee039SDag-Erling Smørgrav #include <stdio.h> 44333ee039SDag-Erling Smørgrav #include <string.h> 45333ee039SDag-Erling Smørgrav #include <unistd.h> 46076ad2f8SDag-Erling Smørgrav #ifdef USE_SYSTEM_GLOB 47076ad2f8SDag-Erling Smørgrav # include <glob.h> 48076ad2f8SDag-Erling Smørgrav #else 49076ad2f8SDag-Erling Smørgrav # include "openbsd-compat/glob.h" 50076ad2f8SDag-Erling Smørgrav #endif 51e4a9863fSDag-Erling Smørgrav #ifdef HAVE_UTIL_H 52e4a9863fSDag-Erling Smørgrav #include <util.h> 53e4a9863fSDag-Erling Smørgrav #endif 54bc5531deSDag-Erling Smørgrav #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) 55bc5531deSDag-Erling Smørgrav # include <vis.h> 56bc5531deSDag-Erling Smørgrav #endif 57333ee039SDag-Erling Smørgrav 58511b41d2SMark Murray #include "xmalloc.h" 59333ee039SDag-Erling Smørgrav #include "ssh.h" 60190cef3dSDag-Erling Smørgrav #include "ssherr.h" 61e8aafc91SKris Kennaway #include "compat.h" 62ca3176e7SBrian Feldman #include "cipher.h" 63ca3176e7SBrian Feldman #include "pathnames.h" 64ca3176e7SBrian Feldman #include "log.h" 65bc5531deSDag-Erling Smørgrav #include "sshkey.h" 66a0ee8cc6SDag-Erling Smørgrav #include "misc.h" 67ca3176e7SBrian Feldman #include "readconf.h" 68ca3176e7SBrian Feldman #include "match.h" 69ca3176e7SBrian Feldman #include "kex.h" 70ca3176e7SBrian Feldman #include "mac.h" 71f7167e0eSDag-Erling Smørgrav #include "uidswap.h" 72bc5531deSDag-Erling Smørgrav #include "myproposal.h" 73bc5531deSDag-Erling Smørgrav #include "digest.h" 74cce7d346SDag-Erling Smørgrav #include "version.h" 75511b41d2SMark Murray 76511b41d2SMark Murray /* Format of the configuration file: 77511b41d2SMark Murray 78511b41d2SMark Murray # Configuration data is parsed as follows: 79511b41d2SMark Murray # 1. command line options 80511b41d2SMark Murray # 2. user-specific file 81511b41d2SMark Murray # 3. system-wide file 82511b41d2SMark Murray # Any configuration value is only changed the first time it is set. 83511b41d2SMark Murray # Thus, host-specific definitions should be at the beginning of the 84511b41d2SMark Murray # configuration file, and defaults at the end. 85511b41d2SMark Murray 86511b41d2SMark Murray # Host-specific declarations. These may override anything above. A single 87511b41d2SMark Murray # host may match multiple declarations; these are processed in the order 88511b41d2SMark Murray # that they are given in. 89511b41d2SMark Murray 90511b41d2SMark Murray Host *.ngs.fi ngs.fi 9180628bacSDag-Erling Smørgrav User foo 92511b41d2SMark Murray 93511b41d2SMark Murray Host fake.com 94511b41d2SMark Murray HostName another.host.name.real.org 95511b41d2SMark Murray User blaah 96511b41d2SMark Murray Port 34289 97511b41d2SMark Murray ForwardX11 no 98511b41d2SMark Murray ForwardAgent no 99511b41d2SMark Murray 100511b41d2SMark Murray Host books.com 101511b41d2SMark Murray RemoteForward 9999 shadows.cs.hut.fi:9999 102d93a896eSDag-Erling Smørgrav Ciphers 3des-cbc 103511b41d2SMark Murray 104511b41d2SMark Murray Host fascist.blob.com 105511b41d2SMark Murray Port 23123 106511b41d2SMark Murray User tylonen 107511b41d2SMark Murray PasswordAuthentication no 108511b41d2SMark Murray 109511b41d2SMark Murray Host puukko.hut.fi 110511b41d2SMark Murray User t35124p 111511b41d2SMark Murray ProxyCommand ssh-proxy %h %p 112511b41d2SMark Murray 113511b41d2SMark Murray Host *.fr 11480628bacSDag-Erling Smørgrav PublicKeyAuthentication no 115511b41d2SMark Murray 116511b41d2SMark Murray Host *.su 117d93a896eSDag-Erling Smørgrav Ciphers aes128-ctr 118511b41d2SMark Murray PasswordAuthentication no 119511b41d2SMark Murray 120b74df5b2SDag-Erling Smørgrav Host vpn.fake.com 121b74df5b2SDag-Erling Smørgrav Tunnel yes 122b74df5b2SDag-Erling Smørgrav TunnelDevice 3 123b74df5b2SDag-Erling Smørgrav 124511b41d2SMark Murray # Defaults for various options 125511b41d2SMark Murray Host * 126511b41d2SMark Murray ForwardAgent no 127ca3176e7SBrian Feldman ForwardX11 no 128511b41d2SMark Murray PasswordAuthentication yes 129511b41d2SMark Murray RSAAuthentication yes 130511b41d2SMark Murray RhostsRSAAuthentication yes 131511b41d2SMark Murray StrictHostKeyChecking yes 1321ec0d754SDag-Erling Smørgrav TcpKeepAlive no 133511b41d2SMark Murray IdentityFile ~/.ssh/identity 134511b41d2SMark Murray Port 22 135511b41d2SMark Murray EscapeChar ~ 136511b41d2SMark Murray 137511b41d2SMark Murray */ 138511b41d2SMark Murray 139076ad2f8SDag-Erling Smørgrav static int read_config_file_depth(const char *filename, struct passwd *pw, 140076ad2f8SDag-Erling Smørgrav const char *host, const char *original_host, Options *options, 141076ad2f8SDag-Erling Smørgrav int flags, int *activep, int depth); 142076ad2f8SDag-Erling Smørgrav static int process_config_line_depth(Options *options, struct passwd *pw, 143076ad2f8SDag-Erling Smørgrav const char *host, const char *original_host, char *line, 144076ad2f8SDag-Erling Smørgrav const char *filename, int linenum, int *activep, int flags, int depth); 145076ad2f8SDag-Erling Smørgrav 146511b41d2SMark Murray /* Keyword tokens. */ 147511b41d2SMark Murray 148511b41d2SMark Murray typedef enum { 149511b41d2SMark Murray oBadOption, 150eccfee6eSDag-Erling Smørgrav oVersionAddendum, 151076ad2f8SDag-Erling Smørgrav oHost, oMatch, oInclude, 152e2f6069cSDag-Erling Smørgrav oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout, 153e2f6069cSDag-Erling Smørgrav oGatewayPorts, oExitOnForwardFailure, 15480628bacSDag-Erling Smørgrav oPasswordAuthentication, oRSAAuthentication, 155ca3176e7SBrian Feldman oChallengeResponseAuthentication, oXAuthLocation, 156511b41d2SMark Murray oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward, 157076ad2f8SDag-Erling Smørgrav oCertificateFile, oAddKeysToAgent, oIdentityAgent, 158f7167e0eSDag-Erling Smørgrav oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand, 159511b41d2SMark Murray oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, 160511b41d2SMark Murray oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, 1611ec0d754SDag-Erling Smørgrav oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts, 1624f52dfbbSDag-Erling Smørgrav oUsePrivilegedPort, oLogFacility, oLogLevel, oCiphers, oMacs, 163bc5531deSDag-Erling Smørgrav oPubkeyAuthentication, 164ca3176e7SBrian Feldman oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, 165ca3176e7SBrian Feldman oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, 16647dd1d1bSDag-Erling Smørgrav oHostKeyAlgorithms, oBindAddress, oBindInterface, oPKCS11Provider, 1679e2cbe04SDag-Erling Smørgrav oClearAllForwardings, oNoHostAuthenticationForLocalhost, 168cf2b5f3bSDag-Erling Smørgrav oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, 169cf2b5f3bSDag-Erling Smørgrav oAddressFamily, oGssAuthentication, oGssDelegateCreds, 1705962c0e9SDag-Erling Smørgrav oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, 171190cef3dSDag-Erling Smørgrav oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist, 172e2f6069cSDag-Erling Smørgrav oHashKnownHosts, 1734f52dfbbSDag-Erling Smørgrav oTunnel, oTunnelDevice, 1744f52dfbbSDag-Erling Smørgrav oLocalCommand, oPermitLocalCommand, oRemoteCommand, 175acc1a9efSDag-Erling Smørgrav oVisualHostKey, 176f7167e0eSDag-Erling Smørgrav oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, 177f7167e0eSDag-Erling Smørgrav oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, 178f7167e0eSDag-Erling Smørgrav oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, 179bc5531deSDag-Erling Smørgrav oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys, 180bc5531deSDag-Erling Smørgrav oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes, 1812f513db7SEd Maste oPubkeyAcceptedKeyTypes, oCASignatureAlgorithms, oProxyJump, 1824f52dfbbSDag-Erling Smørgrav oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported 183511b41d2SMark Murray } OpCodes; 184511b41d2SMark Murray 185511b41d2SMark Murray /* Textual representations of the tokens. */ 186511b41d2SMark Murray 187511b41d2SMark Murray static struct { 188511b41d2SMark Murray const char *name; 189511b41d2SMark Murray OpCodes opcode; 190511b41d2SMark Murray } keywords[] = { 191d93a896eSDag-Erling Smørgrav /* Deprecated options */ 1924f52dfbbSDag-Erling Smørgrav { "protocol", oIgnore }, /* NB. silently ignored */ 1934f52dfbbSDag-Erling Smørgrav { "cipher", oDeprecated }, 194d93a896eSDag-Erling Smørgrav { "fallbacktorsh", oDeprecated }, 195d93a896eSDag-Erling Smørgrav { "globalknownhostsfile2", oDeprecated }, 196d93a896eSDag-Erling Smørgrav { "rhostsauthentication", oDeprecated }, 197d93a896eSDag-Erling Smørgrav { "userknownhostsfile2", oDeprecated }, 198d93a896eSDag-Erling Smørgrav { "useroaming", oDeprecated }, 199d93a896eSDag-Erling Smørgrav { "usersh", oDeprecated }, 200190cef3dSDag-Erling Smørgrav { "useprivilegedport", oDeprecated }, 201d93a896eSDag-Erling Smørgrav 202d93a896eSDag-Erling Smørgrav /* Unsupported options */ 203d93a896eSDag-Erling Smørgrav { "afstokenpassing", oUnsupported }, 204d93a896eSDag-Erling Smørgrav { "kerberosauthentication", oUnsupported }, 205d93a896eSDag-Erling Smørgrav { "kerberostgtpassing", oUnsupported }, 206d93a896eSDag-Erling Smørgrav 207d93a896eSDag-Erling Smørgrav /* Sometimes-unsupported options */ 208d93a896eSDag-Erling Smørgrav #if defined(GSSAPI) 209d93a896eSDag-Erling Smørgrav { "gssapiauthentication", oGssAuthentication }, 210d93a896eSDag-Erling Smørgrav { "gssapidelegatecredentials", oGssDelegateCreds }, 211d93a896eSDag-Erling Smørgrav # else 212d93a896eSDag-Erling Smørgrav { "gssapiauthentication", oUnsupported }, 213d93a896eSDag-Erling Smørgrav { "gssapidelegatecredentials", oUnsupported }, 214d93a896eSDag-Erling Smørgrav #endif 215d93a896eSDag-Erling Smørgrav #ifdef ENABLE_PKCS11 216d93a896eSDag-Erling Smørgrav { "smartcarddevice", oPKCS11Provider }, 217d93a896eSDag-Erling Smørgrav { "pkcs11provider", oPKCS11Provider }, 218d93a896eSDag-Erling Smørgrav # else 219d93a896eSDag-Erling Smørgrav { "smartcarddevice", oUnsupported }, 220d93a896eSDag-Erling Smørgrav { "pkcs11provider", oUnsupported }, 221d93a896eSDag-Erling Smørgrav #endif 222d93a896eSDag-Erling Smørgrav { "rsaauthentication", oUnsupported }, 223d93a896eSDag-Erling Smørgrav { "rhostsrsaauthentication", oUnsupported }, 224d93a896eSDag-Erling Smørgrav { "compressionlevel", oUnsupported }, 225d93a896eSDag-Erling Smørgrav 226511b41d2SMark Murray { "forwardagent", oForwardAgent }, 227511b41d2SMark Murray { "forwardx11", oForwardX11 }, 2281ec0d754SDag-Erling Smørgrav { "forwardx11trusted", oForwardX11Trusted }, 229e2f6069cSDag-Erling Smørgrav { "forwardx11timeout", oForwardX11Timeout }, 230333ee039SDag-Erling Smørgrav { "exitonforwardfailure", oExitOnForwardFailure }, 231c2d3a559SKris Kennaway { "xauthlocation", oXAuthLocation }, 232511b41d2SMark Murray { "gatewayports", oGatewayPorts }, 233511b41d2SMark Murray { "passwordauthentication", oPasswordAuthentication }, 23409958426SBrian Feldman { "kbdinteractiveauthentication", oKbdInteractiveAuthentication }, 23509958426SBrian Feldman { "kbdinteractivedevices", oKbdInteractiveDevices }, 236ca3176e7SBrian Feldman { "pubkeyauthentication", oPubkeyAuthentication }, 237ca3176e7SBrian Feldman { "dsaauthentication", oPubkeyAuthentication }, /* alias */ 238ca3176e7SBrian Feldman { "hostbasedauthentication", oHostbasedAuthentication }, 239ca3176e7SBrian Feldman { "challengeresponseauthentication", oChallengeResponseAuthentication }, 240190cef3dSDag-Erling Smørgrav { "skeyauthentication", oUnsupported }, 241ca3176e7SBrian Feldman { "tisauthentication", oChallengeResponseAuthentication }, /* alias */ 242511b41d2SMark Murray { "identityfile", oIdentityFile }, 243cce7d346SDag-Erling Smørgrav { "identityfile2", oIdentityFile }, /* obsolete */ 2445962c0e9SDag-Erling Smørgrav { "identitiesonly", oIdentitiesOnly }, 245acc1a9efSDag-Erling Smørgrav { "certificatefile", oCertificateFile }, 246acc1a9efSDag-Erling Smørgrav { "addkeystoagent", oAddKeysToAgent }, 247076ad2f8SDag-Erling Smørgrav { "identityagent", oIdentityAgent }, 248511b41d2SMark Murray { "hostname", oHostName }, 249ca3176e7SBrian Feldman { "hostkeyalias", oHostKeyAlias }, 250511b41d2SMark Murray { "proxycommand", oProxyCommand }, 251511b41d2SMark Murray { "port", oPort }, 252e8aafc91SKris Kennaway { "ciphers", oCiphers }, 253ca3176e7SBrian Feldman { "macs", oMacs }, 254511b41d2SMark Murray { "remoteforward", oRemoteForward }, 255511b41d2SMark Murray { "localforward", oLocalForward }, 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 }, 272ca3176e7SBrian Feldman { "dynamicforward", oDynamicForward }, 273ca3176e7SBrian Feldman { "preferredauthentications", oPreferredAuthentications }, 274ca3176e7SBrian Feldman { "hostkeyalgorithms", oHostKeyAlgorithms }, 2752f513db7SEd Maste { "casignaturealgorithms", oCASignatureAlgorithms }, 276af12a3e7SDag-Erling Smørgrav { "bindaddress", oBindAddress }, 27747dd1d1bSDag-Erling Smørgrav { "bindinterface", oBindInterface }, 278af12a3e7SDag-Erling Smørgrav { "clearallforwardings", oClearAllForwardings }, 279e73e9afaSDag-Erling Smørgrav { "enablesshkeysign", oEnableSSHKeysign }, 280cf2b5f3bSDag-Erling Smørgrav { "verifyhostkeydns", oVerifyHostKeyDNS }, 281af12a3e7SDag-Erling Smørgrav { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost }, 282cf2b5f3bSDag-Erling Smørgrav { "rekeylimit", oRekeyLimit }, 283cf2b5f3bSDag-Erling Smørgrav { "connecttimeout", oConnectTimeout }, 284cf2b5f3bSDag-Erling Smørgrav { "addressfamily", oAddressFamily }, 2851ec0d754SDag-Erling Smørgrav { "serveraliveinterval", oServerAliveInterval }, 2861ec0d754SDag-Erling Smørgrav { "serveralivecountmax", oServerAliveCountMax }, 28721e764dfSDag-Erling Smørgrav { "sendenv", oSendEnv }, 288190cef3dSDag-Erling Smørgrav { "setenv", oSetEnv }, 28921e764dfSDag-Erling Smørgrav { "controlpath", oControlPath }, 29021e764dfSDag-Erling Smørgrav { "controlmaster", oControlMaster }, 291e2f6069cSDag-Erling Smørgrav { "controlpersist", oControlPersist }, 292aa49c926SDag-Erling Smørgrav { "hashknownhosts", oHashKnownHosts }, 293076ad2f8SDag-Erling Smørgrav { "include", oInclude }, 294b74df5b2SDag-Erling Smørgrav { "tunnel", oTunnel }, 295b74df5b2SDag-Erling Smørgrav { "tunneldevice", oTunnelDevice }, 296b74df5b2SDag-Erling Smørgrav { "localcommand", oLocalCommand }, 297b74df5b2SDag-Erling Smørgrav { "permitlocalcommand", oPermitLocalCommand }, 2984f52dfbbSDag-Erling Smørgrav { "remotecommand", oRemoteCommand }, 299d4af9e69SDag-Erling Smørgrav { "visualhostkey", oVisualHostKey }, 3004a421b63SDag-Erling Smørgrav { "kexalgorithms", oKexAlgorithms }, 3014a421b63SDag-Erling Smørgrav { "ipqos", oIPQoS }, 302e146993eSDag-Erling Smørgrav { "requesttty", oRequestTTY }, 303f7167e0eSDag-Erling Smørgrav { "proxyusefdpass", oProxyUseFdpass }, 304f7167e0eSDag-Erling Smørgrav { "canonicaldomains", oCanonicalDomains }, 305f7167e0eSDag-Erling Smørgrav { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal }, 306f7167e0eSDag-Erling Smørgrav { "canonicalizehostname", oCanonicalizeHostname }, 307f7167e0eSDag-Erling Smørgrav { "canonicalizemaxdots", oCanonicalizeMaxDots }, 308f7167e0eSDag-Erling Smørgrav { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs }, 309a0ee8cc6SDag-Erling Smørgrav { "streamlocalbindmask", oStreamLocalBindMask }, 310a0ee8cc6SDag-Erling Smørgrav { "streamlocalbindunlink", oStreamLocalBindUnlink }, 311bc5531deSDag-Erling Smørgrav { "revokedhostkeys", oRevokedHostKeys }, 312bc5531deSDag-Erling Smørgrav { "fingerprinthash", oFingerprintHash }, 313bc5531deSDag-Erling Smørgrav { "updatehostkeys", oUpdateHostkeys }, 314bc5531deSDag-Erling Smørgrav { "hostbasedkeytypes", oHostbasedKeyTypes }, 315eccfee6eSDag-Erling Smørgrav { "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes }, 316e4a9863fSDag-Erling Smørgrav { "ignoreunknown", oIgnoreUnknown }, 317076ad2f8SDag-Erling Smørgrav { "proxyjump", oProxyJump }, 318076ad2f8SDag-Erling Smørgrav 3199860d96eSDag-Erling Smørgrav { "hpndisabled", oDeprecated }, 3209860d96eSDag-Erling Smørgrav { "hpnbuffersize", oDeprecated }, 3219860d96eSDag-Erling Smørgrav { "tcprcvbufpoll", oDeprecated }, 3229860d96eSDag-Erling Smørgrav { "tcprcvbuf", oDeprecated }, 32363620802SDag-Erling Smørgrav { "noneenabled", oUnsupported }, 32463620802SDag-Erling Smørgrav { "noneswitch", oUnsupported }, 325975616f0SDag-Erling Smørgrav { "versionaddendum", oVersionAddendum }, 32635762f59SEd Schouten 327af12a3e7SDag-Erling Smørgrav { NULL, oBadOption } 328511b41d2SMark Murray }; 329511b41d2SMark Murray 330511b41d2SMark Murray /* 331511b41d2SMark Murray * Adds a local TCP/IP port forward to options. Never returns if there is an 332511b41d2SMark Murray * error. 333511b41d2SMark Murray */ 334511b41d2SMark Murray 335511b41d2SMark Murray void 336a0ee8cc6SDag-Erling Smørgrav add_local_forward(Options *options, const struct Forward *newfwd) 337511b41d2SMark Murray { 338a0ee8cc6SDag-Erling Smørgrav struct Forward *fwd; 339*9e14b918SEd Maste int i; 34003f6c5cdSDag-Erling Smørgrav 341076ad2f8SDag-Erling Smørgrav /* Don't add duplicates */ 342076ad2f8SDag-Erling Smørgrav for (i = 0; i < options->num_local_forwards; i++) { 343076ad2f8SDag-Erling Smørgrav if (forward_equals(newfwd, options->local_forwards + i)) 344076ad2f8SDag-Erling Smørgrav return; 345076ad2f8SDag-Erling Smørgrav } 346557f75e5SDag-Erling Smørgrav options->local_forwards = xreallocarray(options->local_forwards, 347e2f6069cSDag-Erling Smørgrav options->num_local_forwards + 1, 348e2f6069cSDag-Erling Smørgrav sizeof(*options->local_forwards)); 349511b41d2SMark Murray fwd = &options->local_forwards[options->num_local_forwards++]; 350aa49c926SDag-Erling Smørgrav 351cce7d346SDag-Erling Smørgrav fwd->listen_host = newfwd->listen_host; 352aa49c926SDag-Erling Smørgrav fwd->listen_port = newfwd->listen_port; 353a0ee8cc6SDag-Erling Smørgrav fwd->listen_path = newfwd->listen_path; 354cce7d346SDag-Erling Smørgrav fwd->connect_host = newfwd->connect_host; 355aa49c926SDag-Erling Smørgrav fwd->connect_port = newfwd->connect_port; 356a0ee8cc6SDag-Erling Smørgrav fwd->connect_path = newfwd->connect_path; 357511b41d2SMark Murray } 358511b41d2SMark Murray 359511b41d2SMark Murray /* 360511b41d2SMark Murray * Adds a remote TCP/IP port forward to options. Never returns if there is 361511b41d2SMark Murray * an error. 362511b41d2SMark Murray */ 363511b41d2SMark Murray 364511b41d2SMark Murray void 365a0ee8cc6SDag-Erling Smørgrav add_remote_forward(Options *options, const struct Forward *newfwd) 366511b41d2SMark Murray { 367a0ee8cc6SDag-Erling Smørgrav struct Forward *fwd; 368076ad2f8SDag-Erling Smørgrav int i; 369e2f6069cSDag-Erling Smørgrav 370076ad2f8SDag-Erling Smørgrav /* Don't add duplicates */ 371076ad2f8SDag-Erling Smørgrav for (i = 0; i < options->num_remote_forwards; i++) { 372076ad2f8SDag-Erling Smørgrav if (forward_equals(newfwd, options->remote_forwards + i)) 373076ad2f8SDag-Erling Smørgrav return; 374076ad2f8SDag-Erling Smørgrav } 375557f75e5SDag-Erling Smørgrav options->remote_forwards = xreallocarray(options->remote_forwards, 376e2f6069cSDag-Erling Smørgrav options->num_remote_forwards + 1, 377e2f6069cSDag-Erling Smørgrav sizeof(*options->remote_forwards)); 378511b41d2SMark Murray fwd = &options->remote_forwards[options->num_remote_forwards++]; 379aa49c926SDag-Erling Smørgrav 380cce7d346SDag-Erling Smørgrav fwd->listen_host = newfwd->listen_host; 381aa49c926SDag-Erling Smørgrav fwd->listen_port = newfwd->listen_port; 382a0ee8cc6SDag-Erling Smørgrav fwd->listen_path = newfwd->listen_path; 383cce7d346SDag-Erling Smørgrav fwd->connect_host = newfwd->connect_host; 384aa49c926SDag-Erling Smørgrav fwd->connect_port = newfwd->connect_port; 385a0ee8cc6SDag-Erling Smørgrav fwd->connect_path = newfwd->connect_path; 386462c32cbSDag-Erling Smørgrav fwd->handle = newfwd->handle; 387e2f6069cSDag-Erling Smørgrav fwd->allocated_port = 0; 388511b41d2SMark Murray } 389511b41d2SMark Murray 390af12a3e7SDag-Erling Smørgrav static void 391af12a3e7SDag-Erling Smørgrav clear_forwardings(Options *options) 392af12a3e7SDag-Erling Smørgrav { 393af12a3e7SDag-Erling Smørgrav int i; 394af12a3e7SDag-Erling Smørgrav 395aa49c926SDag-Erling Smørgrav for (i = 0; i < options->num_local_forwards; i++) { 396e4a9863fSDag-Erling Smørgrav free(options->local_forwards[i].listen_host); 397a0ee8cc6SDag-Erling Smørgrav free(options->local_forwards[i].listen_path); 398e4a9863fSDag-Erling Smørgrav free(options->local_forwards[i].connect_host); 399a0ee8cc6SDag-Erling Smørgrav free(options->local_forwards[i].connect_path); 400aa49c926SDag-Erling Smørgrav } 401e2f6069cSDag-Erling Smørgrav if (options->num_local_forwards > 0) { 402e4a9863fSDag-Erling Smørgrav free(options->local_forwards); 403e2f6069cSDag-Erling Smørgrav options->local_forwards = NULL; 404e2f6069cSDag-Erling Smørgrav } 405af12a3e7SDag-Erling Smørgrav options->num_local_forwards = 0; 406aa49c926SDag-Erling Smørgrav for (i = 0; i < options->num_remote_forwards; i++) { 407e4a9863fSDag-Erling Smørgrav free(options->remote_forwards[i].listen_host); 408a0ee8cc6SDag-Erling Smørgrav free(options->remote_forwards[i].listen_path); 409e4a9863fSDag-Erling Smørgrav free(options->remote_forwards[i].connect_host); 410a0ee8cc6SDag-Erling Smørgrav free(options->remote_forwards[i].connect_path); 411aa49c926SDag-Erling Smørgrav } 412e2f6069cSDag-Erling Smørgrav if (options->num_remote_forwards > 0) { 413e4a9863fSDag-Erling Smørgrav free(options->remote_forwards); 414e2f6069cSDag-Erling Smørgrav options->remote_forwards = NULL; 415e2f6069cSDag-Erling Smørgrav } 416af12a3e7SDag-Erling Smørgrav options->num_remote_forwards = 0; 417b74df5b2SDag-Erling Smørgrav options->tun_open = SSH_TUNMODE_NO; 418af12a3e7SDag-Erling Smørgrav } 419af12a3e7SDag-Erling Smørgrav 420fa67e83cSDag-Erling Smørgrav void 421acc1a9efSDag-Erling Smørgrav add_certificate_file(Options *options, const char *path, int userprovided) 422acc1a9efSDag-Erling Smørgrav { 423acc1a9efSDag-Erling Smørgrav int i; 424acc1a9efSDag-Erling Smørgrav 425acc1a9efSDag-Erling Smørgrav if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES) 426acc1a9efSDag-Erling Smørgrav fatal("Too many certificate files specified (max %d)", 427acc1a9efSDag-Erling Smørgrav SSH_MAX_CERTIFICATE_FILES); 428acc1a9efSDag-Erling Smørgrav 429acc1a9efSDag-Erling Smørgrav /* Avoid registering duplicates */ 430acc1a9efSDag-Erling Smørgrav for (i = 0; i < options->num_certificate_files; i++) { 431acc1a9efSDag-Erling Smørgrav if (options->certificate_file_userprovided[i] == userprovided && 432acc1a9efSDag-Erling Smørgrav strcmp(options->certificate_files[i], path) == 0) { 433acc1a9efSDag-Erling Smørgrav debug2("%s: ignoring duplicate key %s", __func__, path); 434acc1a9efSDag-Erling Smørgrav return; 435acc1a9efSDag-Erling Smørgrav } 436acc1a9efSDag-Erling Smørgrav } 437acc1a9efSDag-Erling Smørgrav 438acc1a9efSDag-Erling Smørgrav options->certificate_file_userprovided[options->num_certificate_files] = 439acc1a9efSDag-Erling Smørgrav userprovided; 440acc1a9efSDag-Erling Smørgrav options->certificate_files[options->num_certificate_files++] = 441acc1a9efSDag-Erling Smørgrav xstrdup(path); 442acc1a9efSDag-Erling Smørgrav } 443acc1a9efSDag-Erling Smørgrav 444acc1a9efSDag-Erling Smørgrav void 445fa67e83cSDag-Erling Smørgrav add_identity_file(Options *options, const char *dir, const char *filename, 446fa67e83cSDag-Erling Smørgrav int userprovided) 447fa67e83cSDag-Erling Smørgrav { 448fa67e83cSDag-Erling Smørgrav char *path; 449a0ee8cc6SDag-Erling Smørgrav int i; 450fa67e83cSDag-Erling Smørgrav 451fa67e83cSDag-Erling Smørgrav if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES) 452fa67e83cSDag-Erling Smørgrav fatal("Too many identity files specified (max %d)", 453fa67e83cSDag-Erling Smørgrav SSH_MAX_IDENTITY_FILES); 454fa67e83cSDag-Erling Smørgrav 455fa67e83cSDag-Erling Smørgrav if (dir == NULL) /* no dir, filename is absolute */ 456fa67e83cSDag-Erling Smørgrav path = xstrdup(filename); 4574f52dfbbSDag-Erling Smørgrav else if (xasprintf(&path, "%s%s", dir, filename) >= PATH_MAX) 4584f52dfbbSDag-Erling Smørgrav fatal("Identity file path %s too long", path); 459fa67e83cSDag-Erling Smørgrav 460a0ee8cc6SDag-Erling Smørgrav /* Avoid registering duplicates */ 461a0ee8cc6SDag-Erling Smørgrav for (i = 0; i < options->num_identity_files; i++) { 462a0ee8cc6SDag-Erling Smørgrav if (options->identity_file_userprovided[i] == userprovided && 463a0ee8cc6SDag-Erling Smørgrav strcmp(options->identity_files[i], path) == 0) { 464a0ee8cc6SDag-Erling Smørgrav debug2("%s: ignoring duplicate key %s", __func__, path); 465a0ee8cc6SDag-Erling Smørgrav free(path); 466a0ee8cc6SDag-Erling Smørgrav return; 467a0ee8cc6SDag-Erling Smørgrav } 468a0ee8cc6SDag-Erling Smørgrav } 469a0ee8cc6SDag-Erling Smørgrav 470fa67e83cSDag-Erling Smørgrav options->identity_file_userprovided[options->num_identity_files] = 471fa67e83cSDag-Erling Smørgrav userprovided; 472fa67e83cSDag-Erling Smørgrav options->identity_files[options->num_identity_files++] = path; 473fa67e83cSDag-Erling Smørgrav } 474fa67e83cSDag-Erling Smørgrav 475f7167e0eSDag-Erling Smørgrav int 476f7167e0eSDag-Erling Smørgrav default_ssh_port(void) 477f7167e0eSDag-Erling Smørgrav { 478f7167e0eSDag-Erling Smørgrav static int port; 479f7167e0eSDag-Erling Smørgrav struct servent *sp; 480f7167e0eSDag-Erling Smørgrav 481f7167e0eSDag-Erling Smørgrav if (port == 0) { 482f7167e0eSDag-Erling Smørgrav sp = getservbyname(SSH_SERVICE_NAME, "tcp"); 483f7167e0eSDag-Erling Smørgrav port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT; 484f7167e0eSDag-Erling Smørgrav } 485f7167e0eSDag-Erling Smørgrav return port; 486f7167e0eSDag-Erling Smørgrav } 487f7167e0eSDag-Erling Smørgrav 488f7167e0eSDag-Erling Smørgrav /* 489f7167e0eSDag-Erling Smørgrav * Execute a command in a shell. 490f7167e0eSDag-Erling Smørgrav * Return its exit status or -1 on abnormal exit. 491f7167e0eSDag-Erling Smørgrav */ 492f7167e0eSDag-Erling Smørgrav static int 493f7167e0eSDag-Erling Smørgrav execute_in_shell(const char *cmd) 494f7167e0eSDag-Erling Smørgrav { 495acc1a9efSDag-Erling Smørgrav char *shell; 496f7167e0eSDag-Erling Smørgrav pid_t pid; 497f7167e0eSDag-Erling Smørgrav int devnull, status; 498f7167e0eSDag-Erling Smørgrav 499f7167e0eSDag-Erling Smørgrav if ((shell = getenv("SHELL")) == NULL) 500f7167e0eSDag-Erling Smørgrav shell = _PATH_BSHELL; 501f7167e0eSDag-Erling Smørgrav 502f7167e0eSDag-Erling Smørgrav /* Need this to redirect subprocess stdin/out */ 503f7167e0eSDag-Erling Smørgrav if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) 504f7167e0eSDag-Erling Smørgrav fatal("open(/dev/null): %s", strerror(errno)); 505f7167e0eSDag-Erling Smørgrav 506f7167e0eSDag-Erling Smørgrav debug("Executing command: '%.500s'", cmd); 507f7167e0eSDag-Erling Smørgrav 508f7167e0eSDag-Erling Smørgrav /* Fork and execute the command. */ 509f7167e0eSDag-Erling Smørgrav if ((pid = fork()) == 0) { 510f7167e0eSDag-Erling Smørgrav char *argv[4]; 511f7167e0eSDag-Erling Smørgrav 512f7167e0eSDag-Erling Smørgrav /* Redirect child stdin and stdout. Leave stderr */ 513f7167e0eSDag-Erling Smørgrav if (dup2(devnull, STDIN_FILENO) == -1) 514f7167e0eSDag-Erling Smørgrav fatal("dup2: %s", strerror(errno)); 515f7167e0eSDag-Erling Smørgrav if (dup2(devnull, STDOUT_FILENO) == -1) 516f7167e0eSDag-Erling Smørgrav fatal("dup2: %s", strerror(errno)); 517f7167e0eSDag-Erling Smørgrav if (devnull > STDERR_FILENO) 518f7167e0eSDag-Erling Smørgrav close(devnull); 519f7167e0eSDag-Erling Smørgrav closefrom(STDERR_FILENO + 1); 520f7167e0eSDag-Erling Smørgrav 521f7167e0eSDag-Erling Smørgrav argv[0] = shell; 522f7167e0eSDag-Erling Smørgrav argv[1] = "-c"; 523acc1a9efSDag-Erling Smørgrav argv[2] = xstrdup(cmd); 524f7167e0eSDag-Erling Smørgrav argv[3] = NULL; 525f7167e0eSDag-Erling Smørgrav 526f7167e0eSDag-Erling Smørgrav execv(argv[0], argv); 527f7167e0eSDag-Erling Smørgrav error("Unable to execute '%.100s': %s", cmd, strerror(errno)); 528f7167e0eSDag-Erling Smørgrav /* Die with signal to make this error apparent to parent. */ 529f7167e0eSDag-Erling Smørgrav signal(SIGTERM, SIG_DFL); 530f7167e0eSDag-Erling Smørgrav kill(getpid(), SIGTERM); 531f7167e0eSDag-Erling Smørgrav _exit(1); 532f7167e0eSDag-Erling Smørgrav } 533f7167e0eSDag-Erling Smørgrav /* Parent. */ 534f7167e0eSDag-Erling Smørgrav if (pid < 0) 535f7167e0eSDag-Erling Smørgrav fatal("%s: fork: %.100s", __func__, strerror(errno)); 536f7167e0eSDag-Erling Smørgrav 537f7167e0eSDag-Erling Smørgrav close(devnull); 538f7167e0eSDag-Erling Smørgrav 539f7167e0eSDag-Erling Smørgrav while (waitpid(pid, &status, 0) == -1) { 540f7167e0eSDag-Erling Smørgrav if (errno != EINTR && errno != EAGAIN) 541f7167e0eSDag-Erling Smørgrav fatal("%s: waitpid: %s", __func__, strerror(errno)); 542f7167e0eSDag-Erling Smørgrav } 543f7167e0eSDag-Erling Smørgrav if (!WIFEXITED(status)) { 544f7167e0eSDag-Erling Smørgrav error("command '%.100s' exited abnormally", cmd); 545f7167e0eSDag-Erling Smørgrav return -1; 546f7167e0eSDag-Erling Smørgrav } 547f7167e0eSDag-Erling Smørgrav debug3("command returned status %d", WEXITSTATUS(status)); 548f7167e0eSDag-Erling Smørgrav return WEXITSTATUS(status); 549f7167e0eSDag-Erling Smørgrav } 550f7167e0eSDag-Erling Smørgrav 551f7167e0eSDag-Erling Smørgrav /* 552f7167e0eSDag-Erling Smørgrav * Parse and execute a Match directive. 553f7167e0eSDag-Erling Smørgrav */ 554f7167e0eSDag-Erling Smørgrav static int 555f7167e0eSDag-Erling Smørgrav match_cfg_line(Options *options, char **condition, struct passwd *pw, 556bc5531deSDag-Erling Smørgrav const char *host_arg, const char *original_host, int post_canon, 557bc5531deSDag-Erling Smørgrav const char *filename, int linenum) 558f7167e0eSDag-Erling Smørgrav { 559bc5531deSDag-Erling Smørgrav char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria; 560f7167e0eSDag-Erling Smørgrav const char *ruser; 561bc5531deSDag-Erling Smørgrav int r, port, this_result, result = 1, attributes = 0, negate; 562f7167e0eSDag-Erling Smørgrav char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; 563190cef3dSDag-Erling Smørgrav char uidstr[32]; 564f7167e0eSDag-Erling Smørgrav 565f7167e0eSDag-Erling Smørgrav /* 566f7167e0eSDag-Erling Smørgrav * Configuration is likely to be incomplete at this point so we 567f7167e0eSDag-Erling Smørgrav * must be prepared to use default values. 568f7167e0eSDag-Erling Smørgrav */ 569f7167e0eSDag-Erling Smørgrav port = options->port <= 0 ? default_ssh_port() : options->port; 570f7167e0eSDag-Erling Smørgrav ruser = options->user == NULL ? pw->pw_name : options->user; 571acc1a9efSDag-Erling Smørgrav if (post_canon) { 572acc1a9efSDag-Erling Smørgrav host = xstrdup(options->hostname); 573acc1a9efSDag-Erling Smørgrav } else if (options->hostname != NULL) { 574f7167e0eSDag-Erling Smørgrav /* NB. Please keep in sync with ssh.c:main() */ 575f7167e0eSDag-Erling Smørgrav host = percent_expand(options->hostname, 576f7167e0eSDag-Erling Smørgrav "h", host_arg, (char *)NULL); 577acc1a9efSDag-Erling Smørgrav } else { 578f7167e0eSDag-Erling Smørgrav host = xstrdup(host_arg); 579acc1a9efSDag-Erling Smørgrav } 580f7167e0eSDag-Erling Smørgrav 581bc5531deSDag-Erling Smørgrav debug2("checking match for '%s' host %s originally %s", 582bc5531deSDag-Erling Smørgrav cp, host, original_host); 583bc5531deSDag-Erling Smørgrav while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') { 584bc5531deSDag-Erling Smørgrav criteria = NULL; 585bc5531deSDag-Erling Smørgrav this_result = 1; 586bc5531deSDag-Erling Smørgrav if ((negate = attrib[0] == '!')) 587bc5531deSDag-Erling Smørgrav attrib++; 588bc5531deSDag-Erling Smørgrav /* criteria "all" and "canonical" have no argument */ 589f7167e0eSDag-Erling Smørgrav if (strcasecmp(attrib, "all") == 0) { 590bc5531deSDag-Erling Smørgrav if (attributes > 1 || 591f7167e0eSDag-Erling Smørgrav ((arg = strdelim(&cp)) != NULL && *arg != '\0')) { 592bc5531deSDag-Erling Smørgrav error("%.200s line %d: '%s' cannot be combined " 593bc5531deSDag-Erling Smørgrav "with other Match attributes", 594bc5531deSDag-Erling Smørgrav filename, linenum, oattrib); 595f7167e0eSDag-Erling Smørgrav result = -1; 596f7167e0eSDag-Erling Smørgrav goto out; 597f7167e0eSDag-Erling Smørgrav } 598bc5531deSDag-Erling Smørgrav if (result) 599bc5531deSDag-Erling Smørgrav result = negate ? 0 : 1; 600f7167e0eSDag-Erling Smørgrav goto out; 601f7167e0eSDag-Erling Smørgrav } 602bc5531deSDag-Erling Smørgrav attributes++; 603bc5531deSDag-Erling Smørgrav if (strcasecmp(attrib, "canonical") == 0) { 604bc5531deSDag-Erling Smørgrav r = !!post_canon; /* force bitmask member to boolean */ 605bc5531deSDag-Erling Smørgrav if (r == (negate ? 1 : 0)) 606bc5531deSDag-Erling Smørgrav this_result = result = 0; 607bc5531deSDag-Erling Smørgrav debug3("%.200s line %d: %smatched '%s'", 608bc5531deSDag-Erling Smørgrav filename, linenum, 609bc5531deSDag-Erling Smørgrav this_result ? "" : "not ", oattrib); 610bc5531deSDag-Erling Smørgrav continue; 611bc5531deSDag-Erling Smørgrav } 612bc5531deSDag-Erling Smørgrav /* All other criteria require an argument */ 613f7167e0eSDag-Erling Smørgrav if ((arg = strdelim(&cp)) == NULL || *arg == '\0') { 614f7167e0eSDag-Erling Smørgrav error("Missing Match criteria for %s", attrib); 615f7167e0eSDag-Erling Smørgrav result = -1; 616f7167e0eSDag-Erling Smørgrav goto out; 617f7167e0eSDag-Erling Smørgrav } 618f7167e0eSDag-Erling Smørgrav if (strcasecmp(attrib, "host") == 0) { 619bc5531deSDag-Erling Smørgrav criteria = xstrdup(host); 620557f75e5SDag-Erling Smørgrav r = match_hostname(host, arg) == 1; 621bc5531deSDag-Erling Smørgrav if (r == (negate ? 1 : 0)) 622bc5531deSDag-Erling Smørgrav this_result = result = 0; 623f7167e0eSDag-Erling Smørgrav } else if (strcasecmp(attrib, "originalhost") == 0) { 624bc5531deSDag-Erling Smørgrav criteria = xstrdup(original_host); 625557f75e5SDag-Erling Smørgrav r = match_hostname(original_host, arg) == 1; 626bc5531deSDag-Erling Smørgrav if (r == (negate ? 1 : 0)) 627bc5531deSDag-Erling Smørgrav this_result = result = 0; 628f7167e0eSDag-Erling Smørgrav } else if (strcasecmp(attrib, "user") == 0) { 629bc5531deSDag-Erling Smørgrav criteria = xstrdup(ruser); 630557f75e5SDag-Erling Smørgrav r = match_pattern_list(ruser, arg, 0) == 1; 631bc5531deSDag-Erling Smørgrav if (r == (negate ? 1 : 0)) 632bc5531deSDag-Erling Smørgrav this_result = result = 0; 633f7167e0eSDag-Erling Smørgrav } else if (strcasecmp(attrib, "localuser") == 0) { 634bc5531deSDag-Erling Smørgrav criteria = xstrdup(pw->pw_name); 635557f75e5SDag-Erling Smørgrav r = match_pattern_list(pw->pw_name, arg, 0) == 1; 636bc5531deSDag-Erling Smørgrav if (r == (negate ? 1 : 0)) 637bc5531deSDag-Erling Smørgrav this_result = result = 0; 638f7167e0eSDag-Erling Smørgrav } else if (strcasecmp(attrib, "exec") == 0) { 639f7167e0eSDag-Erling Smørgrav if (gethostname(thishost, sizeof(thishost)) == -1) 640f7167e0eSDag-Erling Smørgrav fatal("gethostname: %s", strerror(errno)); 641f7167e0eSDag-Erling Smørgrav strlcpy(shorthost, thishost, sizeof(shorthost)); 642f7167e0eSDag-Erling Smørgrav shorthost[strcspn(thishost, ".")] = '\0'; 643f7167e0eSDag-Erling Smørgrav snprintf(portstr, sizeof(portstr), "%d", port); 644190cef3dSDag-Erling Smørgrav snprintf(uidstr, sizeof(uidstr), "%llu", 645190cef3dSDag-Erling Smørgrav (unsigned long long)pw->pw_uid); 646f7167e0eSDag-Erling Smørgrav 647f7167e0eSDag-Erling Smørgrav cmd = percent_expand(arg, 648f7167e0eSDag-Erling Smørgrav "L", shorthost, 649f7167e0eSDag-Erling Smørgrav "d", pw->pw_dir, 650f7167e0eSDag-Erling Smørgrav "h", host, 651f7167e0eSDag-Erling Smørgrav "l", thishost, 652bc5531deSDag-Erling Smørgrav "n", original_host, 653f7167e0eSDag-Erling Smørgrav "p", portstr, 654f7167e0eSDag-Erling Smørgrav "r", ruser, 655f7167e0eSDag-Erling Smørgrav "u", pw->pw_name, 656190cef3dSDag-Erling Smørgrav "i", uidstr, 657f7167e0eSDag-Erling Smørgrav (char *)NULL); 658b83788ffSDag-Erling Smørgrav if (result != 1) { 659b83788ffSDag-Erling Smørgrav /* skip execution if prior predicate failed */ 660bc5531deSDag-Erling Smørgrav debug3("%.200s line %d: skipped exec " 661bc5531deSDag-Erling Smørgrav "\"%.100s\"", filename, linenum, cmd); 662bc5531deSDag-Erling Smørgrav free(cmd); 663bc5531deSDag-Erling Smørgrav continue; 664bc5531deSDag-Erling Smørgrav } 665f7167e0eSDag-Erling Smørgrav r = execute_in_shell(cmd); 666f7167e0eSDag-Erling Smørgrav if (r == -1) { 667b83788ffSDag-Erling Smørgrav fatal("%.200s line %d: match exec " 668b83788ffSDag-Erling Smørgrav "'%.100s' error", filename, 669b83788ffSDag-Erling Smørgrav linenum, cmd); 670b83788ffSDag-Erling Smørgrav } 671bc5531deSDag-Erling Smørgrav criteria = xstrdup(cmd); 672f7167e0eSDag-Erling Smørgrav free(cmd); 673bc5531deSDag-Erling Smørgrav /* Force exit status to boolean */ 674bc5531deSDag-Erling Smørgrav r = r == 0; 675bc5531deSDag-Erling Smørgrav if (r == (negate ? 1 : 0)) 676bc5531deSDag-Erling Smørgrav this_result = result = 0; 677f7167e0eSDag-Erling Smørgrav } else { 678f7167e0eSDag-Erling Smørgrav error("Unsupported Match attribute %s", attrib); 679f7167e0eSDag-Erling Smørgrav result = -1; 680f7167e0eSDag-Erling Smørgrav goto out; 681f7167e0eSDag-Erling Smørgrav } 682bc5531deSDag-Erling Smørgrav debug3("%.200s line %d: %smatched '%s \"%.100s\"' ", 683bc5531deSDag-Erling Smørgrav filename, linenum, this_result ? "": "not ", 684bc5531deSDag-Erling Smørgrav oattrib, criteria); 685bc5531deSDag-Erling Smørgrav free(criteria); 686f7167e0eSDag-Erling Smørgrav } 687f7167e0eSDag-Erling Smørgrav if (attributes == 0) { 688f7167e0eSDag-Erling Smørgrav error("One or more attributes required for Match"); 689f7167e0eSDag-Erling Smørgrav result = -1; 690f7167e0eSDag-Erling Smørgrav goto out; 691f7167e0eSDag-Erling Smørgrav } 692f7167e0eSDag-Erling Smørgrav out: 693bc5531deSDag-Erling Smørgrav if (result != -1) 694bc5531deSDag-Erling Smørgrav debug2("match %sfound", result ? "" : "not "); 695bc5531deSDag-Erling Smørgrav *condition = cp; 696f7167e0eSDag-Erling Smørgrav free(host); 697f7167e0eSDag-Erling Smørgrav return result; 698f7167e0eSDag-Erling Smørgrav } 699f7167e0eSDag-Erling Smørgrav 700190cef3dSDag-Erling Smørgrav /* Remove environment variable by pattern */ 701190cef3dSDag-Erling Smørgrav static void 702190cef3dSDag-Erling Smørgrav rm_env(Options *options, const char *arg, const char *filename, int linenum) 703190cef3dSDag-Erling Smørgrav { 704190cef3dSDag-Erling Smørgrav int i, j; 705190cef3dSDag-Erling Smørgrav char *cp; 706190cef3dSDag-Erling Smørgrav 707190cef3dSDag-Erling Smørgrav /* Remove an environment variable */ 708190cef3dSDag-Erling Smørgrav for (i = 0; i < options->num_send_env; ) { 709190cef3dSDag-Erling Smørgrav cp = xstrdup(options->send_env[i]); 710190cef3dSDag-Erling Smørgrav if (!match_pattern(cp, arg + 1)) { 711190cef3dSDag-Erling Smørgrav free(cp); 712190cef3dSDag-Erling Smørgrav i++; 713190cef3dSDag-Erling Smørgrav continue; 714190cef3dSDag-Erling Smørgrav } 715190cef3dSDag-Erling Smørgrav debug3("%s line %d: removing environment %s", 716190cef3dSDag-Erling Smørgrav filename, linenum, cp); 717190cef3dSDag-Erling Smørgrav free(cp); 718190cef3dSDag-Erling Smørgrav free(options->send_env[i]); 719190cef3dSDag-Erling Smørgrav options->send_env[i] = NULL; 720190cef3dSDag-Erling Smørgrav for (j = i; j < options->num_send_env - 1; j++) { 721190cef3dSDag-Erling Smørgrav options->send_env[j] = options->send_env[j + 1]; 722190cef3dSDag-Erling Smørgrav options->send_env[j + 1] = NULL; 723190cef3dSDag-Erling Smørgrav } 724190cef3dSDag-Erling Smørgrav options->num_send_env--; 725190cef3dSDag-Erling Smørgrav /* NB. don't increment i */ 726190cef3dSDag-Erling Smørgrav } 727190cef3dSDag-Erling Smørgrav } 728190cef3dSDag-Erling Smørgrav 729511b41d2SMark Murray /* 730ca3176e7SBrian Feldman * Returns the number of the token pointed to by cp or oBadOption. 731511b41d2SMark Murray */ 732511b41d2SMark Murray static OpCodes 733e4a9863fSDag-Erling Smørgrav parse_token(const char *cp, const char *filename, int linenum, 734e4a9863fSDag-Erling Smørgrav const char *ignored_unknown) 735511b41d2SMark Murray { 736e4a9863fSDag-Erling Smørgrav int i; 737511b41d2SMark Murray 738511b41d2SMark Murray for (i = 0; keywords[i].name; i++) 739e4a9863fSDag-Erling Smørgrav if (strcmp(cp, keywords[i].name) == 0) 740511b41d2SMark Murray return keywords[i].opcode; 741557f75e5SDag-Erling Smørgrav if (ignored_unknown != NULL && 742557f75e5SDag-Erling Smørgrav match_pattern_list(cp, ignored_unknown, 1) == 1) 743e4a9863fSDag-Erling Smørgrav return oIgnoredUnknownOption; 744ca3176e7SBrian Feldman error("%s: line %d: Bad configuration option: %s", 745511b41d2SMark Murray filename, linenum, cp); 746511b41d2SMark Murray return oBadOption; 747511b41d2SMark Murray } 748511b41d2SMark Murray 749f7167e0eSDag-Erling Smørgrav /* Multistate option parsing */ 750f7167e0eSDag-Erling Smørgrav struct multistate { 751f7167e0eSDag-Erling Smørgrav char *key; 752f7167e0eSDag-Erling Smørgrav int value; 753f7167e0eSDag-Erling Smørgrav }; 754f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_flag[] = { 755f7167e0eSDag-Erling Smørgrav { "true", 1 }, 756f7167e0eSDag-Erling Smørgrav { "false", 0 }, 757f7167e0eSDag-Erling Smørgrav { "yes", 1 }, 758f7167e0eSDag-Erling Smørgrav { "no", 0 }, 759f7167e0eSDag-Erling Smørgrav { NULL, -1 } 760f7167e0eSDag-Erling Smørgrav }; 761f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_yesnoask[] = { 762f7167e0eSDag-Erling Smørgrav { "true", 1 }, 763f7167e0eSDag-Erling Smørgrav { "false", 0 }, 764f7167e0eSDag-Erling Smørgrav { "yes", 1 }, 765f7167e0eSDag-Erling Smørgrav { "no", 0 }, 766f7167e0eSDag-Erling Smørgrav { "ask", 2 }, 767f7167e0eSDag-Erling Smørgrav { NULL, -1 } 768f7167e0eSDag-Erling Smørgrav }; 7694f52dfbbSDag-Erling Smørgrav static const struct multistate multistate_strict_hostkey[] = { 7704f52dfbbSDag-Erling Smørgrav { "true", SSH_STRICT_HOSTKEY_YES }, 7714f52dfbbSDag-Erling Smørgrav { "false", SSH_STRICT_HOSTKEY_OFF }, 7724f52dfbbSDag-Erling Smørgrav { "yes", SSH_STRICT_HOSTKEY_YES }, 7734f52dfbbSDag-Erling Smørgrav { "no", SSH_STRICT_HOSTKEY_OFF }, 7744f52dfbbSDag-Erling Smørgrav { "ask", SSH_STRICT_HOSTKEY_ASK }, 7754f52dfbbSDag-Erling Smørgrav { "off", SSH_STRICT_HOSTKEY_OFF }, 7764f52dfbbSDag-Erling Smørgrav { "accept-new", SSH_STRICT_HOSTKEY_NEW }, 7774f52dfbbSDag-Erling Smørgrav { NULL, -1 } 7784f52dfbbSDag-Erling Smørgrav }; 779acc1a9efSDag-Erling Smørgrav static const struct multistate multistate_yesnoaskconfirm[] = { 780acc1a9efSDag-Erling Smørgrav { "true", 1 }, 781acc1a9efSDag-Erling Smørgrav { "false", 0 }, 782acc1a9efSDag-Erling Smørgrav { "yes", 1 }, 783acc1a9efSDag-Erling Smørgrav { "no", 0 }, 784acc1a9efSDag-Erling Smørgrav { "ask", 2 }, 785acc1a9efSDag-Erling Smørgrav { "confirm", 3 }, 786acc1a9efSDag-Erling Smørgrav { NULL, -1 } 787acc1a9efSDag-Erling Smørgrav }; 788f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_addressfamily[] = { 789f7167e0eSDag-Erling Smørgrav { "inet", AF_INET }, 790f7167e0eSDag-Erling Smørgrav { "inet6", AF_INET6 }, 791f7167e0eSDag-Erling Smørgrav { "any", AF_UNSPEC }, 792f7167e0eSDag-Erling Smørgrav { NULL, -1 } 793f7167e0eSDag-Erling Smørgrav }; 794f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_controlmaster[] = { 795f7167e0eSDag-Erling Smørgrav { "true", SSHCTL_MASTER_YES }, 796f7167e0eSDag-Erling Smørgrav { "yes", SSHCTL_MASTER_YES }, 797f7167e0eSDag-Erling Smørgrav { "false", SSHCTL_MASTER_NO }, 798f7167e0eSDag-Erling Smørgrav { "no", SSHCTL_MASTER_NO }, 799f7167e0eSDag-Erling Smørgrav { "auto", SSHCTL_MASTER_AUTO }, 800f7167e0eSDag-Erling Smørgrav { "ask", SSHCTL_MASTER_ASK }, 801f7167e0eSDag-Erling Smørgrav { "autoask", SSHCTL_MASTER_AUTO_ASK }, 802f7167e0eSDag-Erling Smørgrav { NULL, -1 } 803f7167e0eSDag-Erling Smørgrav }; 804f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_tunnel[] = { 805f7167e0eSDag-Erling Smørgrav { "ethernet", SSH_TUNMODE_ETHERNET }, 806f7167e0eSDag-Erling Smørgrav { "point-to-point", SSH_TUNMODE_POINTOPOINT }, 807f7167e0eSDag-Erling Smørgrav { "true", SSH_TUNMODE_DEFAULT }, 808f7167e0eSDag-Erling Smørgrav { "yes", SSH_TUNMODE_DEFAULT }, 809f7167e0eSDag-Erling Smørgrav { "false", SSH_TUNMODE_NO }, 810f7167e0eSDag-Erling Smørgrav { "no", SSH_TUNMODE_NO }, 811f7167e0eSDag-Erling Smørgrav { NULL, -1 } 812f7167e0eSDag-Erling Smørgrav }; 813f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_requesttty[] = { 814f7167e0eSDag-Erling Smørgrav { "true", REQUEST_TTY_YES }, 815f7167e0eSDag-Erling Smørgrav { "yes", REQUEST_TTY_YES }, 816f7167e0eSDag-Erling Smørgrav { "false", REQUEST_TTY_NO }, 817f7167e0eSDag-Erling Smørgrav { "no", REQUEST_TTY_NO }, 818f7167e0eSDag-Erling Smørgrav { "force", REQUEST_TTY_FORCE }, 819f7167e0eSDag-Erling Smørgrav { "auto", REQUEST_TTY_AUTO }, 820f7167e0eSDag-Erling Smørgrav { NULL, -1 } 821f7167e0eSDag-Erling Smørgrav }; 822f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_canonicalizehostname[] = { 823f7167e0eSDag-Erling Smørgrav { "true", SSH_CANONICALISE_YES }, 824f7167e0eSDag-Erling Smørgrav { "false", SSH_CANONICALISE_NO }, 825f7167e0eSDag-Erling Smørgrav { "yes", SSH_CANONICALISE_YES }, 826f7167e0eSDag-Erling Smørgrav { "no", SSH_CANONICALISE_NO }, 827f7167e0eSDag-Erling Smørgrav { "always", SSH_CANONICALISE_ALWAYS }, 828f7167e0eSDag-Erling Smørgrav { NULL, -1 } 829f7167e0eSDag-Erling Smørgrav }; 830f7167e0eSDag-Erling Smørgrav 831511b41d2SMark Murray /* 832511b41d2SMark Murray * Processes a single option line as used in the configuration files. This 833511b41d2SMark Murray * only sets those values that have not already been set. 834511b41d2SMark Murray */ 835511b41d2SMark Murray int 836f7167e0eSDag-Erling Smørgrav process_config_line(Options *options, struct passwd *pw, const char *host, 837bc5531deSDag-Erling Smørgrav const char *original_host, char *line, const char *filename, 838bc5531deSDag-Erling Smørgrav int linenum, int *activep, int flags) 839511b41d2SMark Murray { 840076ad2f8SDag-Erling Smørgrav return process_config_line_depth(options, pw, host, original_host, 841076ad2f8SDag-Erling Smørgrav line, filename, linenum, activep, flags, 0); 842076ad2f8SDag-Erling Smørgrav } 843076ad2f8SDag-Erling Smørgrav 844076ad2f8SDag-Erling Smørgrav #define WHITESPACE " \t\r\n" 845076ad2f8SDag-Erling Smørgrav static int 846076ad2f8SDag-Erling Smørgrav process_config_line_depth(Options *options, struct passwd *pw, const char *host, 847076ad2f8SDag-Erling Smørgrav const char *original_host, char *line, const char *filename, 848076ad2f8SDag-Erling Smørgrav int linenum, int *activep, int flags, int depth) 849076ad2f8SDag-Erling Smørgrav { 850e146993eSDag-Erling Smørgrav char *s, **charptr, *endofnumber, *keyword, *arg, *arg2; 851e146993eSDag-Erling Smørgrav char **cpptr, fwdarg[256]; 852e4a9863fSDag-Erling Smørgrav u_int i, *uintptr, max_entries = 0; 853076ad2f8SDag-Erling Smørgrav int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0; 8544f52dfbbSDag-Erling Smørgrav int remotefwd, dynamicfwd; 855d4af9e69SDag-Erling Smørgrav LogLevel *log_level_ptr; 8564f52dfbbSDag-Erling Smørgrav SyslogFacility *log_facility_ptr; 857e4a9863fSDag-Erling Smørgrav long long val64; 858e73e9afaSDag-Erling Smørgrav size_t len; 859a0ee8cc6SDag-Erling Smørgrav struct Forward fwd; 860f7167e0eSDag-Erling Smørgrav const struct multistate *multistate_ptr; 861f7167e0eSDag-Erling Smørgrav struct allowed_cname *cname; 862076ad2f8SDag-Erling Smørgrav glob_t gl; 86347dd1d1bSDag-Erling Smørgrav const char *errstr; 864f7167e0eSDag-Erling Smørgrav 865f7167e0eSDag-Erling Smørgrav if (activep == NULL) { /* We are processing a command line directive */ 866f7167e0eSDag-Erling Smørgrav cmdline = 1; 867f7167e0eSDag-Erling Smørgrav activep = &cmdline; 868f7167e0eSDag-Erling Smørgrav } 869511b41d2SMark Murray 870d93a896eSDag-Erling Smørgrav /* Strip trailing whitespace. Allow \f (form feed) at EOL only */ 871557f75e5SDag-Erling Smørgrav if ((len = strlen(line)) == 0) 872557f75e5SDag-Erling Smørgrav return 0; 873557f75e5SDag-Erling Smørgrav for (len--; len > 0; len--) { 874d93a896eSDag-Erling Smørgrav if (strchr(WHITESPACE "\f", line[len]) == NULL) 875cf2b5f3bSDag-Erling Smørgrav break; 876cf2b5f3bSDag-Erling Smørgrav line[len] = '\0'; 877cf2b5f3bSDag-Erling Smørgrav } 878cf2b5f3bSDag-Erling Smørgrav 879c2d3a559SKris Kennaway s = line; 880c2d3a559SKris Kennaway /* Get the keyword. (Each line is supposed to begin with a keyword). */ 881333ee039SDag-Erling Smørgrav if ((keyword = strdelim(&s)) == NULL) 882333ee039SDag-Erling Smørgrav return 0; 883c2d3a559SKris Kennaway /* Ignore leading whitespace. */ 884c2d3a559SKris Kennaway if (*keyword == '\0') 885c2d3a559SKris Kennaway keyword = strdelim(&s); 886ca3176e7SBrian Feldman if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#') 887511b41d2SMark Murray return 0; 888e4a9863fSDag-Erling Smørgrav /* Match lowercase keyword */ 889f7167e0eSDag-Erling Smørgrav lowercase(keyword); 890511b41d2SMark Murray 891e4a9863fSDag-Erling Smørgrav opcode = parse_token(keyword, filename, linenum, 892e4a9863fSDag-Erling Smørgrav options->ignored_unknown); 893511b41d2SMark Murray 894511b41d2SMark Murray switch (opcode) { 895511b41d2SMark Murray case oBadOption: 896511b41d2SMark Murray /* don't panic, but count bad options */ 897511b41d2SMark Murray return -1; 8984f52dfbbSDag-Erling Smørgrav case oIgnore: 8994f52dfbbSDag-Erling Smørgrav return 0; 900e4a9863fSDag-Erling Smørgrav case oIgnoredUnknownOption: 901e4a9863fSDag-Erling Smørgrav debug("%s line %d: Ignored unknown option \"%s\"", 902e4a9863fSDag-Erling Smørgrav filename, linenum, keyword); 903e4a9863fSDag-Erling Smørgrav return 0; 904cf2b5f3bSDag-Erling Smørgrav case oConnectTimeout: 905cf2b5f3bSDag-Erling Smørgrav intptr = &options->connection_timeout; 9061ec0d754SDag-Erling Smørgrav parse_time: 907cf2b5f3bSDag-Erling Smørgrav arg = strdelim(&s); 908cf2b5f3bSDag-Erling Smørgrav if (!arg || *arg == '\0') 909cf2b5f3bSDag-Erling Smørgrav fatal("%s line %d: missing time value.", 910cf2b5f3bSDag-Erling Smørgrav filename, linenum); 911bc5531deSDag-Erling Smørgrav if (strcmp(arg, "none") == 0) 912bc5531deSDag-Erling Smørgrav value = -1; 913bc5531deSDag-Erling Smørgrav else if ((value = convtime(arg)) == -1) 914cf2b5f3bSDag-Erling Smørgrav fatal("%s line %d: invalid time value.", 915cf2b5f3bSDag-Erling Smørgrav filename, linenum); 916d4af9e69SDag-Erling Smørgrav if (*activep && *intptr == -1) 917cf2b5f3bSDag-Erling Smørgrav *intptr = value; 918cf2b5f3bSDag-Erling Smørgrav break; 919cf2b5f3bSDag-Erling Smørgrav 920511b41d2SMark Murray case oForwardAgent: 921511b41d2SMark Murray intptr = &options->forward_agent; 922511b41d2SMark Murray parse_flag: 923f7167e0eSDag-Erling Smørgrav multistate_ptr = multistate_flag; 924f7167e0eSDag-Erling Smørgrav parse_multistate: 925c2d3a559SKris Kennaway arg = strdelim(&s); 926c2d3a559SKris Kennaway if (!arg || *arg == '\0') 927f7167e0eSDag-Erling Smørgrav fatal("%s line %d: missing argument.", 928f7167e0eSDag-Erling Smørgrav filename, linenum); 929f7167e0eSDag-Erling Smørgrav value = -1; 930f7167e0eSDag-Erling Smørgrav for (i = 0; multistate_ptr[i].key != NULL; i++) { 931f7167e0eSDag-Erling Smørgrav if (strcasecmp(arg, multistate_ptr[i].key) == 0) { 932f7167e0eSDag-Erling Smørgrav value = multistate_ptr[i].value; 933f7167e0eSDag-Erling Smørgrav break; 934f7167e0eSDag-Erling Smørgrav } 935f7167e0eSDag-Erling Smørgrav } 936f7167e0eSDag-Erling Smørgrav if (value == -1) 937f7167e0eSDag-Erling Smørgrav fatal("%s line %d: unsupported option \"%s\".", 938f7167e0eSDag-Erling Smørgrav filename, linenum, arg); 939511b41d2SMark Murray if (*activep && *intptr == -1) 940511b41d2SMark Murray *intptr = value; 941511b41d2SMark Murray break; 942511b41d2SMark Murray 943511b41d2SMark Murray case oForwardX11: 944511b41d2SMark Murray intptr = &options->forward_x11; 945511b41d2SMark Murray goto parse_flag; 946511b41d2SMark Murray 9471ec0d754SDag-Erling Smørgrav case oForwardX11Trusted: 9481ec0d754SDag-Erling Smørgrav intptr = &options->forward_x11_trusted; 9491ec0d754SDag-Erling Smørgrav goto parse_flag; 9501ec0d754SDag-Erling Smørgrav 951e2f6069cSDag-Erling Smørgrav case oForwardX11Timeout: 952e2f6069cSDag-Erling Smørgrav intptr = &options->forward_x11_timeout; 953e2f6069cSDag-Erling Smørgrav goto parse_time; 954e2f6069cSDag-Erling Smørgrav 955511b41d2SMark Murray case oGatewayPorts: 956a0ee8cc6SDag-Erling Smørgrav intptr = &options->fwd_opts.gateway_ports; 957511b41d2SMark Murray goto parse_flag; 958511b41d2SMark Murray 959333ee039SDag-Erling Smørgrav case oExitOnForwardFailure: 960333ee039SDag-Erling Smørgrav intptr = &options->exit_on_forward_failure; 961333ee039SDag-Erling Smørgrav goto parse_flag; 962333ee039SDag-Erling Smørgrav 963511b41d2SMark Murray case oPasswordAuthentication: 964511b41d2SMark Murray intptr = &options->password_authentication; 965511b41d2SMark Murray goto parse_flag; 966511b41d2SMark Murray 96709958426SBrian Feldman case oKbdInteractiveAuthentication: 96809958426SBrian Feldman intptr = &options->kbd_interactive_authentication; 96909958426SBrian Feldman goto parse_flag; 97009958426SBrian Feldman 97109958426SBrian Feldman case oKbdInteractiveDevices: 97209958426SBrian Feldman charptr = &options->kbd_interactive_devices; 97309958426SBrian Feldman goto parse_string; 97409958426SBrian Feldman 975ca3176e7SBrian Feldman case oPubkeyAuthentication: 976ca3176e7SBrian Feldman intptr = &options->pubkey_authentication; 977e8aafc91SKris Kennaway goto parse_flag; 978e8aafc91SKris Kennaway 979ca3176e7SBrian Feldman case oHostbasedAuthentication: 980ca3176e7SBrian Feldman intptr = &options->hostbased_authentication; 981511b41d2SMark Murray goto parse_flag; 982511b41d2SMark Murray 983af12a3e7SDag-Erling Smørgrav case oChallengeResponseAuthentication: 984af12a3e7SDag-Erling Smørgrav intptr = &options->challenge_response_authentication; 985af12a3e7SDag-Erling Smørgrav goto parse_flag; 986cf2b5f3bSDag-Erling Smørgrav 987cf2b5f3bSDag-Erling Smørgrav case oGssAuthentication: 988cf2b5f3bSDag-Erling Smørgrav intptr = &options->gss_authentication; 989511b41d2SMark Murray goto parse_flag; 990cf2b5f3bSDag-Erling Smørgrav 991cf2b5f3bSDag-Erling Smørgrav case oGssDelegateCreds: 992cf2b5f3bSDag-Erling Smørgrav intptr = &options->gss_deleg_creds; 993ca3176e7SBrian Feldman goto parse_flag; 994cf2b5f3bSDag-Erling Smørgrav 995511b41d2SMark Murray case oBatchMode: 996511b41d2SMark Murray intptr = &options->batch_mode; 997511b41d2SMark Murray goto parse_flag; 998511b41d2SMark Murray 999511b41d2SMark Murray case oCheckHostIP: 1000511b41d2SMark Murray intptr = &options->check_host_ip; 1001511b41d2SMark Murray goto parse_flag; 1002511b41d2SMark Murray 1003cf2b5f3bSDag-Erling Smørgrav case oVerifyHostKeyDNS: 1004cf2b5f3bSDag-Erling Smørgrav intptr = &options->verify_host_key_dns; 1005f7167e0eSDag-Erling Smørgrav multistate_ptr = multistate_yesnoask; 1006f7167e0eSDag-Erling Smørgrav goto parse_multistate; 1007cf2b5f3bSDag-Erling Smørgrav 1008511b41d2SMark Murray case oStrictHostKeyChecking: 1009511b41d2SMark Murray intptr = &options->strict_host_key_checking; 10104f52dfbbSDag-Erling Smørgrav multistate_ptr = multistate_strict_hostkey; 1011f7167e0eSDag-Erling Smørgrav goto parse_multistate; 1012511b41d2SMark Murray 1013511b41d2SMark Murray case oCompression: 1014511b41d2SMark Murray intptr = &options->compression; 1015511b41d2SMark Murray goto parse_flag; 1016511b41d2SMark Murray 10171ec0d754SDag-Erling Smørgrav case oTCPKeepAlive: 10181ec0d754SDag-Erling Smørgrav intptr = &options->tcp_keep_alive; 1019511b41d2SMark Murray goto parse_flag; 1020511b41d2SMark Murray 1021af12a3e7SDag-Erling Smørgrav case oNoHostAuthenticationForLocalhost: 1022af12a3e7SDag-Erling Smørgrav intptr = &options->no_host_authentication_for_localhost; 1023af12a3e7SDag-Erling Smørgrav goto parse_flag; 1024af12a3e7SDag-Erling Smørgrav 1025511b41d2SMark Murray case oNumberOfPasswordPrompts: 1026511b41d2SMark Murray intptr = &options->number_of_password_prompts; 1027511b41d2SMark Murray goto parse_int; 1028511b41d2SMark Murray 1029cf2b5f3bSDag-Erling Smørgrav case oRekeyLimit: 1030cf2b5f3bSDag-Erling Smørgrav arg = strdelim(&s); 1031cf2b5f3bSDag-Erling Smørgrav if (!arg || *arg == '\0') 1032e4a9863fSDag-Erling Smørgrav fatal("%.200s line %d: Missing argument.", filename, 1033e4a9863fSDag-Erling Smørgrav linenum); 1034e4a9863fSDag-Erling Smørgrav if (strcmp(arg, "default") == 0) { 1035e4a9863fSDag-Erling Smørgrav val64 = 0; 1036e4a9863fSDag-Erling Smørgrav } else { 1037e4a9863fSDag-Erling Smørgrav if (scan_scaled(arg, &val64) == -1) 1038e4a9863fSDag-Erling Smørgrav fatal("%.200s line %d: Bad number '%s': %s", 1039e4a9863fSDag-Erling Smørgrav filename, linenum, arg, strerror(errno)); 1040e4a9863fSDag-Erling Smørgrav if (val64 != 0 && val64 < 16) 1041333ee039SDag-Erling Smørgrav fatal("%.200s line %d: RekeyLimit too small", 1042333ee039SDag-Erling Smørgrav filename, linenum); 1043e4a9863fSDag-Erling Smørgrav } 1044d4af9e69SDag-Erling Smørgrav if (*activep && options->rekey_limit == -1) 1045acc1a9efSDag-Erling Smørgrav options->rekey_limit = val64; 1046e4a9863fSDag-Erling Smørgrav if (s != NULL) { /* optional rekey interval present */ 1047e4a9863fSDag-Erling Smørgrav if (strcmp(s, "none") == 0) { 1048e4a9863fSDag-Erling Smørgrav (void)strdelim(&s); /* discard */ 1049e4a9863fSDag-Erling Smørgrav break; 1050e4a9863fSDag-Erling Smørgrav } 1051e4a9863fSDag-Erling Smørgrav intptr = &options->rekey_interval; 1052e4a9863fSDag-Erling Smørgrav goto parse_time; 1053e4a9863fSDag-Erling Smørgrav } 1054cf2b5f3bSDag-Erling Smørgrav break; 1055cf2b5f3bSDag-Erling Smørgrav 1056511b41d2SMark Murray case oIdentityFile: 1057c2d3a559SKris Kennaway arg = strdelim(&s); 1058c2d3a559SKris Kennaway if (!arg || *arg == '\0') 1059511b41d2SMark Murray fatal("%.200s line %d: Missing argument.", filename, linenum); 1060511b41d2SMark Murray if (*activep) { 1061ca3176e7SBrian Feldman intptr = &options->num_identity_files; 1062e8aafc91SKris Kennaway if (*intptr >= SSH_MAX_IDENTITY_FILES) 1063511b41d2SMark Murray fatal("%.200s line %d: Too many identity files specified (max %d).", 1064511b41d2SMark Murray filename, linenum, SSH_MAX_IDENTITY_FILES); 1065bc5531deSDag-Erling Smørgrav add_identity_file(options, NULL, 1066bc5531deSDag-Erling Smørgrav arg, flags & SSHCONF_USERCONF); 1067511b41d2SMark Murray } 1068511b41d2SMark Murray break; 1069511b41d2SMark Murray 1070acc1a9efSDag-Erling Smørgrav case oCertificateFile: 1071acc1a9efSDag-Erling Smørgrav arg = strdelim(&s); 1072acc1a9efSDag-Erling Smørgrav if (!arg || *arg == '\0') 1073acc1a9efSDag-Erling Smørgrav fatal("%.200s line %d: Missing argument.", 1074acc1a9efSDag-Erling Smørgrav filename, linenum); 1075acc1a9efSDag-Erling Smørgrav if (*activep) { 1076acc1a9efSDag-Erling Smørgrav intptr = &options->num_certificate_files; 1077acc1a9efSDag-Erling Smørgrav if (*intptr >= SSH_MAX_CERTIFICATE_FILES) { 1078acc1a9efSDag-Erling Smørgrav fatal("%.200s line %d: Too many certificate " 1079acc1a9efSDag-Erling Smørgrav "files specified (max %d).", 1080acc1a9efSDag-Erling Smørgrav filename, linenum, 1081acc1a9efSDag-Erling Smørgrav SSH_MAX_CERTIFICATE_FILES); 1082acc1a9efSDag-Erling Smørgrav } 1083acc1a9efSDag-Erling Smørgrav add_certificate_file(options, arg, 1084acc1a9efSDag-Erling Smørgrav flags & SSHCONF_USERCONF); 1085acc1a9efSDag-Erling Smørgrav } 1086acc1a9efSDag-Erling Smørgrav break; 1087acc1a9efSDag-Erling Smørgrav 1088c2d3a559SKris Kennaway case oXAuthLocation: 1089c2d3a559SKris Kennaway charptr=&options->xauth_location; 1090c2d3a559SKris Kennaway goto parse_string; 1091c2d3a559SKris Kennaway 1092511b41d2SMark Murray case oUser: 1093511b41d2SMark Murray charptr = &options->user; 1094511b41d2SMark Murray parse_string: 1095c2d3a559SKris Kennaway arg = strdelim(&s); 1096c2d3a559SKris Kennaway if (!arg || *arg == '\0') 1097e146993eSDag-Erling Smørgrav fatal("%.200s line %d: Missing argument.", 1098e146993eSDag-Erling Smørgrav filename, linenum); 1099511b41d2SMark Murray if (*activep && *charptr == NULL) 1100c2d3a559SKris Kennaway *charptr = xstrdup(arg); 1101511b41d2SMark Murray break; 1102511b41d2SMark Murray 1103511b41d2SMark Murray case oGlobalKnownHostsFile: 1104e146993eSDag-Erling Smørgrav cpptr = (char **)&options->system_hostfiles; 1105e146993eSDag-Erling Smørgrav uintptr = &options->num_system_hostfiles; 1106e146993eSDag-Erling Smørgrav max_entries = SSH_MAX_HOSTS_FILES; 1107e146993eSDag-Erling Smørgrav parse_char_array: 1108e146993eSDag-Erling Smørgrav if (*activep && *uintptr == 0) { 1109e146993eSDag-Erling Smørgrav while ((arg = strdelim(&s)) != NULL && *arg != '\0') { 1110e146993eSDag-Erling Smørgrav if ((*uintptr) >= max_entries) 1111e146993eSDag-Erling Smørgrav fatal("%s line %d: " 1112e146993eSDag-Erling Smørgrav "too many authorized keys files.", 1113e146993eSDag-Erling Smørgrav filename, linenum); 1114e146993eSDag-Erling Smørgrav cpptr[(*uintptr)++] = xstrdup(arg); 1115e146993eSDag-Erling Smørgrav } 1116e146993eSDag-Erling Smørgrav } 1117e146993eSDag-Erling Smørgrav return 0; 1118511b41d2SMark Murray 1119511b41d2SMark Murray case oUserKnownHostsFile: 1120e146993eSDag-Erling Smørgrav cpptr = (char **)&options->user_hostfiles; 1121e146993eSDag-Erling Smørgrav uintptr = &options->num_user_hostfiles; 1122e146993eSDag-Erling Smørgrav max_entries = SSH_MAX_HOSTS_FILES; 1123e146993eSDag-Erling Smørgrav goto parse_char_array; 1124e8aafc91SKris Kennaway 1125511b41d2SMark Murray case oHostName: 1126511b41d2SMark Murray charptr = &options->hostname; 1127511b41d2SMark Murray goto parse_string; 1128511b41d2SMark Murray 1129ca3176e7SBrian Feldman case oHostKeyAlias: 1130ca3176e7SBrian Feldman charptr = &options->host_key_alias; 1131ca3176e7SBrian Feldman goto parse_string; 1132ca3176e7SBrian Feldman 1133ca3176e7SBrian Feldman case oPreferredAuthentications: 1134ca3176e7SBrian Feldman charptr = &options->preferred_authentications; 1135ca3176e7SBrian Feldman goto parse_string; 1136ca3176e7SBrian Feldman 1137af12a3e7SDag-Erling Smørgrav case oBindAddress: 1138af12a3e7SDag-Erling Smørgrav charptr = &options->bind_address; 1139af12a3e7SDag-Erling Smørgrav goto parse_string; 1140af12a3e7SDag-Erling Smørgrav 114147dd1d1bSDag-Erling Smørgrav case oBindInterface: 114247dd1d1bSDag-Erling Smørgrav charptr = &options->bind_interface; 114347dd1d1bSDag-Erling Smørgrav goto parse_string; 114447dd1d1bSDag-Erling Smørgrav 1145b15c8340SDag-Erling Smørgrav case oPKCS11Provider: 1146b15c8340SDag-Erling Smørgrav charptr = &options->pkcs11_provider; 1147af12a3e7SDag-Erling Smørgrav goto parse_string; 1148af12a3e7SDag-Erling Smørgrav 1149511b41d2SMark Murray case oProxyCommand: 1150b74df5b2SDag-Erling Smørgrav charptr = &options->proxy_command; 1151076ad2f8SDag-Erling Smørgrav /* Ignore ProxyCommand if ProxyJump already specified */ 1152076ad2f8SDag-Erling Smørgrav if (options->jump_host != NULL) 1153076ad2f8SDag-Erling Smørgrav charptr = &options->jump_host; /* Skip below */ 1154b74df5b2SDag-Erling Smørgrav parse_command: 1155cf2b5f3bSDag-Erling Smørgrav if (s == NULL) 1156cf2b5f3bSDag-Erling Smørgrav fatal("%.200s line %d: Missing argument.", filename, linenum); 1157e73e9afaSDag-Erling Smørgrav len = strspn(s, WHITESPACE "="); 1158511b41d2SMark Murray if (*activep && *charptr == NULL) 1159e73e9afaSDag-Erling Smørgrav *charptr = xstrdup(s + len); 1160511b41d2SMark Murray return 0; 1161511b41d2SMark Murray 1162076ad2f8SDag-Erling Smørgrav case oProxyJump: 1163076ad2f8SDag-Erling Smørgrav if (s == NULL) { 1164076ad2f8SDag-Erling Smørgrav fatal("%.200s line %d: Missing argument.", 1165076ad2f8SDag-Erling Smørgrav filename, linenum); 1166076ad2f8SDag-Erling Smørgrav } 1167076ad2f8SDag-Erling Smørgrav len = strspn(s, WHITESPACE "="); 1168076ad2f8SDag-Erling Smørgrav if (parse_jump(s + len, options, *activep) == -1) { 1169076ad2f8SDag-Erling Smørgrav fatal("%.200s line %d: Invalid ProxyJump \"%s\"", 1170076ad2f8SDag-Erling Smørgrav filename, linenum, s + len); 1171076ad2f8SDag-Erling Smørgrav } 1172076ad2f8SDag-Erling Smørgrav return 0; 1173076ad2f8SDag-Erling Smørgrav 1174511b41d2SMark Murray case oPort: 11752f513db7SEd Maste arg = strdelim(&s); 11762f513db7SEd Maste if (!arg || *arg == '\0') 11772f513db7SEd Maste fatal("%.200s line %d: Missing argument.", 11782f513db7SEd Maste filename, linenum); 11792f513db7SEd Maste value = a2port(arg); 11802f513db7SEd Maste if (value <= 0) 11812f513db7SEd Maste fatal("%.200s line %d: Bad port '%s'.", 11822f513db7SEd Maste filename, linenum, arg); 11832f513db7SEd Maste if (*activep && options->port == -1) 11842f513db7SEd Maste options->port = value; 11852f513db7SEd Maste break; 11862f513db7SEd Maste 11872f513db7SEd Maste case oConnectionAttempts: 11882f513db7SEd Maste intptr = &options->connection_attempts; 1189511b41d2SMark Murray parse_int: 1190c2d3a559SKris Kennaway arg = strdelim(&s); 119147dd1d1bSDag-Erling Smørgrav if ((errstr = atoi_err(arg, &value)) != NULL) 119247dd1d1bSDag-Erling Smørgrav fatal("%s line %d: integer value %s.", 119347dd1d1bSDag-Erling Smørgrav filename, linenum, errstr); 1194511b41d2SMark Murray if (*activep && *intptr == -1) 1195511b41d2SMark Murray *intptr = value; 1196511b41d2SMark Murray break; 1197511b41d2SMark Murray 1198e8aafc91SKris Kennaway case oCiphers: 1199c2d3a559SKris Kennaway arg = strdelim(&s); 1200c2d3a559SKris Kennaway if (!arg || *arg == '\0') 1201db1cb46cSKris Kennaway fatal("%.200s line %d: Missing argument.", filename, linenum); 1202d93a896eSDag-Erling Smørgrav if (*arg != '-' && !ciphers_valid(*arg == '+' ? arg + 1 : arg)) 1203e8aafc91SKris Kennaway fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.", 1204c2d3a559SKris Kennaway filename, linenum, arg ? arg : "<NONE>"); 1205e8aafc91SKris Kennaway if (*activep && options->ciphers == NULL) 1206c2d3a559SKris Kennaway options->ciphers = xstrdup(arg); 1207e8aafc91SKris Kennaway break; 1208e8aafc91SKris Kennaway 1209ca3176e7SBrian Feldman case oMacs: 1210ca3176e7SBrian Feldman arg = strdelim(&s); 1211ca3176e7SBrian Feldman if (!arg || *arg == '\0') 1212ca3176e7SBrian Feldman fatal("%.200s line %d: Missing argument.", filename, linenum); 1213d93a896eSDag-Erling Smørgrav if (*arg != '-' && !mac_valid(*arg == '+' ? arg + 1 : arg)) 1214ca3176e7SBrian Feldman fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.", 1215ca3176e7SBrian Feldman filename, linenum, arg ? arg : "<NONE>"); 1216ca3176e7SBrian Feldman if (*activep && options->macs == NULL) 1217ca3176e7SBrian Feldman options->macs = xstrdup(arg); 1218ca3176e7SBrian Feldman break; 1219ca3176e7SBrian Feldman 12204a421b63SDag-Erling Smørgrav case oKexAlgorithms: 12214a421b63SDag-Erling Smørgrav arg = strdelim(&s); 12224a421b63SDag-Erling Smørgrav if (!arg || *arg == '\0') 12234a421b63SDag-Erling Smørgrav fatal("%.200s line %d: Missing argument.", 12244a421b63SDag-Erling Smørgrav filename, linenum); 1225d93a896eSDag-Erling Smørgrav if (*arg != '-' && 1226d93a896eSDag-Erling Smørgrav !kex_names_valid(*arg == '+' ? arg + 1 : arg)) 12274a421b63SDag-Erling Smørgrav fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.", 12284a421b63SDag-Erling Smørgrav filename, linenum, arg ? arg : "<NONE>"); 12294a421b63SDag-Erling Smørgrav if (*activep && options->kex_algorithms == NULL) 12304a421b63SDag-Erling Smørgrav options->kex_algorithms = xstrdup(arg); 12314a421b63SDag-Erling Smørgrav break; 12324a421b63SDag-Erling Smørgrav 1233ca3176e7SBrian Feldman case oHostKeyAlgorithms: 1234eccfee6eSDag-Erling Smørgrav charptr = &options->hostkeyalgorithms; 1235eccfee6eSDag-Erling Smørgrav parse_keytypes: 1236ca3176e7SBrian Feldman arg = strdelim(&s); 1237ca3176e7SBrian Feldman if (!arg || *arg == '\0') 1238eccfee6eSDag-Erling Smørgrav fatal("%.200s line %d: Missing argument.", 1239eccfee6eSDag-Erling Smørgrav filename, linenum); 1240d93a896eSDag-Erling Smørgrav if (*arg != '-' && 1241d93a896eSDag-Erling Smørgrav !sshkey_names_valid2(*arg == '+' ? arg + 1 : arg, 1)) 1242eccfee6eSDag-Erling Smørgrav fatal("%s line %d: Bad key types '%s'.", 1243ca3176e7SBrian Feldman filename, linenum, arg ? arg : "<NONE>"); 1244eccfee6eSDag-Erling Smørgrav if (*activep && *charptr == NULL) 1245eccfee6eSDag-Erling Smørgrav *charptr = xstrdup(arg); 1246ca3176e7SBrian Feldman break; 1247ca3176e7SBrian Feldman 12482f513db7SEd Maste case oCASignatureAlgorithms: 12492f513db7SEd Maste charptr = &options->ca_sign_algorithms; 12502f513db7SEd Maste goto parse_keytypes; 12512f513db7SEd Maste 1252511b41d2SMark Murray case oLogLevel: 1253d4af9e69SDag-Erling Smørgrav log_level_ptr = &options->log_level; 1254c2d3a559SKris Kennaway arg = strdelim(&s); 1255c2d3a559SKris Kennaway value = log_level_number(arg); 1256af12a3e7SDag-Erling Smørgrav if (value == SYSLOG_LEVEL_NOT_SET) 1257ca3176e7SBrian Feldman fatal("%.200s line %d: unsupported log level '%s'", 1258c2d3a559SKris Kennaway filename, linenum, arg ? arg : "<NONE>"); 1259d4af9e69SDag-Erling Smørgrav if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET) 1260d4af9e69SDag-Erling Smørgrav *log_level_ptr = (LogLevel) value; 1261511b41d2SMark Murray break; 1262511b41d2SMark Murray 12634f52dfbbSDag-Erling Smørgrav case oLogFacility: 12644f52dfbbSDag-Erling Smørgrav log_facility_ptr = &options->log_facility; 12654f52dfbbSDag-Erling Smørgrav arg = strdelim(&s); 12664f52dfbbSDag-Erling Smørgrav value = log_facility_number(arg); 12674f52dfbbSDag-Erling Smørgrav if (value == SYSLOG_FACILITY_NOT_SET) 12684f52dfbbSDag-Erling Smørgrav fatal("%.200s line %d: unsupported log facility '%s'", 12694f52dfbbSDag-Erling Smørgrav filename, linenum, arg ? arg : "<NONE>"); 12704f52dfbbSDag-Erling Smørgrav if (*log_facility_ptr == -1) 12714f52dfbbSDag-Erling Smørgrav *log_facility_ptr = (SyslogFacility) value; 12724f52dfbbSDag-Erling Smørgrav break; 12734f52dfbbSDag-Erling Smørgrav 1274af12a3e7SDag-Erling Smørgrav case oLocalForward: 1275511b41d2SMark Murray case oRemoteForward: 1276cce7d346SDag-Erling Smørgrav case oDynamicForward: 1277c2d3a559SKris Kennaway arg = strdelim(&s); 1278aa49c926SDag-Erling Smørgrav if (arg == NULL || *arg == '\0') 1279af12a3e7SDag-Erling Smørgrav fatal("%.200s line %d: Missing port argument.", 1280af12a3e7SDag-Erling Smørgrav filename, linenum); 1281cce7d346SDag-Erling Smørgrav 12824f52dfbbSDag-Erling Smørgrav remotefwd = (opcode == oRemoteForward); 12834f52dfbbSDag-Erling Smørgrav dynamicfwd = (opcode == oDynamicForward); 12844f52dfbbSDag-Erling Smørgrav 12854f52dfbbSDag-Erling Smørgrav if (!dynamicfwd) { 1286aa49c926SDag-Erling Smørgrav arg2 = strdelim(&s); 12874f52dfbbSDag-Erling Smørgrav if (arg2 == NULL || *arg2 == '\0') { 12884f52dfbbSDag-Erling Smørgrav if (remotefwd) 12894f52dfbbSDag-Erling Smørgrav dynamicfwd = 1; 12904f52dfbbSDag-Erling Smørgrav else 12914f52dfbbSDag-Erling Smørgrav fatal("%.200s line %d: Missing target " 12924f52dfbbSDag-Erling Smørgrav "argument.", filename, linenum); 12934f52dfbbSDag-Erling Smørgrav } else { 1294aa49c926SDag-Erling Smørgrav /* construct a string for parse_forward */ 12954f52dfbbSDag-Erling Smørgrav snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, 12964f52dfbbSDag-Erling Smørgrav arg2); 1297cce7d346SDag-Erling Smørgrav } 12984f52dfbbSDag-Erling Smørgrav } 12994f52dfbbSDag-Erling Smørgrav if (dynamicfwd) 13004f52dfbbSDag-Erling Smørgrav strlcpy(fwdarg, arg, sizeof(fwdarg)); 1301aa49c926SDag-Erling Smørgrav 13024f52dfbbSDag-Erling Smørgrav if (parse_forward(&fwd, fwdarg, dynamicfwd, remotefwd) == 0) 1303af12a3e7SDag-Erling Smørgrav fatal("%.200s line %d: Bad forwarding specification.", 1304511b41d2SMark Murray filename, linenum); 1305aa49c926SDag-Erling Smørgrav 1306af12a3e7SDag-Erling Smørgrav if (*activep) { 13074f52dfbbSDag-Erling Smørgrav if (remotefwd) { 1308aa49c926SDag-Erling Smørgrav add_remote_forward(options, &fwd); 13094f52dfbbSDag-Erling Smørgrav } else { 13104f52dfbbSDag-Erling Smørgrav add_local_forward(options, &fwd); 13114f52dfbbSDag-Erling Smørgrav } 1312af12a3e7SDag-Erling Smørgrav } 1313511b41d2SMark Murray break; 1314511b41d2SMark Murray 1315af12a3e7SDag-Erling Smørgrav case oClearAllForwardings: 1316af12a3e7SDag-Erling Smørgrav intptr = &options->clear_forwardings; 1317af12a3e7SDag-Erling Smørgrav goto parse_flag; 1318af12a3e7SDag-Erling Smørgrav 1319511b41d2SMark Murray case oHost: 1320f7167e0eSDag-Erling Smørgrav if (cmdline) 1321f7167e0eSDag-Erling Smørgrav fatal("Host directive not supported as a command-line " 1322f7167e0eSDag-Erling Smørgrav "option"); 1323511b41d2SMark Murray *activep = 0; 1324e146993eSDag-Erling Smørgrav arg2 = NULL; 1325e146993eSDag-Erling Smørgrav while ((arg = strdelim(&s)) != NULL && *arg != '\0') { 1326076ad2f8SDag-Erling Smørgrav if ((flags & SSHCONF_NEVERMATCH) != 0) 1327076ad2f8SDag-Erling Smørgrav break; 1328e146993eSDag-Erling Smørgrav negated = *arg == '!'; 1329e146993eSDag-Erling Smørgrav if (negated) 1330e146993eSDag-Erling Smørgrav arg++; 1331c2d3a559SKris Kennaway if (match_pattern(host, arg)) { 1332e146993eSDag-Erling Smørgrav if (negated) { 1333e146993eSDag-Erling Smørgrav debug("%.200s line %d: Skipping Host " 1334e146993eSDag-Erling Smørgrav "block because of negated match " 1335e146993eSDag-Erling Smørgrav "for %.100s", filename, linenum, 1336e146993eSDag-Erling Smørgrav arg); 1337e146993eSDag-Erling Smørgrav *activep = 0; 1338511b41d2SMark Murray break; 1339511b41d2SMark Murray } 1340e146993eSDag-Erling Smørgrav if (!*activep) 1341e146993eSDag-Erling Smørgrav arg2 = arg; /* logged below */ 1342e146993eSDag-Erling Smørgrav *activep = 1; 1343e146993eSDag-Erling Smørgrav } 1344e146993eSDag-Erling Smørgrav } 1345e146993eSDag-Erling Smørgrav if (*activep) 1346e146993eSDag-Erling Smørgrav debug("%.200s line %d: Applying options for %.100s", 1347e146993eSDag-Erling Smørgrav filename, linenum, arg2); 1348c2d3a559SKris Kennaway /* Avoid garbage check below, as strdelim is done. */ 1349511b41d2SMark Murray return 0; 1350511b41d2SMark Murray 1351f7167e0eSDag-Erling Smørgrav case oMatch: 1352f7167e0eSDag-Erling Smørgrav if (cmdline) 1353f7167e0eSDag-Erling Smørgrav fatal("Host directive not supported as a command-line " 1354f7167e0eSDag-Erling Smørgrav "option"); 1355bc5531deSDag-Erling Smørgrav value = match_cfg_line(options, &s, pw, host, original_host, 1356bc5531deSDag-Erling Smørgrav flags & SSHCONF_POSTCANON, filename, linenum); 1357f7167e0eSDag-Erling Smørgrav if (value < 0) 1358f7167e0eSDag-Erling Smørgrav fatal("%.200s line %d: Bad Match condition", filename, 1359f7167e0eSDag-Erling Smørgrav linenum); 1360076ad2f8SDag-Erling Smørgrav *activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value; 1361f7167e0eSDag-Erling Smørgrav break; 1362f7167e0eSDag-Erling Smørgrav 1363511b41d2SMark Murray case oEscapeChar: 1364511b41d2SMark Murray intptr = &options->escape_char; 1365c2d3a559SKris Kennaway arg = strdelim(&s); 1366c2d3a559SKris Kennaway if (!arg || *arg == '\0') 1367511b41d2SMark Murray fatal("%.200s line %d: Missing argument.", filename, linenum); 1368557f75e5SDag-Erling Smørgrav if (strcmp(arg, "none") == 0) 1369557f75e5SDag-Erling Smørgrav value = SSH_ESCAPECHAR_NONE; 1370557f75e5SDag-Erling Smørgrav else if (arg[1] == '\0') 1371557f75e5SDag-Erling Smørgrav value = (u_char) arg[0]; 1372557f75e5SDag-Erling Smørgrav else if (arg[0] == '^' && arg[2] == 0 && 1373ca3176e7SBrian Feldman (u_char) arg[1] >= 64 && (u_char) arg[1] < 128) 1374ca3176e7SBrian Feldman value = (u_char) arg[1] & 31; 1375511b41d2SMark Murray else { 1376511b41d2SMark Murray fatal("%.200s line %d: Bad escape character.", 1377511b41d2SMark Murray filename, linenum); 1378511b41d2SMark Murray /* NOTREACHED */ 1379511b41d2SMark Murray value = 0; /* Avoid compiler warning. */ 1380511b41d2SMark Murray } 1381511b41d2SMark Murray if (*activep && *intptr == -1) 1382511b41d2SMark Murray *intptr = value; 1383511b41d2SMark Murray break; 1384511b41d2SMark Murray 1385cf2b5f3bSDag-Erling Smørgrav case oAddressFamily: 1386cf2b5f3bSDag-Erling Smørgrav intptr = &options->address_family; 1387f7167e0eSDag-Erling Smørgrav multistate_ptr = multistate_addressfamily; 1388f7167e0eSDag-Erling Smørgrav goto parse_multistate; 1389cf2b5f3bSDag-Erling Smørgrav 1390e73e9afaSDag-Erling Smørgrav case oEnableSSHKeysign: 1391e73e9afaSDag-Erling Smørgrav intptr = &options->enable_ssh_keysign; 1392e73e9afaSDag-Erling Smørgrav goto parse_flag; 1393e73e9afaSDag-Erling Smørgrav 13945962c0e9SDag-Erling Smørgrav case oIdentitiesOnly: 13955962c0e9SDag-Erling Smørgrav intptr = &options->identities_only; 13965962c0e9SDag-Erling Smørgrav goto parse_flag; 13975962c0e9SDag-Erling Smørgrav 13981ec0d754SDag-Erling Smørgrav case oServerAliveInterval: 13991ec0d754SDag-Erling Smørgrav intptr = &options->server_alive_interval; 14001ec0d754SDag-Erling Smørgrav goto parse_time; 14011ec0d754SDag-Erling Smørgrav 14021ec0d754SDag-Erling Smørgrav case oServerAliveCountMax: 14031ec0d754SDag-Erling Smørgrav intptr = &options->server_alive_count_max; 14041ec0d754SDag-Erling Smørgrav goto parse_int; 14051ec0d754SDag-Erling Smørgrav 140621e764dfSDag-Erling Smørgrav case oSendEnv: 140721e764dfSDag-Erling Smørgrav while ((arg = strdelim(&s)) != NULL && *arg != '\0') { 140821e764dfSDag-Erling Smørgrav if (strchr(arg, '=') != NULL) 140921e764dfSDag-Erling Smørgrav fatal("%s line %d: Invalid environment name.", 141021e764dfSDag-Erling Smørgrav filename, linenum); 1411aa49c926SDag-Erling Smørgrav if (!*activep) 1412aa49c926SDag-Erling Smørgrav continue; 1413190cef3dSDag-Erling Smørgrav if (*arg == '-') { 1414190cef3dSDag-Erling Smørgrav /* Removing an env var */ 1415190cef3dSDag-Erling Smørgrav rm_env(options, arg, filename, linenum); 1416190cef3dSDag-Erling Smørgrav continue; 1417190cef3dSDag-Erling Smørgrav } else { 1418190cef3dSDag-Erling Smørgrav /* Adding an env var */ 1419190cef3dSDag-Erling Smørgrav if (options->num_send_env >= INT_MAX) 142021e764dfSDag-Erling Smørgrav fatal("%s line %d: too many send env.", 142121e764dfSDag-Erling Smørgrav filename, linenum); 1422190cef3dSDag-Erling Smørgrav options->send_env = xrecallocarray( 1423190cef3dSDag-Erling Smørgrav options->send_env, options->num_send_env, 1424190cef3dSDag-Erling Smørgrav options->num_send_env + 1, 1425190cef3dSDag-Erling Smørgrav sizeof(*options->send_env)); 142621e764dfSDag-Erling Smørgrav options->send_env[options->num_send_env++] = 142721e764dfSDag-Erling Smørgrav xstrdup(arg); 142821e764dfSDag-Erling Smørgrav } 1429190cef3dSDag-Erling Smørgrav } 1430190cef3dSDag-Erling Smørgrav break; 1431190cef3dSDag-Erling Smørgrav 1432190cef3dSDag-Erling Smørgrav case oSetEnv: 1433190cef3dSDag-Erling Smørgrav value = options->num_setenv; 1434190cef3dSDag-Erling Smørgrav while ((arg = strdelimw(&s)) != NULL && *arg != '\0') { 1435190cef3dSDag-Erling Smørgrav if (strchr(arg, '=') == NULL) 1436190cef3dSDag-Erling Smørgrav fatal("%s line %d: Invalid SetEnv.", 1437190cef3dSDag-Erling Smørgrav filename, linenum); 1438190cef3dSDag-Erling Smørgrav if (!*activep || value != 0) 1439190cef3dSDag-Erling Smørgrav continue; 1440190cef3dSDag-Erling Smørgrav /* Adding a setenv var */ 1441190cef3dSDag-Erling Smørgrav if (options->num_setenv >= INT_MAX) 1442190cef3dSDag-Erling Smørgrav fatal("%s line %d: too many SetEnv.", 1443190cef3dSDag-Erling Smørgrav filename, linenum); 1444190cef3dSDag-Erling Smørgrav options->setenv = xrecallocarray( 1445190cef3dSDag-Erling Smørgrav options->setenv, options->num_setenv, 1446190cef3dSDag-Erling Smørgrav options->num_setenv + 1, sizeof(*options->setenv)); 1447190cef3dSDag-Erling Smørgrav options->setenv[options->num_setenv++] = xstrdup(arg); 1448190cef3dSDag-Erling Smørgrav } 144921e764dfSDag-Erling Smørgrav break; 145021e764dfSDag-Erling Smørgrav 145121e764dfSDag-Erling Smørgrav case oControlPath: 145221e764dfSDag-Erling Smørgrav charptr = &options->control_path; 145321e764dfSDag-Erling Smørgrav goto parse_string; 145421e764dfSDag-Erling Smørgrav 145521e764dfSDag-Erling Smørgrav case oControlMaster: 145621e764dfSDag-Erling Smørgrav intptr = &options->control_master; 1457f7167e0eSDag-Erling Smørgrav multistate_ptr = multistate_controlmaster; 1458f7167e0eSDag-Erling Smørgrav goto parse_multistate; 145921e764dfSDag-Erling Smørgrav 1460e2f6069cSDag-Erling Smørgrav case oControlPersist: 1461e2f6069cSDag-Erling Smørgrav /* no/false/yes/true, or a time spec */ 1462e2f6069cSDag-Erling Smørgrav intptr = &options->control_persist; 1463e2f6069cSDag-Erling Smørgrav arg = strdelim(&s); 1464e2f6069cSDag-Erling Smørgrav if (!arg || *arg == '\0') 1465e2f6069cSDag-Erling Smørgrav fatal("%.200s line %d: Missing ControlPersist" 1466e2f6069cSDag-Erling Smørgrav " argument.", filename, linenum); 1467e2f6069cSDag-Erling Smørgrav value = 0; 1468e2f6069cSDag-Erling Smørgrav value2 = 0; /* timeout */ 1469e2f6069cSDag-Erling Smørgrav if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) 1470e2f6069cSDag-Erling Smørgrav value = 0; 1471e2f6069cSDag-Erling Smørgrav else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) 1472e2f6069cSDag-Erling Smørgrav value = 1; 1473e2f6069cSDag-Erling Smørgrav else if ((value2 = convtime(arg)) >= 0) 1474e2f6069cSDag-Erling Smørgrav value = 1; 1475e2f6069cSDag-Erling Smørgrav else 1476e2f6069cSDag-Erling Smørgrav fatal("%.200s line %d: Bad ControlPersist argument.", 1477e2f6069cSDag-Erling Smørgrav filename, linenum); 1478e2f6069cSDag-Erling Smørgrav if (*activep && *intptr == -1) { 1479e2f6069cSDag-Erling Smørgrav *intptr = value; 1480e2f6069cSDag-Erling Smørgrav options->control_persist_timeout = value2; 1481e2f6069cSDag-Erling Smørgrav } 1482e2f6069cSDag-Erling Smørgrav break; 1483e2f6069cSDag-Erling Smørgrav 1484aa49c926SDag-Erling Smørgrav case oHashKnownHosts: 1485aa49c926SDag-Erling Smørgrav intptr = &options->hash_known_hosts; 1486aa49c926SDag-Erling Smørgrav goto parse_flag; 1487aa49c926SDag-Erling Smørgrav 1488b74df5b2SDag-Erling Smørgrav case oTunnel: 1489b74df5b2SDag-Erling Smørgrav intptr = &options->tun_open; 1490f7167e0eSDag-Erling Smørgrav multistate_ptr = multistate_tunnel; 1491f7167e0eSDag-Erling Smørgrav goto parse_multistate; 1492b74df5b2SDag-Erling Smørgrav 1493b74df5b2SDag-Erling Smørgrav case oTunnelDevice: 1494b74df5b2SDag-Erling Smørgrav arg = strdelim(&s); 1495b74df5b2SDag-Erling Smørgrav if (!arg || *arg == '\0') 1496b74df5b2SDag-Erling Smørgrav fatal("%.200s line %d: Missing argument.", filename, linenum); 1497b74df5b2SDag-Erling Smørgrav value = a2tun(arg, &value2); 1498b74df5b2SDag-Erling Smørgrav if (value == SSH_TUNID_ERR) 1499b74df5b2SDag-Erling Smørgrav fatal("%.200s line %d: Bad tun device.", filename, linenum); 1500b74df5b2SDag-Erling Smørgrav if (*activep) { 1501b74df5b2SDag-Erling Smørgrav options->tun_local = value; 1502b74df5b2SDag-Erling Smørgrav options->tun_remote = value2; 1503b74df5b2SDag-Erling Smørgrav } 1504b74df5b2SDag-Erling Smørgrav break; 1505b74df5b2SDag-Erling Smørgrav 1506b74df5b2SDag-Erling Smørgrav case oLocalCommand: 1507b74df5b2SDag-Erling Smørgrav charptr = &options->local_command; 1508b74df5b2SDag-Erling Smørgrav goto parse_command; 1509b74df5b2SDag-Erling Smørgrav 1510b74df5b2SDag-Erling Smørgrav case oPermitLocalCommand: 1511b74df5b2SDag-Erling Smørgrav intptr = &options->permit_local_command; 1512b74df5b2SDag-Erling Smørgrav goto parse_flag; 1513b74df5b2SDag-Erling Smørgrav 15144f52dfbbSDag-Erling Smørgrav case oRemoteCommand: 15154f52dfbbSDag-Erling Smørgrav charptr = &options->remote_command; 15164f52dfbbSDag-Erling Smørgrav goto parse_command; 15174f52dfbbSDag-Erling Smørgrav 1518d4af9e69SDag-Erling Smørgrav case oVisualHostKey: 1519d4af9e69SDag-Erling Smørgrav intptr = &options->visual_host_key; 1520d4af9e69SDag-Erling Smørgrav goto parse_flag; 1521d4af9e69SDag-Erling Smørgrav 1522076ad2f8SDag-Erling Smørgrav case oInclude: 1523076ad2f8SDag-Erling Smørgrav if (cmdline) 1524076ad2f8SDag-Erling Smørgrav fatal("Include directive not supported as a " 1525076ad2f8SDag-Erling Smørgrav "command-line option"); 1526076ad2f8SDag-Erling Smørgrav value = 0; 1527076ad2f8SDag-Erling Smørgrav while ((arg = strdelim(&s)) != NULL && *arg != '\0') { 1528076ad2f8SDag-Erling Smørgrav /* 1529076ad2f8SDag-Erling Smørgrav * Ensure all paths are anchored. User configuration 1530076ad2f8SDag-Erling Smørgrav * files may begin with '~/' but system configurations 1531076ad2f8SDag-Erling Smørgrav * must not. If the path is relative, then treat it 1532076ad2f8SDag-Erling Smørgrav * as living in ~/.ssh for user configurations or 1533076ad2f8SDag-Erling Smørgrav * /etc/ssh for system ones. 1534076ad2f8SDag-Erling Smørgrav */ 1535076ad2f8SDag-Erling Smørgrav if (*arg == '~' && (flags & SSHCONF_USERCONF) == 0) 1536076ad2f8SDag-Erling Smørgrav fatal("%.200s line %d: bad include path %s.", 1537076ad2f8SDag-Erling Smørgrav filename, linenum, arg); 1538076ad2f8SDag-Erling Smørgrav if (*arg != '/' && *arg != '~') { 1539076ad2f8SDag-Erling Smørgrav xasprintf(&arg2, "%s/%s", 1540076ad2f8SDag-Erling Smørgrav (flags & SSHCONF_USERCONF) ? 1541076ad2f8SDag-Erling Smørgrav "~/" _PATH_SSH_USER_DIR : SSHDIR, arg); 1542076ad2f8SDag-Erling Smørgrav } else 1543076ad2f8SDag-Erling Smørgrav arg2 = xstrdup(arg); 1544076ad2f8SDag-Erling Smørgrav memset(&gl, 0, sizeof(gl)); 1545076ad2f8SDag-Erling Smørgrav r = glob(arg2, GLOB_TILDE, NULL, &gl); 1546076ad2f8SDag-Erling Smørgrav if (r == GLOB_NOMATCH) { 1547076ad2f8SDag-Erling Smørgrav debug("%.200s line %d: include %s matched no " 1548076ad2f8SDag-Erling Smørgrav "files",filename, linenum, arg2); 1549d93a896eSDag-Erling Smørgrav free(arg2); 1550076ad2f8SDag-Erling Smørgrav continue; 1551076ad2f8SDag-Erling Smørgrav } else if (r != 0 || gl.gl_pathc < 0) 1552076ad2f8SDag-Erling Smørgrav fatal("%.200s line %d: glob failed for %s.", 1553076ad2f8SDag-Erling Smørgrav filename, linenum, arg2); 1554076ad2f8SDag-Erling Smørgrav free(arg2); 1555076ad2f8SDag-Erling Smørgrav oactive = *activep; 1556076ad2f8SDag-Erling Smørgrav for (i = 0; i < (u_int)gl.gl_pathc; i++) { 1557076ad2f8SDag-Erling Smørgrav debug3("%.200s line %d: Including file %s " 1558076ad2f8SDag-Erling Smørgrav "depth %d%s", filename, linenum, 1559076ad2f8SDag-Erling Smørgrav gl.gl_pathv[i], depth, 1560076ad2f8SDag-Erling Smørgrav oactive ? "" : " (parse only)"); 1561076ad2f8SDag-Erling Smørgrav r = read_config_file_depth(gl.gl_pathv[i], 1562076ad2f8SDag-Erling Smørgrav pw, host, original_host, options, 1563076ad2f8SDag-Erling Smørgrav flags | SSHCONF_CHECKPERM | 1564076ad2f8SDag-Erling Smørgrav (oactive ? 0 : SSHCONF_NEVERMATCH), 1565076ad2f8SDag-Erling Smørgrav activep, depth + 1); 1566d93a896eSDag-Erling Smørgrav if (r != 1 && errno != ENOENT) { 1567d93a896eSDag-Erling Smørgrav fatal("Can't open user config file " 1568d93a896eSDag-Erling Smørgrav "%.100s: %.100s", gl.gl_pathv[i], 1569d93a896eSDag-Erling Smørgrav strerror(errno)); 1570d93a896eSDag-Erling Smørgrav } 1571076ad2f8SDag-Erling Smørgrav /* 1572076ad2f8SDag-Erling Smørgrav * don't let Match in includes clobber the 1573076ad2f8SDag-Erling Smørgrav * containing file's Match state. 1574076ad2f8SDag-Erling Smørgrav */ 1575076ad2f8SDag-Erling Smørgrav *activep = oactive; 1576076ad2f8SDag-Erling Smørgrav if (r != 1) 1577076ad2f8SDag-Erling Smørgrav value = -1; 1578076ad2f8SDag-Erling Smørgrav } 1579076ad2f8SDag-Erling Smørgrav globfree(&gl); 1580076ad2f8SDag-Erling Smørgrav } 1581076ad2f8SDag-Erling Smørgrav if (value != 0) 1582076ad2f8SDag-Erling Smørgrav return value; 1583076ad2f8SDag-Erling Smørgrav break; 1584076ad2f8SDag-Erling Smørgrav 15854a421b63SDag-Erling Smørgrav case oIPQoS: 15864a421b63SDag-Erling Smørgrav arg = strdelim(&s); 15874a421b63SDag-Erling Smørgrav if ((value = parse_ipqos(arg)) == -1) 15884a421b63SDag-Erling Smørgrav fatal("%s line %d: Bad IPQoS value: %s", 15894a421b63SDag-Erling Smørgrav filename, linenum, arg); 15904a421b63SDag-Erling Smørgrav arg = strdelim(&s); 15914a421b63SDag-Erling Smørgrav if (arg == NULL) 15924a421b63SDag-Erling Smørgrav value2 = value; 15934a421b63SDag-Erling Smørgrav else if ((value2 = parse_ipqos(arg)) == -1) 15944a421b63SDag-Erling Smørgrav fatal("%s line %d: Bad IPQoS value: %s", 15954a421b63SDag-Erling Smørgrav filename, linenum, arg); 15964a421b63SDag-Erling Smørgrav if (*activep) { 15974a421b63SDag-Erling Smørgrav options->ip_qos_interactive = value; 15984a421b63SDag-Erling Smørgrav options->ip_qos_bulk = value2; 15994a421b63SDag-Erling Smørgrav } 16004a421b63SDag-Erling Smørgrav break; 16014a421b63SDag-Erling Smørgrav 1602e146993eSDag-Erling Smørgrav case oRequestTTY: 1603e146993eSDag-Erling Smørgrav intptr = &options->request_tty; 1604f7167e0eSDag-Erling Smørgrav multistate_ptr = multistate_requesttty; 1605f7167e0eSDag-Erling Smørgrav goto parse_multistate; 1606975616f0SDag-Erling Smørgrav 1607e146993eSDag-Erling Smørgrav case oVersionAddendum: 1608462c32cbSDag-Erling Smørgrav if (s == NULL) 1609462c32cbSDag-Erling Smørgrav fatal("%.200s line %d: Missing argument.", filename, 1610462c32cbSDag-Erling Smørgrav linenum); 1611462c32cbSDag-Erling Smørgrav len = strspn(s, WHITESPACE); 1612462c32cbSDag-Erling Smørgrav if (*activep && options->version_addendum == NULL) { 1613462c32cbSDag-Erling Smørgrav if (strcasecmp(s + len, "none") == 0) 1614462c32cbSDag-Erling Smørgrav options->version_addendum = xstrdup(""); 1615462c32cbSDag-Erling Smørgrav else if (strchr(s + len, '\r') != NULL) 1616462c32cbSDag-Erling Smørgrav fatal("%.200s line %d: Invalid argument", 1617462c32cbSDag-Erling Smørgrav filename, linenum); 1618462c32cbSDag-Erling Smørgrav else 1619462c32cbSDag-Erling Smørgrav options->version_addendum = xstrdup(s + len); 1620462c32cbSDag-Erling Smørgrav } 1621462c32cbSDag-Erling Smørgrav return 0; 1622e146993eSDag-Erling Smørgrav 1623e4a9863fSDag-Erling Smørgrav case oIgnoreUnknown: 1624e4a9863fSDag-Erling Smørgrav charptr = &options->ignored_unknown; 1625e4a9863fSDag-Erling Smørgrav goto parse_string; 1626e4a9863fSDag-Erling Smørgrav 1627f7167e0eSDag-Erling Smørgrav case oProxyUseFdpass: 1628f7167e0eSDag-Erling Smørgrav intptr = &options->proxy_use_fdpass; 1629f7167e0eSDag-Erling Smørgrav goto parse_flag; 1630f7167e0eSDag-Erling Smørgrav 1631f7167e0eSDag-Erling Smørgrav case oCanonicalDomains: 1632f7167e0eSDag-Erling Smørgrav value = options->num_canonical_domains != 0; 1633f7167e0eSDag-Erling Smørgrav while ((arg = strdelim(&s)) != NULL && *arg != '\0') { 163447dd1d1bSDag-Erling Smørgrav if (!valid_domain(arg, 1, &errstr)) { 163547dd1d1bSDag-Erling Smørgrav fatal("%s line %d: %s", filename, linenum, 163647dd1d1bSDag-Erling Smørgrav errstr); 163747dd1d1bSDag-Erling Smørgrav } 1638f7167e0eSDag-Erling Smørgrav if (!*activep || value) 1639f7167e0eSDag-Erling Smørgrav continue; 1640f7167e0eSDag-Erling Smørgrav if (options->num_canonical_domains >= MAX_CANON_DOMAINS) 1641f7167e0eSDag-Erling Smørgrav fatal("%s line %d: too many hostname suffixes.", 1642f7167e0eSDag-Erling Smørgrav filename, linenum); 1643f7167e0eSDag-Erling Smørgrav options->canonical_domains[ 1644f7167e0eSDag-Erling Smørgrav options->num_canonical_domains++] = xstrdup(arg); 1645f7167e0eSDag-Erling Smørgrav } 1646f7167e0eSDag-Erling Smørgrav break; 1647f7167e0eSDag-Erling Smørgrav 1648f7167e0eSDag-Erling Smørgrav case oCanonicalizePermittedCNAMEs: 1649f7167e0eSDag-Erling Smørgrav value = options->num_permitted_cnames != 0; 1650f7167e0eSDag-Erling Smørgrav while ((arg = strdelim(&s)) != NULL && *arg != '\0') { 1651f7167e0eSDag-Erling Smørgrav /* Either '*' for everything or 'list:list' */ 1652f7167e0eSDag-Erling Smørgrav if (strcmp(arg, "*") == 0) 1653f7167e0eSDag-Erling Smørgrav arg2 = arg; 1654f7167e0eSDag-Erling Smørgrav else { 1655f7167e0eSDag-Erling Smørgrav lowercase(arg); 1656f7167e0eSDag-Erling Smørgrav if ((arg2 = strchr(arg, ':')) == NULL || 1657f7167e0eSDag-Erling Smørgrav arg2[1] == '\0') { 1658f7167e0eSDag-Erling Smørgrav fatal("%s line %d: " 1659f7167e0eSDag-Erling Smørgrav "Invalid permitted CNAME \"%s\"", 1660f7167e0eSDag-Erling Smørgrav filename, linenum, arg); 1661f7167e0eSDag-Erling Smørgrav } 1662f7167e0eSDag-Erling Smørgrav *arg2 = '\0'; 1663f7167e0eSDag-Erling Smørgrav arg2++; 1664f7167e0eSDag-Erling Smørgrav } 1665f7167e0eSDag-Erling Smørgrav if (!*activep || value) 1666f7167e0eSDag-Erling Smørgrav continue; 1667f7167e0eSDag-Erling Smørgrav if (options->num_permitted_cnames >= MAX_CANON_DOMAINS) 1668f7167e0eSDag-Erling Smørgrav fatal("%s line %d: too many permitted CNAMEs.", 1669f7167e0eSDag-Erling Smørgrav filename, linenum); 1670f7167e0eSDag-Erling Smørgrav cname = options->permitted_cnames + 1671f7167e0eSDag-Erling Smørgrav options->num_permitted_cnames++; 1672f7167e0eSDag-Erling Smørgrav cname->source_list = xstrdup(arg); 1673f7167e0eSDag-Erling Smørgrav cname->target_list = xstrdup(arg2); 1674f7167e0eSDag-Erling Smørgrav } 1675f7167e0eSDag-Erling Smørgrav break; 1676f7167e0eSDag-Erling Smørgrav 1677f7167e0eSDag-Erling Smørgrav case oCanonicalizeHostname: 1678f7167e0eSDag-Erling Smørgrav intptr = &options->canonicalize_hostname; 1679f7167e0eSDag-Erling Smørgrav multistate_ptr = multistate_canonicalizehostname; 1680f7167e0eSDag-Erling Smørgrav goto parse_multistate; 1681f7167e0eSDag-Erling Smørgrav 1682f7167e0eSDag-Erling Smørgrav case oCanonicalizeMaxDots: 1683f7167e0eSDag-Erling Smørgrav intptr = &options->canonicalize_max_dots; 1684f7167e0eSDag-Erling Smørgrav goto parse_int; 1685f7167e0eSDag-Erling Smørgrav 1686f7167e0eSDag-Erling Smørgrav case oCanonicalizeFallbackLocal: 1687f7167e0eSDag-Erling Smørgrav intptr = &options->canonicalize_fallback_local; 1688f7167e0eSDag-Erling Smørgrav goto parse_flag; 1689f7167e0eSDag-Erling Smørgrav 1690a0ee8cc6SDag-Erling Smørgrav case oStreamLocalBindMask: 1691a0ee8cc6SDag-Erling Smørgrav arg = strdelim(&s); 1692a0ee8cc6SDag-Erling Smørgrav if (!arg || *arg == '\0') 1693a0ee8cc6SDag-Erling Smørgrav fatal("%.200s line %d: Missing StreamLocalBindMask argument.", filename, linenum); 1694a0ee8cc6SDag-Erling Smørgrav /* Parse mode in octal format */ 1695a0ee8cc6SDag-Erling Smørgrav value = strtol(arg, &endofnumber, 8); 1696a0ee8cc6SDag-Erling Smørgrav if (arg == endofnumber || value < 0 || value > 0777) 1697a0ee8cc6SDag-Erling Smørgrav fatal("%.200s line %d: Bad mask.", filename, linenum); 1698a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_mask = (mode_t)value; 1699a0ee8cc6SDag-Erling Smørgrav break; 1700a0ee8cc6SDag-Erling Smørgrav 1701a0ee8cc6SDag-Erling Smørgrav case oStreamLocalBindUnlink: 1702a0ee8cc6SDag-Erling Smørgrav intptr = &options->fwd_opts.streamlocal_bind_unlink; 1703a0ee8cc6SDag-Erling Smørgrav goto parse_flag; 1704a0ee8cc6SDag-Erling Smørgrav 1705bc5531deSDag-Erling Smørgrav case oRevokedHostKeys: 1706bc5531deSDag-Erling Smørgrav charptr = &options->revoked_host_keys; 1707bc5531deSDag-Erling Smørgrav goto parse_string; 1708bc5531deSDag-Erling Smørgrav 1709bc5531deSDag-Erling Smørgrav case oFingerprintHash: 1710bc5531deSDag-Erling Smørgrav intptr = &options->fingerprint_hash; 1711bc5531deSDag-Erling Smørgrav arg = strdelim(&s); 1712bc5531deSDag-Erling Smørgrav if (!arg || *arg == '\0') 1713bc5531deSDag-Erling Smørgrav fatal("%.200s line %d: Missing argument.", 1714bc5531deSDag-Erling Smørgrav filename, linenum); 1715bc5531deSDag-Erling Smørgrav if ((value = ssh_digest_alg_by_name(arg)) == -1) 1716bc5531deSDag-Erling Smørgrav fatal("%.200s line %d: Invalid hash algorithm \"%s\".", 1717bc5531deSDag-Erling Smørgrav filename, linenum, arg); 1718bc5531deSDag-Erling Smørgrav if (*activep && *intptr == -1) 1719bc5531deSDag-Erling Smørgrav *intptr = value; 1720bc5531deSDag-Erling Smørgrav break; 1721bc5531deSDag-Erling Smørgrav 1722bc5531deSDag-Erling Smørgrav case oUpdateHostkeys: 1723bc5531deSDag-Erling Smørgrav intptr = &options->update_hostkeys; 1724bc5531deSDag-Erling Smørgrav multistate_ptr = multistate_yesnoask; 1725bc5531deSDag-Erling Smørgrav goto parse_multistate; 1726bc5531deSDag-Erling Smørgrav 1727bc5531deSDag-Erling Smørgrav case oHostbasedKeyTypes: 1728bc5531deSDag-Erling Smørgrav charptr = &options->hostbased_key_types; 1729eccfee6eSDag-Erling Smørgrav goto parse_keytypes; 1730eccfee6eSDag-Erling Smørgrav 1731eccfee6eSDag-Erling Smørgrav case oPubkeyAcceptedKeyTypes: 1732eccfee6eSDag-Erling Smørgrav charptr = &options->pubkey_key_types; 1733eccfee6eSDag-Erling Smørgrav goto parse_keytypes; 1734bc5531deSDag-Erling Smørgrav 1735acc1a9efSDag-Erling Smørgrav case oAddKeysToAgent: 1736acc1a9efSDag-Erling Smørgrav intptr = &options->add_keys_to_agent; 1737acc1a9efSDag-Erling Smørgrav multistate_ptr = multistate_yesnoaskconfirm; 1738acc1a9efSDag-Erling Smørgrav goto parse_multistate; 1739acc1a9efSDag-Erling Smørgrav 1740076ad2f8SDag-Erling Smørgrav case oIdentityAgent: 1741076ad2f8SDag-Erling Smørgrav charptr = &options->identity_agent; 17422f513db7SEd Maste arg = strdelim(&s); 17432f513db7SEd Maste if (!arg || *arg == '\0') 17442f513db7SEd Maste fatal("%.200s line %d: Missing argument.", 17452f513db7SEd Maste filename, linenum); 17462f513db7SEd Maste /* Extra validation if the string represents an env var. */ 17472f513db7SEd Maste if (arg[0] == '$' && !valid_env_name(arg + 1)) { 17482f513db7SEd Maste fatal("%.200s line %d: Invalid environment name %s.", 17492f513db7SEd Maste filename, linenum, arg); 17502f513db7SEd Maste } 17512f513db7SEd Maste if (*activep && *charptr == NULL) 17522f513db7SEd Maste *charptr = xstrdup(arg); 17532f513db7SEd Maste break; 1754076ad2f8SDag-Erling Smørgrav 175580628bacSDag-Erling Smørgrav case oDeprecated: 175680628bacSDag-Erling Smørgrav debug("%s line %d: Deprecated option \"%s\"", 175780628bacSDag-Erling Smørgrav filename, linenum, keyword); 175880628bacSDag-Erling Smørgrav return 0; 175980628bacSDag-Erling Smørgrav 1760cf2b5f3bSDag-Erling Smørgrav case oUnsupported: 1761cf2b5f3bSDag-Erling Smørgrav error("%s line %d: Unsupported option \"%s\"", 1762cf2b5f3bSDag-Erling Smørgrav filename, linenum, keyword); 1763cf2b5f3bSDag-Erling Smørgrav return 0; 1764cf2b5f3bSDag-Erling Smørgrav 1765511b41d2SMark Murray default: 1766bc5531deSDag-Erling Smørgrav fatal("%s: Unimplemented opcode %d", __func__, opcode); 1767511b41d2SMark Murray } 1768511b41d2SMark Murray 1769511b41d2SMark Murray /* Check that there is no garbage at end of line. */ 1770ca3176e7SBrian Feldman if ((arg = strdelim(&s)) != NULL && *arg != '\0') { 1771c2d3a559SKris Kennaway fatal("%.200s line %d: garbage at end of line; \"%.200s\".", 1772c2d3a559SKris Kennaway filename, linenum, arg); 1773c2d3a559SKris Kennaway } 1774511b41d2SMark Murray return 0; 1775511b41d2SMark Murray } 1776511b41d2SMark Murray 1777511b41d2SMark Murray /* 1778511b41d2SMark Murray * Reads the config file and modifies the options accordingly. Options 1779511b41d2SMark Murray * should already be initialized before this call. This never returns if 1780af12a3e7SDag-Erling Smørgrav * there is an error. If the file does not exist, this returns 0. 1781511b41d2SMark Murray */ 1782af12a3e7SDag-Erling Smørgrav int 1783f7167e0eSDag-Erling Smørgrav read_config_file(const char *filename, struct passwd *pw, const char *host, 1784bc5531deSDag-Erling Smørgrav const char *original_host, Options *options, int flags) 1785511b41d2SMark Murray { 1786076ad2f8SDag-Erling Smørgrav int active = 1; 1787076ad2f8SDag-Erling Smørgrav 1788076ad2f8SDag-Erling Smørgrav return read_config_file_depth(filename, pw, host, original_host, 1789076ad2f8SDag-Erling Smørgrav options, flags, &active, 0); 1790076ad2f8SDag-Erling Smørgrav } 1791076ad2f8SDag-Erling Smørgrav 1792076ad2f8SDag-Erling Smørgrav #define READCONF_MAX_DEPTH 16 1793076ad2f8SDag-Erling Smørgrav static int 1794076ad2f8SDag-Erling Smørgrav read_config_file_depth(const char *filename, struct passwd *pw, 1795076ad2f8SDag-Erling Smørgrav const char *host, const char *original_host, Options *options, 1796076ad2f8SDag-Erling Smørgrav int flags, int *activep, int depth) 1797076ad2f8SDag-Erling Smørgrav { 1798511b41d2SMark Murray FILE *f; 1799190cef3dSDag-Erling Smørgrav char *line = NULL; 1800190cef3dSDag-Erling Smørgrav size_t linesize = 0; 1801076ad2f8SDag-Erling Smørgrav int linenum; 1802511b41d2SMark Murray int bad_options = 0; 1803511b41d2SMark Murray 1804076ad2f8SDag-Erling Smørgrav if (depth < 0 || depth > READCONF_MAX_DEPTH) 1805076ad2f8SDag-Erling Smørgrav fatal("Too many recursive configuration includes"); 1806076ad2f8SDag-Erling Smørgrav 180721e764dfSDag-Erling Smørgrav if ((f = fopen(filename, "r")) == NULL) 1808af12a3e7SDag-Erling Smørgrav return 0; 1809511b41d2SMark Murray 181073370613SDag-Erling Smørgrav if (flags & SSHCONF_CHECKPERM) { 181121e764dfSDag-Erling Smørgrav struct stat sb; 181221e764dfSDag-Erling Smørgrav 181321e764dfSDag-Erling Smørgrav if (fstat(fileno(f), &sb) == -1) 181421e764dfSDag-Erling Smørgrav fatal("fstat %s: %s", filename, strerror(errno)); 181521e764dfSDag-Erling Smørgrav if (((sb.st_uid != 0 && sb.st_uid != getuid()) || 181621e764dfSDag-Erling Smørgrav (sb.st_mode & 022) != 0)) 181721e764dfSDag-Erling Smørgrav fatal("Bad owner or permissions on %s", filename); 181821e764dfSDag-Erling Smørgrav } 181921e764dfSDag-Erling Smørgrav 1820511b41d2SMark Murray debug("Reading configuration data %.200s", filename); 1821511b41d2SMark Murray 1822511b41d2SMark Murray /* 1823511b41d2SMark Murray * Mark that we are now processing the options. This flag is turned 1824511b41d2SMark Murray * on/off by Host specifications. 1825511b41d2SMark Murray */ 1826511b41d2SMark Murray linenum = 0; 1827190cef3dSDag-Erling Smørgrav while (getline(&line, &linesize, f) != -1) { 1828511b41d2SMark Murray /* Update line number counter. */ 1829511b41d2SMark Murray linenum++; 1830076ad2f8SDag-Erling Smørgrav if (process_config_line_depth(options, pw, host, original_host, 1831076ad2f8SDag-Erling Smørgrav line, filename, linenum, activep, flags, depth) != 0) 1832511b41d2SMark Murray bad_options++; 1833511b41d2SMark Murray } 1834190cef3dSDag-Erling Smørgrav free(line); 1835511b41d2SMark Murray fclose(f); 1836511b41d2SMark Murray if (bad_options > 0) 1837ca3176e7SBrian Feldman fatal("%s: terminating, %d bad configuration options", 1838511b41d2SMark Murray filename, bad_options); 1839af12a3e7SDag-Erling Smørgrav return 1; 1840511b41d2SMark Murray } 1841511b41d2SMark Murray 1842b83788ffSDag-Erling Smørgrav /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ 1843b83788ffSDag-Erling Smørgrav int 1844b83788ffSDag-Erling Smørgrav option_clear_or_none(const char *o) 1845b83788ffSDag-Erling Smørgrav { 1846b83788ffSDag-Erling Smørgrav return o == NULL || strcasecmp(o, "none") == 0; 1847b83788ffSDag-Erling Smørgrav } 1848b83788ffSDag-Erling Smørgrav 1849511b41d2SMark Murray /* 1850511b41d2SMark Murray * Initializes options to special values that indicate that they have not yet 1851511b41d2SMark Murray * been set. Read_config_file will only set options with this value. Options 1852511b41d2SMark Murray * are processed in the following order: command line, user config file, 1853511b41d2SMark Murray * system config file. Last, fill_default_options is called. 1854511b41d2SMark Murray */ 1855511b41d2SMark Murray 1856511b41d2SMark Murray void 1857511b41d2SMark Murray initialize_options(Options * options) 1858511b41d2SMark Murray { 1859511b41d2SMark Murray memset(options, 'X', sizeof(*options)); 1860eccfee6eSDag-Erling Smørgrav options->version_addendum = NULL; 1861511b41d2SMark Murray options->forward_agent = -1; 1862511b41d2SMark Murray options->forward_x11 = -1; 18631ec0d754SDag-Erling Smørgrav options->forward_x11_trusted = -1; 1864e2f6069cSDag-Erling Smørgrav options->forward_x11_timeout = -1; 1865076ad2f8SDag-Erling Smørgrav options->stdio_forward_host = NULL; 1866076ad2f8SDag-Erling Smørgrav options->stdio_forward_port = 0; 1867076ad2f8SDag-Erling Smørgrav options->clear_forwardings = -1; 1868333ee039SDag-Erling Smørgrav options->exit_on_forward_failure = -1; 1869c2d3a559SKris Kennaway options->xauth_location = NULL; 1870a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.gateway_ports = -1; 1871a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_mask = (mode_t)-1; 1872a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_unlink = -1; 1873ca3176e7SBrian Feldman options->pubkey_authentication = -1; 1874af12a3e7SDag-Erling Smørgrav options->challenge_response_authentication = -1; 1875cf2b5f3bSDag-Erling Smørgrav options->gss_authentication = -1; 1876cf2b5f3bSDag-Erling Smørgrav options->gss_deleg_creds = -1; 1877511b41d2SMark Murray options->password_authentication = -1; 187809958426SBrian Feldman options->kbd_interactive_authentication = -1; 187909958426SBrian Feldman options->kbd_interactive_devices = NULL; 1880ca3176e7SBrian Feldman options->hostbased_authentication = -1; 1881511b41d2SMark Murray options->batch_mode = -1; 1882511b41d2SMark Murray options->check_host_ip = -1; 1883511b41d2SMark Murray options->strict_host_key_checking = -1; 1884511b41d2SMark Murray options->compression = -1; 18851ec0d754SDag-Erling Smørgrav options->tcp_keep_alive = -1; 1886511b41d2SMark Murray options->port = -1; 1887cf2b5f3bSDag-Erling Smørgrav options->address_family = -1; 1888511b41d2SMark Murray options->connection_attempts = -1; 1889cf2b5f3bSDag-Erling Smørgrav options->connection_timeout = -1; 1890511b41d2SMark Murray options->number_of_password_prompts = -1; 1891e8aafc91SKris Kennaway options->ciphers = NULL; 1892ca3176e7SBrian Feldman options->macs = NULL; 18934a421b63SDag-Erling Smørgrav options->kex_algorithms = NULL; 1894ca3176e7SBrian Feldman options->hostkeyalgorithms = NULL; 18952f513db7SEd Maste options->ca_sign_algorithms = NULL; 1896511b41d2SMark Murray options->num_identity_files = 0; 1897acc1a9efSDag-Erling Smørgrav options->num_certificate_files = 0; 1898511b41d2SMark Murray options->hostname = NULL; 1899ca3176e7SBrian Feldman options->host_key_alias = NULL; 1900511b41d2SMark Murray options->proxy_command = NULL; 1901076ad2f8SDag-Erling Smørgrav options->jump_user = NULL; 1902076ad2f8SDag-Erling Smørgrav options->jump_host = NULL; 1903076ad2f8SDag-Erling Smørgrav options->jump_port = -1; 1904076ad2f8SDag-Erling Smørgrav options->jump_extra = NULL; 1905511b41d2SMark Murray options->user = NULL; 1906511b41d2SMark Murray options->escape_char = -1; 1907e146993eSDag-Erling Smørgrav options->num_system_hostfiles = 0; 1908e146993eSDag-Erling Smørgrav options->num_user_hostfiles = 0; 1909e2f6069cSDag-Erling Smørgrav options->local_forwards = NULL; 1910511b41d2SMark Murray options->num_local_forwards = 0; 1911e2f6069cSDag-Erling Smørgrav options->remote_forwards = NULL; 1912511b41d2SMark Murray options->num_remote_forwards = 0; 19134f52dfbbSDag-Erling Smørgrav options->log_facility = SYSLOG_FACILITY_NOT_SET; 1914af12a3e7SDag-Erling Smørgrav options->log_level = SYSLOG_LEVEL_NOT_SET; 1915ca3176e7SBrian Feldman options->preferred_authentications = NULL; 1916af12a3e7SDag-Erling Smørgrav options->bind_address = NULL; 191747dd1d1bSDag-Erling Smørgrav options->bind_interface = NULL; 1918b15c8340SDag-Erling Smørgrav options->pkcs11_provider = NULL; 1919e73e9afaSDag-Erling Smørgrav options->enable_ssh_keysign = - 1; 1920af12a3e7SDag-Erling Smørgrav options->no_host_authentication_for_localhost = - 1; 19215962c0e9SDag-Erling Smørgrav options->identities_only = - 1; 1922cf2b5f3bSDag-Erling Smørgrav options->rekey_limit = - 1; 1923e4a9863fSDag-Erling Smørgrav options->rekey_interval = -1; 1924cf2b5f3bSDag-Erling Smørgrav options->verify_host_key_dns = -1; 19251ec0d754SDag-Erling Smørgrav options->server_alive_interval = -1; 19261ec0d754SDag-Erling Smørgrav options->server_alive_count_max = -1; 1927190cef3dSDag-Erling Smørgrav options->send_env = NULL; 192821e764dfSDag-Erling Smørgrav options->num_send_env = 0; 1929190cef3dSDag-Erling Smørgrav options->setenv = NULL; 1930190cef3dSDag-Erling Smørgrav options->num_setenv = 0; 193121e764dfSDag-Erling Smørgrav options->control_path = NULL; 193221e764dfSDag-Erling Smørgrav options->control_master = -1; 1933e2f6069cSDag-Erling Smørgrav options->control_persist = -1; 1934e2f6069cSDag-Erling Smørgrav options->control_persist_timeout = 0; 1935aa49c926SDag-Erling Smørgrav options->hash_known_hosts = -1; 1936b74df5b2SDag-Erling Smørgrav options->tun_open = -1; 1937b74df5b2SDag-Erling Smørgrav options->tun_local = -1; 1938b74df5b2SDag-Erling Smørgrav options->tun_remote = -1; 1939b74df5b2SDag-Erling Smørgrav options->local_command = NULL; 1940b74df5b2SDag-Erling Smørgrav options->permit_local_command = -1; 19414f52dfbbSDag-Erling Smørgrav options->remote_command = NULL; 1942acc1a9efSDag-Erling Smørgrav options->add_keys_to_agent = -1; 1943076ad2f8SDag-Erling Smørgrav options->identity_agent = NULL; 1944d4af9e69SDag-Erling Smørgrav options->visual_host_key = -1; 19454a421b63SDag-Erling Smørgrav options->ip_qos_interactive = -1; 19464a421b63SDag-Erling Smørgrav options->ip_qos_bulk = -1; 1947e146993eSDag-Erling Smørgrav options->request_tty = -1; 1948f7167e0eSDag-Erling Smørgrav options->proxy_use_fdpass = -1; 1949e4a9863fSDag-Erling Smørgrav options->ignored_unknown = NULL; 1950f7167e0eSDag-Erling Smørgrav options->num_canonical_domains = 0; 1951f7167e0eSDag-Erling Smørgrav options->num_permitted_cnames = 0; 1952f7167e0eSDag-Erling Smørgrav options->canonicalize_max_dots = -1; 1953f7167e0eSDag-Erling Smørgrav options->canonicalize_fallback_local = -1; 1954f7167e0eSDag-Erling Smørgrav options->canonicalize_hostname = -1; 1955bc5531deSDag-Erling Smørgrav options->revoked_host_keys = NULL; 1956bc5531deSDag-Erling Smørgrav options->fingerprint_hash = -1; 1957bc5531deSDag-Erling Smørgrav options->update_hostkeys = -1; 1958bc5531deSDag-Erling Smørgrav options->hostbased_key_types = NULL; 1959eccfee6eSDag-Erling Smørgrav options->pubkey_key_types = NULL; 1960511b41d2SMark Murray } 1961511b41d2SMark Murray 1962511b41d2SMark Murray /* 1963b83788ffSDag-Erling Smørgrav * A petite version of fill_default_options() that just fills the options 1964b83788ffSDag-Erling Smørgrav * needed for hostname canonicalization to proceed. 1965b83788ffSDag-Erling Smørgrav */ 1966b83788ffSDag-Erling Smørgrav void 1967b83788ffSDag-Erling Smørgrav fill_default_options_for_canonicalization(Options *options) 1968b83788ffSDag-Erling Smørgrav { 1969b83788ffSDag-Erling Smørgrav if (options->canonicalize_max_dots == -1) 1970b83788ffSDag-Erling Smørgrav options->canonicalize_max_dots = 1; 1971b83788ffSDag-Erling Smørgrav if (options->canonicalize_fallback_local == -1) 1972b83788ffSDag-Erling Smørgrav options->canonicalize_fallback_local = 1; 1973b83788ffSDag-Erling Smørgrav if (options->canonicalize_hostname == -1) 1974b83788ffSDag-Erling Smørgrav options->canonicalize_hostname = SSH_CANONICALISE_NO; 1975b83788ffSDag-Erling Smørgrav } 1976b83788ffSDag-Erling Smørgrav 1977b83788ffSDag-Erling Smørgrav /* 1978511b41d2SMark Murray * Called after processing other sources of option data, this fills those 1979511b41d2SMark Murray * options for which no value has been specified with their default values. 1980511b41d2SMark Murray */ 1981511b41d2SMark Murray void 1982511b41d2SMark Murray fill_default_options(Options * options) 1983511b41d2SMark Murray { 19842f513db7SEd Maste char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig; 1985190cef3dSDag-Erling Smørgrav int r; 198677c2fe20SDag-Erling Smørgrav #ifdef VMWARE_GUEST_WORKAROUND 198777c2fe20SDag-Erling Smørgrav char scval[7]; /* "vmware\0" */ 198877c2fe20SDag-Erling Smørgrav size_t scsiz = sizeof(scval); 198977c2fe20SDag-Erling Smørgrav int vmwguest = 0; 199077c2fe20SDag-Erling Smørgrav 199177c2fe20SDag-Erling Smørgrav if (sysctlbyname("kern.vm_guest", scval, &scsiz, NULL, 0) == 0 && 199277c2fe20SDag-Erling Smørgrav strcmp(scval, "vmware") == 0) 199377c2fe20SDag-Erling Smørgrav vmwguest = 1; 199477c2fe20SDag-Erling Smørgrav #endif 1995190cef3dSDag-Erling Smørgrav 1996511b41d2SMark Murray if (options->forward_agent == -1) 1997db1cb46cSKris Kennaway options->forward_agent = 0; 1998511b41d2SMark Murray if (options->forward_x11 == -1) 19995dc73ebeSBrian Feldman options->forward_x11 = 0; 20001ec0d754SDag-Erling Smørgrav if (options->forward_x11_trusted == -1) 20011ec0d754SDag-Erling Smørgrav options->forward_x11_trusted = 0; 2002e2f6069cSDag-Erling Smørgrav if (options->forward_x11_timeout == -1) 2003e2f6069cSDag-Erling Smørgrav options->forward_x11_timeout = 1200; 2004076ad2f8SDag-Erling Smørgrav /* 2005076ad2f8SDag-Erling Smørgrav * stdio forwarding (-W) changes the default for these but we defer 2006076ad2f8SDag-Erling Smørgrav * setting the values so they can be overridden. 2007076ad2f8SDag-Erling Smørgrav */ 2008333ee039SDag-Erling Smørgrav if (options->exit_on_forward_failure == -1) 2009076ad2f8SDag-Erling Smørgrav options->exit_on_forward_failure = 2010076ad2f8SDag-Erling Smørgrav options->stdio_forward_host != NULL ? 1 : 0; 2011076ad2f8SDag-Erling Smørgrav if (options->clear_forwardings == -1) 2012076ad2f8SDag-Erling Smørgrav options->clear_forwardings = 2013076ad2f8SDag-Erling Smørgrav options->stdio_forward_host != NULL ? 1 : 0; 2014076ad2f8SDag-Erling Smørgrav if (options->clear_forwardings == 1) 2015076ad2f8SDag-Erling Smørgrav clear_forwardings(options); 2016076ad2f8SDag-Erling Smørgrav 2017c2d3a559SKris Kennaway if (options->xauth_location == NULL) 2018af12a3e7SDag-Erling Smørgrav options->xauth_location = _PATH_XAUTH; 2019a0ee8cc6SDag-Erling Smørgrav if (options->fwd_opts.gateway_ports == -1) 2020a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.gateway_ports = 0; 2021a0ee8cc6SDag-Erling Smørgrav if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1) 2022a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_mask = 0177; 2023a0ee8cc6SDag-Erling Smørgrav if (options->fwd_opts.streamlocal_bind_unlink == -1) 2024a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_unlink = 0; 2025ca3176e7SBrian Feldman if (options->pubkey_authentication == -1) 2026ca3176e7SBrian Feldman options->pubkey_authentication = 1; 2027af12a3e7SDag-Erling Smørgrav if (options->challenge_response_authentication == -1) 2028af12a3e7SDag-Erling Smørgrav options->challenge_response_authentication = 1; 2029cf2b5f3bSDag-Erling Smørgrav if (options->gss_authentication == -1) 20301ec0d754SDag-Erling Smørgrav options->gss_authentication = 0; 2031cf2b5f3bSDag-Erling Smørgrav if (options->gss_deleg_creds == -1) 2032cf2b5f3bSDag-Erling Smørgrav options->gss_deleg_creds = 0; 2033511b41d2SMark Murray if (options->password_authentication == -1) 2034511b41d2SMark Murray options->password_authentication = 1; 203509958426SBrian Feldman if (options->kbd_interactive_authentication == -1) 2036ca3176e7SBrian Feldman options->kbd_interactive_authentication = 1; 2037ca3176e7SBrian Feldman if (options->hostbased_authentication == -1) 2038ca3176e7SBrian Feldman options->hostbased_authentication = 0; 2039511b41d2SMark Murray if (options->batch_mode == -1) 2040511b41d2SMark Murray options->batch_mode = 0; 2041511b41d2SMark Murray if (options->check_host_ip == -1) 2042975616f0SDag-Erling Smørgrav options->check_host_ip = 0; 2043511b41d2SMark Murray if (options->strict_host_key_checking == -1) 20444f52dfbbSDag-Erling Smørgrav options->strict_host_key_checking = SSH_STRICT_HOSTKEY_ASK; 2045511b41d2SMark Murray if (options->compression == -1) 2046511b41d2SMark Murray options->compression = 0; 20471ec0d754SDag-Erling Smørgrav if (options->tcp_keep_alive == -1) 20481ec0d754SDag-Erling Smørgrav options->tcp_keep_alive = 1; 2049511b41d2SMark Murray if (options->port == -1) 2050511b41d2SMark Murray options->port = 0; /* Filled in ssh_connect. */ 2051cf2b5f3bSDag-Erling Smørgrav if (options->address_family == -1) 2052cf2b5f3bSDag-Erling Smørgrav options->address_family = AF_UNSPEC; 2053511b41d2SMark Murray if (options->connection_attempts == -1) 2054af12a3e7SDag-Erling Smørgrav options->connection_attempts = 1; 2055511b41d2SMark Murray if (options->number_of_password_prompts == -1) 2056511b41d2SMark Murray options->number_of_password_prompts = 3; 2057ca3176e7SBrian Feldman /* options->hostkeyalgorithms, default set in myproposals.h */ 2058acc1a9efSDag-Erling Smørgrav if (options->add_keys_to_agent == -1) 2059acc1a9efSDag-Erling Smørgrav options->add_keys_to_agent = 0; 2060511b41d2SMark Murray if (options->num_identity_files == 0) { 20614f52dfbbSDag-Erling Smørgrav add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_RSA, 0); 20624f52dfbbSDag-Erling Smørgrav add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0); 20634a421b63SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC 20644f52dfbbSDag-Erling Smørgrav add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0); 20654a421b63SDag-Erling Smørgrav #endif 2066f7167e0eSDag-Erling Smørgrav add_identity_file(options, "~/", 2067f7167e0eSDag-Erling Smørgrav _PATH_SSH_CLIENT_ID_ED25519, 0); 206847dd1d1bSDag-Erling Smørgrav add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_XMSS, 0); 2069ca3176e7SBrian Feldman } 2070511b41d2SMark Murray if (options->escape_char == -1) 2071511b41d2SMark Murray options->escape_char = '~'; 2072e146993eSDag-Erling Smørgrav if (options->num_system_hostfiles == 0) { 2073e146993eSDag-Erling Smørgrav options->system_hostfiles[options->num_system_hostfiles++] = 2074e146993eSDag-Erling Smørgrav xstrdup(_PATH_SSH_SYSTEM_HOSTFILE); 2075e146993eSDag-Erling Smørgrav options->system_hostfiles[options->num_system_hostfiles++] = 2076e146993eSDag-Erling Smørgrav xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2); 2077e146993eSDag-Erling Smørgrav } 2078e146993eSDag-Erling Smørgrav if (options->num_user_hostfiles == 0) { 2079e146993eSDag-Erling Smørgrav options->user_hostfiles[options->num_user_hostfiles++] = 2080e146993eSDag-Erling Smørgrav xstrdup(_PATH_SSH_USER_HOSTFILE); 2081e146993eSDag-Erling Smørgrav options->user_hostfiles[options->num_user_hostfiles++] = 2082e146993eSDag-Erling Smørgrav xstrdup(_PATH_SSH_USER_HOSTFILE2); 2083e146993eSDag-Erling Smørgrav } 2084af12a3e7SDag-Erling Smørgrav if (options->log_level == SYSLOG_LEVEL_NOT_SET) 2085511b41d2SMark Murray options->log_level = SYSLOG_LEVEL_INFO; 20864f52dfbbSDag-Erling Smørgrav if (options->log_facility == SYSLOG_FACILITY_NOT_SET) 20874f52dfbbSDag-Erling Smørgrav options->log_facility = SYSLOG_FACILITY_USER; 2088af12a3e7SDag-Erling Smørgrav if (options->no_host_authentication_for_localhost == - 1) 2089af12a3e7SDag-Erling Smørgrav options->no_host_authentication_for_localhost = 0; 20905962c0e9SDag-Erling Smørgrav if (options->identities_only == -1) 20915962c0e9SDag-Erling Smørgrav options->identities_only = 0; 2092e73e9afaSDag-Erling Smørgrav if (options->enable_ssh_keysign == -1) 2093e73e9afaSDag-Erling Smørgrav options->enable_ssh_keysign = 0; 2094cf2b5f3bSDag-Erling Smørgrav if (options->rekey_limit == -1) 2095cf2b5f3bSDag-Erling Smørgrav options->rekey_limit = 0; 2096e4a9863fSDag-Erling Smørgrav if (options->rekey_interval == -1) 2097e4a9863fSDag-Erling Smørgrav options->rekey_interval = 0; 209883c6a524SDag-Erling Smørgrav #if HAVE_LDNS 209983c6a524SDag-Erling Smørgrav if (options->verify_host_key_dns == -1) 210083c6a524SDag-Erling Smørgrav /* automatically trust a verified SSHFP record */ 210183c6a524SDag-Erling Smørgrav options->verify_host_key_dns = 1; 210283c6a524SDag-Erling Smørgrav #else 2103cf2b5f3bSDag-Erling Smørgrav if (options->verify_host_key_dns == -1) 2104cf2b5f3bSDag-Erling Smørgrav options->verify_host_key_dns = 0; 210583c6a524SDag-Erling Smørgrav #endif 21061ec0d754SDag-Erling Smørgrav if (options->server_alive_interval == -1) 21071ec0d754SDag-Erling Smørgrav options->server_alive_interval = 0; 21081ec0d754SDag-Erling Smørgrav if (options->server_alive_count_max == -1) 21091ec0d754SDag-Erling Smørgrav options->server_alive_count_max = 3; 211021e764dfSDag-Erling Smørgrav if (options->control_master == -1) 211121e764dfSDag-Erling Smørgrav options->control_master = 0; 2112e2f6069cSDag-Erling Smørgrav if (options->control_persist == -1) { 2113e2f6069cSDag-Erling Smørgrav options->control_persist = 0; 2114e2f6069cSDag-Erling Smørgrav options->control_persist_timeout = 0; 2115e2f6069cSDag-Erling Smørgrav } 2116aa49c926SDag-Erling Smørgrav if (options->hash_known_hosts == -1) 2117aa49c926SDag-Erling Smørgrav options->hash_known_hosts = 0; 2118b74df5b2SDag-Erling Smørgrav if (options->tun_open == -1) 2119b74df5b2SDag-Erling Smørgrav options->tun_open = SSH_TUNMODE_NO; 2120b74df5b2SDag-Erling Smørgrav if (options->tun_local == -1) 2121b74df5b2SDag-Erling Smørgrav options->tun_local = SSH_TUNID_ANY; 2122b74df5b2SDag-Erling Smørgrav if (options->tun_remote == -1) 2123b74df5b2SDag-Erling Smørgrav options->tun_remote = SSH_TUNID_ANY; 2124b74df5b2SDag-Erling Smørgrav if (options->permit_local_command == -1) 2125b74df5b2SDag-Erling Smørgrav options->permit_local_command = 0; 2126d4af9e69SDag-Erling Smørgrav if (options->visual_host_key == -1) 2127d4af9e69SDag-Erling Smørgrav options->visual_host_key = 0; 21284a421b63SDag-Erling Smørgrav if (options->ip_qos_interactive == -1) 212977c2fe20SDag-Erling Smørgrav #ifdef VMWARE_GUEST_WORKAROUND 213077c2fe20SDag-Erling Smørgrav if (vmwguest) 213177c2fe20SDag-Erling Smørgrav options->ip_qos_interactive = IPTOS_LOWDELAY; 213277c2fe20SDag-Erling Smørgrav else 213377c2fe20SDag-Erling Smørgrav #endif 2134190cef3dSDag-Erling Smørgrav options->ip_qos_interactive = IPTOS_DSCP_AF21; 21354a421b63SDag-Erling Smørgrav if (options->ip_qos_bulk == -1) 213677c2fe20SDag-Erling Smørgrav #ifdef VMWARE_GUEST_WORKAROUND 213777c2fe20SDag-Erling Smørgrav if (vmwguest) 213877c2fe20SDag-Erling Smørgrav options->ip_qos_bulk = IPTOS_THROUGHPUT; 213977c2fe20SDag-Erling Smørgrav else 214077c2fe20SDag-Erling Smørgrav #endif 2141190cef3dSDag-Erling Smørgrav options->ip_qos_bulk = IPTOS_DSCP_CS1; 2142e146993eSDag-Erling Smørgrav if (options->request_tty == -1) 2143e146993eSDag-Erling Smørgrav options->request_tty = REQUEST_TTY_AUTO; 2144f7167e0eSDag-Erling Smørgrav if (options->proxy_use_fdpass == -1) 2145f7167e0eSDag-Erling Smørgrav options->proxy_use_fdpass = 0; 2146f7167e0eSDag-Erling Smørgrav if (options->canonicalize_max_dots == -1) 2147f7167e0eSDag-Erling Smørgrav options->canonicalize_max_dots = 1; 2148f7167e0eSDag-Erling Smørgrav if (options->canonicalize_fallback_local == -1) 2149f7167e0eSDag-Erling Smørgrav options->canonicalize_fallback_local = 1; 2150f7167e0eSDag-Erling Smørgrav if (options->canonicalize_hostname == -1) 2151f7167e0eSDag-Erling Smørgrav options->canonicalize_hostname = SSH_CANONICALISE_NO; 2152bc5531deSDag-Erling Smørgrav if (options->fingerprint_hash == -1) 2153bc5531deSDag-Erling Smørgrav options->fingerprint_hash = SSH_FP_HASH_DEFAULT; 2154bc5531deSDag-Erling Smørgrav if (options->update_hostkeys == -1) 2155bc5531deSDag-Erling Smørgrav options->update_hostkeys = 0; 2156190cef3dSDag-Erling Smørgrav 2157190cef3dSDag-Erling Smørgrav /* Expand KEX name lists */ 2158190cef3dSDag-Erling Smørgrav all_cipher = cipher_alg_list(',', 0); 2159190cef3dSDag-Erling Smørgrav all_mac = mac_alg_list(','); 2160190cef3dSDag-Erling Smørgrav all_kex = kex_alg_list(','); 2161190cef3dSDag-Erling Smørgrav all_key = sshkey_alg_list(0, 0, 1, ','); 21622f513db7SEd Maste all_sig = sshkey_alg_list(0, 1, 1, ','); 2163190cef3dSDag-Erling Smørgrav #define ASSEMBLE(what, defaults, all) \ 2164190cef3dSDag-Erling Smørgrav do { \ 2165190cef3dSDag-Erling Smørgrav if ((r = kex_assemble_names(&options->what, \ 2166190cef3dSDag-Erling Smørgrav defaults, all)) != 0) \ 2167190cef3dSDag-Erling Smørgrav fatal("%s: %s: %s", __func__, #what, ssh_err(r)); \ 2168190cef3dSDag-Erling Smørgrav } while (0) 2169190cef3dSDag-Erling Smørgrav ASSEMBLE(ciphers, KEX_SERVER_ENCRYPT, all_cipher); 2170190cef3dSDag-Erling Smørgrav ASSEMBLE(macs, KEX_SERVER_MAC, all_mac); 2171190cef3dSDag-Erling Smørgrav ASSEMBLE(kex_algorithms, KEX_SERVER_KEX, all_kex); 2172190cef3dSDag-Erling Smørgrav ASSEMBLE(hostbased_key_types, KEX_DEFAULT_PK_ALG, all_key); 2173190cef3dSDag-Erling Smørgrav ASSEMBLE(pubkey_key_types, KEX_DEFAULT_PK_ALG, all_key); 21742f513db7SEd Maste ASSEMBLE(ca_sign_algorithms, SSH_ALLOWED_CA_SIGALGS, all_sig); 2175190cef3dSDag-Erling Smørgrav #undef ASSEMBLE 2176190cef3dSDag-Erling Smørgrav free(all_cipher); 2177190cef3dSDag-Erling Smørgrav free(all_mac); 2178190cef3dSDag-Erling Smørgrav free(all_kex); 2179190cef3dSDag-Erling Smørgrav free(all_key); 21802f513db7SEd Maste free(all_sig); 2181bc5531deSDag-Erling Smørgrav 2182f7167e0eSDag-Erling Smørgrav #define CLEAR_ON_NONE(v) \ 2183f7167e0eSDag-Erling Smørgrav do { \ 2184b83788ffSDag-Erling Smørgrav if (option_clear_or_none(v)) { \ 2185f7167e0eSDag-Erling Smørgrav free(v); \ 2186f7167e0eSDag-Erling Smørgrav v = NULL; \ 2187f7167e0eSDag-Erling Smørgrav } \ 2188f7167e0eSDag-Erling Smørgrav } while(0) 2189f7167e0eSDag-Erling Smørgrav CLEAR_ON_NONE(options->local_command); 21904f52dfbbSDag-Erling Smørgrav CLEAR_ON_NONE(options->remote_command); 2191f7167e0eSDag-Erling Smørgrav CLEAR_ON_NONE(options->proxy_command); 2192f7167e0eSDag-Erling Smørgrav CLEAR_ON_NONE(options->control_path); 2193bc5531deSDag-Erling Smørgrav CLEAR_ON_NONE(options->revoked_host_keys); 2194190cef3dSDag-Erling Smørgrav if (options->jump_host != NULL && 2195190cef3dSDag-Erling Smørgrav strcmp(options->jump_host, "none") == 0 && 2196190cef3dSDag-Erling Smørgrav options->jump_port == 0 && options->jump_user == NULL) { 2197190cef3dSDag-Erling Smørgrav free(options->jump_host); 2198190cef3dSDag-Erling Smørgrav options->jump_host = NULL; 2199190cef3dSDag-Erling Smørgrav } 2200076ad2f8SDag-Erling Smørgrav /* options->identity_agent distinguishes NULL from 'none' */ 2201511b41d2SMark Murray /* options->user will be set in the main program if appropriate */ 2202511b41d2SMark Murray /* options->hostname will be set in the main program if appropriate */ 2203ca3176e7SBrian Feldman /* options->host_key_alias should not be set by default */ 2204ca3176e7SBrian Feldman /* options->preferred_authentications will be set in ssh */ 2205462c32cbSDag-Erling Smørgrav if (options->version_addendum == NULL) 2206462c32cbSDag-Erling Smørgrav options->version_addendum = xstrdup(SSH_VERSION_FREEBSD); 2207511b41d2SMark Murray } 2208aa49c926SDag-Erling Smørgrav 2209a0ee8cc6SDag-Erling Smørgrav struct fwdarg { 2210a0ee8cc6SDag-Erling Smørgrav char *arg; 2211a0ee8cc6SDag-Erling Smørgrav int ispath; 2212a0ee8cc6SDag-Erling Smørgrav }; 2213a0ee8cc6SDag-Erling Smørgrav 2214a0ee8cc6SDag-Erling Smørgrav /* 2215a0ee8cc6SDag-Erling Smørgrav * parse_fwd_field 2216a0ee8cc6SDag-Erling Smørgrav * parses the next field in a port forwarding specification. 2217a0ee8cc6SDag-Erling Smørgrav * sets fwd to the parsed field and advances p past the colon 2218a0ee8cc6SDag-Erling Smørgrav * or sets it to NULL at end of string. 2219a0ee8cc6SDag-Erling Smørgrav * returns 0 on success, else non-zero. 2220a0ee8cc6SDag-Erling Smørgrav */ 2221a0ee8cc6SDag-Erling Smørgrav static int 2222a0ee8cc6SDag-Erling Smørgrav parse_fwd_field(char **p, struct fwdarg *fwd) 2223a0ee8cc6SDag-Erling Smørgrav { 2224a0ee8cc6SDag-Erling Smørgrav char *ep, *cp = *p; 2225a0ee8cc6SDag-Erling Smørgrav int ispath = 0; 2226a0ee8cc6SDag-Erling Smørgrav 2227a0ee8cc6SDag-Erling Smørgrav if (*cp == '\0') { 2228a0ee8cc6SDag-Erling Smørgrav *p = NULL; 2229a0ee8cc6SDag-Erling Smørgrav return -1; /* end of string */ 2230a0ee8cc6SDag-Erling Smørgrav } 2231a0ee8cc6SDag-Erling Smørgrav 2232a0ee8cc6SDag-Erling Smørgrav /* 2233a0ee8cc6SDag-Erling Smørgrav * A field escaped with square brackets is used literally. 2234a0ee8cc6SDag-Erling Smørgrav * XXX - allow ']' to be escaped via backslash? 2235a0ee8cc6SDag-Erling Smørgrav */ 2236a0ee8cc6SDag-Erling Smørgrav if (*cp == '[') { 2237a0ee8cc6SDag-Erling Smørgrav /* find matching ']' */ 2238a0ee8cc6SDag-Erling Smørgrav for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) { 2239a0ee8cc6SDag-Erling Smørgrav if (*ep == '/') 2240a0ee8cc6SDag-Erling Smørgrav ispath = 1; 2241a0ee8cc6SDag-Erling Smørgrav } 2242a0ee8cc6SDag-Erling Smørgrav /* no matching ']' or not at end of field. */ 2243a0ee8cc6SDag-Erling Smørgrav if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0')) 2244a0ee8cc6SDag-Erling Smørgrav return -1; 2245a0ee8cc6SDag-Erling Smørgrav /* NUL terminate the field and advance p past the colon */ 2246a0ee8cc6SDag-Erling Smørgrav *ep++ = '\0'; 2247a0ee8cc6SDag-Erling Smørgrav if (*ep != '\0') 2248a0ee8cc6SDag-Erling Smørgrav *ep++ = '\0'; 2249a0ee8cc6SDag-Erling Smørgrav fwd->arg = cp + 1; 2250a0ee8cc6SDag-Erling Smørgrav fwd->ispath = ispath; 2251a0ee8cc6SDag-Erling Smørgrav *p = ep; 2252a0ee8cc6SDag-Erling Smørgrav return 0; 2253a0ee8cc6SDag-Erling Smørgrav } 2254a0ee8cc6SDag-Erling Smørgrav 2255a0ee8cc6SDag-Erling Smørgrav for (cp = *p; *cp != '\0'; cp++) { 2256a0ee8cc6SDag-Erling Smørgrav switch (*cp) { 2257a0ee8cc6SDag-Erling Smørgrav case '\\': 2258a0ee8cc6SDag-Erling Smørgrav memmove(cp, cp + 1, strlen(cp + 1) + 1); 2259557f75e5SDag-Erling Smørgrav if (*cp == '\0') 2260557f75e5SDag-Erling Smørgrav return -1; 2261a0ee8cc6SDag-Erling Smørgrav break; 2262a0ee8cc6SDag-Erling Smørgrav case '/': 2263a0ee8cc6SDag-Erling Smørgrav ispath = 1; 2264a0ee8cc6SDag-Erling Smørgrav break; 2265a0ee8cc6SDag-Erling Smørgrav case ':': 2266a0ee8cc6SDag-Erling Smørgrav *cp++ = '\0'; 2267a0ee8cc6SDag-Erling Smørgrav goto done; 2268a0ee8cc6SDag-Erling Smørgrav } 2269a0ee8cc6SDag-Erling Smørgrav } 2270a0ee8cc6SDag-Erling Smørgrav done: 2271a0ee8cc6SDag-Erling Smørgrav fwd->arg = *p; 2272a0ee8cc6SDag-Erling Smørgrav fwd->ispath = ispath; 2273a0ee8cc6SDag-Erling Smørgrav *p = cp; 2274a0ee8cc6SDag-Erling Smørgrav return 0; 2275a0ee8cc6SDag-Erling Smørgrav } 2276a0ee8cc6SDag-Erling Smørgrav 2277aa49c926SDag-Erling Smørgrav /* 2278aa49c926SDag-Erling Smørgrav * parse_forward 2279aa49c926SDag-Erling Smørgrav * parses a string containing a port forwarding specification of the form: 2280cce7d346SDag-Erling Smørgrav * dynamicfwd == 0 2281a0ee8cc6SDag-Erling Smørgrav * [listenhost:]listenport|listenpath:connecthost:connectport|connectpath 2282a0ee8cc6SDag-Erling Smørgrav * listenpath:connectpath 2283cce7d346SDag-Erling Smørgrav * dynamicfwd == 1 2284cce7d346SDag-Erling Smørgrav * [listenhost:]listenport 2285aa49c926SDag-Erling Smørgrav * returns number of arguments parsed or zero on error 2286aa49c926SDag-Erling Smørgrav */ 2287aa49c926SDag-Erling Smørgrav int 2288a0ee8cc6SDag-Erling Smørgrav parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd) 2289aa49c926SDag-Erling Smørgrav { 2290a0ee8cc6SDag-Erling Smørgrav struct fwdarg fwdargs[4]; 2291a0ee8cc6SDag-Erling Smørgrav char *p, *cp; 2292aa49c926SDag-Erling Smørgrav int i; 2293aa49c926SDag-Erling Smørgrav 2294a0ee8cc6SDag-Erling Smørgrav memset(fwd, 0, sizeof(*fwd)); 2295a0ee8cc6SDag-Erling Smørgrav memset(fwdargs, 0, sizeof(fwdargs)); 2296aa49c926SDag-Erling Smørgrav 2297aa49c926SDag-Erling Smørgrav cp = p = xstrdup(fwdspec); 2298aa49c926SDag-Erling Smørgrav 2299aa49c926SDag-Erling Smørgrav /* skip leading spaces */ 2300f7167e0eSDag-Erling Smørgrav while (isspace((u_char)*cp)) 2301aa49c926SDag-Erling Smørgrav cp++; 2302aa49c926SDag-Erling Smørgrav 2303a0ee8cc6SDag-Erling Smørgrav for (i = 0; i < 4; ++i) { 2304a0ee8cc6SDag-Erling Smørgrav if (parse_fwd_field(&cp, &fwdargs[i]) != 0) 2305aa49c926SDag-Erling Smørgrav break; 2306a0ee8cc6SDag-Erling Smørgrav } 2307aa49c926SDag-Erling Smørgrav 2308cce7d346SDag-Erling Smørgrav /* Check for trailing garbage */ 2309a0ee8cc6SDag-Erling Smørgrav if (cp != NULL && *cp != '\0') { 2310aa49c926SDag-Erling Smørgrav i = 0; /* failure */ 2311a0ee8cc6SDag-Erling Smørgrav } 2312aa49c926SDag-Erling Smørgrav 2313aa49c926SDag-Erling Smørgrav switch (i) { 2314cce7d346SDag-Erling Smørgrav case 1: 2315a0ee8cc6SDag-Erling Smørgrav if (fwdargs[0].ispath) { 2316a0ee8cc6SDag-Erling Smørgrav fwd->listen_path = xstrdup(fwdargs[0].arg); 2317a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = PORT_STREAMLOCAL; 2318a0ee8cc6SDag-Erling Smørgrav } else { 2319cce7d346SDag-Erling Smørgrav fwd->listen_host = NULL; 2320a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = a2port(fwdargs[0].arg); 2321a0ee8cc6SDag-Erling Smørgrav } 2322cce7d346SDag-Erling Smørgrav fwd->connect_host = xstrdup("socks"); 2323cce7d346SDag-Erling Smørgrav break; 2324cce7d346SDag-Erling Smørgrav 2325cce7d346SDag-Erling Smørgrav case 2: 2326a0ee8cc6SDag-Erling Smørgrav if (fwdargs[0].ispath && fwdargs[1].ispath) { 2327a0ee8cc6SDag-Erling Smørgrav fwd->listen_path = xstrdup(fwdargs[0].arg); 2328a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = PORT_STREAMLOCAL; 2329a0ee8cc6SDag-Erling Smørgrav fwd->connect_path = xstrdup(fwdargs[1].arg); 2330a0ee8cc6SDag-Erling Smørgrav fwd->connect_port = PORT_STREAMLOCAL; 2331a0ee8cc6SDag-Erling Smørgrav } else if (fwdargs[1].ispath) { 2332a0ee8cc6SDag-Erling Smørgrav fwd->listen_host = NULL; 2333a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = a2port(fwdargs[0].arg); 2334a0ee8cc6SDag-Erling Smørgrav fwd->connect_path = xstrdup(fwdargs[1].arg); 2335a0ee8cc6SDag-Erling Smørgrav fwd->connect_port = PORT_STREAMLOCAL; 2336a0ee8cc6SDag-Erling Smørgrav } else { 2337a0ee8cc6SDag-Erling Smørgrav fwd->listen_host = xstrdup(fwdargs[0].arg); 2338a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = a2port(fwdargs[1].arg); 2339cce7d346SDag-Erling Smørgrav fwd->connect_host = xstrdup("socks"); 2340a0ee8cc6SDag-Erling Smørgrav } 2341cce7d346SDag-Erling Smørgrav break; 2342cce7d346SDag-Erling Smørgrav 2343aa49c926SDag-Erling Smørgrav case 3: 2344a0ee8cc6SDag-Erling Smørgrav if (fwdargs[0].ispath) { 2345a0ee8cc6SDag-Erling Smørgrav fwd->listen_path = xstrdup(fwdargs[0].arg); 2346a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = PORT_STREAMLOCAL; 2347a0ee8cc6SDag-Erling Smørgrav fwd->connect_host = xstrdup(fwdargs[1].arg); 2348a0ee8cc6SDag-Erling Smørgrav fwd->connect_port = a2port(fwdargs[2].arg); 2349a0ee8cc6SDag-Erling Smørgrav } else if (fwdargs[2].ispath) { 2350a0ee8cc6SDag-Erling Smørgrav fwd->listen_host = xstrdup(fwdargs[0].arg); 2351a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = a2port(fwdargs[1].arg); 2352a0ee8cc6SDag-Erling Smørgrav fwd->connect_path = xstrdup(fwdargs[2].arg); 2353a0ee8cc6SDag-Erling Smørgrav fwd->connect_port = PORT_STREAMLOCAL; 2354a0ee8cc6SDag-Erling Smørgrav } else { 2355aa49c926SDag-Erling Smørgrav fwd->listen_host = NULL; 2356a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = a2port(fwdargs[0].arg); 2357a0ee8cc6SDag-Erling Smørgrav fwd->connect_host = xstrdup(fwdargs[1].arg); 2358a0ee8cc6SDag-Erling Smørgrav fwd->connect_port = a2port(fwdargs[2].arg); 2359a0ee8cc6SDag-Erling Smørgrav } 2360aa49c926SDag-Erling Smørgrav break; 2361aa49c926SDag-Erling Smørgrav 2362aa49c926SDag-Erling Smørgrav case 4: 2363a0ee8cc6SDag-Erling Smørgrav fwd->listen_host = xstrdup(fwdargs[0].arg); 2364a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = a2port(fwdargs[1].arg); 2365a0ee8cc6SDag-Erling Smørgrav fwd->connect_host = xstrdup(fwdargs[2].arg); 2366a0ee8cc6SDag-Erling Smørgrav fwd->connect_port = a2port(fwdargs[3].arg); 2367aa49c926SDag-Erling Smørgrav break; 2368aa49c926SDag-Erling Smørgrav default: 2369aa49c926SDag-Erling Smørgrav i = 0; /* failure */ 2370aa49c926SDag-Erling Smørgrav } 2371aa49c926SDag-Erling Smørgrav 2372e4a9863fSDag-Erling Smørgrav free(p); 2373aa49c926SDag-Erling Smørgrav 2374cce7d346SDag-Erling Smørgrav if (dynamicfwd) { 2375cce7d346SDag-Erling Smørgrav if (!(i == 1 || i == 2)) 2376cce7d346SDag-Erling Smørgrav goto fail_free; 2377cce7d346SDag-Erling Smørgrav } else { 2378a0ee8cc6SDag-Erling Smørgrav if (!(i == 3 || i == 4)) { 2379a0ee8cc6SDag-Erling Smørgrav if (fwd->connect_path == NULL && 2380a0ee8cc6SDag-Erling Smørgrav fwd->listen_path == NULL) 2381cce7d346SDag-Erling Smørgrav goto fail_free; 2382a0ee8cc6SDag-Erling Smørgrav } 2383a0ee8cc6SDag-Erling Smørgrav if (fwd->connect_port <= 0 && fwd->connect_path == NULL) 2384cce7d346SDag-Erling Smørgrav goto fail_free; 2385cce7d346SDag-Erling Smørgrav } 2386cce7d346SDag-Erling Smørgrav 2387a0ee8cc6SDag-Erling Smørgrav if ((fwd->listen_port < 0 && fwd->listen_path == NULL) || 2388a0ee8cc6SDag-Erling Smørgrav (!remotefwd && fwd->listen_port == 0)) 2389aa49c926SDag-Erling Smørgrav goto fail_free; 2390aa49c926SDag-Erling Smørgrav if (fwd->connect_host != NULL && 2391aa49c926SDag-Erling Smørgrav strlen(fwd->connect_host) >= NI_MAXHOST) 2392aa49c926SDag-Erling Smørgrav goto fail_free; 2393a0ee8cc6SDag-Erling Smørgrav /* XXX - if connecting to a remote socket, max sun len may not match this host */ 2394a0ee8cc6SDag-Erling Smørgrav if (fwd->connect_path != NULL && 2395a0ee8cc6SDag-Erling Smørgrav strlen(fwd->connect_path) >= PATH_MAX_SUN) 2396a0ee8cc6SDag-Erling Smørgrav goto fail_free; 2397cce7d346SDag-Erling Smørgrav if (fwd->listen_host != NULL && 2398cce7d346SDag-Erling Smørgrav strlen(fwd->listen_host) >= NI_MAXHOST) 2399cce7d346SDag-Erling Smørgrav goto fail_free; 2400a0ee8cc6SDag-Erling Smørgrav if (fwd->listen_path != NULL && 2401a0ee8cc6SDag-Erling Smørgrav strlen(fwd->listen_path) >= PATH_MAX_SUN) 2402a0ee8cc6SDag-Erling Smørgrav goto fail_free; 2403aa49c926SDag-Erling Smørgrav 2404aa49c926SDag-Erling Smørgrav return (i); 2405aa49c926SDag-Erling Smørgrav 2406aa49c926SDag-Erling Smørgrav fail_free: 2407e4a9863fSDag-Erling Smørgrav free(fwd->connect_host); 2408cce7d346SDag-Erling Smørgrav fwd->connect_host = NULL; 2409a0ee8cc6SDag-Erling Smørgrav free(fwd->connect_path); 2410a0ee8cc6SDag-Erling Smørgrav fwd->connect_path = NULL; 2411e4a9863fSDag-Erling Smørgrav free(fwd->listen_host); 2412cce7d346SDag-Erling Smørgrav fwd->listen_host = NULL; 2413a0ee8cc6SDag-Erling Smørgrav free(fwd->listen_path); 2414a0ee8cc6SDag-Erling Smørgrav fwd->listen_path = NULL; 2415aa49c926SDag-Erling Smørgrav return (0); 2416aa49c926SDag-Erling Smørgrav } 2417bc5531deSDag-Erling Smørgrav 2418076ad2f8SDag-Erling Smørgrav int 2419076ad2f8SDag-Erling Smørgrav parse_jump(const char *s, Options *o, int active) 2420076ad2f8SDag-Erling Smørgrav { 2421076ad2f8SDag-Erling Smørgrav char *orig, *sdup, *cp; 2422076ad2f8SDag-Erling Smørgrav char *host = NULL, *user = NULL; 2423076ad2f8SDag-Erling Smørgrav int ret = -1, port = -1, first; 2424076ad2f8SDag-Erling Smørgrav 2425076ad2f8SDag-Erling Smørgrav active &= o->proxy_command == NULL && o->jump_host == NULL; 2426076ad2f8SDag-Erling Smørgrav 2427076ad2f8SDag-Erling Smørgrav orig = sdup = xstrdup(s); 2428076ad2f8SDag-Erling Smørgrav first = active; 2429076ad2f8SDag-Erling Smørgrav do { 2430190cef3dSDag-Erling Smørgrav if (strcasecmp(s, "none") == 0) 2431190cef3dSDag-Erling Smørgrav break; 2432076ad2f8SDag-Erling Smørgrav if ((cp = strrchr(sdup, ',')) == NULL) 2433076ad2f8SDag-Erling Smørgrav cp = sdup; /* last */ 2434076ad2f8SDag-Erling Smørgrav else 2435076ad2f8SDag-Erling Smørgrav *cp++ = '\0'; 2436076ad2f8SDag-Erling Smørgrav 2437076ad2f8SDag-Erling Smørgrav if (first) { 2438076ad2f8SDag-Erling Smørgrav /* First argument and configuration is active */ 243947dd1d1bSDag-Erling Smørgrav if (parse_ssh_uri(cp, &user, &host, &port) == -1 || 244047dd1d1bSDag-Erling Smørgrav parse_user_host_port(cp, &user, &host, &port) != 0) 2441076ad2f8SDag-Erling Smørgrav goto out; 2442076ad2f8SDag-Erling Smørgrav } else { 2443076ad2f8SDag-Erling Smørgrav /* Subsequent argument or inactive configuration */ 244447dd1d1bSDag-Erling Smørgrav if (parse_ssh_uri(cp, NULL, NULL, NULL) == -1 || 244547dd1d1bSDag-Erling Smørgrav parse_user_host_port(cp, NULL, NULL, NULL) != 0) 2446076ad2f8SDag-Erling Smørgrav goto out; 2447076ad2f8SDag-Erling Smørgrav } 2448076ad2f8SDag-Erling Smørgrav first = 0; /* only check syntax for subsequent hosts */ 2449076ad2f8SDag-Erling Smørgrav } while (cp != sdup); 2450076ad2f8SDag-Erling Smørgrav /* success */ 2451076ad2f8SDag-Erling Smørgrav if (active) { 2452190cef3dSDag-Erling Smørgrav if (strcasecmp(s, "none") == 0) { 2453190cef3dSDag-Erling Smørgrav o->jump_host = xstrdup("none"); 2454190cef3dSDag-Erling Smørgrav o->jump_port = 0; 2455190cef3dSDag-Erling Smørgrav } else { 2456076ad2f8SDag-Erling Smørgrav o->jump_user = user; 2457076ad2f8SDag-Erling Smørgrav o->jump_host = host; 2458076ad2f8SDag-Erling Smørgrav o->jump_port = port; 2459076ad2f8SDag-Erling Smørgrav o->proxy_command = xstrdup("none"); 2460076ad2f8SDag-Erling Smørgrav user = host = NULL; 2461076ad2f8SDag-Erling Smørgrav if ((cp = strrchr(s, ',')) != NULL && cp != s) { 2462076ad2f8SDag-Erling Smørgrav o->jump_extra = xstrdup(s); 2463076ad2f8SDag-Erling Smørgrav o->jump_extra[cp - s] = '\0'; 2464076ad2f8SDag-Erling Smørgrav } 2465076ad2f8SDag-Erling Smørgrav } 2466190cef3dSDag-Erling Smørgrav } 2467076ad2f8SDag-Erling Smørgrav ret = 0; 2468076ad2f8SDag-Erling Smørgrav out: 2469076ad2f8SDag-Erling Smørgrav free(orig); 2470076ad2f8SDag-Erling Smørgrav free(user); 2471076ad2f8SDag-Erling Smørgrav free(host); 2472076ad2f8SDag-Erling Smørgrav return ret; 2473076ad2f8SDag-Erling Smørgrav } 2474076ad2f8SDag-Erling Smørgrav 247547dd1d1bSDag-Erling Smørgrav int 247647dd1d1bSDag-Erling Smørgrav parse_ssh_uri(const char *uri, char **userp, char **hostp, int *portp) 247747dd1d1bSDag-Erling Smørgrav { 247847dd1d1bSDag-Erling Smørgrav char *path; 247947dd1d1bSDag-Erling Smørgrav int r; 248047dd1d1bSDag-Erling Smørgrav 248147dd1d1bSDag-Erling Smørgrav r = parse_uri("ssh", uri, userp, hostp, portp, &path); 248247dd1d1bSDag-Erling Smørgrav if (r == 0 && path != NULL) 248347dd1d1bSDag-Erling Smørgrav r = -1; /* path not allowed */ 248447dd1d1bSDag-Erling Smørgrav return r; 248547dd1d1bSDag-Erling Smørgrav } 248647dd1d1bSDag-Erling Smørgrav 2487bc5531deSDag-Erling Smørgrav /* XXX the following is a near-vebatim copy from servconf.c; refactor */ 2488bc5531deSDag-Erling Smørgrav static const char * 2489bc5531deSDag-Erling Smørgrav fmt_multistate_int(int val, const struct multistate *m) 2490bc5531deSDag-Erling Smørgrav { 2491bc5531deSDag-Erling Smørgrav u_int i; 2492bc5531deSDag-Erling Smørgrav 2493bc5531deSDag-Erling Smørgrav for (i = 0; m[i].key != NULL; i++) { 2494bc5531deSDag-Erling Smørgrav if (m[i].value == val) 2495bc5531deSDag-Erling Smørgrav return m[i].key; 2496bc5531deSDag-Erling Smørgrav } 2497bc5531deSDag-Erling Smørgrav return "UNKNOWN"; 2498bc5531deSDag-Erling Smørgrav } 2499bc5531deSDag-Erling Smørgrav 2500bc5531deSDag-Erling Smørgrav static const char * 2501bc5531deSDag-Erling Smørgrav fmt_intarg(OpCodes code, int val) 2502bc5531deSDag-Erling Smørgrav { 2503bc5531deSDag-Erling Smørgrav if (val == -1) 2504bc5531deSDag-Erling Smørgrav return "unset"; 2505bc5531deSDag-Erling Smørgrav switch (code) { 2506bc5531deSDag-Erling Smørgrav case oAddressFamily: 2507bc5531deSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_addressfamily); 2508bc5531deSDag-Erling Smørgrav case oVerifyHostKeyDNS: 2509bc5531deSDag-Erling Smørgrav case oUpdateHostkeys: 2510bc5531deSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_yesnoask); 25114f52dfbbSDag-Erling Smørgrav case oStrictHostKeyChecking: 25124f52dfbbSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_strict_hostkey); 2513bc5531deSDag-Erling Smørgrav case oControlMaster: 2514bc5531deSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_controlmaster); 2515bc5531deSDag-Erling Smørgrav case oTunnel: 2516bc5531deSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_tunnel); 2517bc5531deSDag-Erling Smørgrav case oRequestTTY: 2518bc5531deSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_requesttty); 2519bc5531deSDag-Erling Smørgrav case oCanonicalizeHostname: 2520bc5531deSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_canonicalizehostname); 2521190cef3dSDag-Erling Smørgrav case oAddKeysToAgent: 2522190cef3dSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_yesnoaskconfirm); 2523bc5531deSDag-Erling Smørgrav case oFingerprintHash: 2524bc5531deSDag-Erling Smørgrav return ssh_digest_alg_name(val); 2525bc5531deSDag-Erling Smørgrav default: 2526bc5531deSDag-Erling Smørgrav switch (val) { 2527bc5531deSDag-Erling Smørgrav case 0: 2528bc5531deSDag-Erling Smørgrav return "no"; 2529bc5531deSDag-Erling Smørgrav case 1: 2530bc5531deSDag-Erling Smørgrav return "yes"; 2531bc5531deSDag-Erling Smørgrav default: 2532bc5531deSDag-Erling Smørgrav return "UNKNOWN"; 2533bc5531deSDag-Erling Smørgrav } 2534bc5531deSDag-Erling Smørgrav } 2535bc5531deSDag-Erling Smørgrav } 2536bc5531deSDag-Erling Smørgrav 2537bc5531deSDag-Erling Smørgrav static const char * 2538bc5531deSDag-Erling Smørgrav lookup_opcode_name(OpCodes code) 2539bc5531deSDag-Erling Smørgrav { 2540bc5531deSDag-Erling Smørgrav u_int i; 2541bc5531deSDag-Erling Smørgrav 2542bc5531deSDag-Erling Smørgrav for (i = 0; keywords[i].name != NULL; i++) 2543bc5531deSDag-Erling Smørgrav if (keywords[i].opcode == code) 2544bc5531deSDag-Erling Smørgrav return(keywords[i].name); 2545bc5531deSDag-Erling Smørgrav return "UNKNOWN"; 2546bc5531deSDag-Erling Smørgrav } 2547bc5531deSDag-Erling Smørgrav 2548bc5531deSDag-Erling Smørgrav static void 2549bc5531deSDag-Erling Smørgrav dump_cfg_int(OpCodes code, int val) 2550bc5531deSDag-Erling Smørgrav { 2551bc5531deSDag-Erling Smørgrav printf("%s %d\n", lookup_opcode_name(code), val); 2552bc5531deSDag-Erling Smørgrav } 2553bc5531deSDag-Erling Smørgrav 2554bc5531deSDag-Erling Smørgrav static void 2555bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(OpCodes code, int val) 2556bc5531deSDag-Erling Smørgrav { 2557bc5531deSDag-Erling Smørgrav printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val)); 2558bc5531deSDag-Erling Smørgrav } 2559bc5531deSDag-Erling Smørgrav 2560bc5531deSDag-Erling Smørgrav static void 2561bc5531deSDag-Erling Smørgrav dump_cfg_string(OpCodes code, const char *val) 2562bc5531deSDag-Erling Smørgrav { 2563bc5531deSDag-Erling Smørgrav if (val == NULL) 2564bc5531deSDag-Erling Smørgrav return; 2565bc5531deSDag-Erling Smørgrav printf("%s %s\n", lookup_opcode_name(code), val); 2566bc5531deSDag-Erling Smørgrav } 2567bc5531deSDag-Erling Smørgrav 2568bc5531deSDag-Erling Smørgrav static void 2569bc5531deSDag-Erling Smørgrav dump_cfg_strarray(OpCodes code, u_int count, char **vals) 2570bc5531deSDag-Erling Smørgrav { 2571bc5531deSDag-Erling Smørgrav u_int i; 2572bc5531deSDag-Erling Smørgrav 2573bc5531deSDag-Erling Smørgrav for (i = 0; i < count; i++) 2574bc5531deSDag-Erling Smørgrav printf("%s %s\n", lookup_opcode_name(code), vals[i]); 2575bc5531deSDag-Erling Smørgrav } 2576bc5531deSDag-Erling Smørgrav 2577bc5531deSDag-Erling Smørgrav static void 2578bc5531deSDag-Erling Smørgrav dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals) 2579bc5531deSDag-Erling Smørgrav { 2580bc5531deSDag-Erling Smørgrav u_int i; 2581bc5531deSDag-Erling Smørgrav 2582bc5531deSDag-Erling Smørgrav printf("%s", lookup_opcode_name(code)); 2583bc5531deSDag-Erling Smørgrav for (i = 0; i < count; i++) 2584bc5531deSDag-Erling Smørgrav printf(" %s", vals[i]); 2585bc5531deSDag-Erling Smørgrav printf("\n"); 2586bc5531deSDag-Erling Smørgrav } 2587bc5531deSDag-Erling Smørgrav 2588bc5531deSDag-Erling Smørgrav static void 2589bc5531deSDag-Erling Smørgrav dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds) 2590bc5531deSDag-Erling Smørgrav { 2591bc5531deSDag-Erling Smørgrav const struct Forward *fwd; 2592bc5531deSDag-Erling Smørgrav u_int i; 2593bc5531deSDag-Erling Smørgrav 2594bc5531deSDag-Erling Smørgrav /* oDynamicForward */ 2595bc5531deSDag-Erling Smørgrav for (i = 0; i < count; i++) { 2596bc5531deSDag-Erling Smørgrav fwd = &fwds[i]; 2597d93a896eSDag-Erling Smørgrav if (code == oDynamicForward && fwd->connect_host != NULL && 2598bc5531deSDag-Erling Smørgrav strcmp(fwd->connect_host, "socks") != 0) 2599bc5531deSDag-Erling Smørgrav continue; 2600d93a896eSDag-Erling Smørgrav if (code == oLocalForward && fwd->connect_host != NULL && 2601bc5531deSDag-Erling Smørgrav strcmp(fwd->connect_host, "socks") == 0) 2602bc5531deSDag-Erling Smørgrav continue; 2603bc5531deSDag-Erling Smørgrav printf("%s", lookup_opcode_name(code)); 2604bc5531deSDag-Erling Smørgrav if (fwd->listen_port == PORT_STREAMLOCAL) 2605bc5531deSDag-Erling Smørgrav printf(" %s", fwd->listen_path); 2606bc5531deSDag-Erling Smørgrav else if (fwd->listen_host == NULL) 2607bc5531deSDag-Erling Smørgrav printf(" %d", fwd->listen_port); 2608bc5531deSDag-Erling Smørgrav else { 2609bc5531deSDag-Erling Smørgrav printf(" [%s]:%d", 2610bc5531deSDag-Erling Smørgrav fwd->listen_host, fwd->listen_port); 2611bc5531deSDag-Erling Smørgrav } 2612bc5531deSDag-Erling Smørgrav if (code != oDynamicForward) { 2613bc5531deSDag-Erling Smørgrav if (fwd->connect_port == PORT_STREAMLOCAL) 2614bc5531deSDag-Erling Smørgrav printf(" %s", fwd->connect_path); 2615bc5531deSDag-Erling Smørgrav else if (fwd->connect_host == NULL) 2616bc5531deSDag-Erling Smørgrav printf(" %d", fwd->connect_port); 2617bc5531deSDag-Erling Smørgrav else { 2618bc5531deSDag-Erling Smørgrav printf(" [%s]:%d", 2619bc5531deSDag-Erling Smørgrav fwd->connect_host, fwd->connect_port); 2620bc5531deSDag-Erling Smørgrav } 2621bc5531deSDag-Erling Smørgrav } 2622bc5531deSDag-Erling Smørgrav printf("\n"); 2623bc5531deSDag-Erling Smørgrav } 2624bc5531deSDag-Erling Smørgrav } 2625bc5531deSDag-Erling Smørgrav 2626bc5531deSDag-Erling Smørgrav void 2627bc5531deSDag-Erling Smørgrav dump_client_config(Options *o, const char *host) 2628bc5531deSDag-Erling Smørgrav { 2629bc5531deSDag-Erling Smørgrav int i; 2630190cef3dSDag-Erling Smørgrav char buf[8], *all_key; 2631bc5531deSDag-Erling Smørgrav 2632acc1a9efSDag-Erling Smørgrav /* This is normally prepared in ssh_kex2 */ 2633190cef3dSDag-Erling Smørgrav all_key = sshkey_alg_list(0, 0, 1, ','); 2634190cef3dSDag-Erling Smørgrav if (kex_assemble_names( &o->hostkeyalgorithms, 2635190cef3dSDag-Erling Smørgrav KEX_DEFAULT_PK_ALG, all_key) != 0) 2636acc1a9efSDag-Erling Smørgrav fatal("%s: kex_assemble_names failed", __func__); 2637190cef3dSDag-Erling Smørgrav free(all_key); 2638acc1a9efSDag-Erling Smørgrav 2639bc5531deSDag-Erling Smørgrav /* Most interesting options first: user, host, port */ 2640bc5531deSDag-Erling Smørgrav dump_cfg_string(oUser, o->user); 2641bc5531deSDag-Erling Smørgrav dump_cfg_string(oHostName, host); 2642bc5531deSDag-Erling Smørgrav dump_cfg_int(oPort, o->port); 2643bc5531deSDag-Erling Smørgrav 2644bc5531deSDag-Erling Smørgrav /* Flag options */ 2645190cef3dSDag-Erling Smørgrav dump_cfg_fmtint(oAddKeysToAgent, o->add_keys_to_agent); 2646bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oAddressFamily, o->address_family); 2647bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oBatchMode, o->batch_mode); 2648bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local); 2649bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname); 2650bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oChallengeResponseAuthentication, o->challenge_response_authentication); 2651bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oCheckHostIP, o->check_host_ip); 2652bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oCompression, o->compression); 2653bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oControlMaster, o->control_master); 2654bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign); 2655076ad2f8SDag-Erling Smørgrav dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings); 2656bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure); 2657bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash); 2658bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oForwardAgent, o->forward_agent); 2659bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oForwardX11, o->forward_x11); 2660bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted); 2661bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports); 2662bc5531deSDag-Erling Smørgrav #ifdef GSSAPI 2663bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oGssAuthentication, o->gss_authentication); 2664bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds); 2665bc5531deSDag-Erling Smørgrav #endif /* GSSAPI */ 2666bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts); 2667bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication); 2668bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oIdentitiesOnly, o->identities_only); 2669bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication); 2670bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost); 2671bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication); 2672bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command); 2673bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass); 2674bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication); 2675bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oRequestTTY, o->request_tty); 2676bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); 2677bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking); 2678bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive); 2679bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oTunnel, o->tun_open); 2680bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns); 2681bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oVisualHostKey, o->visual_host_key); 2682bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys); 2683bc5531deSDag-Erling Smørgrav 2684bc5531deSDag-Erling Smørgrav /* Integer options */ 2685bc5531deSDag-Erling Smørgrav dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots); 2686bc5531deSDag-Erling Smørgrav dump_cfg_int(oConnectionAttempts, o->connection_attempts); 2687bc5531deSDag-Erling Smørgrav dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout); 2688bc5531deSDag-Erling Smørgrav dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts); 2689bc5531deSDag-Erling Smørgrav dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max); 2690bc5531deSDag-Erling Smørgrav dump_cfg_int(oServerAliveInterval, o->server_alive_interval); 2691bc5531deSDag-Erling Smørgrav 2692bc5531deSDag-Erling Smørgrav /* String options */ 2693bc5531deSDag-Erling Smørgrav dump_cfg_string(oBindAddress, o->bind_address); 269447dd1d1bSDag-Erling Smørgrav dump_cfg_string(oBindInterface, o->bind_interface); 2695bc5531deSDag-Erling Smørgrav dump_cfg_string(oCiphers, o->ciphers ? o->ciphers : KEX_CLIENT_ENCRYPT); 2696bc5531deSDag-Erling Smørgrav dump_cfg_string(oControlPath, o->control_path); 2697acc1a9efSDag-Erling Smørgrav dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms); 2698bc5531deSDag-Erling Smørgrav dump_cfg_string(oHostKeyAlias, o->host_key_alias); 2699bc5531deSDag-Erling Smørgrav dump_cfg_string(oHostbasedKeyTypes, o->hostbased_key_types); 2700076ad2f8SDag-Erling Smørgrav dump_cfg_string(oIdentityAgent, o->identity_agent); 2701190cef3dSDag-Erling Smørgrav dump_cfg_string(oIgnoreUnknown, o->ignored_unknown); 2702bc5531deSDag-Erling Smørgrav dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices); 2703bc5531deSDag-Erling Smørgrav dump_cfg_string(oKexAlgorithms, o->kex_algorithms ? o->kex_algorithms : KEX_CLIENT_KEX); 27042f513db7SEd Maste dump_cfg_string(oCASignatureAlgorithms, o->ca_sign_algorithms ? o->ca_sign_algorithms : SSH_ALLOWED_CA_SIGALGS); 2705bc5531deSDag-Erling Smørgrav dump_cfg_string(oLocalCommand, o->local_command); 27064f52dfbbSDag-Erling Smørgrav dump_cfg_string(oRemoteCommand, o->remote_command); 2707bc5531deSDag-Erling Smørgrav dump_cfg_string(oLogLevel, log_level_name(o->log_level)); 2708bc5531deSDag-Erling Smørgrav dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC); 2709d93a896eSDag-Erling Smørgrav #ifdef ENABLE_PKCS11 2710bc5531deSDag-Erling Smørgrav dump_cfg_string(oPKCS11Provider, o->pkcs11_provider); 2711d93a896eSDag-Erling Smørgrav #endif 2712bc5531deSDag-Erling Smørgrav dump_cfg_string(oPreferredAuthentications, o->preferred_authentications); 2713acc1a9efSDag-Erling Smørgrav dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types); 2714bc5531deSDag-Erling Smørgrav dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys); 2715bc5531deSDag-Erling Smørgrav dump_cfg_string(oXAuthLocation, o->xauth_location); 2716bc5531deSDag-Erling Smørgrav 2717bc5531deSDag-Erling Smørgrav /* Forwards */ 2718bc5531deSDag-Erling Smørgrav dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards); 2719bc5531deSDag-Erling Smørgrav dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards); 2720bc5531deSDag-Erling Smørgrav dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards); 2721bc5531deSDag-Erling Smørgrav 2722bc5531deSDag-Erling Smørgrav /* String array options */ 2723bc5531deSDag-Erling Smørgrav dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files); 2724bc5531deSDag-Erling Smørgrav dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains); 2725190cef3dSDag-Erling Smørgrav dump_cfg_strarray(oCertificateFile, o->num_certificate_files, o->certificate_files); 2726bc5531deSDag-Erling Smørgrav dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles); 2727bc5531deSDag-Erling Smørgrav dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles); 2728bc5531deSDag-Erling Smørgrav dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env); 2729190cef3dSDag-Erling Smørgrav dump_cfg_strarray(oSetEnv, o->num_setenv, o->setenv); 2730bc5531deSDag-Erling Smørgrav 2731bc5531deSDag-Erling Smørgrav /* Special cases */ 2732bc5531deSDag-Erling Smørgrav 2733bc5531deSDag-Erling Smørgrav /* oConnectTimeout */ 2734bc5531deSDag-Erling Smørgrav if (o->connection_timeout == -1) 2735bc5531deSDag-Erling Smørgrav printf("connecttimeout none\n"); 2736bc5531deSDag-Erling Smørgrav else 2737bc5531deSDag-Erling Smørgrav dump_cfg_int(oConnectTimeout, o->connection_timeout); 2738bc5531deSDag-Erling Smørgrav 2739bc5531deSDag-Erling Smørgrav /* oTunnelDevice */ 2740bc5531deSDag-Erling Smørgrav printf("tunneldevice"); 2741bc5531deSDag-Erling Smørgrav if (o->tun_local == SSH_TUNID_ANY) 2742bc5531deSDag-Erling Smørgrav printf(" any"); 2743bc5531deSDag-Erling Smørgrav else 2744bc5531deSDag-Erling Smørgrav printf(" %d", o->tun_local); 2745bc5531deSDag-Erling Smørgrav if (o->tun_remote == SSH_TUNID_ANY) 2746bc5531deSDag-Erling Smørgrav printf(":any"); 2747bc5531deSDag-Erling Smørgrav else 2748bc5531deSDag-Erling Smørgrav printf(":%d", o->tun_remote); 2749bc5531deSDag-Erling Smørgrav printf("\n"); 2750bc5531deSDag-Erling Smørgrav 2751bc5531deSDag-Erling Smørgrav /* oCanonicalizePermittedCNAMEs */ 2752bc5531deSDag-Erling Smørgrav if ( o->num_permitted_cnames > 0) { 2753bc5531deSDag-Erling Smørgrav printf("canonicalizePermittedcnames"); 2754bc5531deSDag-Erling Smørgrav for (i = 0; i < o->num_permitted_cnames; i++) { 2755bc5531deSDag-Erling Smørgrav printf(" %s:%s", o->permitted_cnames[i].source_list, 2756bc5531deSDag-Erling Smørgrav o->permitted_cnames[i].target_list); 2757bc5531deSDag-Erling Smørgrav } 2758bc5531deSDag-Erling Smørgrav printf("\n"); 2759bc5531deSDag-Erling Smørgrav } 2760bc5531deSDag-Erling Smørgrav 2761bc5531deSDag-Erling Smørgrav /* oControlPersist */ 2762bc5531deSDag-Erling Smørgrav if (o->control_persist == 0 || o->control_persist_timeout == 0) 2763bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oControlPersist, o->control_persist); 2764bc5531deSDag-Erling Smørgrav else 2765bc5531deSDag-Erling Smørgrav dump_cfg_int(oControlPersist, o->control_persist_timeout); 2766bc5531deSDag-Erling Smørgrav 2767bc5531deSDag-Erling Smørgrav /* oEscapeChar */ 2768bc5531deSDag-Erling Smørgrav if (o->escape_char == SSH_ESCAPECHAR_NONE) 2769bc5531deSDag-Erling Smørgrav printf("escapechar none\n"); 2770bc5531deSDag-Erling Smørgrav else { 2771076ad2f8SDag-Erling Smørgrav vis(buf, o->escape_char, VIS_WHITE, 0); 2772076ad2f8SDag-Erling Smørgrav printf("escapechar %s\n", buf); 2773bc5531deSDag-Erling Smørgrav } 2774bc5531deSDag-Erling Smørgrav 2775bc5531deSDag-Erling Smørgrav /* oIPQoS */ 2776bc5531deSDag-Erling Smørgrav printf("ipqos %s ", iptos2str(o->ip_qos_interactive)); 2777bc5531deSDag-Erling Smørgrav printf("%s\n", iptos2str(o->ip_qos_bulk)); 2778bc5531deSDag-Erling Smørgrav 2779bc5531deSDag-Erling Smørgrav /* oRekeyLimit */ 2780acc1a9efSDag-Erling Smørgrav printf("rekeylimit %llu %d\n", 2781acc1a9efSDag-Erling Smørgrav (unsigned long long)o->rekey_limit, o->rekey_interval); 2782bc5531deSDag-Erling Smørgrav 2783bc5531deSDag-Erling Smørgrav /* oStreamLocalBindMask */ 2784bc5531deSDag-Erling Smørgrav printf("streamlocalbindmask 0%o\n", 2785bc5531deSDag-Erling Smørgrav o->fwd_opts.streamlocal_bind_mask); 2786076ad2f8SDag-Erling Smørgrav 2787190cef3dSDag-Erling Smørgrav /* oLogFacility */ 2788190cef3dSDag-Erling Smørgrav printf("syslogfacility %s\n", log_facility_name(o->log_facility)); 2789190cef3dSDag-Erling Smørgrav 2790076ad2f8SDag-Erling Smørgrav /* oProxyCommand / oProxyJump */ 2791076ad2f8SDag-Erling Smørgrav if (o->jump_host == NULL) 2792076ad2f8SDag-Erling Smørgrav dump_cfg_string(oProxyCommand, o->proxy_command); 2793076ad2f8SDag-Erling Smørgrav else { 2794076ad2f8SDag-Erling Smørgrav /* Check for numeric addresses */ 2795076ad2f8SDag-Erling Smørgrav i = strchr(o->jump_host, ':') != NULL || 2796076ad2f8SDag-Erling Smørgrav strspn(o->jump_host, "1234567890.") == strlen(o->jump_host); 2797076ad2f8SDag-Erling Smørgrav snprintf(buf, sizeof(buf), "%d", o->jump_port); 2798076ad2f8SDag-Erling Smørgrav printf("proxyjump %s%s%s%s%s%s%s%s%s\n", 2799076ad2f8SDag-Erling Smørgrav /* optional additional jump spec */ 2800076ad2f8SDag-Erling Smørgrav o->jump_extra == NULL ? "" : o->jump_extra, 2801076ad2f8SDag-Erling Smørgrav o->jump_extra == NULL ? "" : ",", 2802076ad2f8SDag-Erling Smørgrav /* optional user */ 2803076ad2f8SDag-Erling Smørgrav o->jump_user == NULL ? "" : o->jump_user, 2804076ad2f8SDag-Erling Smørgrav o->jump_user == NULL ? "" : "@", 2805076ad2f8SDag-Erling Smørgrav /* opening [ if hostname is numeric */ 2806076ad2f8SDag-Erling Smørgrav i ? "[" : "", 2807076ad2f8SDag-Erling Smørgrav /* mandatory hostname */ 2808076ad2f8SDag-Erling Smørgrav o->jump_host, 2809076ad2f8SDag-Erling Smørgrav /* closing ] if hostname is numeric */ 2810076ad2f8SDag-Erling Smørgrav i ? "]" : "", 2811076ad2f8SDag-Erling Smørgrav /* optional port number */ 2812076ad2f8SDag-Erling Smørgrav o->jump_port <= 0 ? "" : ":", 2813076ad2f8SDag-Erling Smørgrav o->jump_port <= 0 ? "" : buf); 2814076ad2f8SDag-Erling Smørgrav } 2815bc5531deSDag-Erling Smørgrav } 2816