1264377Sdes/* $OpenBSD: readconf.c,v 1.218 2014/02/23 20:11:36 djm Exp $ */ 2224638Sbrooks/* $FreeBSD: releng/10.2/crypto/openssh/readconf.c 294050 2016-01-14 22:45:33Z glebius $ */ 357429Smarkm/* 457429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi> 557429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 657429Smarkm * All rights reserved 757429Smarkm * Functions for reading the configuration files. 860576Skris * 965674Skris * As far as I am concerned, the code I have written for this software 1065674Skris * can be used freely for any purpose. Any derived versions of this 1165674Skris * software must be clearly marked as such, and if the derived work is 1265674Skris * incompatible with the protocol description in the RFC file, it must be 1365674Skris * called by a name other than "ssh" or "Secure Shell". 1457429Smarkm */ 1557429Smarkm 1657429Smarkm#include "includes.h" 17162856Sdes__RCSID("$FreeBSD: releng/10.2/crypto/openssh/readconf.c 294050 2016-01-14 22:45:33Z glebius $"); 1857429Smarkm 19162856Sdes#include <sys/types.h> 20162856Sdes#include <sys/stat.h> 21162856Sdes#include <sys/socket.h> 22181918Sdes#include <sys/sysctl.h> 23262566Sdes#include <sys/wait.h> 24162856Sdes 25162856Sdes#include <netinet/in.h> 26221420Sdes#include <netinet/in_systm.h> 27221420Sdes#include <netinet/ip.h> 28264377Sdes#include <arpa/inet.h> 29162856Sdes 30162856Sdes#include <ctype.h> 31162856Sdes#include <errno.h> 32262566Sdes#include <fcntl.h> 33162856Sdes#include <netdb.h> 34262566Sdes#ifdef HAVE_PATHS_H 35262566Sdes# include <paths.h> 36262566Sdes#endif 37262566Sdes#include <pwd.h> 38162856Sdes#include <signal.h> 39162856Sdes#include <stdarg.h> 40162856Sdes#include <stdio.h> 41162856Sdes#include <string.h> 42162856Sdes#include <unistd.h> 43255767Sdes#ifdef HAVE_UTIL_H 44255767Sdes#include <util.h> 45255767Sdes#endif 46162856Sdes 47162856Sdes#include "xmalloc.h" 4857429Smarkm#include "ssh.h" 4976262Sgreen#include "compat.h" 5076262Sgreen#include "cipher.h" 5176262Sgreen#include "pathnames.h" 5276262Sgreen#include "log.h" 53162856Sdes#include "key.h" 5457429Smarkm#include "readconf.h" 5560576Skris#include "match.h" 5676262Sgreen#include "misc.h" 57162856Sdes#include "buffer.h" 5876262Sgreen#include "kex.h" 5976262Sgreen#include "mac.h" 60262566Sdes#include "uidswap.h" 61192595Sdes#include "version.h" 6257429Smarkm 6357429Smarkm/* Format of the configuration file: 6457429Smarkm 6557429Smarkm # Configuration data is parsed as follows: 6657429Smarkm # 1. command line options 6757429Smarkm # 2. user-specific file 6857429Smarkm # 3. system-wide file 6957429Smarkm # Any configuration value is only changed the first time it is set. 7057429Smarkm # Thus, host-specific definitions should be at the beginning of the 7157429Smarkm # configuration file, and defaults at the end. 7257429Smarkm 7357429Smarkm # Host-specific declarations. These may override anything above. A single 7457429Smarkm # host may match multiple declarations; these are processed in the order 7557429Smarkm # that they are given in. 7657429Smarkm 7757429Smarkm Host *.ngs.fi ngs.fi 7898684Sdes User foo 7957429Smarkm 8057429Smarkm Host fake.com 8157429Smarkm HostName another.host.name.real.org 8257429Smarkm User blaah 8357429Smarkm Port 34289 8457429Smarkm ForwardX11 no 8557429Smarkm ForwardAgent no 8657429Smarkm 8757429Smarkm Host books.com 8857429Smarkm RemoteForward 9999 shadows.cs.hut.fi:9999 8957429Smarkm Cipher 3des 9057429Smarkm 9157429Smarkm Host fascist.blob.com 9257429Smarkm Port 23123 9357429Smarkm User tylonen 9457429Smarkm PasswordAuthentication no 9557429Smarkm 9657429Smarkm Host puukko.hut.fi 9757429Smarkm User t35124p 9857429Smarkm ProxyCommand ssh-proxy %h %p 9957429Smarkm 10057429Smarkm Host *.fr 10198684Sdes PublicKeyAuthentication no 10257429Smarkm 10357429Smarkm Host *.su 10457429Smarkm Cipher none 10557429Smarkm PasswordAuthentication no 10657429Smarkm 107157019Sdes Host vpn.fake.com 108157019Sdes Tunnel yes 109157019Sdes TunnelDevice 3 110157019Sdes 11157429Smarkm # Defaults for various options 11257429Smarkm Host * 11357429Smarkm ForwardAgent no 11476262Sgreen ForwardX11 no 11557429Smarkm PasswordAuthentication yes 11657429Smarkm RSAAuthentication yes 11757429Smarkm RhostsRSAAuthentication yes 11857429Smarkm StrictHostKeyChecking yes 119126277Sdes TcpKeepAlive no 12057429Smarkm IdentityFile ~/.ssh/identity 12157429Smarkm Port 22 12257429Smarkm EscapeChar ~ 12357429Smarkm 12457429Smarkm*/ 12557429Smarkm 12657429Smarkm/* Keyword tokens. */ 12757429Smarkm 12857429Smarkmtypedef enum { 12957429Smarkm oBadOption, 130262566Sdes oHost, oMatch, 131215116Sdes oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout, 132215116Sdes oGatewayPorts, oExitOnForwardFailure, 13398684Sdes oPasswordAuthentication, oRSAAuthentication, 13476262Sgreen oChallengeResponseAuthentication, oXAuthLocation, 13557429Smarkm oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward, 136262566Sdes oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand, 13757429Smarkm oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, 13857429Smarkm oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, 139126277Sdes oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts, 14076262Sgreen oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs, 14176262Sgreen oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication, 14276262Sgreen oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, 14376262Sgreen oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, 144204917Sdes oHostKeyAlgorithms, oBindAddress, oPKCS11Provider, 14593698Sdes oClearAllForwardings, oNoHostAuthenticationForLocalhost, 146124211Sdes oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, 147124211Sdes oAddressFamily, oGssAuthentication, oGssDelegateCreds, 148128461Sdes oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, 149215116Sdes oSendEnv, oControlPath, oControlMaster, oControlPersist, 150215116Sdes oHashKnownHosts, 151157019Sdes oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, 152264377Sdes oVisualHostKey, oUseRoaming, 153262566Sdes oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, 154262566Sdes oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, 155262566Sdes oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, 156255767Sdes oIgnoredUnknownOption, 157224638Sbrooks oHPNDisabled, oHPNBufferSize, oTcpRcvBufPoll, oTcpRcvBuf, 158224638Sbrooks#ifdef NONE_CIPHER_ENABLED 159224638Sbrooks oNoneEnabled, oNoneSwitch, 160224638Sbrooks#endif 161255767Sdes oVersionAddendum, oDeprecated, oUnsupported 16257429Smarkm} OpCodes; 16357429Smarkm 16457429Smarkm/* Textual representations of the tokens. */ 16557429Smarkm 16657429Smarkmstatic struct { 16757429Smarkm const char *name; 16857429Smarkm OpCodes opcode; 16957429Smarkm} keywords[] = { 17057429Smarkm { "forwardagent", oForwardAgent }, 17157429Smarkm { "forwardx11", oForwardX11 }, 172126277Sdes { "forwardx11trusted", oForwardX11Trusted }, 173215116Sdes { "forwardx11timeout", oForwardX11Timeout }, 174162856Sdes { "exitonforwardfailure", oExitOnForwardFailure }, 17565674Skris { "xauthlocation", oXAuthLocation }, 17657429Smarkm { "gatewayports", oGatewayPorts }, 17757429Smarkm { "useprivilegedport", oUsePrivilegedPort }, 178124211Sdes { "rhostsauthentication", oDeprecated }, 17957429Smarkm { "passwordauthentication", oPasswordAuthentication }, 18069591Sgreen { "kbdinteractiveauthentication", oKbdInteractiveAuthentication }, 18169591Sgreen { "kbdinteractivedevices", oKbdInteractiveDevices }, 18257429Smarkm { "rsaauthentication", oRSAAuthentication }, 18376262Sgreen { "pubkeyauthentication", oPubkeyAuthentication }, 18476262Sgreen { "dsaauthentication", oPubkeyAuthentication }, /* alias */ 18576262Sgreen { "rhostsrsaauthentication", oRhostsRSAAuthentication }, 18676262Sgreen { "hostbasedauthentication", oHostbasedAuthentication }, 18776262Sgreen { "challengeresponseauthentication", oChallengeResponseAuthentication }, 18876262Sgreen { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */ 18976262Sgreen { "tisauthentication", oChallengeResponseAuthentication }, /* alias */ 190124211Sdes { "kerberosauthentication", oUnsupported }, 191124211Sdes { "kerberostgtpassing", oUnsupported }, 192124211Sdes { "afstokenpassing", oUnsupported }, 193124211Sdes#if defined(GSSAPI) 194124211Sdes { "gssapiauthentication", oGssAuthentication }, 195124211Sdes { "gssapidelegatecredentials", oGssDelegateCreds }, 196124211Sdes#else 197124211Sdes { "gssapiauthentication", oUnsupported }, 198124211Sdes { "gssapidelegatecredentials", oUnsupported }, 19992559Sdes#endif 20098684Sdes { "fallbacktorsh", oDeprecated }, 20198684Sdes { "usersh", oDeprecated }, 20257429Smarkm { "identityfile", oIdentityFile }, 203192595Sdes { "identityfile2", oIdentityFile }, /* obsolete */ 204128460Sdes { "identitiesonly", oIdentitiesOnly }, 20557429Smarkm { "hostname", oHostName }, 20676262Sgreen { "hostkeyalias", oHostKeyAlias }, 20757429Smarkm { "proxycommand", oProxyCommand }, 20857429Smarkm { "port", oPort }, 20957429Smarkm { "cipher", oCipher }, 21060576Skris { "ciphers", oCiphers }, 21176262Sgreen { "macs", oMacs }, 21260576Skris { "protocol", oProtocol }, 21357429Smarkm { "remoteforward", oRemoteForward }, 21457429Smarkm { "localforward", oLocalForward }, 21557429Smarkm { "user", oUser }, 21657429Smarkm { "host", oHost }, 217262566Sdes { "match", oMatch }, 21857429Smarkm { "escapechar", oEscapeChar }, 21957429Smarkm { "globalknownhostsfile", oGlobalKnownHostsFile }, 220226046Sdes { "globalknownhostsfile2", oDeprecated }, 221192595Sdes { "userknownhostsfile", oUserKnownHostsFile }, 222226046Sdes { "userknownhostsfile2", oDeprecated }, 22357429Smarkm { "connectionattempts", oConnectionAttempts }, 22457429Smarkm { "batchmode", oBatchMode }, 22557429Smarkm { "checkhostip", oCheckHostIP }, 22657429Smarkm { "stricthostkeychecking", oStrictHostKeyChecking }, 22757429Smarkm { "compression", oCompression }, 22857429Smarkm { "compressionlevel", oCompressionLevel }, 229126277Sdes { "tcpkeepalive", oTCPKeepAlive }, 230126277Sdes { "keepalive", oTCPKeepAlive }, /* obsolete */ 23157429Smarkm { "numberofpasswordprompts", oNumberOfPasswordPrompts }, 23257429Smarkm { "loglevel", oLogLevel }, 23376262Sgreen { "dynamicforward", oDynamicForward }, 23476262Sgreen { "preferredauthentications", oPreferredAuthentications }, 23576262Sgreen { "hostkeyalgorithms", oHostKeyAlgorithms }, 23692559Sdes { "bindaddress", oBindAddress }, 237204917Sdes#ifdef ENABLE_PKCS11 238204917Sdes { "smartcarddevice", oPKCS11Provider }, 239204917Sdes { "pkcs11provider", oPKCS11Provider }, 240124211Sdes#else 241124211Sdes { "smartcarddevice", oUnsupported }, 242204917Sdes { "pkcs11provider", oUnsupported }, 243124211Sdes#endif 24492559Sdes { "clearallforwardings", oClearAllForwardings }, 245113911Sdes { "enablesshkeysign", oEnableSSHKeysign }, 246124211Sdes { "verifyhostkeydns", oVerifyHostKeyDNS }, 24792559Sdes { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost }, 248124211Sdes { "rekeylimit", oRekeyLimit }, 249124211Sdes { "connecttimeout", oConnectTimeout }, 250124211Sdes { "addressfamily", oAddressFamily }, 251126277Sdes { "serveraliveinterval", oServerAliveInterval }, 252126277Sdes { "serveralivecountmax", oServerAliveCountMax }, 253137019Sdes { "sendenv", oSendEnv }, 254137019Sdes { "controlpath", oControlPath }, 255137019Sdes { "controlmaster", oControlMaster }, 256215116Sdes { "controlpersist", oControlPersist }, 257147005Sdes { "hashknownhosts", oHashKnownHosts }, 258157019Sdes { "tunnel", oTunnel }, 259157019Sdes { "tunneldevice", oTunnelDevice }, 260157019Sdes { "localcommand", oLocalCommand }, 261157019Sdes { "permitlocalcommand", oPermitLocalCommand }, 262181111Sdes { "visualhostkey", oVisualHostKey }, 263197679Sdes { "useroaming", oUseRoaming }, 264221420Sdes { "kexalgorithms", oKexAlgorithms }, 265221420Sdes { "ipqos", oIPQoS }, 266226046Sdes { "requesttty", oRequestTTY }, 267262566Sdes { "proxyusefdpass", oProxyUseFdpass }, 268262566Sdes { "canonicaldomains", oCanonicalDomains }, 269262566Sdes { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal }, 270262566Sdes { "canonicalizehostname", oCanonicalizeHostname }, 271262566Sdes { "canonicalizemaxdots", oCanonicalizeMaxDots }, 272262566Sdes { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs }, 273255767Sdes { "ignoreunknown", oIgnoreUnknown }, 274224638Sbrooks { "hpndisabled", oHPNDisabled }, 275224638Sbrooks { "hpnbuffersize", oHPNBufferSize }, 276224638Sbrooks { "tcprcvbufpoll", oTcpRcvBufPoll }, 277224638Sbrooks { "tcprcvbuf", oTcpRcvBuf }, 278224638Sbrooks#ifdef NONE_CIPHER_ENABLED 279224638Sbrooks { "noneenabled", oNoneEnabled }, 280224638Sbrooks { "noneswitch", oNoneSwitch }, 281224638Sbrooks#endif 28299048Sdes { "versionaddendum", oVersionAddendum }, 283231584Sed 28492559Sdes { NULL, oBadOption } 28557429Smarkm}; 28657429Smarkm 28757429Smarkm/* 28857429Smarkm * Adds a local TCP/IP port forward to options. Never returns if there is an 28957429Smarkm * error. 29057429Smarkm */ 29157429Smarkm 29260576Skrisvoid 293147005Sdesadd_local_forward(Options *options, const Forward *newfwd) 29457429Smarkm{ 29557429Smarkm Forward *fwd; 296106130Sdes#ifndef NO_IPPORT_RESERVED_CONCEPT 29757429Smarkm extern uid_t original_real_uid; 298181918Sdes int ipport_reserved; 299181918Sdes#ifdef __FreeBSD__ 300181918Sdes size_t len_ipport_reserved = sizeof(ipport_reserved); 301181918Sdes 302181918Sdes if (sysctlbyname("net.inet.ip.portrange.reservedhigh", 303181918Sdes &ipport_reserved, &len_ipport_reserved, NULL, 0) != 0) 304181918Sdes ipport_reserved = IPPORT_RESERVED; 305181918Sdes else 306181918Sdes ipport_reserved++; 307181918Sdes#else 308181918Sdes ipport_reserved = IPPORT_RESERVED; 309181918Sdes#endif 310181918Sdes if (newfwd->listen_port < ipport_reserved && original_real_uid != 0) 31176262Sgreen fatal("Privileged ports can only be forwarded by root."); 31298941Sdes#endif 313215116Sdes options->local_forwards = xrealloc(options->local_forwards, 314215116Sdes options->num_local_forwards + 1, 315215116Sdes sizeof(*options->local_forwards)); 31657429Smarkm fwd = &options->local_forwards[options->num_local_forwards++]; 317147005Sdes 318192595Sdes fwd->listen_host = newfwd->listen_host; 319147005Sdes fwd->listen_port = newfwd->listen_port; 320192595Sdes fwd->connect_host = newfwd->connect_host; 321147005Sdes fwd->connect_port = newfwd->connect_port; 32257429Smarkm} 32357429Smarkm 32457429Smarkm/* 32557429Smarkm * Adds a remote TCP/IP port forward to options. Never returns if there is 32657429Smarkm * an error. 32757429Smarkm */ 32857429Smarkm 32960576Skrisvoid 330147005Sdesadd_remote_forward(Options *options, const Forward *newfwd) 33157429Smarkm{ 33257429Smarkm Forward *fwd; 333215116Sdes 334215116Sdes options->remote_forwards = xrealloc(options->remote_forwards, 335215116Sdes options->num_remote_forwards + 1, 336215116Sdes sizeof(*options->remote_forwards)); 33757429Smarkm fwd = &options->remote_forwards[options->num_remote_forwards++]; 338147005Sdes 339192595Sdes fwd->listen_host = newfwd->listen_host; 340147005Sdes fwd->listen_port = newfwd->listen_port; 341192595Sdes fwd->connect_host = newfwd->connect_host; 342147005Sdes fwd->connect_port = newfwd->connect_port; 343240075Sdes fwd->handle = newfwd->handle; 344215116Sdes fwd->allocated_port = 0; 34557429Smarkm} 34657429Smarkm 34792559Sdesstatic void 34892559Sdesclear_forwardings(Options *options) 34992559Sdes{ 35092559Sdes int i; 35192559Sdes 352147005Sdes for (i = 0; i < options->num_local_forwards; i++) { 353255767Sdes free(options->local_forwards[i].listen_host); 354255767Sdes free(options->local_forwards[i].connect_host); 355147005Sdes } 356215116Sdes if (options->num_local_forwards > 0) { 357255767Sdes free(options->local_forwards); 358215116Sdes options->local_forwards = NULL; 359215116Sdes } 36092559Sdes options->num_local_forwards = 0; 361147005Sdes for (i = 0; i < options->num_remote_forwards; i++) { 362255767Sdes free(options->remote_forwards[i].listen_host); 363255767Sdes free(options->remote_forwards[i].connect_host); 364147005Sdes } 365215116Sdes if (options->num_remote_forwards > 0) { 366255767Sdes free(options->remote_forwards); 367215116Sdes options->remote_forwards = NULL; 368215116Sdes } 36992559Sdes options->num_remote_forwards = 0; 370157019Sdes options->tun_open = SSH_TUNMODE_NO; 37192559Sdes} 37292559Sdes 373249016Sdesvoid 374249016Sdesadd_identity_file(Options *options, const char *dir, const char *filename, 375249016Sdes int userprovided) 376249016Sdes{ 377249016Sdes char *path; 378249016Sdes 379249016Sdes if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES) 380249016Sdes fatal("Too many identity files specified (max %d)", 381249016Sdes SSH_MAX_IDENTITY_FILES); 382249016Sdes 383249016Sdes if (dir == NULL) /* no dir, filename is absolute */ 384249016Sdes path = xstrdup(filename); 385249016Sdes else 386249016Sdes (void)xasprintf(&path, "%.100s%.100s", dir, filename); 387249016Sdes 388249016Sdes options->identity_file_userprovided[options->num_identity_files] = 389249016Sdes userprovided; 390249016Sdes options->identity_files[options->num_identity_files++] = path; 391249016Sdes} 392249016Sdes 393262566Sdesint 394262566Sdesdefault_ssh_port(void) 395262566Sdes{ 396262566Sdes static int port; 397262566Sdes struct servent *sp; 398262566Sdes 399262566Sdes if (port == 0) { 400262566Sdes sp = getservbyname(SSH_SERVICE_NAME, "tcp"); 401262566Sdes port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT; 402262566Sdes } 403262566Sdes return port; 404262566Sdes} 405262566Sdes 40657429Smarkm/* 407262566Sdes * Execute a command in a shell. 408262566Sdes * Return its exit status or -1 on abnormal exit. 409262566Sdes */ 410262566Sdesstatic int 411262566Sdesexecute_in_shell(const char *cmd) 412262566Sdes{ 413262566Sdes char *shell, *command_string; 414262566Sdes pid_t pid; 415262566Sdes int devnull, status; 416262566Sdes extern uid_t original_real_uid; 417262566Sdes 418262566Sdes if ((shell = getenv("SHELL")) == NULL) 419262566Sdes shell = _PATH_BSHELL; 420262566Sdes 421262566Sdes /* 422262566Sdes * Use "exec" to avoid "sh -c" processes on some platforms 423262566Sdes * (e.g. Solaris) 424262566Sdes */ 425262566Sdes xasprintf(&command_string, "exec %s", cmd); 426262566Sdes 427262566Sdes /* Need this to redirect subprocess stdin/out */ 428262566Sdes if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) 429262566Sdes fatal("open(/dev/null): %s", strerror(errno)); 430262566Sdes 431262566Sdes debug("Executing command: '%.500s'", cmd); 432262566Sdes 433262566Sdes /* Fork and execute the command. */ 434262566Sdes if ((pid = fork()) == 0) { 435262566Sdes char *argv[4]; 436262566Sdes 437262566Sdes /* Child. Permanently give up superuser privileges. */ 438262566Sdes permanently_drop_suid(original_real_uid); 439262566Sdes 440262566Sdes /* Redirect child stdin and stdout. Leave stderr */ 441262566Sdes if (dup2(devnull, STDIN_FILENO) == -1) 442262566Sdes fatal("dup2: %s", strerror(errno)); 443262566Sdes if (dup2(devnull, STDOUT_FILENO) == -1) 444262566Sdes fatal("dup2: %s", strerror(errno)); 445262566Sdes if (devnull > STDERR_FILENO) 446262566Sdes close(devnull); 447262566Sdes closefrom(STDERR_FILENO + 1); 448262566Sdes 449262566Sdes argv[0] = shell; 450262566Sdes argv[1] = "-c"; 451262566Sdes argv[2] = command_string; 452262566Sdes argv[3] = NULL; 453262566Sdes 454262566Sdes execv(argv[0], argv); 455262566Sdes error("Unable to execute '%.100s': %s", cmd, strerror(errno)); 456262566Sdes /* Die with signal to make this error apparent to parent. */ 457262566Sdes signal(SIGTERM, SIG_DFL); 458262566Sdes kill(getpid(), SIGTERM); 459262566Sdes _exit(1); 460262566Sdes } 461262566Sdes /* Parent. */ 462262566Sdes if (pid < 0) 463262566Sdes fatal("%s: fork: %.100s", __func__, strerror(errno)); 464262566Sdes 465262566Sdes close(devnull); 466262566Sdes free(command_string); 467262566Sdes 468262566Sdes while (waitpid(pid, &status, 0) == -1) { 469262566Sdes if (errno != EINTR && errno != EAGAIN) 470262566Sdes fatal("%s: waitpid: %s", __func__, strerror(errno)); 471262566Sdes } 472262566Sdes if (!WIFEXITED(status)) { 473262566Sdes error("command '%.100s' exited abnormally", cmd); 474262566Sdes return -1; 475262566Sdes } 476262566Sdes debug3("command returned status %d", WEXITSTATUS(status)); 477262566Sdes return WEXITSTATUS(status); 478262566Sdes} 479262566Sdes 480262566Sdes/* 481262566Sdes * Parse and execute a Match directive. 482262566Sdes */ 483262566Sdesstatic int 484262566Sdesmatch_cfg_line(Options *options, char **condition, struct passwd *pw, 485262566Sdes const char *host_arg, const char *filename, int linenum) 486262566Sdes{ 487262566Sdes char *arg, *attrib, *cmd, *cp = *condition, *host; 488262566Sdes const char *ruser; 489262566Sdes int r, port, result = 1, attributes = 0; 490262566Sdes size_t len; 491262566Sdes char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; 492262566Sdes 493262566Sdes /* 494262566Sdes * Configuration is likely to be incomplete at this point so we 495262566Sdes * must be prepared to use default values. 496262566Sdes */ 497262566Sdes port = options->port <= 0 ? default_ssh_port() : options->port; 498262566Sdes ruser = options->user == NULL ? pw->pw_name : options->user; 499262566Sdes if (options->hostname != NULL) { 500262566Sdes /* NB. Please keep in sync with ssh.c:main() */ 501262566Sdes host = percent_expand(options->hostname, 502262566Sdes "h", host_arg, (char *)NULL); 503262566Sdes } else 504262566Sdes host = xstrdup(host_arg); 505262566Sdes 506262566Sdes debug3("checking match for '%s' host %s", cp, host); 507262566Sdes while ((attrib = strdelim(&cp)) && *attrib != '\0') { 508262566Sdes attributes++; 509262566Sdes if (strcasecmp(attrib, "all") == 0) { 510262566Sdes if (attributes != 1 || 511262566Sdes ((arg = strdelim(&cp)) != NULL && *arg != '\0')) { 512262566Sdes error("'all' cannot be combined with other " 513262566Sdes "Match attributes"); 514262566Sdes result = -1; 515262566Sdes goto out; 516262566Sdes } 517262566Sdes *condition = cp; 518262566Sdes result = 1; 519262566Sdes goto out; 520262566Sdes } 521262566Sdes if ((arg = strdelim(&cp)) == NULL || *arg == '\0') { 522262566Sdes error("Missing Match criteria for %s", attrib); 523262566Sdes result = -1; 524262566Sdes goto out; 525262566Sdes } 526262566Sdes len = strlen(arg); 527262566Sdes if (strcasecmp(attrib, "host") == 0) { 528262566Sdes if (match_hostname(host, arg, len) != 1) 529262566Sdes result = 0; 530262566Sdes else 531262566Sdes debug("%.200s line %d: matched 'Host %.100s' ", 532262566Sdes filename, linenum, host); 533262566Sdes } else if (strcasecmp(attrib, "originalhost") == 0) { 534262566Sdes if (match_hostname(host_arg, arg, len) != 1) 535262566Sdes result = 0; 536262566Sdes else 537262566Sdes debug("%.200s line %d: matched " 538262566Sdes "'OriginalHost %.100s' ", 539262566Sdes filename, linenum, host_arg); 540262566Sdes } else if (strcasecmp(attrib, "user") == 0) { 541262566Sdes if (match_pattern_list(ruser, arg, len, 0) != 1) 542262566Sdes result = 0; 543262566Sdes else 544262566Sdes debug("%.200s line %d: matched 'User %.100s' ", 545262566Sdes filename, linenum, ruser); 546262566Sdes } else if (strcasecmp(attrib, "localuser") == 0) { 547262566Sdes if (match_pattern_list(pw->pw_name, arg, len, 0) != 1) 548262566Sdes result = 0; 549262566Sdes else 550262566Sdes debug("%.200s line %d: matched " 551262566Sdes "'LocalUser %.100s' ", 552262566Sdes filename, linenum, pw->pw_name); 553262566Sdes } else if (strcasecmp(attrib, "exec") == 0) { 554262566Sdes if (gethostname(thishost, sizeof(thishost)) == -1) 555262566Sdes fatal("gethostname: %s", strerror(errno)); 556262566Sdes strlcpy(shorthost, thishost, sizeof(shorthost)); 557262566Sdes shorthost[strcspn(thishost, ".")] = '\0'; 558262566Sdes snprintf(portstr, sizeof(portstr), "%d", port); 559262566Sdes 560262566Sdes cmd = percent_expand(arg, 561262566Sdes "L", shorthost, 562262566Sdes "d", pw->pw_dir, 563262566Sdes "h", host, 564262566Sdes "l", thishost, 565262566Sdes "n", host_arg, 566262566Sdes "p", portstr, 567262566Sdes "r", ruser, 568262566Sdes "u", pw->pw_name, 569262566Sdes (char *)NULL); 570264377Sdes if (result != 1) { 571264377Sdes /* skip execution if prior predicate failed */ 572264377Sdes debug("%.200s line %d: skipped exec \"%.100s\"", 573262566Sdes filename, linenum, cmd); 574264377Sdes } else { 575264377Sdes r = execute_in_shell(cmd); 576264377Sdes if (r == -1) { 577264377Sdes fatal("%.200s line %d: match exec " 578264377Sdes "'%.100s' error", filename, 579264377Sdes linenum, cmd); 580264377Sdes } else if (r == 0) { 581264377Sdes debug("%.200s line %d: matched " 582264377Sdes "'exec \"%.100s\"'", filename, 583264377Sdes linenum, cmd); 584264377Sdes } else { 585264377Sdes debug("%.200s line %d: no match " 586264377Sdes "'exec \"%.100s\"'", filename, 587264377Sdes linenum, cmd); 588264377Sdes result = 0; 589264377Sdes } 590264377Sdes } 591262566Sdes free(cmd); 592262566Sdes } else { 593262566Sdes error("Unsupported Match attribute %s", attrib); 594262566Sdes result = -1; 595262566Sdes goto out; 596262566Sdes } 597262566Sdes } 598262566Sdes if (attributes == 0) { 599262566Sdes error("One or more attributes required for Match"); 600262566Sdes result = -1; 601262566Sdes goto out; 602262566Sdes } 603262566Sdes debug3("match %sfound", result ? "" : "not "); 604262566Sdes *condition = cp; 605262566Sdes out: 606262566Sdes free(host); 607262566Sdes return result; 608262566Sdes} 609262566Sdes 610262566Sdes/* Check and prepare a domain name: removes trailing '.' and lowercases */ 611262566Sdesstatic void 612262566Sdesvalid_domain(char *name, const char *filename, int linenum) 613262566Sdes{ 614262566Sdes size_t i, l = strlen(name); 615262566Sdes u_char c, last = '\0'; 616262566Sdes 617262566Sdes if (l == 0) 618262566Sdes fatal("%s line %d: empty hostname suffix", filename, linenum); 619262566Sdes if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0])) 620262566Sdes fatal("%s line %d: hostname suffix \"%.100s\" " 621262566Sdes "starts with invalid character", filename, linenum, name); 622262566Sdes for (i = 0; i < l; i++) { 623262566Sdes c = tolower((u_char)name[i]); 624262566Sdes name[i] = (char)c; 625262566Sdes if (last == '.' && c == '.') 626262566Sdes fatal("%s line %d: hostname suffix \"%.100s\" contains " 627262566Sdes "consecutive separators", filename, linenum, name); 628262566Sdes if (c != '.' && c != '-' && !isalnum(c) && 629262566Sdes c != '_') /* technically invalid, but common */ 630262566Sdes fatal("%s line %d: hostname suffix \"%.100s\" contains " 631262566Sdes "invalid characters", filename, linenum, name); 632262566Sdes last = c; 633262566Sdes } 634262566Sdes if (name[l - 1] == '.') 635262566Sdes name[l - 1] = '\0'; 636262566Sdes} 637262566Sdes 638262566Sdes/* 63976262Sgreen * Returns the number of the token pointed to by cp or oBadOption. 64057429Smarkm */ 64160576Skrisstatic OpCodes 642255767Sdesparse_token(const char *cp, const char *filename, int linenum, 643255767Sdes const char *ignored_unknown) 64457429Smarkm{ 645255767Sdes int i; 64657429Smarkm 64757429Smarkm for (i = 0; keywords[i].name; i++) 648255767Sdes if (strcmp(cp, keywords[i].name) == 0) 64957429Smarkm return keywords[i].opcode; 650255767Sdes if (ignored_unknown != NULL && match_pattern_list(cp, ignored_unknown, 651255767Sdes strlen(ignored_unknown), 1) == 1) 652255767Sdes return oIgnoredUnknownOption; 65376262Sgreen error("%s: line %d: Bad configuration option: %s", 65476262Sgreen filename, linenum, cp); 65557429Smarkm return oBadOption; 65657429Smarkm} 65757429Smarkm 658262566Sdes/* Multistate option parsing */ 659262566Sdesstruct multistate { 660262566Sdes char *key; 661262566Sdes int value; 662262566Sdes}; 663262566Sdesstatic const struct multistate multistate_flag[] = { 664262566Sdes { "true", 1 }, 665262566Sdes { "false", 0 }, 666262566Sdes { "yes", 1 }, 667262566Sdes { "no", 0 }, 668262566Sdes { NULL, -1 } 669262566Sdes}; 670262566Sdesstatic const struct multistate multistate_yesnoask[] = { 671262566Sdes { "true", 1 }, 672262566Sdes { "false", 0 }, 673262566Sdes { "yes", 1 }, 674262566Sdes { "no", 0 }, 675262566Sdes { "ask", 2 }, 676262566Sdes { NULL, -1 } 677262566Sdes}; 678262566Sdesstatic const struct multistate multistate_addressfamily[] = { 679262566Sdes { "inet", AF_INET }, 680262566Sdes { "inet6", AF_INET6 }, 681262566Sdes { "any", AF_UNSPEC }, 682262566Sdes { NULL, -1 } 683262566Sdes}; 684262566Sdesstatic const struct multistate multistate_controlmaster[] = { 685262566Sdes { "true", SSHCTL_MASTER_YES }, 686262566Sdes { "yes", SSHCTL_MASTER_YES }, 687262566Sdes { "false", SSHCTL_MASTER_NO }, 688262566Sdes { "no", SSHCTL_MASTER_NO }, 689262566Sdes { "auto", SSHCTL_MASTER_AUTO }, 690262566Sdes { "ask", SSHCTL_MASTER_ASK }, 691262566Sdes { "autoask", SSHCTL_MASTER_AUTO_ASK }, 692262566Sdes { NULL, -1 } 693262566Sdes}; 694262566Sdesstatic const struct multistate multistate_tunnel[] = { 695262566Sdes { "ethernet", SSH_TUNMODE_ETHERNET }, 696262566Sdes { "point-to-point", SSH_TUNMODE_POINTOPOINT }, 697262566Sdes { "true", SSH_TUNMODE_DEFAULT }, 698262566Sdes { "yes", SSH_TUNMODE_DEFAULT }, 699262566Sdes { "false", SSH_TUNMODE_NO }, 700262566Sdes { "no", SSH_TUNMODE_NO }, 701262566Sdes { NULL, -1 } 702262566Sdes}; 703262566Sdesstatic const struct multistate multistate_requesttty[] = { 704262566Sdes { "true", REQUEST_TTY_YES }, 705262566Sdes { "yes", REQUEST_TTY_YES }, 706262566Sdes { "false", REQUEST_TTY_NO }, 707262566Sdes { "no", REQUEST_TTY_NO }, 708262566Sdes { "force", REQUEST_TTY_FORCE }, 709262566Sdes { "auto", REQUEST_TTY_AUTO }, 710262566Sdes { NULL, -1 } 711262566Sdes}; 712262566Sdesstatic const struct multistate multistate_canonicalizehostname[] = { 713262566Sdes { "true", SSH_CANONICALISE_YES }, 714262566Sdes { "false", SSH_CANONICALISE_NO }, 715262566Sdes { "yes", SSH_CANONICALISE_YES }, 716262566Sdes { "no", SSH_CANONICALISE_NO }, 717262566Sdes { "always", SSH_CANONICALISE_ALWAYS }, 718262566Sdes { NULL, -1 } 719262566Sdes}; 720262566Sdes 72157429Smarkm/* 72257429Smarkm * Processes a single option line as used in the configuration files. This 72357429Smarkm * only sets those values that have not already been set. 72457429Smarkm */ 725113911Sdes#define WHITESPACE " \t\r\n" 72657429Smarkmint 727262566Sdesprocess_config_line(Options *options, struct passwd *pw, const char *host, 728262566Sdes char *line, const char *filename, int linenum, int *activep, int userconfig) 72957429Smarkm{ 730226046Sdes char *s, **charptr, *endofnumber, *keyword, *arg, *arg2; 731226046Sdes char **cpptr, fwdarg[256]; 732255767Sdes u_int i, *uintptr, max_entries = 0; 733262566Sdes int negated, opcode, *intptr, value, value2, cmdline = 0; 734181111Sdes LogLevel *log_level_ptr; 735255767Sdes long long val64; 736113911Sdes size_t len; 737147005Sdes Forward fwd; 738262566Sdes const struct multistate *multistate_ptr; 739262566Sdes struct allowed_cname *cname; 74057429Smarkm 741262566Sdes if (activep == NULL) { /* We are processing a command line directive */ 742262566Sdes cmdline = 1; 743262566Sdes activep = &cmdline; 744262566Sdes } 745262566Sdes 746124211Sdes /* Strip trailing whitespace */ 747147005Sdes for (len = strlen(line) - 1; len > 0; len--) { 748124211Sdes if (strchr(WHITESPACE, line[len]) == NULL) 749124211Sdes break; 750124211Sdes line[len] = '\0'; 751124211Sdes } 752124211Sdes 75365674Skris s = line; 75465674Skris /* Get the keyword. (Each line is supposed to begin with a keyword). */ 755162856Sdes if ((keyword = strdelim(&s)) == NULL) 756162856Sdes return 0; 75765674Skris /* Ignore leading whitespace. */ 75865674Skris if (*keyword == '\0') 75965674Skris keyword = strdelim(&s); 76076262Sgreen if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#') 76157429Smarkm return 0; 762255767Sdes /* Match lowercase keyword */ 763262566Sdes lowercase(keyword); 76457429Smarkm 765255767Sdes opcode = parse_token(keyword, filename, linenum, 766255767Sdes options->ignored_unknown); 76757429Smarkm 76857429Smarkm switch (opcode) { 76957429Smarkm case oBadOption: 77057429Smarkm /* don't panic, but count bad options */ 77157429Smarkm return -1; 77257429Smarkm /* NOTREACHED */ 773255767Sdes case oIgnoredUnknownOption: 774255767Sdes debug("%s line %d: Ignored unknown option \"%s\"", 775255767Sdes filename, linenum, keyword); 776255767Sdes return 0; 777124211Sdes case oConnectTimeout: 778124211Sdes intptr = &options->connection_timeout; 779126277Sdesparse_time: 780124211Sdes arg = strdelim(&s); 781124211Sdes if (!arg || *arg == '\0') 782124211Sdes fatal("%s line %d: missing time value.", 783124211Sdes filename, linenum); 784124211Sdes if ((value = convtime(arg)) == -1) 785124211Sdes fatal("%s line %d: invalid time value.", 786124211Sdes filename, linenum); 787181111Sdes if (*activep && *intptr == -1) 788124211Sdes *intptr = value; 789124211Sdes break; 790124211Sdes 79157429Smarkm case oForwardAgent: 79257429Smarkm intptr = &options->forward_agent; 793262566Sdes parse_flag: 794262566Sdes multistate_ptr = multistate_flag; 795262566Sdes parse_multistate: 79665674Skris arg = strdelim(&s); 79765674Skris if (!arg || *arg == '\0') 798262566Sdes fatal("%s line %d: missing argument.", 799262566Sdes filename, linenum); 800262566Sdes value = -1; 801262566Sdes for (i = 0; multistate_ptr[i].key != NULL; i++) { 802262566Sdes if (strcasecmp(arg, multistate_ptr[i].key) == 0) { 803262566Sdes value = multistate_ptr[i].value; 804262566Sdes break; 805262566Sdes } 806262566Sdes } 807262566Sdes if (value == -1) 808262566Sdes fatal("%s line %d: unsupported option \"%s\".", 809262566Sdes filename, linenum, arg); 81057429Smarkm if (*activep && *intptr == -1) 81157429Smarkm *intptr = value; 81257429Smarkm break; 81357429Smarkm 81457429Smarkm case oForwardX11: 81557429Smarkm intptr = &options->forward_x11; 81657429Smarkm goto parse_flag; 81757429Smarkm 818126277Sdes case oForwardX11Trusted: 819126277Sdes intptr = &options->forward_x11_trusted; 820126277Sdes goto parse_flag; 821215116Sdes 822215116Sdes case oForwardX11Timeout: 823215116Sdes intptr = &options->forward_x11_timeout; 824215116Sdes goto parse_time; 825126277Sdes 82657429Smarkm case oGatewayPorts: 82757429Smarkm intptr = &options->gateway_ports; 82857429Smarkm goto parse_flag; 82957429Smarkm 830162856Sdes case oExitOnForwardFailure: 831162856Sdes intptr = &options->exit_on_forward_failure; 832162856Sdes goto parse_flag; 833162856Sdes 83457429Smarkm case oUsePrivilegedPort: 83557429Smarkm intptr = &options->use_privileged_port; 83657429Smarkm goto parse_flag; 83757429Smarkm 83857429Smarkm case oPasswordAuthentication: 83957429Smarkm intptr = &options->password_authentication; 84057429Smarkm goto parse_flag; 84157429Smarkm 84269591Sgreen case oKbdInteractiveAuthentication: 84369591Sgreen intptr = &options->kbd_interactive_authentication; 84469591Sgreen goto parse_flag; 84569591Sgreen 84669591Sgreen case oKbdInteractiveDevices: 84769591Sgreen charptr = &options->kbd_interactive_devices; 84869591Sgreen goto parse_string; 84969591Sgreen 85076262Sgreen case oPubkeyAuthentication: 85176262Sgreen intptr = &options->pubkey_authentication; 85260576Skris goto parse_flag; 85360576Skris 85457429Smarkm case oRSAAuthentication: 85557429Smarkm intptr = &options->rsa_authentication; 85657429Smarkm goto parse_flag; 85757429Smarkm 85857429Smarkm case oRhostsRSAAuthentication: 85957429Smarkm intptr = &options->rhosts_rsa_authentication; 86057429Smarkm goto parse_flag; 86157429Smarkm 86276262Sgreen case oHostbasedAuthentication: 86376262Sgreen intptr = &options->hostbased_authentication; 86457429Smarkm goto parse_flag; 86557429Smarkm 86692559Sdes case oChallengeResponseAuthentication: 86792559Sdes intptr = &options->challenge_response_authentication; 86892559Sdes goto parse_flag; 869124211Sdes 870124211Sdes case oGssAuthentication: 871124211Sdes intptr = &options->gss_authentication; 87257429Smarkm goto parse_flag; 873124211Sdes 874124211Sdes case oGssDelegateCreds: 875124211Sdes intptr = &options->gss_deleg_creds; 87676262Sgreen goto parse_flag; 877124211Sdes 87857429Smarkm case oBatchMode: 87957429Smarkm intptr = &options->batch_mode; 88057429Smarkm goto parse_flag; 88157429Smarkm 88257429Smarkm case oCheckHostIP: 88357429Smarkm intptr = &options->check_host_ip; 88457429Smarkm goto parse_flag; 88557429Smarkm 886124211Sdes case oVerifyHostKeyDNS: 887124211Sdes intptr = &options->verify_host_key_dns; 888262566Sdes multistate_ptr = multistate_yesnoask; 889262566Sdes goto parse_multistate; 890124211Sdes 89157429Smarkm case oStrictHostKeyChecking: 89257429Smarkm intptr = &options->strict_host_key_checking; 893262566Sdes multistate_ptr = multistate_yesnoask; 894262566Sdes goto parse_multistate; 89557429Smarkm 89657429Smarkm case oCompression: 89757429Smarkm intptr = &options->compression; 89857429Smarkm goto parse_flag; 89957429Smarkm 900126277Sdes case oTCPKeepAlive: 901126277Sdes intptr = &options->tcp_keep_alive; 90257429Smarkm goto parse_flag; 90357429Smarkm 90492559Sdes case oNoHostAuthenticationForLocalhost: 90592559Sdes intptr = &options->no_host_authentication_for_localhost; 90692559Sdes goto parse_flag; 90792559Sdes 90857429Smarkm case oNumberOfPasswordPrompts: 90957429Smarkm intptr = &options->number_of_password_prompts; 91057429Smarkm goto parse_int; 91157429Smarkm 91257429Smarkm case oCompressionLevel: 91357429Smarkm intptr = &options->compression_level; 91457429Smarkm goto parse_int; 91557429Smarkm 916124211Sdes case oRekeyLimit: 917124211Sdes arg = strdelim(&s); 918124211Sdes if (!arg || *arg == '\0') 919255767Sdes fatal("%.200s line %d: Missing argument.", filename, 920255767Sdes linenum); 921255767Sdes if (strcmp(arg, "default") == 0) { 922255767Sdes val64 = 0; 923255767Sdes } else { 924255767Sdes if (scan_scaled(arg, &val64) == -1) 925255767Sdes fatal("%.200s line %d: Bad number '%s': %s", 926255767Sdes filename, linenum, arg, strerror(errno)); 927255767Sdes /* check for too-large or too-small limits */ 928255767Sdes if (val64 > UINT_MAX) 929255767Sdes fatal("%.200s line %d: RekeyLimit too large", 930255767Sdes filename, linenum); 931255767Sdes if (val64 != 0 && val64 < 16) 932255767Sdes fatal("%.200s line %d: RekeyLimit too small", 933255767Sdes filename, linenum); 934124211Sdes } 935181111Sdes if (*activep && options->rekey_limit == -1) 936181111Sdes options->rekey_limit = (u_int32_t)val64; 937255767Sdes if (s != NULL) { /* optional rekey interval present */ 938255767Sdes if (strcmp(s, "none") == 0) { 939255767Sdes (void)strdelim(&s); /* discard */ 940255767Sdes break; 941255767Sdes } 942255767Sdes intptr = &options->rekey_interval; 943255767Sdes goto parse_time; 944255767Sdes } 945124211Sdes break; 946124211Sdes 94757429Smarkm case oIdentityFile: 94865674Skris arg = strdelim(&s); 94965674Skris if (!arg || *arg == '\0') 95057429Smarkm fatal("%.200s line %d: Missing argument.", filename, linenum); 95157429Smarkm if (*activep) { 95276262Sgreen intptr = &options->num_identity_files; 95360576Skris if (*intptr >= SSH_MAX_IDENTITY_FILES) 95457429Smarkm fatal("%.200s line %d: Too many identity files specified (max %d).", 95592559Sdes filename, linenum, SSH_MAX_IDENTITY_FILES); 956249839Sdes add_identity_file(options, NULL, arg, userconfig); 95757429Smarkm } 95857429Smarkm break; 95957429Smarkm 96065674Skris case oXAuthLocation: 96165674Skris charptr=&options->xauth_location; 96265674Skris goto parse_string; 96365674Skris 96457429Smarkm case oUser: 96557429Smarkm charptr = &options->user; 96657429Smarkmparse_string: 96765674Skris arg = strdelim(&s); 96865674Skris if (!arg || *arg == '\0') 969226046Sdes fatal("%.200s line %d: Missing argument.", 970226046Sdes filename, linenum); 97157429Smarkm if (*activep && *charptr == NULL) 97265674Skris *charptr = xstrdup(arg); 97357429Smarkm break; 97457429Smarkm 97557429Smarkm case oGlobalKnownHostsFile: 976226046Sdes cpptr = (char **)&options->system_hostfiles; 977226046Sdes uintptr = &options->num_system_hostfiles; 978226046Sdes max_entries = SSH_MAX_HOSTS_FILES; 979226046Sdesparse_char_array: 980226046Sdes if (*activep && *uintptr == 0) { 981226046Sdes while ((arg = strdelim(&s)) != NULL && *arg != '\0') { 982226046Sdes if ((*uintptr) >= max_entries) 983226046Sdes fatal("%s line %d: " 984226046Sdes "too many authorized keys files.", 985226046Sdes filename, linenum); 986226046Sdes cpptr[(*uintptr)++] = xstrdup(arg); 987226046Sdes } 988226046Sdes } 989226046Sdes return 0; 99057429Smarkm 99157429Smarkm case oUserKnownHostsFile: 992226046Sdes cpptr = (char **)&options->user_hostfiles; 993226046Sdes uintptr = &options->num_user_hostfiles; 994226046Sdes max_entries = SSH_MAX_HOSTS_FILES; 995226046Sdes goto parse_char_array; 99657429Smarkm 99757429Smarkm case oHostName: 99857429Smarkm charptr = &options->hostname; 99957429Smarkm goto parse_string; 100057429Smarkm 100176262Sgreen case oHostKeyAlias: 100276262Sgreen charptr = &options->host_key_alias; 100376262Sgreen goto parse_string; 100476262Sgreen 100576262Sgreen case oPreferredAuthentications: 100676262Sgreen charptr = &options->preferred_authentications; 100776262Sgreen goto parse_string; 100876262Sgreen 100992559Sdes case oBindAddress: 101092559Sdes charptr = &options->bind_address; 101192559Sdes goto parse_string; 101292559Sdes 1013204917Sdes case oPKCS11Provider: 1014204917Sdes charptr = &options->pkcs11_provider; 101592559Sdes goto parse_string; 101692559Sdes 101757429Smarkm case oProxyCommand: 1018157019Sdes charptr = &options->proxy_command; 1019157019Sdesparse_command: 1020124211Sdes if (s == NULL) 1021124211Sdes fatal("%.200s line %d: Missing argument.", filename, linenum); 1022113911Sdes len = strspn(s, WHITESPACE "="); 102357429Smarkm if (*activep && *charptr == NULL) 1024113911Sdes *charptr = xstrdup(s + len); 102557429Smarkm return 0; 102657429Smarkm 102757429Smarkm case oPort: 102857429Smarkm intptr = &options->port; 102957429Smarkmparse_int: 103065674Skris arg = strdelim(&s); 103165674Skris if (!arg || *arg == '\0') 103257429Smarkm fatal("%.200s line %d: Missing argument.", filename, linenum); 103365674Skris if (arg[0] < '0' || arg[0] > '9') 103457429Smarkm fatal("%.200s line %d: Bad number.", filename, linenum); 103557429Smarkm 103657429Smarkm /* Octal, decimal, or hex format? */ 103765674Skris value = strtol(arg, &endofnumber, 0); 103865674Skris if (arg == endofnumber) 103957429Smarkm fatal("%.200s line %d: Bad number.", filename, linenum); 104057429Smarkm if (*activep && *intptr == -1) 104157429Smarkm *intptr = value; 104257429Smarkm break; 104357429Smarkm 104457429Smarkm case oConnectionAttempts: 104557429Smarkm intptr = &options->connection_attempts; 104657429Smarkm goto parse_int; 104757429Smarkm 104857429Smarkm case oCipher: 104957429Smarkm intptr = &options->cipher; 105065674Skris arg = strdelim(&s); 105165674Skris if (!arg || *arg == '\0') 105261203Skris fatal("%.200s line %d: Missing argument.", filename, linenum); 105365674Skris value = cipher_number(arg); 105457429Smarkm if (value == -1) 105557429Smarkm fatal("%.200s line %d: Bad cipher '%s'.", 105692559Sdes filename, linenum, arg ? arg : "<NONE>"); 105757429Smarkm if (*activep && *intptr == -1) 105857429Smarkm *intptr = value; 105957429Smarkm break; 106057429Smarkm 106160576Skris case oCiphers: 106265674Skris arg = strdelim(&s); 106365674Skris if (!arg || *arg == '\0') 106461203Skris fatal("%.200s line %d: Missing argument.", filename, linenum); 106565674Skris if (!ciphers_valid(arg)) 106660576Skris fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.", 106792559Sdes filename, linenum, arg ? arg : "<NONE>"); 106860576Skris if (*activep && options->ciphers == NULL) 106965674Skris options->ciphers = xstrdup(arg); 107060576Skris break; 107160576Skris 107276262Sgreen case oMacs: 107376262Sgreen arg = strdelim(&s); 107476262Sgreen if (!arg || *arg == '\0') 107576262Sgreen fatal("%.200s line %d: Missing argument.", filename, linenum); 107676262Sgreen if (!mac_valid(arg)) 107776262Sgreen fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.", 107892559Sdes filename, linenum, arg ? arg : "<NONE>"); 107976262Sgreen if (*activep && options->macs == NULL) 108076262Sgreen options->macs = xstrdup(arg); 108176262Sgreen break; 108276262Sgreen 1083221420Sdes case oKexAlgorithms: 1084221420Sdes arg = strdelim(&s); 1085221420Sdes if (!arg || *arg == '\0') 1086221420Sdes fatal("%.200s line %d: Missing argument.", 1087221420Sdes filename, linenum); 1088221420Sdes if (!kex_names_valid(arg)) 1089221420Sdes fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.", 1090221420Sdes filename, linenum, arg ? arg : "<NONE>"); 1091221420Sdes if (*activep && options->kex_algorithms == NULL) 1092221420Sdes options->kex_algorithms = xstrdup(arg); 1093221420Sdes break; 1094221420Sdes 109576262Sgreen case oHostKeyAlgorithms: 109676262Sgreen arg = strdelim(&s); 109776262Sgreen if (!arg || *arg == '\0') 109876262Sgreen fatal("%.200s line %d: Missing argument.", filename, linenum); 109976262Sgreen if (!key_names_valid2(arg)) 110076262Sgreen fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.", 110192559Sdes filename, linenum, arg ? arg : "<NONE>"); 110276262Sgreen if (*activep && options->hostkeyalgorithms == NULL) 110376262Sgreen options->hostkeyalgorithms = xstrdup(arg); 110476262Sgreen break; 110576262Sgreen 110660576Skris case oProtocol: 110760576Skris intptr = &options->protocol; 110865674Skris arg = strdelim(&s); 110965674Skris if (!arg || *arg == '\0') 111061203Skris fatal("%.200s line %d: Missing argument.", filename, linenum); 111165674Skris value = proto_spec(arg); 111260576Skris if (value == SSH_PROTO_UNKNOWN) 111360576Skris fatal("%.200s line %d: Bad protocol spec '%s'.", 111492559Sdes filename, linenum, arg ? arg : "<NONE>"); 111560576Skris if (*activep && *intptr == SSH_PROTO_UNKNOWN) 111660576Skris *intptr = value; 111760576Skris break; 111860576Skris 111957429Smarkm case oLogLevel: 1120181111Sdes log_level_ptr = &options->log_level; 112165674Skris arg = strdelim(&s); 112265674Skris value = log_level_number(arg); 112392559Sdes if (value == SYSLOG_LEVEL_NOT_SET) 112476262Sgreen fatal("%.200s line %d: unsupported log level '%s'", 112592559Sdes filename, linenum, arg ? arg : "<NONE>"); 1126181111Sdes if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET) 1127181111Sdes *log_level_ptr = (LogLevel) value; 112857429Smarkm break; 112957429Smarkm 113092559Sdes case oLocalForward: 113157429Smarkm case oRemoteForward: 1132192595Sdes case oDynamicForward: 113365674Skris arg = strdelim(&s); 1134147005Sdes if (arg == NULL || *arg == '\0') 113592559Sdes fatal("%.200s line %d: Missing port argument.", 113692559Sdes filename, linenum); 1137147005Sdes 1138192595Sdes if (opcode == oLocalForward || 1139192595Sdes opcode == oRemoteForward) { 1140192595Sdes arg2 = strdelim(&s); 1141192595Sdes if (arg2 == NULL || *arg2 == '\0') 1142192595Sdes fatal("%.200s line %d: Missing target argument.", 1143192595Sdes filename, linenum); 1144147005Sdes 1145192595Sdes /* construct a string for parse_forward */ 1146192595Sdes snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2); 1147192595Sdes } else if (opcode == oDynamicForward) { 1148192595Sdes strlcpy(fwdarg, arg, sizeof(fwdarg)); 1149192595Sdes } 1150192595Sdes 1151192595Sdes if (parse_forward(&fwd, fwdarg, 1152192595Sdes opcode == oDynamicForward ? 1 : 0, 1153192595Sdes opcode == oRemoteForward ? 1 : 0) == 0) 115492559Sdes fatal("%.200s line %d: Bad forwarding specification.", 115592559Sdes filename, linenum); 1156147005Sdes 115792559Sdes if (*activep) { 1158192595Sdes if (opcode == oLocalForward || 1159192595Sdes opcode == oDynamicForward) 1160147005Sdes add_local_forward(options, &fwd); 116192559Sdes else if (opcode == oRemoteForward) 1162147005Sdes add_remote_forward(options, &fwd); 116392559Sdes } 116457429Smarkm break; 116557429Smarkm 116692559Sdes case oClearAllForwardings: 116792559Sdes intptr = &options->clear_forwardings; 116892559Sdes goto parse_flag; 116992559Sdes 117057429Smarkm case oHost: 1171262566Sdes if (cmdline) 1172262566Sdes fatal("Host directive not supported as a command-line " 1173262566Sdes "option"); 117457429Smarkm *activep = 0; 1175226046Sdes arg2 = NULL; 1176226046Sdes while ((arg = strdelim(&s)) != NULL && *arg != '\0') { 1177226046Sdes negated = *arg == '!'; 1178226046Sdes if (negated) 1179226046Sdes arg++; 118065674Skris if (match_pattern(host, arg)) { 1181226046Sdes if (negated) { 1182226046Sdes debug("%.200s line %d: Skipping Host " 1183226046Sdes "block because of negated match " 1184226046Sdes "for %.100s", filename, linenum, 1185226046Sdes arg); 1186226046Sdes *activep = 0; 1187226046Sdes break; 1188226046Sdes } 1189226046Sdes if (!*activep) 1190226046Sdes arg2 = arg; /* logged below */ 119157429Smarkm *activep = 1; 119257429Smarkm } 1193226046Sdes } 1194226046Sdes if (*activep) 1195226046Sdes debug("%.200s line %d: Applying options for %.100s", 1196226046Sdes filename, linenum, arg2); 119765674Skris /* Avoid garbage check below, as strdelim is done. */ 119857429Smarkm return 0; 119957429Smarkm 1200262566Sdes case oMatch: 1201262566Sdes if (cmdline) 1202262566Sdes fatal("Host directive not supported as a command-line " 1203262566Sdes "option"); 1204262566Sdes value = match_cfg_line(options, &s, pw, host, 1205262566Sdes filename, linenum); 1206262566Sdes if (value < 0) 1207262566Sdes fatal("%.200s line %d: Bad Match condition", filename, 1208262566Sdes linenum); 1209262566Sdes *activep = value; 1210262566Sdes break; 1211262566Sdes 121257429Smarkm case oEscapeChar: 121357429Smarkm intptr = &options->escape_char; 121465674Skris arg = strdelim(&s); 121565674Skris if (!arg || *arg == '\0') 121657429Smarkm fatal("%.200s line %d: Missing argument.", filename, linenum); 121765674Skris if (arg[0] == '^' && arg[2] == 0 && 121876262Sgreen (u_char) arg[1] >= 64 && (u_char) arg[1] < 128) 121976262Sgreen value = (u_char) arg[1] & 31; 122065674Skris else if (strlen(arg) == 1) 122176262Sgreen value = (u_char) arg[0]; 122265674Skris else if (strcmp(arg, "none") == 0) 122392559Sdes value = SSH_ESCAPECHAR_NONE; 122457429Smarkm else { 122557429Smarkm fatal("%.200s line %d: Bad escape character.", 122692559Sdes filename, linenum); 122757429Smarkm /* NOTREACHED */ 122857429Smarkm value = 0; /* Avoid compiler warning. */ 122957429Smarkm } 123057429Smarkm if (*activep && *intptr == -1) 123157429Smarkm *intptr = value; 123257429Smarkm break; 123357429Smarkm 1234124211Sdes case oAddressFamily: 1235124211Sdes intptr = &options->address_family; 1236262566Sdes multistate_ptr = multistate_addressfamily; 1237262566Sdes goto parse_multistate; 1238124211Sdes 1239113911Sdes case oEnableSSHKeysign: 1240113911Sdes intptr = &options->enable_ssh_keysign; 1241113911Sdes goto parse_flag; 1242113911Sdes 1243128460Sdes case oIdentitiesOnly: 1244128460Sdes intptr = &options->identities_only; 1245128460Sdes goto parse_flag; 1246128460Sdes 1247126277Sdes case oServerAliveInterval: 1248126277Sdes intptr = &options->server_alive_interval; 1249126277Sdes goto parse_time; 1250126277Sdes 1251126277Sdes case oServerAliveCountMax: 1252126277Sdes intptr = &options->server_alive_count_max; 1253126277Sdes goto parse_int; 1254126277Sdes 1255137019Sdes case oSendEnv: 1256137019Sdes while ((arg = strdelim(&s)) != NULL && *arg != '\0') { 1257137019Sdes if (strchr(arg, '=') != NULL) 1258137019Sdes fatal("%s line %d: Invalid environment name.", 1259137019Sdes filename, linenum); 1260147005Sdes if (!*activep) 1261147005Sdes continue; 1262137019Sdes if (options->num_send_env >= MAX_SEND_ENV) 1263137019Sdes fatal("%s line %d: too many send env.", 1264137019Sdes filename, linenum); 1265137019Sdes options->send_env[options->num_send_env++] = 1266137019Sdes xstrdup(arg); 1267137019Sdes } 1268137019Sdes break; 1269137019Sdes 1270137019Sdes case oControlPath: 1271137019Sdes charptr = &options->control_path; 1272137019Sdes goto parse_string; 1273137019Sdes 1274137019Sdes case oControlMaster: 1275137019Sdes intptr = &options->control_master; 1276262566Sdes multistate_ptr = multistate_controlmaster; 1277262566Sdes goto parse_multistate; 1278137019Sdes 1279215116Sdes case oControlPersist: 1280215116Sdes /* no/false/yes/true, or a time spec */ 1281215116Sdes intptr = &options->control_persist; 1282215116Sdes arg = strdelim(&s); 1283215116Sdes if (!arg || *arg == '\0') 1284215116Sdes fatal("%.200s line %d: Missing ControlPersist" 1285215116Sdes " argument.", filename, linenum); 1286215116Sdes value = 0; 1287215116Sdes value2 = 0; /* timeout */ 1288215116Sdes if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) 1289215116Sdes value = 0; 1290215116Sdes else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) 1291215116Sdes value = 1; 1292215116Sdes else if ((value2 = convtime(arg)) >= 0) 1293215116Sdes value = 1; 1294215116Sdes else 1295215116Sdes fatal("%.200s line %d: Bad ControlPersist argument.", 1296215116Sdes filename, linenum); 1297215116Sdes if (*activep && *intptr == -1) { 1298215116Sdes *intptr = value; 1299215116Sdes options->control_persist_timeout = value2; 1300215116Sdes } 1301215116Sdes break; 1302215116Sdes 1303147005Sdes case oHashKnownHosts: 1304147005Sdes intptr = &options->hash_known_hosts; 1305147005Sdes goto parse_flag; 1306147005Sdes 1307157019Sdes case oTunnel: 1308157019Sdes intptr = &options->tun_open; 1309262566Sdes multistate_ptr = multistate_tunnel; 1310262566Sdes goto parse_multistate; 1311157019Sdes 1312157019Sdes case oTunnelDevice: 1313157019Sdes arg = strdelim(&s); 1314157019Sdes if (!arg || *arg == '\0') 1315157019Sdes fatal("%.200s line %d: Missing argument.", filename, linenum); 1316157019Sdes value = a2tun(arg, &value2); 1317157019Sdes if (value == SSH_TUNID_ERR) 1318157019Sdes fatal("%.200s line %d: Bad tun device.", filename, linenum); 1319157019Sdes if (*activep) { 1320157019Sdes options->tun_local = value; 1321157019Sdes options->tun_remote = value2; 1322157019Sdes } 1323157019Sdes break; 1324157019Sdes 1325157019Sdes case oLocalCommand: 1326157019Sdes charptr = &options->local_command; 1327157019Sdes goto parse_command; 1328157019Sdes 1329157019Sdes case oPermitLocalCommand: 1330157019Sdes intptr = &options->permit_local_command; 1331157019Sdes goto parse_flag; 1332157019Sdes 1333181111Sdes case oVisualHostKey: 1334181111Sdes intptr = &options->visual_host_key; 1335181111Sdes goto parse_flag; 1336181111Sdes 1337221420Sdes case oIPQoS: 1338221420Sdes arg = strdelim(&s); 1339221420Sdes if ((value = parse_ipqos(arg)) == -1) 1340221420Sdes fatal("%s line %d: Bad IPQoS value: %s", 1341221420Sdes filename, linenum, arg); 1342221420Sdes arg = strdelim(&s); 1343221420Sdes if (arg == NULL) 1344221420Sdes value2 = value; 1345221420Sdes else if ((value2 = parse_ipqos(arg)) == -1) 1346221420Sdes fatal("%s line %d: Bad IPQoS value: %s", 1347221420Sdes filename, linenum, arg); 1348221420Sdes if (*activep) { 1349221420Sdes options->ip_qos_interactive = value; 1350221420Sdes options->ip_qos_bulk = value2; 1351221420Sdes } 1352221420Sdes break; 1353221420Sdes 1354197679Sdes case oUseRoaming: 1355197679Sdes intptr = &options->use_roaming; 1356197679Sdes goto parse_flag; 1357197679Sdes 1358226046Sdes case oRequestTTY: 1359226046Sdes intptr = &options->request_tty; 1360262566Sdes multistate_ptr = multistate_requesttty; 1361262566Sdes goto parse_multistate; 136299048Sdes 1363224638Sbrooks case oHPNDisabled: 1364224638Sbrooks intptr = &options->hpn_disabled; 1365224638Sbrooks goto parse_flag; 1366224638Sbrooks 1367224638Sbrooks case oHPNBufferSize: 1368224638Sbrooks intptr = &options->hpn_buffer_size; 1369224638Sbrooks goto parse_int; 1370224638Sbrooks 1371224638Sbrooks case oTcpRcvBufPoll: 1372224638Sbrooks intptr = &options->tcp_rcv_buf_poll; 1373224638Sbrooks goto parse_flag; 1374224638Sbrooks 1375224638Sbrooks case oTcpRcvBuf: 1376224638Sbrooks intptr = &options->tcp_rcv_buf; 1377224638Sbrooks goto parse_int; 1378224638Sbrooks 1379224638Sbrooks#ifdef NONE_CIPHER_ENABLED 1380224638Sbrooks case oNoneEnabled: 1381224638Sbrooks intptr = &options->none_enabled; 1382224638Sbrooks goto parse_flag; 1383231584Sed 1384224638Sbrooks /* 1385231584Sed * We check to see if the command comes from the command line or not. 1386224638Sbrooks * If it does then enable it otherwise fail. NONE must never be a 1387224638Sbrooks * default configuration. 1388224638Sbrooks */ 1389224638Sbrooks case oNoneSwitch: 1390224638Sbrooks if (strcmp(filename,"command-line") == 0) { 1391224638Sbrooks intptr = &options->none_switch; 1392224638Sbrooks goto parse_flag; 1393224638Sbrooks } else { 1394224638Sbrooks debug("NoneSwitch directive found in %.200s.", 1395224638Sbrooks filename); 1396224638Sbrooks error("NoneSwitch is found in %.200s.\n" 1397224638Sbrooks "You may only use this configuration option " 1398224638Sbrooks "from the command line", filename); 1399224638Sbrooks error("Continuing..."); 1400224638Sbrooks return 0; 1401231584Sed } 1402224638Sbrooks#endif 1403224638Sbrooks 1404226046Sdes case oVersionAddendum: 1405240075Sdes if (s == NULL) 1406240075Sdes fatal("%.200s line %d: Missing argument.", filename, 1407240075Sdes linenum); 1408240075Sdes len = strspn(s, WHITESPACE); 1409240075Sdes if (*activep && options->version_addendum == NULL) { 1410240075Sdes if (strcasecmp(s + len, "none") == 0) 1411240075Sdes options->version_addendum = xstrdup(""); 1412240075Sdes else if (strchr(s + len, '\r') != NULL) 1413240075Sdes fatal("%.200s line %d: Invalid argument", 1414240075Sdes filename, linenum); 1415240075Sdes else 1416240075Sdes options->version_addendum = xstrdup(s + len); 1417240075Sdes } 1418240075Sdes return 0; 1419226046Sdes 1420255767Sdes case oIgnoreUnknown: 1421255767Sdes charptr = &options->ignored_unknown; 1422255767Sdes goto parse_string; 1423255767Sdes 1424262566Sdes case oProxyUseFdpass: 1425262566Sdes intptr = &options->proxy_use_fdpass; 1426262566Sdes goto parse_flag; 1427262566Sdes 1428262566Sdes case oCanonicalDomains: 1429262566Sdes value = options->num_canonical_domains != 0; 1430262566Sdes while ((arg = strdelim(&s)) != NULL && *arg != '\0') { 1431262566Sdes valid_domain(arg, filename, linenum); 1432262566Sdes if (!*activep || value) 1433262566Sdes continue; 1434262566Sdes if (options->num_canonical_domains >= MAX_CANON_DOMAINS) 1435262566Sdes fatal("%s line %d: too many hostname suffixes.", 1436262566Sdes filename, linenum); 1437262566Sdes options->canonical_domains[ 1438262566Sdes options->num_canonical_domains++] = xstrdup(arg); 1439262566Sdes } 1440262566Sdes break; 1441262566Sdes 1442262566Sdes case oCanonicalizePermittedCNAMEs: 1443262566Sdes value = options->num_permitted_cnames != 0; 1444262566Sdes while ((arg = strdelim(&s)) != NULL && *arg != '\0') { 1445262566Sdes /* Either '*' for everything or 'list:list' */ 1446262566Sdes if (strcmp(arg, "*") == 0) 1447262566Sdes arg2 = arg; 1448262566Sdes else { 1449262566Sdes lowercase(arg); 1450262566Sdes if ((arg2 = strchr(arg, ':')) == NULL || 1451262566Sdes arg2[1] == '\0') { 1452262566Sdes fatal("%s line %d: " 1453262566Sdes "Invalid permitted CNAME \"%s\"", 1454262566Sdes filename, linenum, arg); 1455262566Sdes } 1456262566Sdes *arg2 = '\0'; 1457262566Sdes arg2++; 1458262566Sdes } 1459262566Sdes if (!*activep || value) 1460262566Sdes continue; 1461262566Sdes if (options->num_permitted_cnames >= MAX_CANON_DOMAINS) 1462262566Sdes fatal("%s line %d: too many permitted CNAMEs.", 1463262566Sdes filename, linenum); 1464262566Sdes cname = options->permitted_cnames + 1465262566Sdes options->num_permitted_cnames++; 1466262566Sdes cname->source_list = xstrdup(arg); 1467262566Sdes cname->target_list = xstrdup(arg2); 1468262566Sdes } 1469262566Sdes break; 1470262566Sdes 1471262566Sdes case oCanonicalizeHostname: 1472262566Sdes intptr = &options->canonicalize_hostname; 1473262566Sdes multistate_ptr = multistate_canonicalizehostname; 1474262566Sdes goto parse_multistate; 1475262566Sdes 1476262566Sdes case oCanonicalizeMaxDots: 1477262566Sdes intptr = &options->canonicalize_max_dots; 1478262566Sdes goto parse_int; 1479262566Sdes 1480262566Sdes case oCanonicalizeFallbackLocal: 1481262566Sdes intptr = &options->canonicalize_fallback_local; 1482262566Sdes goto parse_flag; 1483262566Sdes 148498684Sdes case oDeprecated: 148598684Sdes debug("%s line %d: Deprecated option \"%s\"", 148698684Sdes filename, linenum, keyword); 148798684Sdes return 0; 148898684Sdes 1489124211Sdes case oUnsupported: 1490124211Sdes error("%s line %d: Unsupported option \"%s\"", 1491124211Sdes filename, linenum, keyword); 1492124211Sdes return 0; 1493124211Sdes 149457429Smarkm default: 149557429Smarkm fatal("process_config_line: Unimplemented opcode %d", opcode); 149657429Smarkm } 149757429Smarkm 149857429Smarkm /* Check that there is no garbage at end of line. */ 149976262Sgreen if ((arg = strdelim(&s)) != NULL && *arg != '\0') { 150065674Skris fatal("%.200s line %d: garbage at end of line; \"%.200s\".", 1501149753Sdes filename, linenum, arg); 150265674Skris } 150357429Smarkm return 0; 150457429Smarkm} 150557429Smarkm 150657429Smarkm 150757429Smarkm/* 150857429Smarkm * Reads the config file and modifies the options accordingly. Options 150957429Smarkm * should already be initialized before this call. This never returns if 151092559Sdes * there is an error. If the file does not exist, this returns 0. 151157429Smarkm */ 151257429Smarkm 151392559Sdesint 1514262566Sdesread_config_file(const char *filename, struct passwd *pw, const char *host, 1515262566Sdes Options *options, int flags) 151657429Smarkm{ 151757429Smarkm FILE *f; 151857429Smarkm char line[1024]; 151957429Smarkm int active, linenum; 152057429Smarkm int bad_options = 0; 152157429Smarkm 1522137019Sdes if ((f = fopen(filename, "r")) == NULL) 152392559Sdes return 0; 152457429Smarkm 1525249839Sdes if (flags & SSHCONF_CHECKPERM) { 1526137019Sdes struct stat sb; 1527137019Sdes 1528137019Sdes if (fstat(fileno(f), &sb) == -1) 1529137019Sdes fatal("fstat %s: %s", filename, strerror(errno)); 1530137019Sdes if (((sb.st_uid != 0 && sb.st_uid != getuid()) || 1531137019Sdes (sb.st_mode & 022) != 0)) 1532137019Sdes fatal("Bad owner or permissions on %s", filename); 1533137019Sdes } 1534137019Sdes 153557429Smarkm debug("Reading configuration data %.200s", filename); 153657429Smarkm 153757429Smarkm /* 153857429Smarkm * Mark that we are now processing the options. This flag is turned 153957429Smarkm * on/off by Host specifications. 154057429Smarkm */ 154157429Smarkm active = 1; 154257429Smarkm linenum = 0; 154357429Smarkm while (fgets(line, sizeof(line), f)) { 154457429Smarkm /* Update line number counter. */ 154557429Smarkm linenum++; 1546262566Sdes if (process_config_line(options, pw, host, line, filename, 1547262566Sdes linenum, &active, flags & SSHCONF_USERCONF) != 0) 154857429Smarkm bad_options++; 154957429Smarkm } 155057429Smarkm fclose(f); 155157429Smarkm if (bad_options > 0) 155276262Sgreen fatal("%s: terminating, %d bad configuration options", 155392559Sdes filename, bad_options); 155492559Sdes return 1; 155557429Smarkm} 155657429Smarkm 1557264377Sdes/* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ 1558264377Sdesint 1559264377Sdesoption_clear_or_none(const char *o) 1560264377Sdes{ 1561264377Sdes return o == NULL || strcasecmp(o, "none") == 0; 1562264377Sdes} 1563264377Sdes 156457429Smarkm/* 156557429Smarkm * Initializes options to special values that indicate that they have not yet 156657429Smarkm * been set. Read_config_file will only set options with this value. Options 156757429Smarkm * are processed in the following order: command line, user config file, 156857429Smarkm * system config file. Last, fill_default_options is called. 156957429Smarkm */ 157057429Smarkm 157160576Skrisvoid 157257429Smarkminitialize_options(Options * options) 157357429Smarkm{ 157457429Smarkm memset(options, 'X', sizeof(*options)); 157557429Smarkm options->forward_agent = -1; 157657429Smarkm options->forward_x11 = -1; 1577126277Sdes options->forward_x11_trusted = -1; 1578215116Sdes options->forward_x11_timeout = -1; 1579162856Sdes options->exit_on_forward_failure = -1; 158065674Skris options->xauth_location = NULL; 158157429Smarkm options->gateway_ports = -1; 158257429Smarkm options->use_privileged_port = -1; 158357429Smarkm options->rsa_authentication = -1; 158476262Sgreen options->pubkey_authentication = -1; 158592559Sdes options->challenge_response_authentication = -1; 1586124211Sdes options->gss_authentication = -1; 1587124211Sdes options->gss_deleg_creds = -1; 158857429Smarkm options->password_authentication = -1; 158969591Sgreen options->kbd_interactive_authentication = -1; 159069591Sgreen options->kbd_interactive_devices = NULL; 159157429Smarkm options->rhosts_rsa_authentication = -1; 159276262Sgreen options->hostbased_authentication = -1; 159357429Smarkm options->batch_mode = -1; 159457429Smarkm options->check_host_ip = -1; 159557429Smarkm options->strict_host_key_checking = -1; 159657429Smarkm options->compression = -1; 1597126277Sdes options->tcp_keep_alive = -1; 159857429Smarkm options->compression_level = -1; 159957429Smarkm options->port = -1; 1600124211Sdes options->address_family = -1; 160157429Smarkm options->connection_attempts = -1; 1602124211Sdes options->connection_timeout = -1; 160357429Smarkm options->number_of_password_prompts = -1; 160457429Smarkm options->cipher = -1; 160560576Skris options->ciphers = NULL; 160676262Sgreen options->macs = NULL; 1607221420Sdes options->kex_algorithms = NULL; 160876262Sgreen options->hostkeyalgorithms = NULL; 160960576Skris options->protocol = SSH_PROTO_UNKNOWN; 161057429Smarkm options->num_identity_files = 0; 161157429Smarkm options->hostname = NULL; 161276262Sgreen options->host_key_alias = NULL; 161357429Smarkm options->proxy_command = NULL; 161457429Smarkm options->user = NULL; 161557429Smarkm options->escape_char = -1; 1616226046Sdes options->num_system_hostfiles = 0; 1617226046Sdes options->num_user_hostfiles = 0; 1618215116Sdes options->local_forwards = NULL; 161957429Smarkm options->num_local_forwards = 0; 1620215116Sdes options->remote_forwards = NULL; 162157429Smarkm options->num_remote_forwards = 0; 162292559Sdes options->clear_forwardings = -1; 162392559Sdes options->log_level = SYSLOG_LEVEL_NOT_SET; 162476262Sgreen options->preferred_authentications = NULL; 162592559Sdes options->bind_address = NULL; 1626204917Sdes options->pkcs11_provider = NULL; 1627113911Sdes options->enable_ssh_keysign = - 1; 162892559Sdes options->no_host_authentication_for_localhost = - 1; 1629128460Sdes options->identities_only = - 1; 1630124211Sdes options->rekey_limit = - 1; 1631255767Sdes options->rekey_interval = -1; 1632124211Sdes options->verify_host_key_dns = -1; 1633126277Sdes options->server_alive_interval = -1; 1634126277Sdes options->server_alive_count_max = -1; 1635137019Sdes options->num_send_env = 0; 1636137019Sdes options->control_path = NULL; 1637137019Sdes options->control_master = -1; 1638215116Sdes options->control_persist = -1; 1639215116Sdes options->control_persist_timeout = 0; 1640147005Sdes options->hash_known_hosts = -1; 1641157019Sdes options->tun_open = -1; 1642157019Sdes options->tun_local = -1; 1643157019Sdes options->tun_remote = -1; 1644157019Sdes options->local_command = NULL; 1645157019Sdes options->permit_local_command = -1; 1646294050Sglebius options->use_roaming = 0; 1647181111Sdes options->visual_host_key = -1; 1648221420Sdes options->ip_qos_interactive = -1; 1649221420Sdes options->ip_qos_bulk = -1; 1650226046Sdes options->request_tty = -1; 1651262566Sdes options->proxy_use_fdpass = -1; 1652262566Sdes options->ignored_unknown = NULL; 1653262566Sdes options->num_canonical_domains = 0; 1654262566Sdes options->num_permitted_cnames = 0; 1655262566Sdes options->canonicalize_max_dots = -1; 1656262566Sdes options->canonicalize_fallback_local = -1; 1657262566Sdes options->canonicalize_hostname = -1; 1658240075Sdes options->version_addendum = NULL; 1659224638Sbrooks options->hpn_disabled = -1; 1660224638Sbrooks options->hpn_buffer_size = -1; 1661224638Sbrooks options->tcp_rcv_buf_poll = -1; 1662224638Sbrooks options->tcp_rcv_buf = -1; 1663224638Sbrooks#ifdef NONE_CIPHER_ENABLED 1664224638Sbrooks options->none_enabled = -1; 1665224638Sbrooks options->none_switch = -1; 1666224638Sbrooks#endif 166757429Smarkm} 166857429Smarkm 166957429Smarkm/* 1670264377Sdes * A petite version of fill_default_options() that just fills the options 1671264377Sdes * needed for hostname canonicalization to proceed. 1672264377Sdes */ 1673264377Sdesvoid 1674264377Sdesfill_default_options_for_canonicalization(Options *options) 1675264377Sdes{ 1676264377Sdes if (options->canonicalize_max_dots == -1) 1677264377Sdes options->canonicalize_max_dots = 1; 1678264377Sdes if (options->canonicalize_fallback_local == -1) 1679264377Sdes options->canonicalize_fallback_local = 1; 1680264377Sdes if (options->canonicalize_hostname == -1) 1681264377Sdes options->canonicalize_hostname = SSH_CANONICALISE_NO; 1682264377Sdes} 1683264377Sdes 1684264377Sdes/* 168557429Smarkm * Called after processing other sources of option data, this fills those 168657429Smarkm * options for which no value has been specified with their default values. 168757429Smarkm */ 168860576Skrisvoid 168957429Smarkmfill_default_options(Options * options) 169057429Smarkm{ 169157429Smarkm if (options->forward_agent == -1) 169261203Skris options->forward_agent = 0; 169357429Smarkm if (options->forward_x11 == -1) 169457708Sgreen options->forward_x11 = 0; 1695126277Sdes if (options->forward_x11_trusted == -1) 1696126277Sdes options->forward_x11_trusted = 0; 1697215116Sdes if (options->forward_x11_timeout == -1) 1698215116Sdes options->forward_x11_timeout = 1200; 1699162856Sdes if (options->exit_on_forward_failure == -1) 1700162856Sdes options->exit_on_forward_failure = 0; 170165674Skris if (options->xauth_location == NULL) 170292559Sdes options->xauth_location = _PATH_XAUTH; 170357429Smarkm if (options->gateway_ports == -1) 170457429Smarkm options->gateway_ports = 0; 170557429Smarkm if (options->use_privileged_port == -1) 170676262Sgreen options->use_privileged_port = 0; 170757429Smarkm if (options->rsa_authentication == -1) 170857429Smarkm options->rsa_authentication = 1; 170976262Sgreen if (options->pubkey_authentication == -1) 171076262Sgreen options->pubkey_authentication = 1; 171192559Sdes if (options->challenge_response_authentication == -1) 171292559Sdes options->challenge_response_authentication = 1; 1713124211Sdes if (options->gss_authentication == -1) 1714126277Sdes options->gss_authentication = 0; 1715124211Sdes if (options->gss_deleg_creds == -1) 1716124211Sdes options->gss_deleg_creds = 0; 171757429Smarkm if (options->password_authentication == -1) 171857429Smarkm options->password_authentication = 1; 171969591Sgreen if (options->kbd_interactive_authentication == -1) 172076262Sgreen options->kbd_interactive_authentication = 1; 172157429Smarkm if (options->rhosts_rsa_authentication == -1) 172298684Sdes options->rhosts_rsa_authentication = 0; 172376262Sgreen if (options->hostbased_authentication == -1) 172476262Sgreen options->hostbased_authentication = 0; 172557429Smarkm if (options->batch_mode == -1) 172657429Smarkm options->batch_mode = 0; 172757429Smarkm if (options->check_host_ip == -1) 172899048Sdes options->check_host_ip = 0; 172957429Smarkm if (options->strict_host_key_checking == -1) 173057429Smarkm options->strict_host_key_checking = 2; /* 2 is default */ 173157429Smarkm if (options->compression == -1) 173257429Smarkm options->compression = 0; 1733126277Sdes if (options->tcp_keep_alive == -1) 1734126277Sdes options->tcp_keep_alive = 1; 173557429Smarkm if (options->compression_level == -1) 173657429Smarkm options->compression_level = 6; 173757429Smarkm if (options->port == -1) 173857429Smarkm options->port = 0; /* Filled in ssh_connect. */ 1739124211Sdes if (options->address_family == -1) 1740124211Sdes options->address_family = AF_UNSPEC; 174157429Smarkm if (options->connection_attempts == -1) 174292559Sdes options->connection_attempts = 1; 174357429Smarkm if (options->number_of_password_prompts == -1) 174457429Smarkm options->number_of_password_prompts = 3; 174557429Smarkm /* Selected in ssh_login(). */ 174657429Smarkm if (options->cipher == -1) 174757429Smarkm options->cipher = SSH_CIPHER_NOT_SET; 174860576Skris /* options->ciphers, default set in myproposals.h */ 174976262Sgreen /* options->macs, default set in myproposals.h */ 1750221420Sdes /* options->kex_algorithms, default set in myproposals.h */ 175176262Sgreen /* options->hostkeyalgorithms, default set in myproposals.h */ 175260576Skris if (options->protocol == SSH_PROTO_UNKNOWN) 1753204917Sdes options->protocol = SSH_PROTO_2; 175457429Smarkm if (options->num_identity_files == 0) { 175576262Sgreen if (options->protocol & SSH_PROTO_1) { 1756249839Sdes add_identity_file(options, "~/", 1757249839Sdes _PATH_SSH_CLIENT_IDENTITY, 0); 175876262Sgreen } 175976262Sgreen if (options->protocol & SSH_PROTO_2) { 1760249839Sdes add_identity_file(options, "~/", 1761249839Sdes _PATH_SSH_CLIENT_ID_RSA, 0); 1762249839Sdes add_identity_file(options, "~/", 1763249839Sdes _PATH_SSH_CLIENT_ID_DSA, 0); 1764221420Sdes#ifdef OPENSSL_HAS_ECC 1765249839Sdes add_identity_file(options, "~/", 1766249839Sdes _PATH_SSH_CLIENT_ID_ECDSA, 0); 1767221420Sdes#endif 1768262566Sdes add_identity_file(options, "~/", 1769262566Sdes _PATH_SSH_CLIENT_ID_ED25519, 0); 177076262Sgreen } 177157429Smarkm } 177257429Smarkm if (options->escape_char == -1) 177357429Smarkm options->escape_char = '~'; 1774226046Sdes if (options->num_system_hostfiles == 0) { 1775226046Sdes options->system_hostfiles[options->num_system_hostfiles++] = 1776226046Sdes xstrdup(_PATH_SSH_SYSTEM_HOSTFILE); 1777226046Sdes options->system_hostfiles[options->num_system_hostfiles++] = 1778226046Sdes xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2); 1779226046Sdes } 1780226046Sdes if (options->num_user_hostfiles == 0) { 1781226046Sdes options->user_hostfiles[options->num_user_hostfiles++] = 1782226046Sdes xstrdup(_PATH_SSH_USER_HOSTFILE); 1783226046Sdes options->user_hostfiles[options->num_user_hostfiles++] = 1784226046Sdes xstrdup(_PATH_SSH_USER_HOSTFILE2); 1785226046Sdes } 178692559Sdes if (options->log_level == SYSLOG_LEVEL_NOT_SET) 178757429Smarkm options->log_level = SYSLOG_LEVEL_INFO; 178892559Sdes if (options->clear_forwardings == 1) 178992559Sdes clear_forwardings(options); 179092559Sdes if (options->no_host_authentication_for_localhost == - 1) 179192559Sdes options->no_host_authentication_for_localhost = 0; 1792128460Sdes if (options->identities_only == -1) 1793128460Sdes options->identities_only = 0; 1794113911Sdes if (options->enable_ssh_keysign == -1) 1795113911Sdes options->enable_ssh_keysign = 0; 1796124211Sdes if (options->rekey_limit == -1) 1797124211Sdes options->rekey_limit = 0; 1798255767Sdes if (options->rekey_interval == -1) 1799255767Sdes options->rekey_interval = 0; 1800255461Sdes#if HAVE_LDNS 1801124211Sdes if (options->verify_host_key_dns == -1) 1802255461Sdes /* automatically trust a verified SSHFP record */ 1803255461Sdes options->verify_host_key_dns = 1; 1804255461Sdes#else 1805255461Sdes if (options->verify_host_key_dns == -1) 1806124211Sdes options->verify_host_key_dns = 0; 1807255461Sdes#endif 1808126277Sdes if (options->server_alive_interval == -1) 1809126277Sdes options->server_alive_interval = 0; 1810126277Sdes if (options->server_alive_count_max == -1) 1811126277Sdes options->server_alive_count_max = 3; 1812137019Sdes if (options->control_master == -1) 1813137019Sdes options->control_master = 0; 1814215116Sdes if (options->control_persist == -1) { 1815215116Sdes options->control_persist = 0; 1816215116Sdes options->control_persist_timeout = 0; 1817215116Sdes } 1818147005Sdes if (options->hash_known_hosts == -1) 1819147005Sdes options->hash_known_hosts = 0; 1820157019Sdes if (options->tun_open == -1) 1821157019Sdes options->tun_open = SSH_TUNMODE_NO; 1822157019Sdes if (options->tun_local == -1) 1823157019Sdes options->tun_local = SSH_TUNID_ANY; 1824157019Sdes if (options->tun_remote == -1) 1825157019Sdes options->tun_remote = SSH_TUNID_ANY; 1826157019Sdes if (options->permit_local_command == -1) 1827157019Sdes options->permit_local_command = 0; 1828294050Sglebius options->use_roaming = 0; 1829181111Sdes if (options->visual_host_key == -1) 1830181111Sdes options->visual_host_key = 0; 1831221420Sdes if (options->ip_qos_interactive == -1) 1832221420Sdes options->ip_qos_interactive = IPTOS_LOWDELAY; 1833221420Sdes if (options->ip_qos_bulk == -1) 1834221420Sdes options->ip_qos_bulk = IPTOS_THROUGHPUT; 1835226046Sdes if (options->request_tty == -1) 1836226046Sdes options->request_tty = REQUEST_TTY_AUTO; 1837262566Sdes if (options->proxy_use_fdpass == -1) 1838262566Sdes options->proxy_use_fdpass = 0; 1839262566Sdes if (options->canonicalize_max_dots == -1) 1840262566Sdes options->canonicalize_max_dots = 1; 1841262566Sdes if (options->canonicalize_fallback_local == -1) 1842262566Sdes options->canonicalize_fallback_local = 1; 1843262566Sdes if (options->canonicalize_hostname == -1) 1844262566Sdes options->canonicalize_hostname = SSH_CANONICALISE_NO; 1845262566Sdes#define CLEAR_ON_NONE(v) \ 1846262566Sdes do { \ 1847264377Sdes if (option_clear_or_none(v)) { \ 1848262566Sdes free(v); \ 1849262566Sdes v = NULL; \ 1850262566Sdes } \ 1851262566Sdes } while(0) 1852262566Sdes CLEAR_ON_NONE(options->local_command); 1853262566Sdes CLEAR_ON_NONE(options->proxy_command); 1854262566Sdes CLEAR_ON_NONE(options->control_path); 185557429Smarkm /* options->user will be set in the main program if appropriate */ 185657429Smarkm /* options->hostname will be set in the main program if appropriate */ 185776262Sgreen /* options->host_key_alias should not be set by default */ 185876262Sgreen /* options->preferred_authentications will be set in ssh */ 1859240075Sdes if (options->version_addendum == NULL) 1860240075Sdes options->version_addendum = xstrdup(SSH_VERSION_FREEBSD); 1861224638Sbrooks if (options->hpn_disabled == -1) 1862231584Sed options->hpn_disabled = 0; 1863224638Sbrooks if (options->hpn_buffer_size > -1) 1864224638Sbrooks { 1865224638Sbrooks u_int maxlen; 1866224638Sbrooks 1867224638Sbrooks /* If a user tries to set the size to 0 set it to 1KB. */ 1868224638Sbrooks if (options->hpn_buffer_size == 0) 1869224638Sbrooks options->hpn_buffer_size = 1024; 1870224638Sbrooks /* Limit the buffer to BUFFER_MAX_LEN. */ 1871224638Sbrooks maxlen = buffer_get_max_len(); 1872224638Sbrooks if (options->hpn_buffer_size > (maxlen / 1024)) { 1873224638Sbrooks debug("User requested buffer larger than %ub: %ub. " 1874224638Sbrooks "Request reverted to %ub", maxlen, 1875224638Sbrooks options->hpn_buffer_size * 1024, maxlen); 1876224638Sbrooks options->hpn_buffer_size = maxlen; 1877224638Sbrooks } 1878224638Sbrooks debug("hpn_buffer_size set to %d", options->hpn_buffer_size); 1879224638Sbrooks } 1880224638Sbrooks if (options->tcp_rcv_buf == 0) 1881224638Sbrooks options->tcp_rcv_buf = 1; 1882231584Sed if (options->tcp_rcv_buf > -1) 1883224638Sbrooks options->tcp_rcv_buf *= 1024; 1884224638Sbrooks if (options->tcp_rcv_buf_poll == -1) 1885224638Sbrooks options->tcp_rcv_buf_poll = 1; 1886224638Sbrooks#ifdef NONE_CIPHER_ENABLED 1887224638Sbrooks /* options->none_enabled must not be set by default */ 1888224638Sbrooks if (options->none_switch == -1) 1889224638Sbrooks options->none_switch = 0; 1890224638Sbrooks#endif 189157429Smarkm} 1892147005Sdes 1893147005Sdes/* 1894147005Sdes * parse_forward 1895147005Sdes * parses a string containing a port forwarding specification of the form: 1896192595Sdes * dynamicfwd == 0 1897147005Sdes * [listenhost:]listenport:connecthost:connectport 1898192595Sdes * dynamicfwd == 1 1899192595Sdes * [listenhost:]listenport 1900147005Sdes * returns number of arguments parsed or zero on error 1901147005Sdes */ 1902147005Sdesint 1903192595Sdesparse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd) 1904147005Sdes{ 1905147005Sdes int i; 1906147005Sdes char *p, *cp, *fwdarg[4]; 1907147005Sdes 1908147005Sdes memset(fwd, '\0', sizeof(*fwd)); 1909147005Sdes 1910147005Sdes cp = p = xstrdup(fwdspec); 1911147005Sdes 1912147005Sdes /* skip leading spaces */ 1913262566Sdes while (isspace((u_char)*cp)) 1914147005Sdes cp++; 1915147005Sdes 1916147005Sdes for (i = 0; i < 4; ++i) 1917147005Sdes if ((fwdarg[i] = hpdelim(&cp)) == NULL) 1918147005Sdes break; 1919147005Sdes 1920192595Sdes /* Check for trailing garbage */ 1921147005Sdes if (cp != NULL) 1922147005Sdes i = 0; /* failure */ 1923147005Sdes 1924147005Sdes switch (i) { 1925192595Sdes case 1: 1926192595Sdes fwd->listen_host = NULL; 1927192595Sdes fwd->listen_port = a2port(fwdarg[0]); 1928192595Sdes fwd->connect_host = xstrdup("socks"); 1929192595Sdes break; 1930192595Sdes 1931192595Sdes case 2: 1932192595Sdes fwd->listen_host = xstrdup(cleanhostname(fwdarg[0])); 1933192595Sdes fwd->listen_port = a2port(fwdarg[1]); 1934192595Sdes fwd->connect_host = xstrdup("socks"); 1935192595Sdes break; 1936192595Sdes 1937147005Sdes case 3: 1938147005Sdes fwd->listen_host = NULL; 1939147005Sdes fwd->listen_port = a2port(fwdarg[0]); 1940147005Sdes fwd->connect_host = xstrdup(cleanhostname(fwdarg[1])); 1941147005Sdes fwd->connect_port = a2port(fwdarg[2]); 1942147005Sdes break; 1943147005Sdes 1944147005Sdes case 4: 1945147005Sdes fwd->listen_host = xstrdup(cleanhostname(fwdarg[0])); 1946147005Sdes fwd->listen_port = a2port(fwdarg[1]); 1947147005Sdes fwd->connect_host = xstrdup(cleanhostname(fwdarg[2])); 1948147005Sdes fwd->connect_port = a2port(fwdarg[3]); 1949147005Sdes break; 1950147005Sdes default: 1951147005Sdes i = 0; /* failure */ 1952147005Sdes } 1953147005Sdes 1954255767Sdes free(p); 1955147005Sdes 1956192595Sdes if (dynamicfwd) { 1957192595Sdes if (!(i == 1 || i == 2)) 1958192595Sdes goto fail_free; 1959192595Sdes } else { 1960192595Sdes if (!(i == 3 || i == 4)) 1961192595Sdes goto fail_free; 1962192595Sdes if (fwd->connect_port <= 0) 1963192595Sdes goto fail_free; 1964192595Sdes } 1965192595Sdes 1966192595Sdes if (fwd->listen_port < 0 || (!remotefwd && fwd->listen_port == 0)) 1967147005Sdes goto fail_free; 1968147005Sdes 1969147005Sdes if (fwd->connect_host != NULL && 1970147005Sdes strlen(fwd->connect_host) >= NI_MAXHOST) 1971147005Sdes goto fail_free; 1972192595Sdes if (fwd->listen_host != NULL && 1973192595Sdes strlen(fwd->listen_host) >= NI_MAXHOST) 1974192595Sdes goto fail_free; 1975147005Sdes 1976192595Sdes 1977147005Sdes return (i); 1978147005Sdes 1979147005Sdes fail_free: 1980255767Sdes free(fwd->connect_host); 1981255767Sdes fwd->connect_host = NULL; 1982255767Sdes free(fwd->listen_host); 1983255767Sdes fwd->listen_host = NULL; 1984147005Sdes return (0); 1985147005Sdes} 1986