readconf.c revision 162856
1162856Sdes/* $OpenBSD: readconf.c,v 1.159 2006/08/03 03:34:42 deraadt Exp $ */ 257429Smarkm/* 357429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi> 457429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 557429Smarkm * All rights reserved 657429Smarkm * Functions for reading the configuration files. 760576Skris * 865674Skris * As far as I am concerned, the code I have written for this software 965674Skris * can be used freely for any purpose. Any derived versions of this 1065674Skris * software must be clearly marked as such, and if the derived work is 1165674Skris * incompatible with the protocol description in the RFC file, it must be 1265674Skris * called by a name other than "ssh" or "Secure Shell". 1357429Smarkm */ 1457429Smarkm 1557429Smarkm#include "includes.h" 16162856Sdes__RCSID("$FreeBSD: head/crypto/openssh/readconf.c 162856 2006-09-30 13:38:06Z des $"); 1757429Smarkm 18162856Sdes#include <sys/types.h> 19162856Sdes#include <sys/stat.h> 20162856Sdes#include <sys/socket.h> 21162856Sdes 22162856Sdes#include <netinet/in.h> 23162856Sdes 24162856Sdes#include <ctype.h> 25162856Sdes#include <errno.h> 26162856Sdes#include <netdb.h> 27162856Sdes#include <signal.h> 28162856Sdes#include <stdarg.h> 29162856Sdes#include <stdio.h> 30162856Sdes#include <string.h> 31162856Sdes#include <unistd.h> 32162856Sdes 33162856Sdes#include "xmalloc.h" 3457429Smarkm#include "ssh.h" 3576262Sgreen#include "compat.h" 3676262Sgreen#include "cipher.h" 3776262Sgreen#include "pathnames.h" 3876262Sgreen#include "log.h" 39162856Sdes#include "key.h" 4057429Smarkm#include "readconf.h" 4160576Skris#include "match.h" 4276262Sgreen#include "misc.h" 43162856Sdes#include "buffer.h" 4476262Sgreen#include "kex.h" 4576262Sgreen#include "mac.h" 4657429Smarkm 4757429Smarkm/* Format of the configuration file: 4857429Smarkm 4957429Smarkm # Configuration data is parsed as follows: 5057429Smarkm # 1. command line options 5157429Smarkm # 2. user-specific file 5257429Smarkm # 3. system-wide file 5357429Smarkm # Any configuration value is only changed the first time it is set. 5457429Smarkm # Thus, host-specific definitions should be at the beginning of the 5557429Smarkm # configuration file, and defaults at the end. 5657429Smarkm 5757429Smarkm # Host-specific declarations. These may override anything above. A single 5857429Smarkm # host may match multiple declarations; these are processed in the order 5957429Smarkm # that they are given in. 6057429Smarkm 6157429Smarkm Host *.ngs.fi ngs.fi 6298684Sdes User foo 6357429Smarkm 6457429Smarkm Host fake.com 6557429Smarkm HostName another.host.name.real.org 6657429Smarkm User blaah 6757429Smarkm Port 34289 6857429Smarkm ForwardX11 no 6957429Smarkm ForwardAgent no 7057429Smarkm 7157429Smarkm Host books.com 7257429Smarkm RemoteForward 9999 shadows.cs.hut.fi:9999 7357429Smarkm Cipher 3des 7457429Smarkm 7557429Smarkm Host fascist.blob.com 7657429Smarkm Port 23123 7757429Smarkm User tylonen 7857429Smarkm PasswordAuthentication no 7957429Smarkm 8057429Smarkm Host puukko.hut.fi 8157429Smarkm User t35124p 8257429Smarkm ProxyCommand ssh-proxy %h %p 8357429Smarkm 8457429Smarkm Host *.fr 8598684Sdes PublicKeyAuthentication no 8657429Smarkm 8757429Smarkm Host *.su 8857429Smarkm Cipher none 8957429Smarkm PasswordAuthentication no 9057429Smarkm 91157019Sdes Host vpn.fake.com 92157019Sdes Tunnel yes 93157019Sdes TunnelDevice 3 94157019Sdes 9557429Smarkm # Defaults for various options 9657429Smarkm Host * 9757429Smarkm ForwardAgent no 9876262Sgreen ForwardX11 no 9957429Smarkm PasswordAuthentication yes 10057429Smarkm RSAAuthentication yes 10157429Smarkm RhostsRSAAuthentication yes 10257429Smarkm StrictHostKeyChecking yes 103126277Sdes TcpKeepAlive no 10457429Smarkm IdentityFile ~/.ssh/identity 10557429Smarkm Port 22 10657429Smarkm EscapeChar ~ 10757429Smarkm 10857429Smarkm*/ 10957429Smarkm 11057429Smarkm/* Keyword tokens. */ 11157429Smarkm 11257429Smarkmtypedef enum { 11357429Smarkm oBadOption, 114126277Sdes oForwardAgent, oForwardX11, oForwardX11Trusted, oGatewayPorts, 115162856Sdes oExitOnForwardFailure, 11698684Sdes oPasswordAuthentication, oRSAAuthentication, 11776262Sgreen oChallengeResponseAuthentication, oXAuthLocation, 11857429Smarkm oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward, 11957429Smarkm oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand, 12057429Smarkm oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, 12157429Smarkm oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, 122126277Sdes oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts, 12376262Sgreen oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs, 12476262Sgreen oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication, 12576262Sgreen oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, 12676262Sgreen oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, 12792559Sdes oHostKeyAlgorithms, oBindAddress, oSmartcardDevice, 12893698Sdes oClearAllForwardings, oNoHostAuthenticationForLocalhost, 129124211Sdes oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, 130124211Sdes oAddressFamily, oGssAuthentication, oGssDelegateCreds, 131128461Sdes oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, 132147005Sdes oSendEnv, oControlPath, oControlMaster, oHashKnownHosts, 133157019Sdes oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, 13499048Sdes oVersionAddendum, 135124211Sdes oDeprecated, oUnsupported 13657429Smarkm} OpCodes; 13757429Smarkm 13857429Smarkm/* Textual representations of the tokens. */ 13957429Smarkm 14057429Smarkmstatic struct { 14157429Smarkm const char *name; 14257429Smarkm OpCodes opcode; 14357429Smarkm} keywords[] = { 14457429Smarkm { "forwardagent", oForwardAgent }, 14557429Smarkm { "forwardx11", oForwardX11 }, 146126277Sdes { "forwardx11trusted", oForwardX11Trusted }, 147162856Sdes { "exitonforwardfailure", oExitOnForwardFailure }, 14865674Skris { "xauthlocation", oXAuthLocation }, 14957429Smarkm { "gatewayports", oGatewayPorts }, 15057429Smarkm { "useprivilegedport", oUsePrivilegedPort }, 151124211Sdes { "rhostsauthentication", oDeprecated }, 15257429Smarkm { "passwordauthentication", oPasswordAuthentication }, 15369591Sgreen { "kbdinteractiveauthentication", oKbdInteractiveAuthentication }, 15469591Sgreen { "kbdinteractivedevices", oKbdInteractiveDevices }, 15557429Smarkm { "rsaauthentication", oRSAAuthentication }, 15676262Sgreen { "pubkeyauthentication", oPubkeyAuthentication }, 15776262Sgreen { "dsaauthentication", oPubkeyAuthentication }, /* alias */ 15876262Sgreen { "rhostsrsaauthentication", oRhostsRSAAuthentication }, 15976262Sgreen { "hostbasedauthentication", oHostbasedAuthentication }, 16076262Sgreen { "challengeresponseauthentication", oChallengeResponseAuthentication }, 16176262Sgreen { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */ 16276262Sgreen { "tisauthentication", oChallengeResponseAuthentication }, /* alias */ 163124211Sdes { "kerberosauthentication", oUnsupported }, 164124211Sdes { "kerberostgtpassing", oUnsupported }, 165124211Sdes { "afstokenpassing", oUnsupported }, 166124211Sdes#if defined(GSSAPI) 167124211Sdes { "gssapiauthentication", oGssAuthentication }, 168124211Sdes { "gssapidelegatecredentials", oGssDelegateCreds }, 169124211Sdes#else 170124211Sdes { "gssapiauthentication", oUnsupported }, 171124211Sdes { "gssapidelegatecredentials", oUnsupported }, 17292559Sdes#endif 17398684Sdes { "fallbacktorsh", oDeprecated }, 17498684Sdes { "usersh", oDeprecated }, 17557429Smarkm { "identityfile", oIdentityFile }, 17676262Sgreen { "identityfile2", oIdentityFile }, /* alias */ 177128460Sdes { "identitiesonly", oIdentitiesOnly }, 17857429Smarkm { "hostname", oHostName }, 17976262Sgreen { "hostkeyalias", oHostKeyAlias }, 18057429Smarkm { "proxycommand", oProxyCommand }, 18157429Smarkm { "port", oPort }, 18257429Smarkm { "cipher", oCipher }, 18360576Skris { "ciphers", oCiphers }, 18476262Sgreen { "macs", oMacs }, 18560576Skris { "protocol", oProtocol }, 18657429Smarkm { "remoteforward", oRemoteForward }, 18757429Smarkm { "localforward", oLocalForward }, 18857429Smarkm { "user", oUser }, 18957429Smarkm { "host", oHost }, 19057429Smarkm { "escapechar", oEscapeChar }, 19157429Smarkm { "globalknownhostsfile", oGlobalKnownHostsFile }, 19292559Sdes { "userknownhostsfile", oUserKnownHostsFile }, /* obsolete */ 19360576Skris { "globalknownhostsfile2", oGlobalKnownHostsFile2 }, 19492559Sdes { "userknownhostsfile2", oUserKnownHostsFile2 }, /* obsolete */ 19557429Smarkm { "connectionattempts", oConnectionAttempts }, 19657429Smarkm { "batchmode", oBatchMode }, 19757429Smarkm { "checkhostip", oCheckHostIP }, 19857429Smarkm { "stricthostkeychecking", oStrictHostKeyChecking }, 19957429Smarkm { "compression", oCompression }, 20057429Smarkm { "compressionlevel", oCompressionLevel }, 201126277Sdes { "tcpkeepalive", oTCPKeepAlive }, 202126277Sdes { "keepalive", oTCPKeepAlive }, /* obsolete */ 20357429Smarkm { "numberofpasswordprompts", oNumberOfPasswordPrompts }, 20457429Smarkm { "loglevel", oLogLevel }, 20576262Sgreen { "dynamicforward", oDynamicForward }, 20676262Sgreen { "preferredauthentications", oPreferredAuthentications }, 20776262Sgreen { "hostkeyalgorithms", oHostKeyAlgorithms }, 20892559Sdes { "bindaddress", oBindAddress }, 209124211Sdes#ifdef SMARTCARD 21092559Sdes { "smartcarddevice", oSmartcardDevice }, 211124211Sdes#else 212124211Sdes { "smartcarddevice", oUnsupported }, 213124211Sdes#endif 21492559Sdes { "clearallforwardings", oClearAllForwardings }, 215113911Sdes { "enablesshkeysign", oEnableSSHKeysign }, 216124211Sdes { "verifyhostkeydns", oVerifyHostKeyDNS }, 21792559Sdes { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost }, 218124211Sdes { "rekeylimit", oRekeyLimit }, 219124211Sdes { "connecttimeout", oConnectTimeout }, 220124211Sdes { "addressfamily", oAddressFamily }, 221126277Sdes { "serveraliveinterval", oServerAliveInterval }, 222126277Sdes { "serveralivecountmax", oServerAliveCountMax }, 223137019Sdes { "sendenv", oSendEnv }, 224137019Sdes { "controlpath", oControlPath }, 225137019Sdes { "controlmaster", oControlMaster }, 226147005Sdes { "hashknownhosts", oHashKnownHosts }, 227157019Sdes { "tunnel", oTunnel }, 228157019Sdes { "tunneldevice", oTunnelDevice }, 229157019Sdes { "localcommand", oLocalCommand }, 230157019Sdes { "permitlocalcommand", oPermitLocalCommand }, 23199048Sdes { "versionaddendum", oVersionAddendum }, 23292559Sdes { NULL, oBadOption } 23357429Smarkm}; 23457429Smarkm 23557429Smarkm/* 23657429Smarkm * Adds a local TCP/IP port forward to options. Never returns if there is an 23757429Smarkm * error. 23857429Smarkm */ 23957429Smarkm 24060576Skrisvoid 241147005Sdesadd_local_forward(Options *options, const Forward *newfwd) 24257429Smarkm{ 24357429Smarkm Forward *fwd; 244106130Sdes#ifndef NO_IPPORT_RESERVED_CONCEPT 24557429Smarkm extern uid_t original_real_uid; 246147005Sdes if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0) 24776262Sgreen fatal("Privileged ports can only be forwarded by root."); 24898941Sdes#endif 24957429Smarkm if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION) 25057429Smarkm fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION); 25157429Smarkm fwd = &options->local_forwards[options->num_local_forwards++]; 252147005Sdes 253147005Sdes fwd->listen_host = (newfwd->listen_host == NULL) ? 254147005Sdes NULL : xstrdup(newfwd->listen_host); 255147005Sdes fwd->listen_port = newfwd->listen_port; 256147005Sdes fwd->connect_host = xstrdup(newfwd->connect_host); 257147005Sdes fwd->connect_port = newfwd->connect_port; 25857429Smarkm} 25957429Smarkm 26057429Smarkm/* 26157429Smarkm * Adds a remote TCP/IP port forward to options. Never returns if there is 26257429Smarkm * an error. 26357429Smarkm */ 26457429Smarkm 26560576Skrisvoid 266147005Sdesadd_remote_forward(Options *options, const Forward *newfwd) 26757429Smarkm{ 26857429Smarkm Forward *fwd; 26957429Smarkm if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION) 27057429Smarkm fatal("Too many remote forwards (max %d).", 27192559Sdes SSH_MAX_FORWARDS_PER_DIRECTION); 27257429Smarkm fwd = &options->remote_forwards[options->num_remote_forwards++]; 273147005Sdes 274147005Sdes fwd->listen_host = (newfwd->listen_host == NULL) ? 275147005Sdes NULL : xstrdup(newfwd->listen_host); 276147005Sdes fwd->listen_port = newfwd->listen_port; 277147005Sdes fwd->connect_host = xstrdup(newfwd->connect_host); 278147005Sdes fwd->connect_port = newfwd->connect_port; 27957429Smarkm} 28057429Smarkm 28192559Sdesstatic void 28292559Sdesclear_forwardings(Options *options) 28392559Sdes{ 28492559Sdes int i; 28592559Sdes 286147005Sdes for (i = 0; i < options->num_local_forwards; i++) { 287147005Sdes if (options->local_forwards[i].listen_host != NULL) 288147005Sdes xfree(options->local_forwards[i].listen_host); 289147005Sdes xfree(options->local_forwards[i].connect_host); 290147005Sdes } 29192559Sdes options->num_local_forwards = 0; 292147005Sdes for (i = 0; i < options->num_remote_forwards; i++) { 293147005Sdes if (options->remote_forwards[i].listen_host != NULL) 294147005Sdes xfree(options->remote_forwards[i].listen_host); 295147005Sdes xfree(options->remote_forwards[i].connect_host); 296147005Sdes } 29792559Sdes options->num_remote_forwards = 0; 298157019Sdes options->tun_open = SSH_TUNMODE_NO; 29992559Sdes} 30092559Sdes 30157429Smarkm/* 30276262Sgreen * Returns the number of the token pointed to by cp or oBadOption. 30357429Smarkm */ 30457429Smarkm 30560576Skrisstatic OpCodes 30657429Smarkmparse_token(const char *cp, const char *filename, int linenum) 30757429Smarkm{ 30876262Sgreen u_int i; 30957429Smarkm 31057429Smarkm for (i = 0; keywords[i].name; i++) 31157429Smarkm if (strcasecmp(cp, keywords[i].name) == 0) 31257429Smarkm return keywords[i].opcode; 31357429Smarkm 31476262Sgreen error("%s: line %d: Bad configuration option: %s", 31576262Sgreen filename, linenum, cp); 31657429Smarkm return oBadOption; 31757429Smarkm} 31857429Smarkm 31957429Smarkm/* 32057429Smarkm * Processes a single option line as used in the configuration files. This 32157429Smarkm * only sets those values that have not already been set. 32257429Smarkm */ 323113911Sdes#define WHITESPACE " \t\r\n" 32457429Smarkm 32557429Smarkmint 32657429Smarkmprocess_config_line(Options *options, const char *host, 32757429Smarkm char *line, const char *filename, int linenum, 32857429Smarkm int *activep) 32957429Smarkm{ 330147005Sdes char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256]; 331162856Sdes int opcode, *intptr, value, value2, scale; 332162856Sdes long long orig, val64; 333113911Sdes size_t len; 334147005Sdes Forward fwd; 33557429Smarkm 336124211Sdes /* Strip trailing whitespace */ 337147005Sdes for (len = strlen(line) - 1; len > 0; len--) { 338124211Sdes if (strchr(WHITESPACE, line[len]) == NULL) 339124211Sdes break; 340124211Sdes line[len] = '\0'; 341124211Sdes } 342124211Sdes 34365674Skris s = line; 34465674Skris /* Get the keyword. (Each line is supposed to begin with a keyword). */ 345162856Sdes if ((keyword = strdelim(&s)) == NULL) 346162856Sdes return 0; 34765674Skris /* Ignore leading whitespace. */ 34865674Skris if (*keyword == '\0') 34965674Skris keyword = strdelim(&s); 35076262Sgreen if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#') 35157429Smarkm return 0; 35257429Smarkm 35365674Skris opcode = parse_token(keyword, filename, linenum); 35457429Smarkm 35557429Smarkm switch (opcode) { 35657429Smarkm case oBadOption: 35757429Smarkm /* don't panic, but count bad options */ 35857429Smarkm return -1; 35957429Smarkm /* NOTREACHED */ 360124211Sdes case oConnectTimeout: 361124211Sdes intptr = &options->connection_timeout; 362126277Sdesparse_time: 363124211Sdes arg = strdelim(&s); 364124211Sdes if (!arg || *arg == '\0') 365124211Sdes fatal("%s line %d: missing time value.", 366124211Sdes filename, linenum); 367124211Sdes if ((value = convtime(arg)) == -1) 368124211Sdes fatal("%s line %d: invalid time value.", 369124211Sdes filename, linenum); 370124211Sdes if (*intptr == -1) 371124211Sdes *intptr = value; 372124211Sdes break; 373124211Sdes 37457429Smarkm case oForwardAgent: 37557429Smarkm intptr = &options->forward_agent; 37657429Smarkmparse_flag: 37765674Skris arg = strdelim(&s); 37865674Skris if (!arg || *arg == '\0') 37957429Smarkm fatal("%.200s line %d: Missing yes/no argument.", filename, linenum); 38057429Smarkm value = 0; /* To avoid compiler warning... */ 38165674Skris if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) 38257429Smarkm value = 1; 38365674Skris else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) 38457429Smarkm value = 0; 38557429Smarkm else 38657429Smarkm fatal("%.200s line %d: Bad yes/no argument.", filename, linenum); 38757429Smarkm if (*activep && *intptr == -1) 38857429Smarkm *intptr = value; 38957429Smarkm break; 39057429Smarkm 39157429Smarkm case oForwardX11: 39257429Smarkm intptr = &options->forward_x11; 39357429Smarkm goto parse_flag; 39457429Smarkm 395126277Sdes case oForwardX11Trusted: 396126277Sdes intptr = &options->forward_x11_trusted; 397126277Sdes goto parse_flag; 398126277Sdes 39957429Smarkm case oGatewayPorts: 40057429Smarkm intptr = &options->gateway_ports; 40157429Smarkm goto parse_flag; 40257429Smarkm 403162856Sdes case oExitOnForwardFailure: 404162856Sdes intptr = &options->exit_on_forward_failure; 405162856Sdes goto parse_flag; 406162856Sdes 40757429Smarkm case oUsePrivilegedPort: 40857429Smarkm intptr = &options->use_privileged_port; 40957429Smarkm goto parse_flag; 41057429Smarkm 41157429Smarkm case oPasswordAuthentication: 41257429Smarkm intptr = &options->password_authentication; 41357429Smarkm goto parse_flag; 41457429Smarkm 41569591Sgreen case oKbdInteractiveAuthentication: 41669591Sgreen intptr = &options->kbd_interactive_authentication; 41769591Sgreen goto parse_flag; 41869591Sgreen 41969591Sgreen case oKbdInteractiveDevices: 42069591Sgreen charptr = &options->kbd_interactive_devices; 42169591Sgreen goto parse_string; 42269591Sgreen 42376262Sgreen case oPubkeyAuthentication: 42476262Sgreen intptr = &options->pubkey_authentication; 42560576Skris goto parse_flag; 42660576Skris 42757429Smarkm case oRSAAuthentication: 42857429Smarkm intptr = &options->rsa_authentication; 42957429Smarkm goto parse_flag; 43057429Smarkm 43157429Smarkm case oRhostsRSAAuthentication: 43257429Smarkm intptr = &options->rhosts_rsa_authentication; 43357429Smarkm goto parse_flag; 43457429Smarkm 43576262Sgreen case oHostbasedAuthentication: 43676262Sgreen intptr = &options->hostbased_authentication; 43757429Smarkm goto parse_flag; 43857429Smarkm 43992559Sdes case oChallengeResponseAuthentication: 44092559Sdes intptr = &options->challenge_response_authentication; 44192559Sdes goto parse_flag; 442124211Sdes 443124211Sdes case oGssAuthentication: 444124211Sdes intptr = &options->gss_authentication; 44557429Smarkm goto parse_flag; 446124211Sdes 447124211Sdes case oGssDelegateCreds: 448124211Sdes intptr = &options->gss_deleg_creds; 44976262Sgreen goto parse_flag; 450124211Sdes 45157429Smarkm case oBatchMode: 45257429Smarkm intptr = &options->batch_mode; 45357429Smarkm goto parse_flag; 45457429Smarkm 45557429Smarkm case oCheckHostIP: 45657429Smarkm intptr = &options->check_host_ip; 45757429Smarkm goto parse_flag; 45857429Smarkm 459124211Sdes case oVerifyHostKeyDNS: 460124211Sdes intptr = &options->verify_host_key_dns; 461126277Sdes goto parse_yesnoask; 462124211Sdes 46357429Smarkm case oStrictHostKeyChecking: 46457429Smarkm intptr = &options->strict_host_key_checking; 465126277Sdesparse_yesnoask: 46665674Skris arg = strdelim(&s); 46765674Skris if (!arg || *arg == '\0') 46876262Sgreen fatal("%.200s line %d: Missing yes/no/ask argument.", 46992559Sdes filename, linenum); 47057429Smarkm value = 0; /* To avoid compiler warning... */ 47165674Skris if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) 47257429Smarkm value = 1; 47365674Skris else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) 47457429Smarkm value = 0; 47565674Skris else if (strcmp(arg, "ask") == 0) 47657429Smarkm value = 2; 47757429Smarkm else 47857429Smarkm fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum); 47957429Smarkm if (*activep && *intptr == -1) 48057429Smarkm *intptr = value; 48157429Smarkm break; 48257429Smarkm 48357429Smarkm case oCompression: 48457429Smarkm intptr = &options->compression; 48557429Smarkm goto parse_flag; 48657429Smarkm 487126277Sdes case oTCPKeepAlive: 488126277Sdes intptr = &options->tcp_keep_alive; 48957429Smarkm goto parse_flag; 49057429Smarkm 49192559Sdes case oNoHostAuthenticationForLocalhost: 49292559Sdes intptr = &options->no_host_authentication_for_localhost; 49392559Sdes goto parse_flag; 49492559Sdes 49557429Smarkm case oNumberOfPasswordPrompts: 49657429Smarkm intptr = &options->number_of_password_prompts; 49757429Smarkm goto parse_int; 49857429Smarkm 49957429Smarkm case oCompressionLevel: 50057429Smarkm intptr = &options->compression_level; 50157429Smarkm goto parse_int; 50257429Smarkm 503124211Sdes case oRekeyLimit: 504124211Sdes intptr = &options->rekey_limit; 505124211Sdes arg = strdelim(&s); 506124211Sdes if (!arg || *arg == '\0') 507124211Sdes fatal("%.200s line %d: Missing argument.", filename, linenum); 508124211Sdes if (arg[0] < '0' || arg[0] > '9') 509124211Sdes fatal("%.200s line %d: Bad number.", filename, linenum); 510162856Sdes orig = val64 = strtoll(arg, &endofnumber, 10); 511124211Sdes if (arg == endofnumber) 512124211Sdes fatal("%.200s line %d: Bad number.", filename, linenum); 513124211Sdes switch (toupper(*endofnumber)) { 514162856Sdes case '\0': 515162856Sdes scale = 1; 516162856Sdes break; 517124211Sdes case 'K': 518162856Sdes scale = 1<<10; 519124211Sdes break; 520124211Sdes case 'M': 521162856Sdes scale = 1<<20; 522124211Sdes break; 523124211Sdes case 'G': 524162856Sdes scale = 1<<30; 525124211Sdes break; 526162856Sdes default: 527162856Sdes fatal("%.200s line %d: Invalid RekeyLimit suffix", 528162856Sdes filename, linenum); 529124211Sdes } 530162856Sdes val64 *= scale; 531162856Sdes /* detect integer wrap and too-large limits */ 532162856Sdes if ((val64 / scale) != orig || val64 > INT_MAX) 533162856Sdes fatal("%.200s line %d: RekeyLimit too large", 534162856Sdes filename, linenum); 535162856Sdes if (val64 < 16) 536162856Sdes fatal("%.200s line %d: RekeyLimit too small", 537162856Sdes filename, linenum); 538124211Sdes if (*activep && *intptr == -1) 539162856Sdes *intptr = (int)val64; 540124211Sdes break; 541124211Sdes 54257429Smarkm case oIdentityFile: 54365674Skris arg = strdelim(&s); 54465674Skris if (!arg || *arg == '\0') 54557429Smarkm fatal("%.200s line %d: Missing argument.", filename, linenum); 54657429Smarkm if (*activep) { 54776262Sgreen intptr = &options->num_identity_files; 54860576Skris if (*intptr >= SSH_MAX_IDENTITY_FILES) 54957429Smarkm fatal("%.200s line %d: Too many identity files specified (max %d).", 55092559Sdes filename, linenum, SSH_MAX_IDENTITY_FILES); 55176262Sgreen charptr = &options->identity_files[*intptr]; 55265674Skris *charptr = xstrdup(arg); 55360576Skris *intptr = *intptr + 1; 55457429Smarkm } 55557429Smarkm break; 55657429Smarkm 55765674Skris case oXAuthLocation: 55865674Skris charptr=&options->xauth_location; 55965674Skris goto parse_string; 56065674Skris 56157429Smarkm case oUser: 56257429Smarkm charptr = &options->user; 56357429Smarkmparse_string: 56465674Skris arg = strdelim(&s); 56565674Skris if (!arg || *arg == '\0') 56657429Smarkm fatal("%.200s line %d: Missing argument.", filename, linenum); 56757429Smarkm if (*activep && *charptr == NULL) 56865674Skris *charptr = xstrdup(arg); 56957429Smarkm break; 57057429Smarkm 57157429Smarkm case oGlobalKnownHostsFile: 57257429Smarkm charptr = &options->system_hostfile; 57357429Smarkm goto parse_string; 57457429Smarkm 57557429Smarkm case oUserKnownHostsFile: 57657429Smarkm charptr = &options->user_hostfile; 57757429Smarkm goto parse_string; 57857429Smarkm 57960576Skris case oGlobalKnownHostsFile2: 58060576Skris charptr = &options->system_hostfile2; 58160576Skris goto parse_string; 58260576Skris 58360576Skris case oUserKnownHostsFile2: 58460576Skris charptr = &options->user_hostfile2; 58560576Skris goto parse_string; 58660576Skris 58757429Smarkm case oHostName: 58857429Smarkm charptr = &options->hostname; 58957429Smarkm goto parse_string; 59057429Smarkm 59176262Sgreen case oHostKeyAlias: 59276262Sgreen charptr = &options->host_key_alias; 59376262Sgreen goto parse_string; 59476262Sgreen 59576262Sgreen case oPreferredAuthentications: 59676262Sgreen charptr = &options->preferred_authentications; 59776262Sgreen goto parse_string; 59876262Sgreen 59992559Sdes case oBindAddress: 60092559Sdes charptr = &options->bind_address; 60192559Sdes goto parse_string; 60292559Sdes 60392559Sdes case oSmartcardDevice: 60492559Sdes charptr = &options->smartcard_device; 60592559Sdes goto parse_string; 60692559Sdes 60757429Smarkm case oProxyCommand: 608157019Sdes charptr = &options->proxy_command; 609157019Sdesparse_command: 610124211Sdes if (s == NULL) 611124211Sdes fatal("%.200s line %d: Missing argument.", filename, linenum); 612113911Sdes len = strspn(s, WHITESPACE "="); 61357429Smarkm if (*activep && *charptr == NULL) 614113911Sdes *charptr = xstrdup(s + len); 61557429Smarkm return 0; 61657429Smarkm 61757429Smarkm case oPort: 61857429Smarkm intptr = &options->port; 61957429Smarkmparse_int: 62065674Skris arg = strdelim(&s); 62165674Skris if (!arg || *arg == '\0') 62257429Smarkm fatal("%.200s line %d: Missing argument.", filename, linenum); 62365674Skris if (arg[0] < '0' || arg[0] > '9') 62457429Smarkm fatal("%.200s line %d: Bad number.", filename, linenum); 62557429Smarkm 62657429Smarkm /* Octal, decimal, or hex format? */ 62765674Skris value = strtol(arg, &endofnumber, 0); 62865674Skris if (arg == endofnumber) 62957429Smarkm fatal("%.200s line %d: Bad number.", filename, linenum); 63057429Smarkm if (*activep && *intptr == -1) 63157429Smarkm *intptr = value; 63257429Smarkm break; 63357429Smarkm 63457429Smarkm case oConnectionAttempts: 63557429Smarkm intptr = &options->connection_attempts; 63657429Smarkm goto parse_int; 63757429Smarkm 63857429Smarkm case oCipher: 63957429Smarkm intptr = &options->cipher; 64065674Skris arg = strdelim(&s); 64165674Skris if (!arg || *arg == '\0') 64261203Skris fatal("%.200s line %d: Missing argument.", filename, linenum); 64365674Skris value = cipher_number(arg); 64457429Smarkm if (value == -1) 64557429Smarkm fatal("%.200s line %d: Bad cipher '%s'.", 64692559Sdes filename, linenum, arg ? arg : "<NONE>"); 64757429Smarkm if (*activep && *intptr == -1) 64857429Smarkm *intptr = value; 64957429Smarkm break; 65057429Smarkm 65160576Skris case oCiphers: 65265674Skris arg = strdelim(&s); 65365674Skris if (!arg || *arg == '\0') 65461203Skris fatal("%.200s line %d: Missing argument.", filename, linenum); 65565674Skris if (!ciphers_valid(arg)) 65660576Skris fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.", 65792559Sdes filename, linenum, arg ? arg : "<NONE>"); 65860576Skris if (*activep && options->ciphers == NULL) 65965674Skris options->ciphers = xstrdup(arg); 66060576Skris break; 66160576Skris 66276262Sgreen case oMacs: 66376262Sgreen arg = strdelim(&s); 66476262Sgreen if (!arg || *arg == '\0') 66576262Sgreen fatal("%.200s line %d: Missing argument.", filename, linenum); 66676262Sgreen if (!mac_valid(arg)) 66776262Sgreen fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.", 66892559Sdes filename, linenum, arg ? arg : "<NONE>"); 66976262Sgreen if (*activep && options->macs == NULL) 67076262Sgreen options->macs = xstrdup(arg); 67176262Sgreen break; 67276262Sgreen 67376262Sgreen case oHostKeyAlgorithms: 67476262Sgreen arg = strdelim(&s); 67576262Sgreen if (!arg || *arg == '\0') 67676262Sgreen fatal("%.200s line %d: Missing argument.", filename, linenum); 67776262Sgreen if (!key_names_valid2(arg)) 67876262Sgreen fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.", 67992559Sdes filename, linenum, arg ? arg : "<NONE>"); 68076262Sgreen if (*activep && options->hostkeyalgorithms == NULL) 68176262Sgreen options->hostkeyalgorithms = xstrdup(arg); 68276262Sgreen break; 68376262Sgreen 68460576Skris case oProtocol: 68560576Skris intptr = &options->protocol; 68665674Skris arg = strdelim(&s); 68765674Skris if (!arg || *arg == '\0') 68861203Skris fatal("%.200s line %d: Missing argument.", filename, linenum); 68965674Skris value = proto_spec(arg); 69060576Skris if (value == SSH_PROTO_UNKNOWN) 69160576Skris fatal("%.200s line %d: Bad protocol spec '%s'.", 69292559Sdes filename, linenum, arg ? arg : "<NONE>"); 69360576Skris if (*activep && *intptr == SSH_PROTO_UNKNOWN) 69460576Skris *intptr = value; 69560576Skris break; 69660576Skris 69757429Smarkm case oLogLevel: 69857429Smarkm intptr = (int *) &options->log_level; 69965674Skris arg = strdelim(&s); 70065674Skris value = log_level_number(arg); 70192559Sdes if (value == SYSLOG_LEVEL_NOT_SET) 70276262Sgreen fatal("%.200s line %d: unsupported log level '%s'", 70392559Sdes filename, linenum, arg ? arg : "<NONE>"); 70492559Sdes if (*activep && (LogLevel) *intptr == SYSLOG_LEVEL_NOT_SET) 70557429Smarkm *intptr = (LogLevel) value; 70657429Smarkm break; 70757429Smarkm 70892559Sdes case oLocalForward: 70957429Smarkm case oRemoteForward: 71065674Skris arg = strdelim(&s); 711147005Sdes if (arg == NULL || *arg == '\0') 71292559Sdes fatal("%.200s line %d: Missing port argument.", 71392559Sdes filename, linenum); 714147005Sdes arg2 = strdelim(&s); 715147005Sdes if (arg2 == NULL || *arg2 == '\0') 716147005Sdes fatal("%.200s line %d: Missing target argument.", 71792559Sdes filename, linenum); 718147005Sdes 719147005Sdes /* construct a string for parse_forward */ 720147005Sdes snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2); 721147005Sdes 722147005Sdes if (parse_forward(&fwd, fwdarg) == 0) 72392559Sdes fatal("%.200s line %d: Bad forwarding specification.", 72492559Sdes filename, linenum); 725147005Sdes 72692559Sdes if (*activep) { 72792559Sdes if (opcode == oLocalForward) 728147005Sdes add_local_forward(options, &fwd); 72992559Sdes else if (opcode == oRemoteForward) 730147005Sdes add_remote_forward(options, &fwd); 73192559Sdes } 73257429Smarkm break; 73357429Smarkm 73476262Sgreen case oDynamicForward: 73576262Sgreen arg = strdelim(&s); 73676262Sgreen if (!arg || *arg == '\0') 73776262Sgreen fatal("%.200s line %d: Missing port argument.", 73876262Sgreen filename, linenum); 739147005Sdes memset(&fwd, '\0', sizeof(fwd)); 740147005Sdes fwd.connect_host = "socks"; 741147005Sdes fwd.listen_host = hpdelim(&arg); 742147005Sdes if (fwd.listen_host == NULL || 743147005Sdes strlen(fwd.listen_host) >= NI_MAXHOST) 744147005Sdes fatal("%.200s line %d: Bad forwarding specification.", 745147005Sdes filename, linenum); 746147005Sdes if (arg) { 747147005Sdes fwd.listen_port = a2port(arg); 748147005Sdes fwd.listen_host = cleanhostname(fwd.listen_host); 749147005Sdes } else { 750147005Sdes fwd.listen_port = a2port(fwd.listen_host); 751149753Sdes fwd.listen_host = NULL; 752147005Sdes } 753147005Sdes if (fwd.listen_port == 0) 75476262Sgreen fatal("%.200s line %d: Badly formatted port number.", 75576262Sgreen filename, linenum); 75692559Sdes if (*activep) 757147005Sdes add_local_forward(options, &fwd); 75876262Sgreen break; 75976262Sgreen 76092559Sdes case oClearAllForwardings: 76192559Sdes intptr = &options->clear_forwardings; 76292559Sdes goto parse_flag; 76392559Sdes 76457429Smarkm case oHost: 76557429Smarkm *activep = 0; 76665674Skris while ((arg = strdelim(&s)) != NULL && *arg != '\0') 76765674Skris if (match_pattern(host, arg)) { 76865674Skris debug("Applying options for %.100s", arg); 76957429Smarkm *activep = 1; 77057429Smarkm break; 77157429Smarkm } 77265674Skris /* Avoid garbage check below, as strdelim is done. */ 77357429Smarkm return 0; 77457429Smarkm 77557429Smarkm case oEscapeChar: 77657429Smarkm intptr = &options->escape_char; 77765674Skris arg = strdelim(&s); 77865674Skris if (!arg || *arg == '\0') 77957429Smarkm fatal("%.200s line %d: Missing argument.", filename, linenum); 78065674Skris if (arg[0] == '^' && arg[2] == 0 && 78176262Sgreen (u_char) arg[1] >= 64 && (u_char) arg[1] < 128) 78276262Sgreen value = (u_char) arg[1] & 31; 78365674Skris else if (strlen(arg) == 1) 78476262Sgreen value = (u_char) arg[0]; 78565674Skris else if (strcmp(arg, "none") == 0) 78692559Sdes value = SSH_ESCAPECHAR_NONE; 78757429Smarkm else { 78857429Smarkm fatal("%.200s line %d: Bad escape character.", 78992559Sdes filename, linenum); 79057429Smarkm /* NOTREACHED */ 79157429Smarkm value = 0; /* Avoid compiler warning. */ 79257429Smarkm } 79357429Smarkm if (*activep && *intptr == -1) 79457429Smarkm *intptr = value; 79557429Smarkm break; 79657429Smarkm 797124211Sdes case oAddressFamily: 798124211Sdes arg = strdelim(&s); 799149753Sdes if (!arg || *arg == '\0') 800149753Sdes fatal("%s line %d: missing address family.", 801149753Sdes filename, linenum); 802124211Sdes intptr = &options->address_family; 803124211Sdes if (strcasecmp(arg, "inet") == 0) 804124211Sdes value = AF_INET; 805124211Sdes else if (strcasecmp(arg, "inet6") == 0) 806124211Sdes value = AF_INET6; 807124211Sdes else if (strcasecmp(arg, "any") == 0) 808124211Sdes value = AF_UNSPEC; 809124211Sdes else 810124211Sdes fatal("Unsupported AddressFamily \"%s\"", arg); 811124211Sdes if (*activep && *intptr == -1) 812124211Sdes *intptr = value; 813124211Sdes break; 814124211Sdes 815113911Sdes case oEnableSSHKeysign: 816113911Sdes intptr = &options->enable_ssh_keysign; 817113911Sdes goto parse_flag; 818113911Sdes 819128460Sdes case oIdentitiesOnly: 820128460Sdes intptr = &options->identities_only; 821128460Sdes goto parse_flag; 822128460Sdes 823126277Sdes case oServerAliveInterval: 824126277Sdes intptr = &options->server_alive_interval; 825126277Sdes goto parse_time; 826126277Sdes 827126277Sdes case oServerAliveCountMax: 828126277Sdes intptr = &options->server_alive_count_max; 829126277Sdes goto parse_int; 830126277Sdes 831137019Sdes case oSendEnv: 832137019Sdes while ((arg = strdelim(&s)) != NULL && *arg != '\0') { 833137019Sdes if (strchr(arg, '=') != NULL) 834137019Sdes fatal("%s line %d: Invalid environment name.", 835137019Sdes filename, linenum); 836147005Sdes if (!*activep) 837147005Sdes continue; 838137019Sdes if (options->num_send_env >= MAX_SEND_ENV) 839137019Sdes fatal("%s line %d: too many send env.", 840137019Sdes filename, linenum); 841137019Sdes options->send_env[options->num_send_env++] = 842137019Sdes xstrdup(arg); 843137019Sdes } 844137019Sdes break; 845137019Sdes 846137019Sdes case oControlPath: 847137019Sdes charptr = &options->control_path; 848137019Sdes goto parse_string; 849137019Sdes 850137019Sdes case oControlMaster: 851137019Sdes intptr = &options->control_master; 852149753Sdes arg = strdelim(&s); 853149753Sdes if (!arg || *arg == '\0') 854149753Sdes fatal("%.200s line %d: Missing ControlMaster argument.", 855149753Sdes filename, linenum); 856149753Sdes value = 0; /* To avoid compiler warning... */ 857149753Sdes if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) 858149753Sdes value = SSHCTL_MASTER_YES; 859149753Sdes else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) 860149753Sdes value = SSHCTL_MASTER_NO; 861149753Sdes else if (strcmp(arg, "auto") == 0) 862149753Sdes value = SSHCTL_MASTER_AUTO; 863149753Sdes else if (strcmp(arg, "ask") == 0) 864149753Sdes value = SSHCTL_MASTER_ASK; 865149753Sdes else if (strcmp(arg, "autoask") == 0) 866149753Sdes value = SSHCTL_MASTER_AUTO_ASK; 867149753Sdes else 868149753Sdes fatal("%.200s line %d: Bad ControlMaster argument.", 869149753Sdes filename, linenum); 870149753Sdes if (*activep && *intptr == -1) 871149753Sdes *intptr = value; 872149753Sdes break; 873137019Sdes 874147005Sdes case oHashKnownHosts: 875147005Sdes intptr = &options->hash_known_hosts; 876147005Sdes goto parse_flag; 877147005Sdes 878157019Sdes case oTunnel: 879157019Sdes intptr = &options->tun_open; 880157019Sdes arg = strdelim(&s); 881157019Sdes if (!arg || *arg == '\0') 882157019Sdes fatal("%s line %d: Missing yes/point-to-point/" 883157019Sdes "ethernet/no argument.", filename, linenum); 884157019Sdes value = 0; /* silence compiler */ 885157019Sdes if (strcasecmp(arg, "ethernet") == 0) 886157019Sdes value = SSH_TUNMODE_ETHERNET; 887157019Sdes else if (strcasecmp(arg, "point-to-point") == 0) 888157019Sdes value = SSH_TUNMODE_POINTOPOINT; 889157019Sdes else if (strcasecmp(arg, "yes") == 0) 890157019Sdes value = SSH_TUNMODE_DEFAULT; 891157019Sdes else if (strcasecmp(arg, "no") == 0) 892157019Sdes value = SSH_TUNMODE_NO; 893157019Sdes else 894157019Sdes fatal("%s line %d: Bad yes/point-to-point/ethernet/" 895157019Sdes "no argument: %s", filename, linenum, arg); 896157019Sdes if (*activep) 897157019Sdes *intptr = value; 898157019Sdes break; 899157019Sdes 900157019Sdes case oTunnelDevice: 901157019Sdes arg = strdelim(&s); 902157019Sdes if (!arg || *arg == '\0') 903157019Sdes fatal("%.200s line %d: Missing argument.", filename, linenum); 904157019Sdes value = a2tun(arg, &value2); 905157019Sdes if (value == SSH_TUNID_ERR) 906157019Sdes fatal("%.200s line %d: Bad tun device.", filename, linenum); 907157019Sdes if (*activep) { 908157019Sdes options->tun_local = value; 909157019Sdes options->tun_remote = value2; 910157019Sdes } 911157019Sdes break; 912157019Sdes 913157019Sdes case oLocalCommand: 914157019Sdes charptr = &options->local_command; 915157019Sdes goto parse_command; 916157019Sdes 917157019Sdes case oPermitLocalCommand: 918157019Sdes intptr = &options->permit_local_command; 919157019Sdes goto parse_flag; 920157019Sdes 92199048Sdes case oVersionAddendum: 92299048Sdes ssh_version_set_addendum(strtok(s, "\n")); 92399048Sdes do { 92499048Sdes arg = strdelim(&s); 92599048Sdes } while (arg != NULL && *arg != '\0'); 92699048Sdes break; 92799048Sdes 92898684Sdes case oDeprecated: 92998684Sdes debug("%s line %d: Deprecated option \"%s\"", 93098684Sdes filename, linenum, keyword); 93198684Sdes return 0; 93298684Sdes 933124211Sdes case oUnsupported: 934124211Sdes error("%s line %d: Unsupported option \"%s\"", 935124211Sdes filename, linenum, keyword); 936124211Sdes return 0; 937124211Sdes 93857429Smarkm default: 93957429Smarkm fatal("process_config_line: Unimplemented opcode %d", opcode); 94057429Smarkm } 94157429Smarkm 94257429Smarkm /* Check that there is no garbage at end of line. */ 94376262Sgreen if ((arg = strdelim(&s)) != NULL && *arg != '\0') { 94465674Skris fatal("%.200s line %d: garbage at end of line; \"%.200s\".", 945149753Sdes filename, linenum, arg); 94665674Skris } 94757429Smarkm return 0; 94857429Smarkm} 94957429Smarkm 95057429Smarkm 95157429Smarkm/* 95257429Smarkm * Reads the config file and modifies the options accordingly. Options 95357429Smarkm * should already be initialized before this call. This never returns if 95492559Sdes * there is an error. If the file does not exist, this returns 0. 95557429Smarkm */ 95657429Smarkm 95792559Sdesint 958137019Sdesread_config_file(const char *filename, const char *host, Options *options, 959137019Sdes int checkperm) 96057429Smarkm{ 96157429Smarkm FILE *f; 96257429Smarkm char line[1024]; 96357429Smarkm int active, linenum; 96457429Smarkm int bad_options = 0; 96557429Smarkm 96657429Smarkm /* Open the file. */ 967137019Sdes if ((f = fopen(filename, "r")) == NULL) 96892559Sdes return 0; 96957429Smarkm 970137019Sdes if (checkperm) { 971137019Sdes struct stat sb; 972137019Sdes 973137019Sdes if (fstat(fileno(f), &sb) == -1) 974137019Sdes fatal("fstat %s: %s", filename, strerror(errno)); 975137019Sdes if (((sb.st_uid != 0 && sb.st_uid != getuid()) || 976137019Sdes (sb.st_mode & 022) != 0)) 977137019Sdes fatal("Bad owner or permissions on %s", filename); 978137019Sdes } 979137019Sdes 98057429Smarkm debug("Reading configuration data %.200s", filename); 98157429Smarkm 98257429Smarkm /* 98357429Smarkm * Mark that we are now processing the options. This flag is turned 98457429Smarkm * on/off by Host specifications. 98557429Smarkm */ 98657429Smarkm active = 1; 98757429Smarkm linenum = 0; 98857429Smarkm while (fgets(line, sizeof(line), f)) { 98957429Smarkm /* Update line number counter. */ 99057429Smarkm linenum++; 99157429Smarkm if (process_config_line(options, host, line, filename, linenum, &active) != 0) 99257429Smarkm bad_options++; 99357429Smarkm } 99457429Smarkm fclose(f); 99557429Smarkm if (bad_options > 0) 99676262Sgreen fatal("%s: terminating, %d bad configuration options", 99792559Sdes filename, bad_options); 99892559Sdes return 1; 99957429Smarkm} 100057429Smarkm 100157429Smarkm/* 100257429Smarkm * Initializes options to special values that indicate that they have not yet 100357429Smarkm * been set. Read_config_file will only set options with this value. Options 100457429Smarkm * are processed in the following order: command line, user config file, 100557429Smarkm * system config file. Last, fill_default_options is called. 100657429Smarkm */ 100757429Smarkm 100860576Skrisvoid 100957429Smarkminitialize_options(Options * options) 101057429Smarkm{ 101157429Smarkm memset(options, 'X', sizeof(*options)); 101257429Smarkm options->forward_agent = -1; 101357429Smarkm options->forward_x11 = -1; 1014126277Sdes options->forward_x11_trusted = -1; 1015162856Sdes options->exit_on_forward_failure = -1; 101665674Skris options->xauth_location = NULL; 101757429Smarkm options->gateway_ports = -1; 101857429Smarkm options->use_privileged_port = -1; 101957429Smarkm options->rsa_authentication = -1; 102076262Sgreen options->pubkey_authentication = -1; 102192559Sdes options->challenge_response_authentication = -1; 1022124211Sdes options->gss_authentication = -1; 1023124211Sdes options->gss_deleg_creds = -1; 102457429Smarkm options->password_authentication = -1; 102569591Sgreen options->kbd_interactive_authentication = -1; 102669591Sgreen options->kbd_interactive_devices = NULL; 102757429Smarkm options->rhosts_rsa_authentication = -1; 102876262Sgreen options->hostbased_authentication = -1; 102957429Smarkm options->batch_mode = -1; 103057429Smarkm options->check_host_ip = -1; 103157429Smarkm options->strict_host_key_checking = -1; 103257429Smarkm options->compression = -1; 1033126277Sdes options->tcp_keep_alive = -1; 103457429Smarkm options->compression_level = -1; 103557429Smarkm options->port = -1; 1036124211Sdes options->address_family = -1; 103757429Smarkm options->connection_attempts = -1; 1038124211Sdes options->connection_timeout = -1; 103957429Smarkm options->number_of_password_prompts = -1; 104057429Smarkm options->cipher = -1; 104160576Skris options->ciphers = NULL; 104276262Sgreen options->macs = NULL; 104376262Sgreen options->hostkeyalgorithms = NULL; 104460576Skris options->protocol = SSH_PROTO_UNKNOWN; 104557429Smarkm options->num_identity_files = 0; 104657429Smarkm options->hostname = NULL; 104776262Sgreen options->host_key_alias = NULL; 104857429Smarkm options->proxy_command = NULL; 104957429Smarkm options->user = NULL; 105057429Smarkm options->escape_char = -1; 105157429Smarkm options->system_hostfile = NULL; 105257429Smarkm options->user_hostfile = NULL; 105360576Skris options->system_hostfile2 = NULL; 105460576Skris options->user_hostfile2 = NULL; 105557429Smarkm options->num_local_forwards = 0; 105657429Smarkm options->num_remote_forwards = 0; 105792559Sdes options->clear_forwardings = -1; 105892559Sdes options->log_level = SYSLOG_LEVEL_NOT_SET; 105976262Sgreen options->preferred_authentications = NULL; 106092559Sdes options->bind_address = NULL; 106192559Sdes options->smartcard_device = NULL; 1062113911Sdes options->enable_ssh_keysign = - 1; 106392559Sdes options->no_host_authentication_for_localhost = - 1; 1064128460Sdes options->identities_only = - 1; 1065124211Sdes options->rekey_limit = - 1; 1066124211Sdes options->verify_host_key_dns = -1; 1067126277Sdes options->server_alive_interval = -1; 1068126277Sdes options->server_alive_count_max = -1; 1069137019Sdes options->num_send_env = 0; 1070137019Sdes options->control_path = NULL; 1071137019Sdes options->control_master = -1; 1072147005Sdes options->hash_known_hosts = -1; 1073157019Sdes options->tun_open = -1; 1074157019Sdes options->tun_local = -1; 1075157019Sdes options->tun_remote = -1; 1076157019Sdes options->local_command = NULL; 1077157019Sdes options->permit_local_command = -1; 107857429Smarkm} 107957429Smarkm 108057429Smarkm/* 108157429Smarkm * Called after processing other sources of option data, this fills those 108257429Smarkm * options for which no value has been specified with their default values. 108357429Smarkm */ 108457429Smarkm 108560576Skrisvoid 108657429Smarkmfill_default_options(Options * options) 108757429Smarkm{ 108876262Sgreen int len; 108976262Sgreen 109057429Smarkm if (options->forward_agent == -1) 109161203Skris options->forward_agent = 0; 109257429Smarkm if (options->forward_x11 == -1) 109357708Sgreen options->forward_x11 = 0; 1094126277Sdes if (options->forward_x11_trusted == -1) 1095126277Sdes options->forward_x11_trusted = 0; 1096162856Sdes if (options->exit_on_forward_failure == -1) 1097162856Sdes options->exit_on_forward_failure = 0; 109865674Skris if (options->xauth_location == NULL) 109992559Sdes options->xauth_location = _PATH_XAUTH; 110057429Smarkm if (options->gateway_ports == -1) 110157429Smarkm options->gateway_ports = 0; 110257429Smarkm if (options->use_privileged_port == -1) 110376262Sgreen options->use_privileged_port = 0; 110457429Smarkm if (options->rsa_authentication == -1) 110557429Smarkm options->rsa_authentication = 1; 110676262Sgreen if (options->pubkey_authentication == -1) 110776262Sgreen options->pubkey_authentication = 1; 110892559Sdes if (options->challenge_response_authentication == -1) 110992559Sdes options->challenge_response_authentication = 1; 1110124211Sdes if (options->gss_authentication == -1) 1111126277Sdes options->gss_authentication = 0; 1112124211Sdes if (options->gss_deleg_creds == -1) 1113124211Sdes options->gss_deleg_creds = 0; 111457429Smarkm if (options->password_authentication == -1) 111557429Smarkm options->password_authentication = 1; 111669591Sgreen if (options->kbd_interactive_authentication == -1) 111776262Sgreen options->kbd_interactive_authentication = 1; 111857429Smarkm if (options->rhosts_rsa_authentication == -1) 111998684Sdes options->rhosts_rsa_authentication = 0; 112076262Sgreen if (options->hostbased_authentication == -1) 112176262Sgreen options->hostbased_authentication = 0; 112257429Smarkm if (options->batch_mode == -1) 112357429Smarkm options->batch_mode = 0; 112457429Smarkm if (options->check_host_ip == -1) 112599048Sdes options->check_host_ip = 0; 112657429Smarkm if (options->strict_host_key_checking == -1) 112757429Smarkm options->strict_host_key_checking = 2; /* 2 is default */ 112857429Smarkm if (options->compression == -1) 112957429Smarkm options->compression = 0; 1130126277Sdes if (options->tcp_keep_alive == -1) 1131126277Sdes options->tcp_keep_alive = 1; 113257429Smarkm if (options->compression_level == -1) 113357429Smarkm options->compression_level = 6; 113457429Smarkm if (options->port == -1) 113557429Smarkm options->port = 0; /* Filled in ssh_connect. */ 1136124211Sdes if (options->address_family == -1) 1137124211Sdes options->address_family = AF_UNSPEC; 113857429Smarkm if (options->connection_attempts == -1) 113992559Sdes options->connection_attempts = 1; 114057429Smarkm if (options->number_of_password_prompts == -1) 114157429Smarkm options->number_of_password_prompts = 3; 114257429Smarkm /* Selected in ssh_login(). */ 114357429Smarkm if (options->cipher == -1) 114457429Smarkm options->cipher = SSH_CIPHER_NOT_SET; 114560576Skris /* options->ciphers, default set in myproposals.h */ 114676262Sgreen /* options->macs, default set in myproposals.h */ 114776262Sgreen /* options->hostkeyalgorithms, default set in myproposals.h */ 114860576Skris if (options->protocol == SSH_PROTO_UNKNOWN) 114976262Sgreen options->protocol = SSH_PROTO_1|SSH_PROTO_2; 115057429Smarkm if (options->num_identity_files == 0) { 115176262Sgreen if (options->protocol & SSH_PROTO_1) { 115276262Sgreen len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1; 115376262Sgreen options->identity_files[options->num_identity_files] = 115476262Sgreen xmalloc(len); 115576262Sgreen snprintf(options->identity_files[options->num_identity_files++], 115676262Sgreen len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY); 115776262Sgreen } 115876262Sgreen if (options->protocol & SSH_PROTO_2) { 115976262Sgreen len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1; 116076262Sgreen options->identity_files[options->num_identity_files] = 116176262Sgreen xmalloc(len); 116276262Sgreen snprintf(options->identity_files[options->num_identity_files++], 116376262Sgreen len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA); 116476262Sgreen 116576262Sgreen len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1; 116676262Sgreen options->identity_files[options->num_identity_files] = 116776262Sgreen xmalloc(len); 116876262Sgreen snprintf(options->identity_files[options->num_identity_files++], 116976262Sgreen len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA); 117076262Sgreen } 117157429Smarkm } 117257429Smarkm if (options->escape_char == -1) 117357429Smarkm options->escape_char = '~'; 117457429Smarkm if (options->system_hostfile == NULL) 117576262Sgreen options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE; 117657429Smarkm if (options->user_hostfile == NULL) 117776262Sgreen options->user_hostfile = _PATH_SSH_USER_HOSTFILE; 117860576Skris if (options->system_hostfile2 == NULL) 117976262Sgreen options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2; 118060576Skris if (options->user_hostfile2 == NULL) 118176262Sgreen options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2; 118292559Sdes if (options->log_level == SYSLOG_LEVEL_NOT_SET) 118357429Smarkm options->log_level = SYSLOG_LEVEL_INFO; 118492559Sdes if (options->clear_forwardings == 1) 118592559Sdes clear_forwardings(options); 118692559Sdes if (options->no_host_authentication_for_localhost == - 1) 118792559Sdes options->no_host_authentication_for_localhost = 0; 1188128460Sdes if (options->identities_only == -1) 1189128460Sdes options->identities_only = 0; 1190113911Sdes if (options->enable_ssh_keysign == -1) 1191113911Sdes options->enable_ssh_keysign = 0; 1192124211Sdes if (options->rekey_limit == -1) 1193124211Sdes options->rekey_limit = 0; 1194124211Sdes if (options->verify_host_key_dns == -1) 1195124211Sdes options->verify_host_key_dns = 0; 1196126277Sdes if (options->server_alive_interval == -1) 1197126277Sdes options->server_alive_interval = 0; 1198126277Sdes if (options->server_alive_count_max == -1) 1199126277Sdes options->server_alive_count_max = 3; 1200137019Sdes if (options->control_master == -1) 1201137019Sdes options->control_master = 0; 1202147005Sdes if (options->hash_known_hosts == -1) 1203147005Sdes options->hash_known_hosts = 0; 1204157019Sdes if (options->tun_open == -1) 1205157019Sdes options->tun_open = SSH_TUNMODE_NO; 1206157019Sdes if (options->tun_local == -1) 1207157019Sdes options->tun_local = SSH_TUNID_ANY; 1208157019Sdes if (options->tun_remote == -1) 1209157019Sdes options->tun_remote = SSH_TUNID_ANY; 1210157019Sdes if (options->permit_local_command == -1) 1211157019Sdes options->permit_local_command = 0; 1212157019Sdes /* options->local_command should not be set by default */ 121357429Smarkm /* options->proxy_command should not be set by default */ 121457429Smarkm /* options->user will be set in the main program if appropriate */ 121557429Smarkm /* options->hostname will be set in the main program if appropriate */ 121676262Sgreen /* options->host_key_alias should not be set by default */ 121776262Sgreen /* options->preferred_authentications will be set in ssh */ 121857429Smarkm} 1219147005Sdes 1220147005Sdes/* 1221147005Sdes * parse_forward 1222147005Sdes * parses a string containing a port forwarding specification of the form: 1223147005Sdes * [listenhost:]listenport:connecthost:connectport 1224147005Sdes * returns number of arguments parsed or zero on error 1225147005Sdes */ 1226147005Sdesint 1227147005Sdesparse_forward(Forward *fwd, const char *fwdspec) 1228147005Sdes{ 1229147005Sdes int i; 1230147005Sdes char *p, *cp, *fwdarg[4]; 1231147005Sdes 1232147005Sdes memset(fwd, '\0', sizeof(*fwd)); 1233147005Sdes 1234147005Sdes cp = p = xstrdup(fwdspec); 1235147005Sdes 1236147005Sdes /* skip leading spaces */ 1237147005Sdes while (*cp && isspace(*cp)) 1238147005Sdes cp++; 1239147005Sdes 1240147005Sdes for (i = 0; i < 4; ++i) 1241147005Sdes if ((fwdarg[i] = hpdelim(&cp)) == NULL) 1242147005Sdes break; 1243147005Sdes 1244147005Sdes /* Check for trailing garbage in 4-arg case*/ 1245147005Sdes if (cp != NULL) 1246147005Sdes i = 0; /* failure */ 1247147005Sdes 1248147005Sdes switch (i) { 1249147005Sdes case 3: 1250147005Sdes fwd->listen_host = NULL; 1251147005Sdes fwd->listen_port = a2port(fwdarg[0]); 1252147005Sdes fwd->connect_host = xstrdup(cleanhostname(fwdarg[1])); 1253147005Sdes fwd->connect_port = a2port(fwdarg[2]); 1254147005Sdes break; 1255147005Sdes 1256147005Sdes case 4: 1257147005Sdes fwd->listen_host = xstrdup(cleanhostname(fwdarg[0])); 1258147005Sdes fwd->listen_port = a2port(fwdarg[1]); 1259147005Sdes fwd->connect_host = xstrdup(cleanhostname(fwdarg[2])); 1260147005Sdes fwd->connect_port = a2port(fwdarg[3]); 1261147005Sdes break; 1262147005Sdes default: 1263147005Sdes i = 0; /* failure */ 1264147005Sdes } 1265147005Sdes 1266147005Sdes xfree(p); 1267147005Sdes 1268147005Sdes if (fwd->listen_port == 0 && fwd->connect_port == 0) 1269147005Sdes goto fail_free; 1270147005Sdes 1271147005Sdes if (fwd->connect_host != NULL && 1272147005Sdes strlen(fwd->connect_host) >= NI_MAXHOST) 1273147005Sdes goto fail_free; 1274147005Sdes 1275147005Sdes return (i); 1276147005Sdes 1277147005Sdes fail_free: 1278147005Sdes if (fwd->connect_host != NULL) 1279147005Sdes xfree(fwd->connect_host); 1280147005Sdes if (fwd->listen_host != NULL) 1281147005Sdes xfree(fwd->listen_host); 1282147005Sdes return (0); 1283147005Sdes} 1284