blob: 9d59493f018777c6003bb471d8189958077b91a3 [file] [log] [blame]
Greg Hartman9768ca42017-06-22 20:49:52 -07001/* $OpenBSD: readconf.c,v 1.270 2017/03/10 04:27:32 djm Exp $ */
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5 * All rights reserved
6 * Functions for reading the configuration files.
7 *
8 * As far as I am concerned, the code I have written for this software
9 * can be used freely for any purpose. Any derived versions of this
10 * software must be clearly marked as such, and if the derived work is
11 * incompatible with the protocol description in the RFC file, it must be
12 * called by a name other than "ssh" or "Secure Shell".
13 */
14
15#include "includes.h"
16
17#include <sys/types.h>
18#include <sys/stat.h>
19#include <sys/socket.h>
Adam Langleyd0592972015-03-30 14:49:51 -070020#include <sys/wait.h>
21#include <sys/un.h>
Greg Hartmanbd77cf72015-02-25 13:21:06 -080022
23#include <netinet/in.h>
24#include <netinet/in_systm.h>
25#include <netinet/ip.h>
Adam Langleyd0592972015-03-30 14:49:51 -070026#include <arpa/inet.h>
Greg Hartmanbd77cf72015-02-25 13:21:06 -080027
28#include <ctype.h>
29#include <errno.h>
Adam Langleyd0592972015-03-30 14:49:51 -070030#include <fcntl.h>
31#include <limits.h>
Greg Hartmanbd77cf72015-02-25 13:21:06 -080032#include <netdb.h>
Adam Langleyd0592972015-03-30 14:49:51 -070033#ifdef HAVE_PATHS_H
34# include <paths.h>
35#endif
36#include <pwd.h>
Greg Hartmanbd77cf72015-02-25 13:21:06 -080037#include <signal.h>
38#include <stdarg.h>
39#include <stdio.h>
40#include <string.h>
41#include <unistd.h>
Greg Hartman9768ca42017-06-22 20:49:52 -070042#ifdef USE_SYSTEM_GLOB
43# include <glob.h>
44#else
45# include "openbsd-compat/glob.h"
46#endif
Adam Langleyd0592972015-03-30 14:49:51 -070047#ifdef HAVE_UTIL_H
48#include <util.h>
49#endif
50#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
51# include <vis.h>
52#endif
Greg Hartmanbd77cf72015-02-25 13:21:06 -080053
54#include "xmalloc.h"
55#include "ssh.h"
56#include "compat.h"
57#include "cipher.h"
58#include "pathnames.h"
59#include "log.h"
Adam Langleyd0592972015-03-30 14:49:51 -070060#include "sshkey.h"
61#include "misc.h"
Greg Hartmanbd77cf72015-02-25 13:21:06 -080062#include "readconf.h"
63#include "match.h"
Greg Hartmanbd77cf72015-02-25 13:21:06 -080064#include "kex.h"
65#include "mac.h"
Adam Langleyd0592972015-03-30 14:49:51 -070066#include "uidswap.h"
67#include "myproposal.h"
68#include "digest.h"
Greg Hartmanbd77cf72015-02-25 13:21:06 -080069
70/* Format of the configuration file:
71
72 # Configuration data is parsed as follows:
73 # 1. command line options
74 # 2. user-specific file
75 # 3. system-wide file
76 # Any configuration value is only changed the first time it is set.
77 # Thus, host-specific definitions should be at the beginning of the
78 # configuration file, and defaults at the end.
79
80 # Host-specific declarations. These may override anything above. A single
81 # host may match multiple declarations; these are processed in the order
82 # that they are given in.
83
84 Host *.ngs.fi ngs.fi
85 User foo
86
87 Host fake.com
88 HostName another.host.name.real.org
89 User blaah
90 Port 34289
91 ForwardX11 no
92 ForwardAgent no
93
94 Host books.com
95 RemoteForward 9999 shadows.cs.hut.fi:9999
Greg Hartman9768ca42017-06-22 20:49:52 -070096 Ciphers 3des-cbc
Greg Hartmanbd77cf72015-02-25 13:21:06 -080097
98 Host fascist.blob.com
99 Port 23123
100 User tylonen
101 PasswordAuthentication no
102
103 Host puukko.hut.fi
104 User t35124p
105 ProxyCommand ssh-proxy %h %p
106
107 Host *.fr
108 PublicKeyAuthentication no
109
110 Host *.su
Greg Hartman9768ca42017-06-22 20:49:52 -0700111 Ciphers aes128-ctr
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800112 PasswordAuthentication no
113
114 Host vpn.fake.com
115 Tunnel yes
116 TunnelDevice 3
117
118 # Defaults for various options
119 Host *
120 ForwardAgent no
121 ForwardX11 no
122 PasswordAuthentication yes
123 RSAAuthentication yes
124 RhostsRSAAuthentication yes
125 StrictHostKeyChecking yes
126 TcpKeepAlive no
127 IdentityFile ~/.ssh/identity
128 Port 22
129 EscapeChar ~
130
131*/
132
Greg Hartman9768ca42017-06-22 20:49:52 -0700133static int read_config_file_depth(const char *filename, struct passwd *pw,
134 const char *host, const char *original_host, Options *options,
135 int flags, int *activep, int depth);
136static int process_config_line_depth(Options *options, struct passwd *pw,
137 const char *host, const char *original_host, char *line,
138 const char *filename, int linenum, int *activep, int flags, int depth);
139
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800140/* Keyword tokens. */
141
142typedef enum {
143 oBadOption,
Greg Hartman9768ca42017-06-22 20:49:52 -0700144 oHost, oMatch, oInclude,
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800145 oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
146 oGatewayPorts, oExitOnForwardFailure,
147 oPasswordAuthentication, oRSAAuthentication,
148 oChallengeResponseAuthentication, oXAuthLocation,
149 oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
Greg Hartman9768ca42017-06-22 20:49:52 -0700150 oCertificateFile, oAddKeysToAgent, oIdentityAgent,
Adam Langleyd0592972015-03-30 14:49:51 -0700151 oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800152 oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
153 oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
154 oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
155 oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
Adam Langleyd0592972015-03-30 14:49:51 -0700156 oPubkeyAuthentication,
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800157 oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
158 oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
159 oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
160 oClearAllForwardings, oNoHostAuthenticationForLocalhost,
161 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
162 oAddressFamily, oGssAuthentication, oGssDelegateCreds,
163 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
164 oSendEnv, oControlPath, oControlMaster, oControlPersist,
165 oHashKnownHosts,
166 oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
Greg Hartman9768ca42017-06-22 20:49:52 -0700167 oVisualHostKey,
Adam Langleyd0592972015-03-30 14:49:51 -0700168 oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
169 oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
170 oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
171 oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
172 oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes,
Greg Hartman9768ca42017-06-22 20:49:52 -0700173 oPubkeyAcceptedKeyTypes, oProxyJump,
Adam Langleyd0592972015-03-30 14:49:51 -0700174 oIgnoredUnknownOption, oDeprecated, oUnsupported
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800175} OpCodes;
176
177/* Textual representations of the tokens. */
178
179static struct {
180 const char *name;
181 OpCodes opcode;
182} keywords[] = {
Greg Hartman9768ca42017-06-22 20:49:52 -0700183 /* Deprecated options */
184 { "fallbacktorsh", oDeprecated },
185 { "globalknownhostsfile2", oDeprecated },
186 { "rhostsauthentication", oDeprecated },
187 { "userknownhostsfile2", oDeprecated },
188 { "useroaming", oDeprecated },
189 { "usersh", oDeprecated },
190
191 /* Unsupported options */
192 { "afstokenpassing", oUnsupported },
193 { "kerberosauthentication", oUnsupported },
194 { "kerberostgtpassing", oUnsupported },
195
196 /* Sometimes-unsupported options */
197#if defined(GSSAPI)
198 { "gssapiauthentication", oGssAuthentication },
199 { "gssapidelegatecredentials", oGssDelegateCreds },
200# else
201 { "gssapiauthentication", oUnsupported },
202 { "gssapidelegatecredentials", oUnsupported },
203#endif
204#ifdef ENABLE_PKCS11
205 { "smartcarddevice", oPKCS11Provider },
206 { "pkcs11provider", oPKCS11Provider },
207# else
208 { "smartcarddevice", oUnsupported },
209 { "pkcs11provider", oUnsupported },
210#endif
211#ifdef WITH_SSH1
212 { "rsaauthentication", oRSAAuthentication },
213 { "rhostsrsaauthentication", oRhostsRSAAuthentication },
214 { "compressionlevel", oCompressionLevel },
215# else
216 { "rsaauthentication", oUnsupported },
217 { "rhostsrsaauthentication", oUnsupported },
218 { "compressionlevel", oUnsupported },
219#endif
220
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800221 { "forwardagent", oForwardAgent },
222 { "forwardx11", oForwardX11 },
223 { "forwardx11trusted", oForwardX11Trusted },
224 { "forwardx11timeout", oForwardX11Timeout },
225 { "exitonforwardfailure", oExitOnForwardFailure },
226 { "xauthlocation", oXAuthLocation },
227 { "gatewayports", oGatewayPorts },
228 { "useprivilegedport", oUsePrivilegedPort },
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800229 { "passwordauthentication", oPasswordAuthentication },
230 { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
231 { "kbdinteractivedevices", oKbdInteractiveDevices },
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800232 { "pubkeyauthentication", oPubkeyAuthentication },
233 { "dsaauthentication", oPubkeyAuthentication }, /* alias */
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800234 { "hostbasedauthentication", oHostbasedAuthentication },
235 { "challengeresponseauthentication", oChallengeResponseAuthentication },
236 { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
237 { "tisauthentication", oChallengeResponseAuthentication }, /* alias */
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800238 { "identityfile", oIdentityFile },
239 { "identityfile2", oIdentityFile }, /* obsolete */
240 { "identitiesonly", oIdentitiesOnly },
Greg Hartman9768ca42017-06-22 20:49:52 -0700241 { "certificatefile", oCertificateFile },
242 { "addkeystoagent", oAddKeysToAgent },
243 { "identityagent", oIdentityAgent },
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800244 { "hostname", oHostName },
245 { "hostkeyalias", oHostKeyAlias },
246 { "proxycommand", oProxyCommand },
247 { "port", oPort },
248 { "cipher", oCipher },
249 { "ciphers", oCiphers },
250 { "macs", oMacs },
251 { "protocol", oProtocol },
252 { "remoteforward", oRemoteForward },
253 { "localforward", oLocalForward },
254 { "user", oUser },
255 { "host", oHost },
Adam Langleyd0592972015-03-30 14:49:51 -0700256 { "match", oMatch },
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800257 { "escapechar", oEscapeChar },
258 { "globalknownhostsfile", oGlobalKnownHostsFile },
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800259 { "userknownhostsfile", oUserKnownHostsFile },
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800260 { "connectionattempts", oConnectionAttempts },
261 { "batchmode", oBatchMode },
262 { "checkhostip", oCheckHostIP },
263 { "stricthostkeychecking", oStrictHostKeyChecking },
264 { "compression", oCompression },
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800265 { "tcpkeepalive", oTCPKeepAlive },
266 { "keepalive", oTCPKeepAlive }, /* obsolete */
267 { "numberofpasswordprompts", oNumberOfPasswordPrompts },
268 { "loglevel", oLogLevel },
269 { "dynamicforward", oDynamicForward },
270 { "preferredauthentications", oPreferredAuthentications },
271 { "hostkeyalgorithms", oHostKeyAlgorithms },
272 { "bindaddress", oBindAddress },
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800273 { "clearallforwardings", oClearAllForwardings },
274 { "enablesshkeysign", oEnableSSHKeysign },
275 { "verifyhostkeydns", oVerifyHostKeyDNS },
276 { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
277 { "rekeylimit", oRekeyLimit },
278 { "connecttimeout", oConnectTimeout },
279 { "addressfamily", oAddressFamily },
280 { "serveraliveinterval", oServerAliveInterval },
281 { "serveralivecountmax", oServerAliveCountMax },
282 { "sendenv", oSendEnv },
283 { "controlpath", oControlPath },
284 { "controlmaster", oControlMaster },
285 { "controlpersist", oControlPersist },
286 { "hashknownhosts", oHashKnownHosts },
Greg Hartman9768ca42017-06-22 20:49:52 -0700287 { "include", oInclude },
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800288 { "tunnel", oTunnel },
289 { "tunneldevice", oTunnelDevice },
290 { "localcommand", oLocalCommand },
291 { "permitlocalcommand", oPermitLocalCommand },
292 { "visualhostkey", oVisualHostKey },
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800293 { "kexalgorithms", oKexAlgorithms },
294 { "ipqos", oIPQoS },
295 { "requesttty", oRequestTTY },
Adam Langleyd0592972015-03-30 14:49:51 -0700296 { "proxyusefdpass", oProxyUseFdpass },
297 { "canonicaldomains", oCanonicalDomains },
298 { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
299 { "canonicalizehostname", oCanonicalizeHostname },
300 { "canonicalizemaxdots", oCanonicalizeMaxDots },
301 { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
302 { "streamlocalbindmask", oStreamLocalBindMask },
303 { "streamlocalbindunlink", oStreamLocalBindUnlink },
304 { "revokedhostkeys", oRevokedHostKeys },
305 { "fingerprinthash", oFingerprintHash },
306 { "updatehostkeys", oUpdateHostkeys },
307 { "hostbasedkeytypes", oHostbasedKeyTypes },
Greg Hartmanccacbc92016-02-03 09:59:44 -0800308 { "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes },
Adam Langleyd0592972015-03-30 14:49:51 -0700309 { "ignoreunknown", oIgnoreUnknown },
Greg Hartman9768ca42017-06-22 20:49:52 -0700310 { "proxyjump", oProxyJump },
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800311
312 { NULL, oBadOption }
313};
314
315/*
316 * Adds a local TCP/IP port forward to options. Never returns if there is an
317 * error.
318 */
319
320void
Adam Langleyd0592972015-03-30 14:49:51 -0700321add_local_forward(Options *options, const struct Forward *newfwd)
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800322{
Adam Langleyd0592972015-03-30 14:49:51 -0700323 struct Forward *fwd;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800324 extern uid_t original_real_uid;
Greg Hartman9768ca42017-06-22 20:49:52 -0700325 int i;
326
327 if (!bind_permitted(newfwd->listen_port, original_real_uid) &&
Adam Langleyd0592972015-03-30 14:49:51 -0700328 newfwd->listen_path == NULL)
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800329 fatal("Privileged ports can only be forwarded by root.");
Greg Hartman9768ca42017-06-22 20:49:52 -0700330 /* Don't add duplicates */
331 for (i = 0; i < options->num_local_forwards; i++) {
332 if (forward_equals(newfwd, options->local_forwards + i))
333 return;
334 }
Greg Hartmanccacbc92016-02-03 09:59:44 -0800335 options->local_forwards = xreallocarray(options->local_forwards,
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800336 options->num_local_forwards + 1,
337 sizeof(*options->local_forwards));
338 fwd = &options->local_forwards[options->num_local_forwards++];
339
340 fwd->listen_host = newfwd->listen_host;
341 fwd->listen_port = newfwd->listen_port;
Adam Langleyd0592972015-03-30 14:49:51 -0700342 fwd->listen_path = newfwd->listen_path;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800343 fwd->connect_host = newfwd->connect_host;
344 fwd->connect_port = newfwd->connect_port;
Adam Langleyd0592972015-03-30 14:49:51 -0700345 fwd->connect_path = newfwd->connect_path;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800346}
347
348/*
349 * Adds a remote TCP/IP port forward to options. Never returns if there is
350 * an error.
351 */
352
353void
Adam Langleyd0592972015-03-30 14:49:51 -0700354add_remote_forward(Options *options, const struct Forward *newfwd)
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800355{
Adam Langleyd0592972015-03-30 14:49:51 -0700356 struct Forward *fwd;
Greg Hartman9768ca42017-06-22 20:49:52 -0700357 int i;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800358
Greg Hartman9768ca42017-06-22 20:49:52 -0700359 /* Don't add duplicates */
360 for (i = 0; i < options->num_remote_forwards; i++) {
361 if (forward_equals(newfwd, options->remote_forwards + i))
362 return;
363 }
Greg Hartmanccacbc92016-02-03 09:59:44 -0800364 options->remote_forwards = xreallocarray(options->remote_forwards,
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800365 options->num_remote_forwards + 1,
366 sizeof(*options->remote_forwards));
367 fwd = &options->remote_forwards[options->num_remote_forwards++];
368
369 fwd->listen_host = newfwd->listen_host;
370 fwd->listen_port = newfwd->listen_port;
Adam Langleyd0592972015-03-30 14:49:51 -0700371 fwd->listen_path = newfwd->listen_path;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800372 fwd->connect_host = newfwd->connect_host;
373 fwd->connect_port = newfwd->connect_port;
Adam Langleyd0592972015-03-30 14:49:51 -0700374 fwd->connect_path = newfwd->connect_path;
375 fwd->handle = newfwd->handle;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800376 fwd->allocated_port = 0;
377}
378
379static void
380clear_forwardings(Options *options)
381{
382 int i;
383
384 for (i = 0; i < options->num_local_forwards; i++) {
Adam Langleyd0592972015-03-30 14:49:51 -0700385 free(options->local_forwards[i].listen_host);
386 free(options->local_forwards[i].listen_path);
387 free(options->local_forwards[i].connect_host);
388 free(options->local_forwards[i].connect_path);
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800389 }
390 if (options->num_local_forwards > 0) {
Adam Langleyd0592972015-03-30 14:49:51 -0700391 free(options->local_forwards);
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800392 options->local_forwards = NULL;
393 }
394 options->num_local_forwards = 0;
395 for (i = 0; i < options->num_remote_forwards; i++) {
Adam Langleyd0592972015-03-30 14:49:51 -0700396 free(options->remote_forwards[i].listen_host);
397 free(options->remote_forwards[i].listen_path);
398 free(options->remote_forwards[i].connect_host);
399 free(options->remote_forwards[i].connect_path);
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800400 }
401 if (options->num_remote_forwards > 0) {
Adam Langleyd0592972015-03-30 14:49:51 -0700402 free(options->remote_forwards);
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800403 options->remote_forwards = NULL;
404 }
405 options->num_remote_forwards = 0;
406 options->tun_open = SSH_TUNMODE_NO;
407}
408
Adam Langleyd0592972015-03-30 14:49:51 -0700409void
Greg Hartman9768ca42017-06-22 20:49:52 -0700410add_certificate_file(Options *options, const char *path, int userprovided)
411{
412 int i;
413
414 if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES)
415 fatal("Too many certificate files specified (max %d)",
416 SSH_MAX_CERTIFICATE_FILES);
417
418 /* Avoid registering duplicates */
419 for (i = 0; i < options->num_certificate_files; i++) {
420 if (options->certificate_file_userprovided[i] == userprovided &&
421 strcmp(options->certificate_files[i], path) == 0) {
422 debug2("%s: ignoring duplicate key %s", __func__, path);
423 return;
424 }
425 }
426
427 options->certificate_file_userprovided[options->num_certificate_files] =
428 userprovided;
429 options->certificate_files[options->num_certificate_files++] =
430 xstrdup(path);
431}
432
433void
Adam Langleyd0592972015-03-30 14:49:51 -0700434add_identity_file(Options *options, const char *dir, const char *filename,
435 int userprovided)
436{
437 char *path;
438 int i;
439
440 if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
441 fatal("Too many identity files specified (max %d)",
442 SSH_MAX_IDENTITY_FILES);
443
444 if (dir == NULL) /* no dir, filename is absolute */
445 path = xstrdup(filename);
446 else
447 (void)xasprintf(&path, "%.100s%.100s", dir, filename);
448
449 /* Avoid registering duplicates */
450 for (i = 0; i < options->num_identity_files; i++) {
451 if (options->identity_file_userprovided[i] == userprovided &&
452 strcmp(options->identity_files[i], path) == 0) {
453 debug2("%s: ignoring duplicate key %s", __func__, path);
454 free(path);
455 return;
456 }
457 }
458
459 options->identity_file_userprovided[options->num_identity_files] =
460 userprovided;
461 options->identity_files[options->num_identity_files++] = path;
462}
463
464int
465default_ssh_port(void)
466{
467 static int port;
468 struct servent *sp;
469
470 if (port == 0) {
471 sp = getservbyname(SSH_SERVICE_NAME, "tcp");
472 port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
473 }
474 return port;
475}
476
477/*
478 * Execute a command in a shell.
479 * Return its exit status or -1 on abnormal exit.
480 */
481static int
482execute_in_shell(const char *cmd)
483{
Greg Hartman9768ca42017-06-22 20:49:52 -0700484 char *shell;
Adam Langleyd0592972015-03-30 14:49:51 -0700485 pid_t pid;
486 int devnull, status;
487 extern uid_t original_real_uid;
488
489 if ((shell = getenv("SHELL")) == NULL)
490 shell = _PATH_BSHELL;
491
Adam Langleyd0592972015-03-30 14:49:51 -0700492 /* Need this to redirect subprocess stdin/out */
493 if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1)
494 fatal("open(/dev/null): %s", strerror(errno));
495
496 debug("Executing command: '%.500s'", cmd);
497
498 /* Fork and execute the command. */
499 if ((pid = fork()) == 0) {
500 char *argv[4];
501
502 /* Child. Permanently give up superuser privileges. */
503 permanently_drop_suid(original_real_uid);
504
505 /* Redirect child stdin and stdout. Leave stderr */
506 if (dup2(devnull, STDIN_FILENO) == -1)
507 fatal("dup2: %s", strerror(errno));
508 if (dup2(devnull, STDOUT_FILENO) == -1)
509 fatal("dup2: %s", strerror(errno));
510 if (devnull > STDERR_FILENO)
511 close(devnull);
512 closefrom(STDERR_FILENO + 1);
513
514 argv[0] = shell;
515 argv[1] = "-c";
Greg Hartman9768ca42017-06-22 20:49:52 -0700516 argv[2] = xstrdup(cmd);
Adam Langleyd0592972015-03-30 14:49:51 -0700517 argv[3] = NULL;
518
519 execv(argv[0], argv);
520 error("Unable to execute '%.100s': %s", cmd, strerror(errno));
521 /* Die with signal to make this error apparent to parent. */
522 signal(SIGTERM, SIG_DFL);
523 kill(getpid(), SIGTERM);
524 _exit(1);
525 }
526 /* Parent. */
527 if (pid < 0)
528 fatal("%s: fork: %.100s", __func__, strerror(errno));
529
530 close(devnull);
Adam Langleyd0592972015-03-30 14:49:51 -0700531
532 while (waitpid(pid, &status, 0) == -1) {
533 if (errno != EINTR && errno != EAGAIN)
534 fatal("%s: waitpid: %s", __func__, strerror(errno));
535 }
536 if (!WIFEXITED(status)) {
537 error("command '%.100s' exited abnormally", cmd);
538 return -1;
539 }
540 debug3("command returned status %d", WEXITSTATUS(status));
541 return WEXITSTATUS(status);
542}
543
544/*
545 * Parse and execute a Match directive.
546 */
547static int
548match_cfg_line(Options *options, char **condition, struct passwd *pw,
549 const char *host_arg, const char *original_host, int post_canon,
550 const char *filename, int linenum)
551{
552 char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria;
553 const char *ruser;
554 int r, port, this_result, result = 1, attributes = 0, negate;
Adam Langleyd0592972015-03-30 14:49:51 -0700555 char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
556
557 /*
558 * Configuration is likely to be incomplete at this point so we
559 * must be prepared to use default values.
560 */
561 port = options->port <= 0 ? default_ssh_port() : options->port;
562 ruser = options->user == NULL ? pw->pw_name : options->user;
Greg Hartman9768ca42017-06-22 20:49:52 -0700563 if (post_canon) {
564 host = xstrdup(options->hostname);
565 } else if (options->hostname != NULL) {
Adam Langleyd0592972015-03-30 14:49:51 -0700566 /* NB. Please keep in sync with ssh.c:main() */
567 host = percent_expand(options->hostname,
568 "h", host_arg, (char *)NULL);
Greg Hartman9768ca42017-06-22 20:49:52 -0700569 } else {
Adam Langleyd0592972015-03-30 14:49:51 -0700570 host = xstrdup(host_arg);
Greg Hartman9768ca42017-06-22 20:49:52 -0700571 }
Adam Langleyd0592972015-03-30 14:49:51 -0700572
573 debug2("checking match for '%s' host %s originally %s",
574 cp, host, original_host);
575 while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') {
576 criteria = NULL;
577 this_result = 1;
578 if ((negate = attrib[0] == '!'))
579 attrib++;
580 /* criteria "all" and "canonical" have no argument */
581 if (strcasecmp(attrib, "all") == 0) {
582 if (attributes > 1 ||
583 ((arg = strdelim(&cp)) != NULL && *arg != '\0')) {
584 error("%.200s line %d: '%s' cannot be combined "
585 "with other Match attributes",
586 filename, linenum, oattrib);
587 result = -1;
588 goto out;
589 }
590 if (result)
591 result = negate ? 0 : 1;
592 goto out;
593 }
594 attributes++;
595 if (strcasecmp(attrib, "canonical") == 0) {
596 r = !!post_canon; /* force bitmask member to boolean */
597 if (r == (negate ? 1 : 0))
598 this_result = result = 0;
599 debug3("%.200s line %d: %smatched '%s'",
600 filename, linenum,
601 this_result ? "" : "not ", oattrib);
602 continue;
603 }
604 /* All other criteria require an argument */
605 if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
606 error("Missing Match criteria for %s", attrib);
607 result = -1;
608 goto out;
609 }
Adam Langleyd0592972015-03-30 14:49:51 -0700610 if (strcasecmp(attrib, "host") == 0) {
611 criteria = xstrdup(host);
Greg Hartmanccacbc92016-02-03 09:59:44 -0800612 r = match_hostname(host, arg) == 1;
Adam Langleyd0592972015-03-30 14:49:51 -0700613 if (r == (negate ? 1 : 0))
614 this_result = result = 0;
615 } else if (strcasecmp(attrib, "originalhost") == 0) {
616 criteria = xstrdup(original_host);
Greg Hartmanccacbc92016-02-03 09:59:44 -0800617 r = match_hostname(original_host, arg) == 1;
Adam Langleyd0592972015-03-30 14:49:51 -0700618 if (r == (negate ? 1 : 0))
619 this_result = result = 0;
620 } else if (strcasecmp(attrib, "user") == 0) {
621 criteria = xstrdup(ruser);
Greg Hartmanccacbc92016-02-03 09:59:44 -0800622 r = match_pattern_list(ruser, arg, 0) == 1;
Adam Langleyd0592972015-03-30 14:49:51 -0700623 if (r == (negate ? 1 : 0))
624 this_result = result = 0;
625 } else if (strcasecmp(attrib, "localuser") == 0) {
626 criteria = xstrdup(pw->pw_name);
Greg Hartmanccacbc92016-02-03 09:59:44 -0800627 r = match_pattern_list(pw->pw_name, arg, 0) == 1;
Adam Langleyd0592972015-03-30 14:49:51 -0700628 if (r == (negate ? 1 : 0))
629 this_result = result = 0;
630 } else if (strcasecmp(attrib, "exec") == 0) {
631 if (gethostname(thishost, sizeof(thishost)) == -1)
632 fatal("gethostname: %s", strerror(errno));
633 strlcpy(shorthost, thishost, sizeof(shorthost));
634 shorthost[strcspn(thishost, ".")] = '\0';
635 snprintf(portstr, sizeof(portstr), "%d", port);
636
637 cmd = percent_expand(arg,
638 "L", shorthost,
639 "d", pw->pw_dir,
640 "h", host,
641 "l", thishost,
642 "n", original_host,
643 "p", portstr,
644 "r", ruser,
645 "u", pw->pw_name,
646 (char *)NULL);
647 if (result != 1) {
648 /* skip execution if prior predicate failed */
649 debug3("%.200s line %d: skipped exec "
650 "\"%.100s\"", filename, linenum, cmd);
651 free(cmd);
652 continue;
653 }
654 r = execute_in_shell(cmd);
655 if (r == -1) {
656 fatal("%.200s line %d: match exec "
657 "'%.100s' error", filename,
658 linenum, cmd);
659 }
660 criteria = xstrdup(cmd);
661 free(cmd);
662 /* Force exit status to boolean */
663 r = r == 0;
664 if (r == (negate ? 1 : 0))
665 this_result = result = 0;
666 } else {
667 error("Unsupported Match attribute %s", attrib);
668 result = -1;
669 goto out;
670 }
671 debug3("%.200s line %d: %smatched '%s \"%.100s\"' ",
672 filename, linenum, this_result ? "": "not ",
673 oattrib, criteria);
674 free(criteria);
675 }
676 if (attributes == 0) {
677 error("One or more attributes required for Match");
678 result = -1;
679 goto out;
680 }
681 out:
682 if (result != -1)
683 debug2("match %sfound", result ? "" : "not ");
684 *condition = cp;
685 free(host);
686 return result;
687}
688
689/* Check and prepare a domain name: removes trailing '.' and lowercases */
690static void
691valid_domain(char *name, const char *filename, int linenum)
692{
693 size_t i, l = strlen(name);
694 u_char c, last = '\0';
695
696 if (l == 0)
697 fatal("%s line %d: empty hostname suffix", filename, linenum);
698 if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0]))
699 fatal("%s line %d: hostname suffix \"%.100s\" "
700 "starts with invalid character", filename, linenum, name);
701 for (i = 0; i < l; i++) {
702 c = tolower((u_char)name[i]);
703 name[i] = (char)c;
704 if (last == '.' && c == '.')
705 fatal("%s line %d: hostname suffix \"%.100s\" contains "
706 "consecutive separators", filename, linenum, name);
707 if (c != '.' && c != '-' && !isalnum(c) &&
708 c != '_') /* technically invalid, but common */
709 fatal("%s line %d: hostname suffix \"%.100s\" contains "
710 "invalid characters", filename, linenum, name);
711 last = c;
712 }
713 if (name[l - 1] == '.')
714 name[l - 1] = '\0';
715}
716
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800717/*
718 * Returns the number of the token pointed to by cp or oBadOption.
719 */
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800720static OpCodes
Adam Langleyd0592972015-03-30 14:49:51 -0700721parse_token(const char *cp, const char *filename, int linenum,
722 const char *ignored_unknown)
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800723{
Adam Langleyd0592972015-03-30 14:49:51 -0700724 int i;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800725
726 for (i = 0; keywords[i].name; i++)
Adam Langleyd0592972015-03-30 14:49:51 -0700727 if (strcmp(cp, keywords[i].name) == 0)
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800728 return keywords[i].opcode;
Greg Hartmanccacbc92016-02-03 09:59:44 -0800729 if (ignored_unknown != NULL &&
730 match_pattern_list(cp, ignored_unknown, 1) == 1)
Adam Langleyd0592972015-03-30 14:49:51 -0700731 return oIgnoredUnknownOption;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800732 error("%s: line %d: Bad configuration option: %s",
733 filename, linenum, cp);
734 return oBadOption;
735}
736
Adam Langleyd0592972015-03-30 14:49:51 -0700737/* Multistate option parsing */
738struct multistate {
739 char *key;
740 int value;
741};
742static const struct multistate multistate_flag[] = {
743 { "true", 1 },
744 { "false", 0 },
745 { "yes", 1 },
746 { "no", 0 },
747 { NULL, -1 }
748};
749static const struct multistate multistate_yesnoask[] = {
750 { "true", 1 },
751 { "false", 0 },
752 { "yes", 1 },
753 { "no", 0 },
754 { "ask", 2 },
755 { NULL, -1 }
756};
Greg Hartman9768ca42017-06-22 20:49:52 -0700757static const struct multistate multistate_yesnoaskconfirm[] = {
758 { "true", 1 },
759 { "false", 0 },
760 { "yes", 1 },
761 { "no", 0 },
762 { "ask", 2 },
763 { "confirm", 3 },
764 { NULL, -1 }
765};
Adam Langleyd0592972015-03-30 14:49:51 -0700766static const struct multistate multistate_addressfamily[] = {
767 { "inet", AF_INET },
768 { "inet6", AF_INET6 },
769 { "any", AF_UNSPEC },
770 { NULL, -1 }
771};
772static const struct multistate multistate_controlmaster[] = {
773 { "true", SSHCTL_MASTER_YES },
774 { "yes", SSHCTL_MASTER_YES },
775 { "false", SSHCTL_MASTER_NO },
776 { "no", SSHCTL_MASTER_NO },
777 { "auto", SSHCTL_MASTER_AUTO },
778 { "ask", SSHCTL_MASTER_ASK },
779 { "autoask", SSHCTL_MASTER_AUTO_ASK },
780 { NULL, -1 }
781};
782static const struct multistate multistate_tunnel[] = {
783 { "ethernet", SSH_TUNMODE_ETHERNET },
784 { "point-to-point", SSH_TUNMODE_POINTOPOINT },
785 { "true", SSH_TUNMODE_DEFAULT },
786 { "yes", SSH_TUNMODE_DEFAULT },
787 { "false", SSH_TUNMODE_NO },
788 { "no", SSH_TUNMODE_NO },
789 { NULL, -1 }
790};
791static const struct multistate multistate_requesttty[] = {
792 { "true", REQUEST_TTY_YES },
793 { "yes", REQUEST_TTY_YES },
794 { "false", REQUEST_TTY_NO },
795 { "no", REQUEST_TTY_NO },
796 { "force", REQUEST_TTY_FORCE },
797 { "auto", REQUEST_TTY_AUTO },
798 { NULL, -1 }
799};
800static const struct multistate multistate_canonicalizehostname[] = {
801 { "true", SSH_CANONICALISE_YES },
802 { "false", SSH_CANONICALISE_NO },
803 { "yes", SSH_CANONICALISE_YES },
804 { "no", SSH_CANONICALISE_NO },
805 { "always", SSH_CANONICALISE_ALWAYS },
806 { NULL, -1 }
807};
808
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800809/*
810 * Processes a single option line as used in the configuration files. This
811 * only sets those values that have not already been set.
812 */
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800813int
Adam Langleyd0592972015-03-30 14:49:51 -0700814process_config_line(Options *options, struct passwd *pw, const char *host,
815 const char *original_host, char *line, const char *filename,
816 int linenum, int *activep, int flags)
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800817{
Greg Hartman9768ca42017-06-22 20:49:52 -0700818 return process_config_line_depth(options, pw, host, original_host,
819 line, filename, linenum, activep, flags, 0);
820}
821
822#define WHITESPACE " \t\r\n"
823static int
824process_config_line_depth(Options *options, struct passwd *pw, const char *host,
825 const char *original_host, char *line, const char *filename,
826 int linenum, int *activep, int flags, int depth)
827{
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800828 char *s, **charptr, *endofnumber, *keyword, *arg, *arg2;
829 char **cpptr, fwdarg[256];
Adam Langleyd0592972015-03-30 14:49:51 -0700830 u_int i, *uintptr, max_entries = 0;
Greg Hartman9768ca42017-06-22 20:49:52 -0700831 int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800832 LogLevel *log_level_ptr;
Adam Langleyd0592972015-03-30 14:49:51 -0700833 long long val64;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800834 size_t len;
Adam Langleyd0592972015-03-30 14:49:51 -0700835 struct Forward fwd;
836 const struct multistate *multistate_ptr;
837 struct allowed_cname *cname;
Greg Hartman9768ca42017-06-22 20:49:52 -0700838 glob_t gl;
Adam Langleyd0592972015-03-30 14:49:51 -0700839
840 if (activep == NULL) { /* We are processing a command line directive */
841 cmdline = 1;
842 activep = &cmdline;
843 }
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800844
Greg Hartman9768ca42017-06-22 20:49:52 -0700845 /* Strip trailing whitespace. Allow \f (form feed) at EOL only */
Greg Hartmanccacbc92016-02-03 09:59:44 -0800846 if ((len = strlen(line)) == 0)
847 return 0;
848 for (len--; len > 0; len--) {
Greg Hartman9768ca42017-06-22 20:49:52 -0700849 if (strchr(WHITESPACE "\f", line[len]) == NULL)
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800850 break;
851 line[len] = '\0';
852 }
853
854 s = line;
855 /* Get the keyword. (Each line is supposed to begin with a keyword). */
856 if ((keyword = strdelim(&s)) == NULL)
857 return 0;
858 /* Ignore leading whitespace. */
859 if (*keyword == '\0')
860 keyword = strdelim(&s);
861 if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
862 return 0;
Adam Langleyd0592972015-03-30 14:49:51 -0700863 /* Match lowercase keyword */
864 lowercase(keyword);
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800865
Adam Langleyd0592972015-03-30 14:49:51 -0700866 opcode = parse_token(keyword, filename, linenum,
867 options->ignored_unknown);
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800868
869 switch (opcode) {
870 case oBadOption:
871 /* don't panic, but count bad options */
872 return -1;
Adam Langleyd0592972015-03-30 14:49:51 -0700873 case oIgnoredUnknownOption:
874 debug("%s line %d: Ignored unknown option \"%s\"",
875 filename, linenum, keyword);
876 return 0;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800877 case oConnectTimeout:
878 intptr = &options->connection_timeout;
879parse_time:
880 arg = strdelim(&s);
881 if (!arg || *arg == '\0')
882 fatal("%s line %d: missing time value.",
883 filename, linenum);
Adam Langleyd0592972015-03-30 14:49:51 -0700884 if (strcmp(arg, "none") == 0)
885 value = -1;
886 else if ((value = convtime(arg)) == -1)
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800887 fatal("%s line %d: invalid time value.",
888 filename, linenum);
889 if (*activep && *intptr == -1)
890 *intptr = value;
891 break;
892
893 case oForwardAgent:
894 intptr = &options->forward_agent;
Adam Langleyd0592972015-03-30 14:49:51 -0700895 parse_flag:
896 multistate_ptr = multistate_flag;
897 parse_multistate:
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800898 arg = strdelim(&s);
899 if (!arg || *arg == '\0')
Adam Langleyd0592972015-03-30 14:49:51 -0700900 fatal("%s line %d: missing argument.",
901 filename, linenum);
902 value = -1;
903 for (i = 0; multistate_ptr[i].key != NULL; i++) {
904 if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
905 value = multistate_ptr[i].value;
906 break;
907 }
908 }
909 if (value == -1)
910 fatal("%s line %d: unsupported option \"%s\".",
911 filename, linenum, arg);
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800912 if (*activep && *intptr == -1)
913 *intptr = value;
914 break;
915
916 case oForwardX11:
917 intptr = &options->forward_x11;
918 goto parse_flag;
919
920 case oForwardX11Trusted:
921 intptr = &options->forward_x11_trusted;
922 goto parse_flag;
Adam Langleyd0592972015-03-30 14:49:51 -0700923
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800924 case oForwardX11Timeout:
925 intptr = &options->forward_x11_timeout;
926 goto parse_time;
927
928 case oGatewayPorts:
Adam Langleyd0592972015-03-30 14:49:51 -0700929 intptr = &options->fwd_opts.gateway_ports;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800930 goto parse_flag;
931
932 case oExitOnForwardFailure:
933 intptr = &options->exit_on_forward_failure;
934 goto parse_flag;
935
936 case oUsePrivilegedPort:
937 intptr = &options->use_privileged_port;
938 goto parse_flag;
939
940 case oPasswordAuthentication:
941 intptr = &options->password_authentication;
942 goto parse_flag;
943
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800944 case oKbdInteractiveAuthentication:
945 intptr = &options->kbd_interactive_authentication;
946 goto parse_flag;
947
948 case oKbdInteractiveDevices:
949 charptr = &options->kbd_interactive_devices;
950 goto parse_string;
951
952 case oPubkeyAuthentication:
953 intptr = &options->pubkey_authentication;
954 goto parse_flag;
955
956 case oRSAAuthentication:
957 intptr = &options->rsa_authentication;
958 goto parse_flag;
959
960 case oRhostsRSAAuthentication:
961 intptr = &options->rhosts_rsa_authentication;
962 goto parse_flag;
963
964 case oHostbasedAuthentication:
965 intptr = &options->hostbased_authentication;
966 goto parse_flag;
967
968 case oChallengeResponseAuthentication:
969 intptr = &options->challenge_response_authentication;
970 goto parse_flag;
971
972 case oGssAuthentication:
973 intptr = &options->gss_authentication;
974 goto parse_flag;
975
976 case oGssDelegateCreds:
977 intptr = &options->gss_deleg_creds;
978 goto parse_flag;
979
980 case oBatchMode:
981 intptr = &options->batch_mode;
982 goto parse_flag;
983
984 case oCheckHostIP:
985 intptr = &options->check_host_ip;
986 goto parse_flag;
987
988 case oVerifyHostKeyDNS:
989 intptr = &options->verify_host_key_dns;
Adam Langleyd0592972015-03-30 14:49:51 -0700990 multistate_ptr = multistate_yesnoask;
991 goto parse_multistate;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800992
993 case oStrictHostKeyChecking:
994 intptr = &options->strict_host_key_checking;
Adam Langleyd0592972015-03-30 14:49:51 -0700995 multistate_ptr = multistate_yesnoask;
996 goto parse_multistate;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800997
998 case oCompression:
999 intptr = &options->compression;
1000 goto parse_flag;
1001
1002 case oTCPKeepAlive:
1003 intptr = &options->tcp_keep_alive;
1004 goto parse_flag;
1005
1006 case oNoHostAuthenticationForLocalhost:
1007 intptr = &options->no_host_authentication_for_localhost;
1008 goto parse_flag;
1009
1010 case oNumberOfPasswordPrompts:
1011 intptr = &options->number_of_password_prompts;
1012 goto parse_int;
1013
1014 case oCompressionLevel:
1015 intptr = &options->compression_level;
1016 goto parse_int;
1017
1018 case oRekeyLimit:
1019 arg = strdelim(&s);
1020 if (!arg || *arg == '\0')
Adam Langleyd0592972015-03-30 14:49:51 -07001021 fatal("%.200s line %d: Missing argument.", filename,
1022 linenum);
1023 if (strcmp(arg, "default") == 0) {
1024 val64 = 0;
1025 } else {
1026 if (scan_scaled(arg, &val64) == -1)
1027 fatal("%.200s line %d: Bad number '%s': %s",
1028 filename, linenum, arg, strerror(errno));
Adam Langleyd0592972015-03-30 14:49:51 -07001029 if (val64 != 0 && val64 < 16)
1030 fatal("%.200s line %d: RekeyLimit too small",
1031 filename, linenum);
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001032 }
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001033 if (*activep && options->rekey_limit == -1)
Greg Hartman9768ca42017-06-22 20:49:52 -07001034 options->rekey_limit = val64;
Adam Langleyd0592972015-03-30 14:49:51 -07001035 if (s != NULL) { /* optional rekey interval present */
1036 if (strcmp(s, "none") == 0) {
1037 (void)strdelim(&s); /* discard */
1038 break;
1039 }
1040 intptr = &options->rekey_interval;
1041 goto parse_time;
1042 }
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001043 break;
1044
1045 case oIdentityFile:
1046 arg = strdelim(&s);
1047 if (!arg || *arg == '\0')
1048 fatal("%.200s line %d: Missing argument.", filename, linenum);
1049 if (*activep) {
1050 intptr = &options->num_identity_files;
1051 if (*intptr >= SSH_MAX_IDENTITY_FILES)
1052 fatal("%.200s line %d: Too many identity files specified (max %d).",
1053 filename, linenum, SSH_MAX_IDENTITY_FILES);
Adam Langleyd0592972015-03-30 14:49:51 -07001054 add_identity_file(options, NULL,
1055 arg, flags & SSHCONF_USERCONF);
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001056 }
1057 break;
1058
Greg Hartman9768ca42017-06-22 20:49:52 -07001059 case oCertificateFile:
1060 arg = strdelim(&s);
1061 if (!arg || *arg == '\0')
1062 fatal("%.200s line %d: Missing argument.",
1063 filename, linenum);
1064 if (*activep) {
1065 intptr = &options->num_certificate_files;
1066 if (*intptr >= SSH_MAX_CERTIFICATE_FILES) {
1067 fatal("%.200s line %d: Too many certificate "
1068 "files specified (max %d).",
1069 filename, linenum,
1070 SSH_MAX_CERTIFICATE_FILES);
1071 }
1072 add_certificate_file(options, arg,
1073 flags & SSHCONF_USERCONF);
1074 }
1075 break;
1076
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001077 case oXAuthLocation:
1078 charptr=&options->xauth_location;
1079 goto parse_string;
1080
1081 case oUser:
1082 charptr = &options->user;
1083parse_string:
1084 arg = strdelim(&s);
1085 if (!arg || *arg == '\0')
1086 fatal("%.200s line %d: Missing argument.",
1087 filename, linenum);
1088 if (*activep && *charptr == NULL)
1089 *charptr = xstrdup(arg);
1090 break;
1091
1092 case oGlobalKnownHostsFile:
1093 cpptr = (char **)&options->system_hostfiles;
1094 uintptr = &options->num_system_hostfiles;
1095 max_entries = SSH_MAX_HOSTS_FILES;
1096parse_char_array:
1097 if (*activep && *uintptr == 0) {
1098 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1099 if ((*uintptr) >= max_entries)
1100 fatal("%s line %d: "
1101 "too many authorized keys files.",
1102 filename, linenum);
1103 cpptr[(*uintptr)++] = xstrdup(arg);
1104 }
1105 }
1106 return 0;
1107
1108 case oUserKnownHostsFile:
1109 cpptr = (char **)&options->user_hostfiles;
1110 uintptr = &options->num_user_hostfiles;
1111 max_entries = SSH_MAX_HOSTS_FILES;
1112 goto parse_char_array;
1113
1114 case oHostName:
1115 charptr = &options->hostname;
1116 goto parse_string;
1117
1118 case oHostKeyAlias:
1119 charptr = &options->host_key_alias;
1120 goto parse_string;
1121
1122 case oPreferredAuthentications:
1123 charptr = &options->preferred_authentications;
1124 goto parse_string;
1125
1126 case oBindAddress:
1127 charptr = &options->bind_address;
1128 goto parse_string;
1129
1130 case oPKCS11Provider:
1131 charptr = &options->pkcs11_provider;
1132 goto parse_string;
1133
1134 case oProxyCommand:
1135 charptr = &options->proxy_command;
Greg Hartman9768ca42017-06-22 20:49:52 -07001136 /* Ignore ProxyCommand if ProxyJump already specified */
1137 if (options->jump_host != NULL)
1138 charptr = &options->jump_host; /* Skip below */
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001139parse_command:
1140 if (s == NULL)
1141 fatal("%.200s line %d: Missing argument.", filename, linenum);
1142 len = strspn(s, WHITESPACE "=");
1143 if (*activep && *charptr == NULL)
1144 *charptr = xstrdup(s + len);
1145 return 0;
1146
Greg Hartman9768ca42017-06-22 20:49:52 -07001147 case oProxyJump:
1148 if (s == NULL) {
1149 fatal("%.200s line %d: Missing argument.",
1150 filename, linenum);
1151 }
1152 len = strspn(s, WHITESPACE "=");
1153 if (parse_jump(s + len, options, *activep) == -1) {
1154 fatal("%.200s line %d: Invalid ProxyJump \"%s\"",
1155 filename, linenum, s + len);
1156 }
1157 return 0;
1158
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001159 case oPort:
1160 intptr = &options->port;
1161parse_int:
1162 arg = strdelim(&s);
1163 if (!arg || *arg == '\0')
1164 fatal("%.200s line %d: Missing argument.", filename, linenum);
1165 if (arg[0] < '0' || arg[0] > '9')
1166 fatal("%.200s line %d: Bad number.", filename, linenum);
1167
1168 /* Octal, decimal, or hex format? */
1169 value = strtol(arg, &endofnumber, 0);
1170 if (arg == endofnumber)
1171 fatal("%.200s line %d: Bad number.", filename, linenum);
1172 if (*activep && *intptr == -1)
1173 *intptr = value;
1174 break;
1175
1176 case oConnectionAttempts:
1177 intptr = &options->connection_attempts;
1178 goto parse_int;
1179
1180 case oCipher:
1181 intptr = &options->cipher;
1182 arg = strdelim(&s);
1183 if (!arg || *arg == '\0')
1184 fatal("%.200s line %d: Missing argument.", filename, linenum);
1185 value = cipher_number(arg);
1186 if (value == -1)
1187 fatal("%.200s line %d: Bad cipher '%s'.",
1188 filename, linenum, arg ? arg : "<NONE>");
1189 if (*activep && *intptr == -1)
1190 *intptr = value;
1191 break;
1192
1193 case oCiphers:
1194 arg = strdelim(&s);
1195 if (!arg || *arg == '\0')
1196 fatal("%.200s line %d: Missing argument.", filename, linenum);
Greg Hartman9768ca42017-06-22 20:49:52 -07001197 if (*arg != '-' && !ciphers_valid(*arg == '+' ? arg + 1 : arg))
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001198 fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
1199 filename, linenum, arg ? arg : "<NONE>");
1200 if (*activep && options->ciphers == NULL)
1201 options->ciphers = xstrdup(arg);
1202 break;
1203
1204 case oMacs:
1205 arg = strdelim(&s);
1206 if (!arg || *arg == '\0')
1207 fatal("%.200s line %d: Missing argument.", filename, linenum);
Greg Hartman9768ca42017-06-22 20:49:52 -07001208 if (*arg != '-' && !mac_valid(*arg == '+' ? arg + 1 : arg))
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001209 fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
1210 filename, linenum, arg ? arg : "<NONE>");
1211 if (*activep && options->macs == NULL)
1212 options->macs = xstrdup(arg);
1213 break;
1214
1215 case oKexAlgorithms:
1216 arg = strdelim(&s);
1217 if (!arg || *arg == '\0')
1218 fatal("%.200s line %d: Missing argument.",
1219 filename, linenum);
Greg Hartman9768ca42017-06-22 20:49:52 -07001220 if (*arg != '-' &&
1221 !kex_names_valid(*arg == '+' ? arg + 1 : arg))
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001222 fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
1223 filename, linenum, arg ? arg : "<NONE>");
1224 if (*activep && options->kex_algorithms == NULL)
1225 options->kex_algorithms = xstrdup(arg);
1226 break;
1227
1228 case oHostKeyAlgorithms:
Greg Hartmanccacbc92016-02-03 09:59:44 -08001229 charptr = &options->hostkeyalgorithms;
1230parse_keytypes:
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001231 arg = strdelim(&s);
1232 if (!arg || *arg == '\0')
Greg Hartmanccacbc92016-02-03 09:59:44 -08001233 fatal("%.200s line %d: Missing argument.",
1234 filename, linenum);
Greg Hartman9768ca42017-06-22 20:49:52 -07001235 if (*arg != '-' &&
1236 !sshkey_names_valid2(*arg == '+' ? arg + 1 : arg, 1))
Greg Hartmanccacbc92016-02-03 09:59:44 -08001237 fatal("%s line %d: Bad key types '%s'.",
1238 filename, linenum, arg ? arg : "<NONE>");
1239 if (*activep && *charptr == NULL)
1240 *charptr = xstrdup(arg);
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001241 break;
1242
1243 case oProtocol:
1244 intptr = &options->protocol;
1245 arg = strdelim(&s);
1246 if (!arg || *arg == '\0')
1247 fatal("%.200s line %d: Missing argument.", filename, linenum);
1248 value = proto_spec(arg);
1249 if (value == SSH_PROTO_UNKNOWN)
1250 fatal("%.200s line %d: Bad protocol spec '%s'.",
1251 filename, linenum, arg ? arg : "<NONE>");
1252 if (*activep && *intptr == SSH_PROTO_UNKNOWN)
1253 *intptr = value;
1254 break;
1255
1256 case oLogLevel:
1257 log_level_ptr = &options->log_level;
1258 arg = strdelim(&s);
1259 value = log_level_number(arg);
1260 if (value == SYSLOG_LEVEL_NOT_SET)
1261 fatal("%.200s line %d: unsupported log level '%s'",
1262 filename, linenum, arg ? arg : "<NONE>");
1263 if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
1264 *log_level_ptr = (LogLevel) value;
1265 break;
1266
1267 case oLocalForward:
1268 case oRemoteForward:
1269 case oDynamicForward:
1270 arg = strdelim(&s);
1271 if (arg == NULL || *arg == '\0')
1272 fatal("%.200s line %d: Missing port argument.",
1273 filename, linenum);
1274
1275 if (opcode == oLocalForward ||
1276 opcode == oRemoteForward) {
1277 arg2 = strdelim(&s);
1278 if (arg2 == NULL || *arg2 == '\0')
1279 fatal("%.200s line %d: Missing target argument.",
1280 filename, linenum);
1281
1282 /* construct a string for parse_forward */
1283 snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
1284 } else if (opcode == oDynamicForward) {
1285 strlcpy(fwdarg, arg, sizeof(fwdarg));
1286 }
1287
1288 if (parse_forward(&fwd, fwdarg,
1289 opcode == oDynamicForward ? 1 : 0,
1290 opcode == oRemoteForward ? 1 : 0) == 0)
1291 fatal("%.200s line %d: Bad forwarding specification.",
1292 filename, linenum);
1293
1294 if (*activep) {
1295 if (opcode == oLocalForward ||
1296 opcode == oDynamicForward)
1297 add_local_forward(options, &fwd);
1298 else if (opcode == oRemoteForward)
1299 add_remote_forward(options, &fwd);
1300 }
1301 break;
1302
1303 case oClearAllForwardings:
1304 intptr = &options->clear_forwardings;
1305 goto parse_flag;
1306
1307 case oHost:
Adam Langleyd0592972015-03-30 14:49:51 -07001308 if (cmdline)
1309 fatal("Host directive not supported as a command-line "
1310 "option");
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001311 *activep = 0;
1312 arg2 = NULL;
1313 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
Greg Hartman9768ca42017-06-22 20:49:52 -07001314 if ((flags & SSHCONF_NEVERMATCH) != 0)
1315 break;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001316 negated = *arg == '!';
1317 if (negated)
1318 arg++;
1319 if (match_pattern(host, arg)) {
1320 if (negated) {
1321 debug("%.200s line %d: Skipping Host "
1322 "block because of negated match "
1323 "for %.100s", filename, linenum,
1324 arg);
1325 *activep = 0;
1326 break;
1327 }
1328 if (!*activep)
1329 arg2 = arg; /* logged below */
1330 *activep = 1;
1331 }
1332 }
1333 if (*activep)
1334 debug("%.200s line %d: Applying options for %.100s",
1335 filename, linenum, arg2);
1336 /* Avoid garbage check below, as strdelim is done. */
1337 return 0;
1338
Adam Langleyd0592972015-03-30 14:49:51 -07001339 case oMatch:
1340 if (cmdline)
1341 fatal("Host directive not supported as a command-line "
1342 "option");
1343 value = match_cfg_line(options, &s, pw, host, original_host,
1344 flags & SSHCONF_POSTCANON, filename, linenum);
1345 if (value < 0)
1346 fatal("%.200s line %d: Bad Match condition", filename,
1347 linenum);
Greg Hartman9768ca42017-06-22 20:49:52 -07001348 *activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value;
Adam Langleyd0592972015-03-30 14:49:51 -07001349 break;
1350
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001351 case oEscapeChar:
1352 intptr = &options->escape_char;
1353 arg = strdelim(&s);
1354 if (!arg || *arg == '\0')
1355 fatal("%.200s line %d: Missing argument.", filename, linenum);
Greg Hartmanccacbc92016-02-03 09:59:44 -08001356 if (strcmp(arg, "none") == 0)
1357 value = SSH_ESCAPECHAR_NONE;
1358 else if (arg[1] == '\0')
1359 value = (u_char) arg[0];
1360 else if (arg[0] == '^' && arg[2] == 0 &&
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001361 (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
1362 value = (u_char) arg[1] & 31;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001363 else {
1364 fatal("%.200s line %d: Bad escape character.",
1365 filename, linenum);
1366 /* NOTREACHED */
1367 value = 0; /* Avoid compiler warning. */
1368 }
1369 if (*activep && *intptr == -1)
1370 *intptr = value;
1371 break;
1372
1373 case oAddressFamily:
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001374 intptr = &options->address_family;
Adam Langleyd0592972015-03-30 14:49:51 -07001375 multistate_ptr = multistate_addressfamily;
1376 goto parse_multistate;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001377
1378 case oEnableSSHKeysign:
1379 intptr = &options->enable_ssh_keysign;
1380 goto parse_flag;
1381
1382 case oIdentitiesOnly:
1383 intptr = &options->identities_only;
1384 goto parse_flag;
1385
1386 case oServerAliveInterval:
1387 intptr = &options->server_alive_interval;
1388 goto parse_time;
1389
1390 case oServerAliveCountMax:
1391 intptr = &options->server_alive_count_max;
1392 goto parse_int;
1393
1394 case oSendEnv:
1395 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1396 if (strchr(arg, '=') != NULL)
1397 fatal("%s line %d: Invalid environment name.",
1398 filename, linenum);
1399 if (!*activep)
1400 continue;
1401 if (options->num_send_env >= MAX_SEND_ENV)
1402 fatal("%s line %d: too many send env.",
1403 filename, linenum);
1404 options->send_env[options->num_send_env++] =
1405 xstrdup(arg);
1406 }
1407 break;
1408
1409 case oControlPath:
1410 charptr = &options->control_path;
1411 goto parse_string;
1412
1413 case oControlMaster:
1414 intptr = &options->control_master;
Adam Langleyd0592972015-03-30 14:49:51 -07001415 multistate_ptr = multistate_controlmaster;
1416 goto parse_multistate;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001417
1418 case oControlPersist:
1419 /* no/false/yes/true, or a time spec */
1420 intptr = &options->control_persist;
1421 arg = strdelim(&s);
1422 if (!arg || *arg == '\0')
1423 fatal("%.200s line %d: Missing ControlPersist"
1424 " argument.", filename, linenum);
1425 value = 0;
1426 value2 = 0; /* timeout */
1427 if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
1428 value = 0;
1429 else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
1430 value = 1;
1431 else if ((value2 = convtime(arg)) >= 0)
1432 value = 1;
1433 else
1434 fatal("%.200s line %d: Bad ControlPersist argument.",
1435 filename, linenum);
1436 if (*activep && *intptr == -1) {
1437 *intptr = value;
1438 options->control_persist_timeout = value2;
1439 }
1440 break;
1441
1442 case oHashKnownHosts:
1443 intptr = &options->hash_known_hosts;
1444 goto parse_flag;
1445
1446 case oTunnel:
1447 intptr = &options->tun_open;
Adam Langleyd0592972015-03-30 14:49:51 -07001448 multistate_ptr = multistate_tunnel;
1449 goto parse_multistate;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001450
1451 case oTunnelDevice:
1452 arg = strdelim(&s);
1453 if (!arg || *arg == '\0')
1454 fatal("%.200s line %d: Missing argument.", filename, linenum);
1455 value = a2tun(arg, &value2);
1456 if (value == SSH_TUNID_ERR)
1457 fatal("%.200s line %d: Bad tun device.", filename, linenum);
1458 if (*activep) {
1459 options->tun_local = value;
1460 options->tun_remote = value2;
1461 }
1462 break;
1463
1464 case oLocalCommand:
1465 charptr = &options->local_command;
1466 goto parse_command;
1467
1468 case oPermitLocalCommand:
1469 intptr = &options->permit_local_command;
1470 goto parse_flag;
1471
1472 case oVisualHostKey:
1473 intptr = &options->visual_host_key;
1474 goto parse_flag;
1475
Greg Hartman9768ca42017-06-22 20:49:52 -07001476 case oInclude:
1477 if (cmdline)
1478 fatal("Include directive not supported as a "
1479 "command-line option");
1480 value = 0;
1481 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1482 /*
1483 * Ensure all paths are anchored. User configuration
1484 * files may begin with '~/' but system configurations
1485 * must not. If the path is relative, then treat it
1486 * as living in ~/.ssh for user configurations or
1487 * /etc/ssh for system ones.
1488 */
1489 if (*arg == '~' && (flags & SSHCONF_USERCONF) == 0)
1490 fatal("%.200s line %d: bad include path %s.",
1491 filename, linenum, arg);
1492 if (*arg != '/' && *arg != '~') {
1493 xasprintf(&arg2, "%s/%s",
1494 (flags & SSHCONF_USERCONF) ?
1495 "~/" _PATH_SSH_USER_DIR : SSHDIR, arg);
1496 } else
1497 arg2 = xstrdup(arg);
1498 memset(&gl, 0, sizeof(gl));
1499 r = glob(arg2, GLOB_TILDE, NULL, &gl);
1500 if (r == GLOB_NOMATCH) {
1501 debug("%.200s line %d: include %s matched no "
1502 "files",filename, linenum, arg2);
1503 free(arg2);
1504 continue;
1505 } else if (r != 0 || gl.gl_pathc < 0)
1506 fatal("%.200s line %d: glob failed for %s.",
1507 filename, linenum, arg2);
1508 free(arg2);
1509 oactive = *activep;
1510 for (i = 0; i < (u_int)gl.gl_pathc; i++) {
1511 debug3("%.200s line %d: Including file %s "
1512 "depth %d%s", filename, linenum,
1513 gl.gl_pathv[i], depth,
1514 oactive ? "" : " (parse only)");
1515 r = read_config_file_depth(gl.gl_pathv[i],
1516 pw, host, original_host, options,
1517 flags | SSHCONF_CHECKPERM |
1518 (oactive ? 0 : SSHCONF_NEVERMATCH),
1519 activep, depth + 1);
1520 if (r != 1 && errno != ENOENT) {
1521 fatal("Can't open user config file "
1522 "%.100s: %.100s", gl.gl_pathv[i],
1523 strerror(errno));
1524 }
1525 /*
1526 * don't let Match in includes clobber the
1527 * containing file's Match state.
1528 */
1529 *activep = oactive;
1530 if (r != 1)
1531 value = -1;
1532 }
1533 globfree(&gl);
1534 }
1535 if (value != 0)
1536 return value;
1537 break;
1538
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001539 case oIPQoS:
1540 arg = strdelim(&s);
1541 if ((value = parse_ipqos(arg)) == -1)
1542 fatal("%s line %d: Bad IPQoS value: %s",
1543 filename, linenum, arg);
1544 arg = strdelim(&s);
1545 if (arg == NULL)
1546 value2 = value;
1547 else if ((value2 = parse_ipqos(arg)) == -1)
1548 fatal("%s line %d: Bad IPQoS value: %s",
1549 filename, linenum, arg);
1550 if (*activep) {
1551 options->ip_qos_interactive = value;
1552 options->ip_qos_bulk = value2;
1553 }
1554 break;
1555
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001556 case oRequestTTY:
Adam Langleyd0592972015-03-30 14:49:51 -07001557 intptr = &options->request_tty;
1558 multistate_ptr = multistate_requesttty;
1559 goto parse_multistate;
1560
1561 case oIgnoreUnknown:
1562 charptr = &options->ignored_unknown;
1563 goto parse_string;
1564
1565 case oProxyUseFdpass:
1566 intptr = &options->proxy_use_fdpass;
1567 goto parse_flag;
1568
1569 case oCanonicalDomains:
1570 value = options->num_canonical_domains != 0;
1571 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1572 valid_domain(arg, filename, linenum);
1573 if (!*activep || value)
1574 continue;
1575 if (options->num_canonical_domains >= MAX_CANON_DOMAINS)
1576 fatal("%s line %d: too many hostname suffixes.",
1577 filename, linenum);
1578 options->canonical_domains[
1579 options->num_canonical_domains++] = xstrdup(arg);
1580 }
1581 break;
1582
1583 case oCanonicalizePermittedCNAMEs:
1584 value = options->num_permitted_cnames != 0;
1585 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1586 /* Either '*' for everything or 'list:list' */
1587 if (strcmp(arg, "*") == 0)
1588 arg2 = arg;
1589 else {
1590 lowercase(arg);
1591 if ((arg2 = strchr(arg, ':')) == NULL ||
1592 arg2[1] == '\0') {
1593 fatal("%s line %d: "
1594 "Invalid permitted CNAME \"%s\"",
1595 filename, linenum, arg);
1596 }
1597 *arg2 = '\0';
1598 arg2++;
1599 }
1600 if (!*activep || value)
1601 continue;
1602 if (options->num_permitted_cnames >= MAX_CANON_DOMAINS)
1603 fatal("%s line %d: too many permitted CNAMEs.",
1604 filename, linenum);
1605 cname = options->permitted_cnames +
1606 options->num_permitted_cnames++;
1607 cname->source_list = xstrdup(arg);
1608 cname->target_list = xstrdup(arg2);
1609 }
1610 break;
1611
1612 case oCanonicalizeHostname:
1613 intptr = &options->canonicalize_hostname;
1614 multistate_ptr = multistate_canonicalizehostname;
1615 goto parse_multistate;
1616
1617 case oCanonicalizeMaxDots:
1618 intptr = &options->canonicalize_max_dots;
1619 goto parse_int;
1620
1621 case oCanonicalizeFallbackLocal:
1622 intptr = &options->canonicalize_fallback_local;
1623 goto parse_flag;
1624
1625 case oStreamLocalBindMask:
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001626 arg = strdelim(&s);
1627 if (!arg || *arg == '\0')
Adam Langleyd0592972015-03-30 14:49:51 -07001628 fatal("%.200s line %d: Missing StreamLocalBindMask argument.", filename, linenum);
1629 /* Parse mode in octal format */
1630 value = strtol(arg, &endofnumber, 8);
1631 if (arg == endofnumber || value < 0 || value > 0777)
1632 fatal("%.200s line %d: Bad mask.", filename, linenum);
1633 options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
1634 break;
1635
1636 case oStreamLocalBindUnlink:
1637 intptr = &options->fwd_opts.streamlocal_bind_unlink;
1638 goto parse_flag;
1639
1640 case oRevokedHostKeys:
1641 charptr = &options->revoked_host_keys;
1642 goto parse_string;
1643
1644 case oFingerprintHash:
1645 intptr = &options->fingerprint_hash;
1646 arg = strdelim(&s);
1647 if (!arg || *arg == '\0')
1648 fatal("%.200s line %d: Missing argument.",
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001649 filename, linenum);
Adam Langleyd0592972015-03-30 14:49:51 -07001650 if ((value = ssh_digest_alg_by_name(arg)) == -1)
1651 fatal("%.200s line %d: Invalid hash algorithm \"%s\".",
1652 filename, linenum, arg);
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001653 if (*activep && *intptr == -1)
1654 *intptr = value;
1655 break;
1656
Adam Langleyd0592972015-03-30 14:49:51 -07001657 case oUpdateHostkeys:
1658 intptr = &options->update_hostkeys;
1659 multistate_ptr = multistate_yesnoask;
1660 goto parse_multistate;
1661
1662 case oHostbasedKeyTypes:
1663 charptr = &options->hostbased_key_types;
Greg Hartmanccacbc92016-02-03 09:59:44 -08001664 goto parse_keytypes;
1665
1666 case oPubkeyAcceptedKeyTypes:
1667 charptr = &options->pubkey_key_types;
1668 goto parse_keytypes;
Adam Langleyd0592972015-03-30 14:49:51 -07001669
Greg Hartman9768ca42017-06-22 20:49:52 -07001670 case oAddKeysToAgent:
1671 intptr = &options->add_keys_to_agent;
1672 multistate_ptr = multistate_yesnoaskconfirm;
1673 goto parse_multistate;
1674
1675 case oIdentityAgent:
1676 charptr = &options->identity_agent;
1677 goto parse_string;
1678
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001679 case oDeprecated:
1680 debug("%s line %d: Deprecated option \"%s\"",
1681 filename, linenum, keyword);
1682 return 0;
1683
1684 case oUnsupported:
1685 error("%s line %d: Unsupported option \"%s\"",
1686 filename, linenum, keyword);
1687 return 0;
1688
1689 default:
Adam Langleyd0592972015-03-30 14:49:51 -07001690 fatal("%s: Unimplemented opcode %d", __func__, opcode);
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001691 }
1692
1693 /* Check that there is no garbage at end of line. */
1694 if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1695 fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
1696 filename, linenum, arg);
1697 }
1698 return 0;
1699}
1700
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001701/*
1702 * Reads the config file and modifies the options accordingly. Options
1703 * should already be initialized before this call. This never returns if
1704 * there is an error. If the file does not exist, this returns 0.
1705 */
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001706int
Adam Langleyd0592972015-03-30 14:49:51 -07001707read_config_file(const char *filename, struct passwd *pw, const char *host,
1708 const char *original_host, Options *options, int flags)
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001709{
Greg Hartman9768ca42017-06-22 20:49:52 -07001710 int active = 1;
1711
1712 return read_config_file_depth(filename, pw, host, original_host,
1713 options, flags, &active, 0);
1714}
1715
1716#define READCONF_MAX_DEPTH 16
1717static int
1718read_config_file_depth(const char *filename, struct passwd *pw,
1719 const char *host, const char *original_host, Options *options,
1720 int flags, int *activep, int depth)
1721{
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001722 FILE *f;
Greg Hartman9768ca42017-06-22 20:49:52 -07001723 char line[4096];
1724 int linenum;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001725 int bad_options = 0;
1726
Greg Hartman9768ca42017-06-22 20:49:52 -07001727 if (depth < 0 || depth > READCONF_MAX_DEPTH)
1728 fatal("Too many recursive configuration includes");
1729
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001730 if ((f = fopen(filename, "r")) == NULL)
1731 return 0;
1732
Adam Langleyd0592972015-03-30 14:49:51 -07001733 if (flags & SSHCONF_CHECKPERM) {
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001734 struct stat sb;
1735
1736 if (fstat(fileno(f), &sb) == -1)
1737 fatal("fstat %s: %s", filename, strerror(errno));
1738 if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
1739 (sb.st_mode & 022) != 0))
1740 fatal("Bad owner or permissions on %s", filename);
1741 }
1742
1743 debug("Reading configuration data %.200s", filename);
1744
1745 /*
1746 * Mark that we are now processing the options. This flag is turned
1747 * on/off by Host specifications.
1748 */
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001749 linenum = 0;
1750 while (fgets(line, sizeof(line), f)) {
1751 /* Update line number counter. */
1752 linenum++;
Greg Hartman9768ca42017-06-22 20:49:52 -07001753 if (strlen(line) == sizeof(line) - 1)
1754 fatal("%s line %d too long", filename, linenum);
1755 if (process_config_line_depth(options, pw, host, original_host,
1756 line, filename, linenum, activep, flags, depth) != 0)
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001757 bad_options++;
1758 }
1759 fclose(f);
1760 if (bad_options > 0)
1761 fatal("%s: terminating, %d bad configuration options",
1762 filename, bad_options);
1763 return 1;
1764}
1765
Adam Langleyd0592972015-03-30 14:49:51 -07001766/* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
1767int
1768option_clear_or_none(const char *o)
1769{
1770 return o == NULL || strcasecmp(o, "none") == 0;
1771}
1772
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001773/*
1774 * Initializes options to special values that indicate that they have not yet
1775 * been set. Read_config_file will only set options with this value. Options
1776 * are processed in the following order: command line, user config file,
1777 * system config file. Last, fill_default_options is called.
1778 */
1779
1780void
1781initialize_options(Options * options)
1782{
1783 memset(options, 'X', sizeof(*options));
1784 options->forward_agent = -1;
1785 options->forward_x11 = -1;
1786 options->forward_x11_trusted = -1;
1787 options->forward_x11_timeout = -1;
Greg Hartman9768ca42017-06-22 20:49:52 -07001788 options->stdio_forward_host = NULL;
1789 options->stdio_forward_port = 0;
1790 options->clear_forwardings = -1;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001791 options->exit_on_forward_failure = -1;
1792 options->xauth_location = NULL;
Adam Langleyd0592972015-03-30 14:49:51 -07001793 options->fwd_opts.gateway_ports = -1;
1794 options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
1795 options->fwd_opts.streamlocal_bind_unlink = -1;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001796 options->use_privileged_port = -1;
1797 options->rsa_authentication = -1;
1798 options->pubkey_authentication = -1;
1799 options->challenge_response_authentication = -1;
1800 options->gss_authentication = -1;
1801 options->gss_deleg_creds = -1;
1802 options->password_authentication = -1;
1803 options->kbd_interactive_authentication = -1;
1804 options->kbd_interactive_devices = NULL;
1805 options->rhosts_rsa_authentication = -1;
1806 options->hostbased_authentication = -1;
1807 options->batch_mode = -1;
1808 options->check_host_ip = -1;
1809 options->strict_host_key_checking = -1;
1810 options->compression = -1;
1811 options->tcp_keep_alive = -1;
1812 options->compression_level = -1;
1813 options->port = -1;
1814 options->address_family = -1;
1815 options->connection_attempts = -1;
1816 options->connection_timeout = -1;
1817 options->number_of_password_prompts = -1;
1818 options->cipher = -1;
1819 options->ciphers = NULL;
1820 options->macs = NULL;
1821 options->kex_algorithms = NULL;
1822 options->hostkeyalgorithms = NULL;
1823 options->protocol = SSH_PROTO_UNKNOWN;
1824 options->num_identity_files = 0;
Greg Hartman9768ca42017-06-22 20:49:52 -07001825 options->num_certificate_files = 0;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001826 options->hostname = NULL;
1827 options->host_key_alias = NULL;
1828 options->proxy_command = NULL;
Greg Hartman9768ca42017-06-22 20:49:52 -07001829 options->jump_user = NULL;
1830 options->jump_host = NULL;
1831 options->jump_port = -1;
1832 options->jump_extra = NULL;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001833 options->user = NULL;
1834 options->escape_char = -1;
1835 options->num_system_hostfiles = 0;
1836 options->num_user_hostfiles = 0;
1837 options->local_forwards = NULL;
1838 options->num_local_forwards = 0;
1839 options->remote_forwards = NULL;
1840 options->num_remote_forwards = 0;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001841 options->log_level = SYSLOG_LEVEL_NOT_SET;
1842 options->preferred_authentications = NULL;
1843 options->bind_address = NULL;
1844 options->pkcs11_provider = NULL;
1845 options->enable_ssh_keysign = - 1;
1846 options->no_host_authentication_for_localhost = - 1;
1847 options->identities_only = - 1;
1848 options->rekey_limit = - 1;
Adam Langleyd0592972015-03-30 14:49:51 -07001849 options->rekey_interval = -1;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001850 options->verify_host_key_dns = -1;
1851 options->server_alive_interval = -1;
1852 options->server_alive_count_max = -1;
1853 options->num_send_env = 0;
1854 options->control_path = NULL;
1855 options->control_master = -1;
1856 options->control_persist = -1;
1857 options->control_persist_timeout = 0;
1858 options->hash_known_hosts = -1;
1859 options->tun_open = -1;
1860 options->tun_local = -1;
1861 options->tun_remote = -1;
1862 options->local_command = NULL;
1863 options->permit_local_command = -1;
Greg Hartman9768ca42017-06-22 20:49:52 -07001864 options->add_keys_to_agent = -1;
1865 options->identity_agent = NULL;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001866 options->visual_host_key = -1;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001867 options->ip_qos_interactive = -1;
1868 options->ip_qos_bulk = -1;
1869 options->request_tty = -1;
Adam Langleyd0592972015-03-30 14:49:51 -07001870 options->proxy_use_fdpass = -1;
1871 options->ignored_unknown = NULL;
1872 options->num_canonical_domains = 0;
1873 options->num_permitted_cnames = 0;
1874 options->canonicalize_max_dots = -1;
1875 options->canonicalize_fallback_local = -1;
1876 options->canonicalize_hostname = -1;
1877 options->revoked_host_keys = NULL;
1878 options->fingerprint_hash = -1;
1879 options->update_hostkeys = -1;
1880 options->hostbased_key_types = NULL;
Greg Hartmanccacbc92016-02-03 09:59:44 -08001881 options->pubkey_key_types = NULL;
Adam Langleyd0592972015-03-30 14:49:51 -07001882}
1883
1884/*
1885 * A petite version of fill_default_options() that just fills the options
1886 * needed for hostname canonicalization to proceed.
1887 */
1888void
1889fill_default_options_for_canonicalization(Options *options)
1890{
1891 if (options->canonicalize_max_dots == -1)
1892 options->canonicalize_max_dots = 1;
1893 if (options->canonicalize_fallback_local == -1)
1894 options->canonicalize_fallback_local = 1;
1895 if (options->canonicalize_hostname == -1)
1896 options->canonicalize_hostname = SSH_CANONICALISE_NO;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001897}
1898
1899/*
1900 * Called after processing other sources of option data, this fills those
1901 * options for which no value has been specified with their default values.
1902 */
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001903void
1904fill_default_options(Options * options)
1905{
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001906 if (options->forward_agent == -1)
1907 options->forward_agent = 0;
1908 if (options->forward_x11 == -1)
1909 options->forward_x11 = 0;
1910 if (options->forward_x11_trusted == -1)
1911 options->forward_x11_trusted = 0;
1912 if (options->forward_x11_timeout == -1)
1913 options->forward_x11_timeout = 1200;
Greg Hartman9768ca42017-06-22 20:49:52 -07001914 /*
1915 * stdio forwarding (-W) changes the default for these but we defer
1916 * setting the values so they can be overridden.
1917 */
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001918 if (options->exit_on_forward_failure == -1)
Greg Hartman9768ca42017-06-22 20:49:52 -07001919 options->exit_on_forward_failure =
1920 options->stdio_forward_host != NULL ? 1 : 0;
1921 if (options->clear_forwardings == -1)
1922 options->clear_forwardings =
1923 options->stdio_forward_host != NULL ? 1 : 0;
1924 if (options->clear_forwardings == 1)
1925 clear_forwardings(options);
1926
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001927 if (options->xauth_location == NULL)
1928 options->xauth_location = _PATH_XAUTH;
Adam Langleyd0592972015-03-30 14:49:51 -07001929 if (options->fwd_opts.gateway_ports == -1)
1930 options->fwd_opts.gateway_ports = 0;
1931 if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
1932 options->fwd_opts.streamlocal_bind_mask = 0177;
1933 if (options->fwd_opts.streamlocal_bind_unlink == -1)
1934 options->fwd_opts.streamlocal_bind_unlink = 0;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001935 if (options->use_privileged_port == -1)
1936 options->use_privileged_port = 0;
1937 if (options->rsa_authentication == -1)
1938 options->rsa_authentication = 1;
1939 if (options->pubkey_authentication == -1)
1940 options->pubkey_authentication = 1;
1941 if (options->challenge_response_authentication == -1)
1942 options->challenge_response_authentication = 1;
1943 if (options->gss_authentication == -1)
1944 options->gss_authentication = 0;
1945 if (options->gss_deleg_creds == -1)
1946 options->gss_deleg_creds = 0;
1947 if (options->password_authentication == -1)
1948 options->password_authentication = 1;
1949 if (options->kbd_interactive_authentication == -1)
1950 options->kbd_interactive_authentication = 1;
1951 if (options->rhosts_rsa_authentication == -1)
1952 options->rhosts_rsa_authentication = 0;
1953 if (options->hostbased_authentication == -1)
1954 options->hostbased_authentication = 0;
1955 if (options->batch_mode == -1)
1956 options->batch_mode = 0;
1957 if (options->check_host_ip == -1)
1958 options->check_host_ip = 1;
1959 if (options->strict_host_key_checking == -1)
1960 options->strict_host_key_checking = 2; /* 2 is default */
1961 if (options->compression == -1)
1962 options->compression = 0;
1963 if (options->tcp_keep_alive == -1)
1964 options->tcp_keep_alive = 1;
1965 if (options->compression_level == -1)
1966 options->compression_level = 6;
1967 if (options->port == -1)
1968 options->port = 0; /* Filled in ssh_connect. */
1969 if (options->address_family == -1)
1970 options->address_family = AF_UNSPEC;
1971 if (options->connection_attempts == -1)
1972 options->connection_attempts = 1;
1973 if (options->number_of_password_prompts == -1)
1974 options->number_of_password_prompts = 3;
1975 /* Selected in ssh_login(). */
1976 if (options->cipher == -1)
1977 options->cipher = SSH_CIPHER_NOT_SET;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001978 /* options->hostkeyalgorithms, default set in myproposals.h */
1979 if (options->protocol == SSH_PROTO_UNKNOWN)
1980 options->protocol = SSH_PROTO_2;
Greg Hartman9768ca42017-06-22 20:49:52 -07001981 if (options->add_keys_to_agent == -1)
1982 options->add_keys_to_agent = 0;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001983 if (options->num_identity_files == 0) {
1984 if (options->protocol & SSH_PROTO_1) {
Adam Langleyd0592972015-03-30 14:49:51 -07001985 add_identity_file(options, "~/",
1986 _PATH_SSH_CLIENT_IDENTITY, 0);
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001987 }
1988 if (options->protocol & SSH_PROTO_2) {
Adam Langleyd0592972015-03-30 14:49:51 -07001989 add_identity_file(options, "~/",
1990 _PATH_SSH_CLIENT_ID_RSA, 0);
1991 add_identity_file(options, "~/",
1992 _PATH_SSH_CLIENT_ID_DSA, 0);
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001993#ifdef OPENSSL_HAS_ECC
Adam Langleyd0592972015-03-30 14:49:51 -07001994 add_identity_file(options, "~/",
1995 _PATH_SSH_CLIENT_ID_ECDSA, 0);
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001996#endif
Adam Langleyd0592972015-03-30 14:49:51 -07001997 add_identity_file(options, "~/",
1998 _PATH_SSH_CLIENT_ID_ED25519, 0);
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001999 }
2000 }
2001 if (options->escape_char == -1)
2002 options->escape_char = '~';
2003 if (options->num_system_hostfiles == 0) {
2004 options->system_hostfiles[options->num_system_hostfiles++] =
2005 xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
2006 options->system_hostfiles[options->num_system_hostfiles++] =
2007 xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
2008 }
2009 if (options->num_user_hostfiles == 0) {
2010 options->user_hostfiles[options->num_user_hostfiles++] =
2011 xstrdup(_PATH_SSH_USER_HOSTFILE);
2012 options->user_hostfiles[options->num_user_hostfiles++] =
2013 xstrdup(_PATH_SSH_USER_HOSTFILE2);
2014 }
2015 if (options->log_level == SYSLOG_LEVEL_NOT_SET)
2016 options->log_level = SYSLOG_LEVEL_INFO;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002017 if (options->no_host_authentication_for_localhost == - 1)
2018 options->no_host_authentication_for_localhost = 0;
2019 if (options->identities_only == -1)
2020 options->identities_only = 0;
2021 if (options->enable_ssh_keysign == -1)
2022 options->enable_ssh_keysign = 0;
2023 if (options->rekey_limit == -1)
2024 options->rekey_limit = 0;
Adam Langleyd0592972015-03-30 14:49:51 -07002025 if (options->rekey_interval == -1)
2026 options->rekey_interval = 0;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002027 if (options->verify_host_key_dns == -1)
2028 options->verify_host_key_dns = 0;
2029 if (options->server_alive_interval == -1)
2030 options->server_alive_interval = 0;
2031 if (options->server_alive_count_max == -1)
2032 options->server_alive_count_max = 3;
2033 if (options->control_master == -1)
2034 options->control_master = 0;
2035 if (options->control_persist == -1) {
2036 options->control_persist = 0;
2037 options->control_persist_timeout = 0;
2038 }
2039 if (options->hash_known_hosts == -1)
2040 options->hash_known_hosts = 0;
2041 if (options->tun_open == -1)
2042 options->tun_open = SSH_TUNMODE_NO;
2043 if (options->tun_local == -1)
2044 options->tun_local = SSH_TUNID_ANY;
2045 if (options->tun_remote == -1)
2046 options->tun_remote = SSH_TUNID_ANY;
2047 if (options->permit_local_command == -1)
2048 options->permit_local_command = 0;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002049 if (options->visual_host_key == -1)
2050 options->visual_host_key = 0;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002051 if (options->ip_qos_interactive == -1)
2052 options->ip_qos_interactive = IPTOS_LOWDELAY;
2053 if (options->ip_qos_bulk == -1)
2054 options->ip_qos_bulk = IPTOS_THROUGHPUT;
2055 if (options->request_tty == -1)
2056 options->request_tty = REQUEST_TTY_AUTO;
Adam Langleyd0592972015-03-30 14:49:51 -07002057 if (options->proxy_use_fdpass == -1)
2058 options->proxy_use_fdpass = 0;
2059 if (options->canonicalize_max_dots == -1)
2060 options->canonicalize_max_dots = 1;
2061 if (options->canonicalize_fallback_local == -1)
2062 options->canonicalize_fallback_local = 1;
2063 if (options->canonicalize_hostname == -1)
2064 options->canonicalize_hostname = SSH_CANONICALISE_NO;
2065 if (options->fingerprint_hash == -1)
2066 options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
2067 if (options->update_hostkeys == -1)
2068 options->update_hostkeys = 0;
Greg Hartmanccacbc92016-02-03 09:59:44 -08002069 if (kex_assemble_names(KEX_CLIENT_ENCRYPT, &options->ciphers) != 0 ||
2070 kex_assemble_names(KEX_CLIENT_MAC, &options->macs) != 0 ||
2071 kex_assemble_names(KEX_CLIENT_KEX, &options->kex_algorithms) != 0 ||
2072 kex_assemble_names(KEX_DEFAULT_PK_ALG,
2073 &options->hostbased_key_types) != 0 ||
2074 kex_assemble_names(KEX_DEFAULT_PK_ALG,
2075 &options->pubkey_key_types) != 0)
2076 fatal("%s: kex_assemble_names failed", __func__);
Adam Langleyd0592972015-03-30 14:49:51 -07002077
2078#define CLEAR_ON_NONE(v) \
2079 do { \
2080 if (option_clear_or_none(v)) { \
2081 free(v); \
2082 v = NULL; \
2083 } \
2084 } while(0)
2085 CLEAR_ON_NONE(options->local_command);
2086 CLEAR_ON_NONE(options->proxy_command);
2087 CLEAR_ON_NONE(options->control_path);
2088 CLEAR_ON_NONE(options->revoked_host_keys);
Greg Hartman9768ca42017-06-22 20:49:52 -07002089 /* options->identity_agent distinguishes NULL from 'none' */
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002090 /* options->user will be set in the main program if appropriate */
2091 /* options->hostname will be set in the main program if appropriate */
2092 /* options->host_key_alias should not be set by default */
2093 /* options->preferred_authentications will be set in ssh */
2094}
2095
Adam Langleyd0592972015-03-30 14:49:51 -07002096struct fwdarg {
2097 char *arg;
2098 int ispath;
2099};
2100
2101/*
2102 * parse_fwd_field
2103 * parses the next field in a port forwarding specification.
2104 * sets fwd to the parsed field and advances p past the colon
2105 * or sets it to NULL at end of string.
2106 * returns 0 on success, else non-zero.
2107 */
2108static int
2109parse_fwd_field(char **p, struct fwdarg *fwd)
2110{
2111 char *ep, *cp = *p;
2112 int ispath = 0;
2113
2114 if (*cp == '\0') {
2115 *p = NULL;
2116 return -1; /* end of string */
2117 }
2118
2119 /*
2120 * A field escaped with square brackets is used literally.
2121 * XXX - allow ']' to be escaped via backslash?
2122 */
2123 if (*cp == '[') {
2124 /* find matching ']' */
2125 for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
2126 if (*ep == '/')
2127 ispath = 1;
2128 }
2129 /* no matching ']' or not at end of field. */
2130 if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
2131 return -1;
2132 /* NUL terminate the field and advance p past the colon */
2133 *ep++ = '\0';
2134 if (*ep != '\0')
2135 *ep++ = '\0';
2136 fwd->arg = cp + 1;
2137 fwd->ispath = ispath;
2138 *p = ep;
2139 return 0;
2140 }
2141
2142 for (cp = *p; *cp != '\0'; cp++) {
2143 switch (*cp) {
2144 case '\\':
2145 memmove(cp, cp + 1, strlen(cp + 1) + 1);
Greg Hartmanccacbc92016-02-03 09:59:44 -08002146 if (*cp == '\0')
2147 return -1;
Adam Langleyd0592972015-03-30 14:49:51 -07002148 break;
2149 case '/':
2150 ispath = 1;
2151 break;
2152 case ':':
2153 *cp++ = '\0';
2154 goto done;
2155 }
2156 }
2157done:
2158 fwd->arg = *p;
2159 fwd->ispath = ispath;
2160 *p = cp;
2161 return 0;
2162}
2163
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002164/*
2165 * parse_forward
2166 * parses a string containing a port forwarding specification of the form:
2167 * dynamicfwd == 0
Adam Langleyd0592972015-03-30 14:49:51 -07002168 * [listenhost:]listenport|listenpath:connecthost:connectport|connectpath
2169 * listenpath:connectpath
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002170 * dynamicfwd == 1
2171 * [listenhost:]listenport
2172 * returns number of arguments parsed or zero on error
2173 */
2174int
Adam Langleyd0592972015-03-30 14:49:51 -07002175parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002176{
Adam Langleyd0592972015-03-30 14:49:51 -07002177 struct fwdarg fwdargs[4];
2178 char *p, *cp;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002179 int i;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002180
Adam Langleyd0592972015-03-30 14:49:51 -07002181 memset(fwd, 0, sizeof(*fwd));
2182 memset(fwdargs, 0, sizeof(fwdargs));
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002183
2184 cp = p = xstrdup(fwdspec);
2185
2186 /* skip leading spaces */
Adam Langleyd0592972015-03-30 14:49:51 -07002187 while (isspace((u_char)*cp))
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002188 cp++;
2189
Adam Langleyd0592972015-03-30 14:49:51 -07002190 for (i = 0; i < 4; ++i) {
2191 if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002192 break;
Adam Langleyd0592972015-03-30 14:49:51 -07002193 }
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002194
2195 /* Check for trailing garbage */
Adam Langleyd0592972015-03-30 14:49:51 -07002196 if (cp != NULL && *cp != '\0') {
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002197 i = 0; /* failure */
Adam Langleyd0592972015-03-30 14:49:51 -07002198 }
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002199
2200 switch (i) {
2201 case 1:
Adam Langleyd0592972015-03-30 14:49:51 -07002202 if (fwdargs[0].ispath) {
2203 fwd->listen_path = xstrdup(fwdargs[0].arg);
2204 fwd->listen_port = PORT_STREAMLOCAL;
2205 } else {
2206 fwd->listen_host = NULL;
2207 fwd->listen_port = a2port(fwdargs[0].arg);
2208 }
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002209 fwd->connect_host = xstrdup("socks");
2210 break;
2211
2212 case 2:
Adam Langleyd0592972015-03-30 14:49:51 -07002213 if (fwdargs[0].ispath && fwdargs[1].ispath) {
2214 fwd->listen_path = xstrdup(fwdargs[0].arg);
2215 fwd->listen_port = PORT_STREAMLOCAL;
2216 fwd->connect_path = xstrdup(fwdargs[1].arg);
2217 fwd->connect_port = PORT_STREAMLOCAL;
2218 } else if (fwdargs[1].ispath) {
2219 fwd->listen_host = NULL;
2220 fwd->listen_port = a2port(fwdargs[0].arg);
2221 fwd->connect_path = xstrdup(fwdargs[1].arg);
2222 fwd->connect_port = PORT_STREAMLOCAL;
2223 } else {
2224 fwd->listen_host = xstrdup(fwdargs[0].arg);
2225 fwd->listen_port = a2port(fwdargs[1].arg);
2226 fwd->connect_host = xstrdup("socks");
2227 }
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002228 break;
2229
2230 case 3:
Adam Langleyd0592972015-03-30 14:49:51 -07002231 if (fwdargs[0].ispath) {
2232 fwd->listen_path = xstrdup(fwdargs[0].arg);
2233 fwd->listen_port = PORT_STREAMLOCAL;
2234 fwd->connect_host = xstrdup(fwdargs[1].arg);
2235 fwd->connect_port = a2port(fwdargs[2].arg);
2236 } else if (fwdargs[2].ispath) {
2237 fwd->listen_host = xstrdup(fwdargs[0].arg);
2238 fwd->listen_port = a2port(fwdargs[1].arg);
2239 fwd->connect_path = xstrdup(fwdargs[2].arg);
2240 fwd->connect_port = PORT_STREAMLOCAL;
2241 } else {
2242 fwd->listen_host = NULL;
2243 fwd->listen_port = a2port(fwdargs[0].arg);
2244 fwd->connect_host = xstrdup(fwdargs[1].arg);
2245 fwd->connect_port = a2port(fwdargs[2].arg);
2246 }
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002247 break;
2248
2249 case 4:
Adam Langleyd0592972015-03-30 14:49:51 -07002250 fwd->listen_host = xstrdup(fwdargs[0].arg);
2251 fwd->listen_port = a2port(fwdargs[1].arg);
2252 fwd->connect_host = xstrdup(fwdargs[2].arg);
2253 fwd->connect_port = a2port(fwdargs[3].arg);
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002254 break;
2255 default:
2256 i = 0; /* failure */
2257 }
2258
Adam Langleyd0592972015-03-30 14:49:51 -07002259 free(p);
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002260
2261 if (dynamicfwd) {
2262 if (!(i == 1 || i == 2))
2263 goto fail_free;
2264 } else {
Adam Langleyd0592972015-03-30 14:49:51 -07002265 if (!(i == 3 || i == 4)) {
2266 if (fwd->connect_path == NULL &&
2267 fwd->listen_path == NULL)
2268 goto fail_free;
2269 }
2270 if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002271 goto fail_free;
2272 }
2273
Adam Langleyd0592972015-03-30 14:49:51 -07002274 if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
2275 (!remotefwd && fwd->listen_port == 0))
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002276 goto fail_free;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002277 if (fwd->connect_host != NULL &&
2278 strlen(fwd->connect_host) >= NI_MAXHOST)
2279 goto fail_free;
Adam Langleyd0592972015-03-30 14:49:51 -07002280 /* XXX - if connecting to a remote socket, max sun len may not match this host */
2281 if (fwd->connect_path != NULL &&
2282 strlen(fwd->connect_path) >= PATH_MAX_SUN)
2283 goto fail_free;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002284 if (fwd->listen_host != NULL &&
2285 strlen(fwd->listen_host) >= NI_MAXHOST)
2286 goto fail_free;
Adam Langleyd0592972015-03-30 14:49:51 -07002287 if (fwd->listen_path != NULL &&
2288 strlen(fwd->listen_path) >= PATH_MAX_SUN)
2289 goto fail_free;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002290
2291 return (i);
2292
2293 fail_free:
Adam Langleyd0592972015-03-30 14:49:51 -07002294 free(fwd->connect_host);
2295 fwd->connect_host = NULL;
2296 free(fwd->connect_path);
2297 fwd->connect_path = NULL;
2298 free(fwd->listen_host);
2299 fwd->listen_host = NULL;
2300 free(fwd->listen_path);
2301 fwd->listen_path = NULL;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002302 return (0);
2303}
Adam Langleyd0592972015-03-30 14:49:51 -07002304
Greg Hartman9768ca42017-06-22 20:49:52 -07002305int
2306parse_jump(const char *s, Options *o, int active)
2307{
2308 char *orig, *sdup, *cp;
2309 char *host = NULL, *user = NULL;
2310 int ret = -1, port = -1, first;
2311
2312 active &= o->proxy_command == NULL && o->jump_host == NULL;
2313
2314 orig = sdup = xstrdup(s);
2315 first = active;
2316 do {
2317 if ((cp = strrchr(sdup, ',')) == NULL)
2318 cp = sdup; /* last */
2319 else
2320 *cp++ = '\0';
2321
2322 if (first) {
2323 /* First argument and configuration is active */
2324 if (parse_user_host_port(cp, &user, &host, &port) != 0)
2325 goto out;
2326 } else {
2327 /* Subsequent argument or inactive configuration */
2328 if (parse_user_host_port(cp, NULL, NULL, NULL) != 0)
2329 goto out;
2330 }
2331 first = 0; /* only check syntax for subsequent hosts */
2332 } while (cp != sdup);
2333 /* success */
2334 if (active) {
2335 o->jump_user = user;
2336 o->jump_host = host;
2337 o->jump_port = port;
2338 o->proxy_command = xstrdup("none");
2339 user = host = NULL;
2340 if ((cp = strrchr(s, ',')) != NULL && cp != s) {
2341 o->jump_extra = xstrdup(s);
2342 o->jump_extra[cp - s] = '\0';
2343 }
2344 }
2345 ret = 0;
2346 out:
2347 free(orig);
2348 free(user);
2349 free(host);
2350 return ret;
2351}
2352
Adam Langleyd0592972015-03-30 14:49:51 -07002353/* XXX the following is a near-vebatim copy from servconf.c; refactor */
2354static const char *
2355fmt_multistate_int(int val, const struct multistate *m)
2356{
2357 u_int i;
2358
2359 for (i = 0; m[i].key != NULL; i++) {
2360 if (m[i].value == val)
2361 return m[i].key;
2362 }
2363 return "UNKNOWN";
2364}
2365
2366static const char *
2367fmt_intarg(OpCodes code, int val)
2368{
2369 if (val == -1)
2370 return "unset";
2371 switch (code) {
2372 case oAddressFamily:
2373 return fmt_multistate_int(val, multistate_addressfamily);
2374 case oVerifyHostKeyDNS:
2375 case oStrictHostKeyChecking:
2376 case oUpdateHostkeys:
2377 return fmt_multistate_int(val, multistate_yesnoask);
2378 case oControlMaster:
2379 return fmt_multistate_int(val, multistate_controlmaster);
2380 case oTunnel:
2381 return fmt_multistate_int(val, multistate_tunnel);
2382 case oRequestTTY:
2383 return fmt_multistate_int(val, multistate_requesttty);
2384 case oCanonicalizeHostname:
2385 return fmt_multistate_int(val, multistate_canonicalizehostname);
2386 case oFingerprintHash:
2387 return ssh_digest_alg_name(val);
2388 case oProtocol:
2389 switch (val) {
2390 case SSH_PROTO_1:
2391 return "1";
2392 case SSH_PROTO_2:
2393 return "2";
2394 case (SSH_PROTO_1|SSH_PROTO_2):
2395 return "2,1";
2396 default:
2397 return "UNKNOWN";
2398 }
2399 default:
2400 switch (val) {
2401 case 0:
2402 return "no";
2403 case 1:
2404 return "yes";
2405 default:
2406 return "UNKNOWN";
2407 }
2408 }
2409}
2410
2411static const char *
2412lookup_opcode_name(OpCodes code)
2413{
2414 u_int i;
2415
2416 for (i = 0; keywords[i].name != NULL; i++)
2417 if (keywords[i].opcode == code)
2418 return(keywords[i].name);
2419 return "UNKNOWN";
2420}
2421
2422static void
2423dump_cfg_int(OpCodes code, int val)
2424{
2425 printf("%s %d\n", lookup_opcode_name(code), val);
2426}
2427
2428static void
2429dump_cfg_fmtint(OpCodes code, int val)
2430{
2431 printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
2432}
2433
2434static void
2435dump_cfg_string(OpCodes code, const char *val)
2436{
2437 if (val == NULL)
2438 return;
2439 printf("%s %s\n", lookup_opcode_name(code), val);
2440}
2441
2442static void
2443dump_cfg_strarray(OpCodes code, u_int count, char **vals)
2444{
2445 u_int i;
2446
2447 for (i = 0; i < count; i++)
2448 printf("%s %s\n", lookup_opcode_name(code), vals[i]);
2449}
2450
2451static void
2452dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
2453{
2454 u_int i;
2455
2456 printf("%s", lookup_opcode_name(code));
2457 for (i = 0; i < count; i++)
2458 printf(" %s", vals[i]);
2459 printf("\n");
2460}
2461
2462static void
2463dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
2464{
2465 const struct Forward *fwd;
2466 u_int i;
2467
2468 /* oDynamicForward */
2469 for (i = 0; i < count; i++) {
2470 fwd = &fwds[i];
Greg Hartman9768ca42017-06-22 20:49:52 -07002471 if (code == oDynamicForward && fwd->connect_host != NULL &&
Adam Langleyd0592972015-03-30 14:49:51 -07002472 strcmp(fwd->connect_host, "socks") != 0)
2473 continue;
Greg Hartman9768ca42017-06-22 20:49:52 -07002474 if (code == oLocalForward && fwd->connect_host != NULL &&
Adam Langleyd0592972015-03-30 14:49:51 -07002475 strcmp(fwd->connect_host, "socks") == 0)
2476 continue;
2477 printf("%s", lookup_opcode_name(code));
2478 if (fwd->listen_port == PORT_STREAMLOCAL)
2479 printf(" %s", fwd->listen_path);
2480 else if (fwd->listen_host == NULL)
2481 printf(" %d", fwd->listen_port);
2482 else {
2483 printf(" [%s]:%d",
2484 fwd->listen_host, fwd->listen_port);
2485 }
2486 if (code != oDynamicForward) {
2487 if (fwd->connect_port == PORT_STREAMLOCAL)
2488 printf(" %s", fwd->connect_path);
2489 else if (fwd->connect_host == NULL)
2490 printf(" %d", fwd->connect_port);
2491 else {
2492 printf(" [%s]:%d",
2493 fwd->connect_host, fwd->connect_port);
2494 }
2495 }
2496 printf("\n");
2497 }
2498}
2499
2500void
2501dump_client_config(Options *o, const char *host)
2502{
2503 int i;
Greg Hartman9768ca42017-06-22 20:49:52 -07002504 char buf[8];
2505
2506 /* This is normally prepared in ssh_kex2 */
2507 if (kex_assemble_names(KEX_DEFAULT_PK_ALG, &o->hostkeyalgorithms) != 0)
2508 fatal("%s: kex_assemble_names failed", __func__);
Adam Langleyd0592972015-03-30 14:49:51 -07002509
2510 /* Most interesting options first: user, host, port */
2511 dump_cfg_string(oUser, o->user);
2512 dump_cfg_string(oHostName, host);
2513 dump_cfg_int(oPort, o->port);
2514
2515 /* Flag options */
2516 dump_cfg_fmtint(oAddressFamily, o->address_family);
2517 dump_cfg_fmtint(oBatchMode, o->batch_mode);
2518 dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local);
2519 dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname);
2520 dump_cfg_fmtint(oChallengeResponseAuthentication, o->challenge_response_authentication);
2521 dump_cfg_fmtint(oCheckHostIP, o->check_host_ip);
2522 dump_cfg_fmtint(oCompression, o->compression);
2523 dump_cfg_fmtint(oControlMaster, o->control_master);
2524 dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
Greg Hartman9768ca42017-06-22 20:49:52 -07002525 dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings);
Adam Langleyd0592972015-03-30 14:49:51 -07002526 dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
2527 dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
2528 dump_cfg_fmtint(oForwardAgent, o->forward_agent);
2529 dump_cfg_fmtint(oForwardX11, o->forward_x11);
2530 dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
2531 dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
2532#ifdef GSSAPI
2533 dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
2534 dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
2535#endif /* GSSAPI */
2536 dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
2537 dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
2538 dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
2539 dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication);
2540 dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost);
2541 dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication);
2542 dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command);
2543 dump_cfg_fmtint(oProtocol, o->protocol);
2544 dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
2545 dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
2546 dump_cfg_fmtint(oRequestTTY, o->request_tty);
Greg Hartman9768ca42017-06-22 20:49:52 -07002547#ifdef WITH_RSA1
Adam Langleyd0592972015-03-30 14:49:51 -07002548 dump_cfg_fmtint(oRhostsRSAAuthentication, o->rhosts_rsa_authentication);
2549 dump_cfg_fmtint(oRSAAuthentication, o->rsa_authentication);
Greg Hartman9768ca42017-06-22 20:49:52 -07002550#endif
Adam Langleyd0592972015-03-30 14:49:51 -07002551 dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
2552 dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking);
2553 dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive);
2554 dump_cfg_fmtint(oTunnel, o->tun_open);
2555 dump_cfg_fmtint(oUsePrivilegedPort, o->use_privileged_port);
2556 dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns);
2557 dump_cfg_fmtint(oVisualHostKey, o->visual_host_key);
2558 dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys);
2559
2560 /* Integer options */
2561 dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots);
Greg Hartman9768ca42017-06-22 20:49:52 -07002562#ifdef WITH_SSH1
Adam Langleyd0592972015-03-30 14:49:51 -07002563 dump_cfg_int(oCompressionLevel, o->compression_level);
Greg Hartman9768ca42017-06-22 20:49:52 -07002564#endif
Adam Langleyd0592972015-03-30 14:49:51 -07002565 dump_cfg_int(oConnectionAttempts, o->connection_attempts);
2566 dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout);
2567 dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
2568 dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
2569 dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
2570
2571 /* String options */
2572 dump_cfg_string(oBindAddress, o->bind_address);
2573 dump_cfg_string(oCiphers, o->ciphers ? o->ciphers : KEX_CLIENT_ENCRYPT);
2574 dump_cfg_string(oControlPath, o->control_path);
Greg Hartman9768ca42017-06-22 20:49:52 -07002575 dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms);
Adam Langleyd0592972015-03-30 14:49:51 -07002576 dump_cfg_string(oHostKeyAlias, o->host_key_alias);
2577 dump_cfg_string(oHostbasedKeyTypes, o->hostbased_key_types);
Greg Hartman9768ca42017-06-22 20:49:52 -07002578 dump_cfg_string(oIdentityAgent, o->identity_agent);
Adam Langleyd0592972015-03-30 14:49:51 -07002579 dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
2580 dump_cfg_string(oKexAlgorithms, o->kex_algorithms ? o->kex_algorithms : KEX_CLIENT_KEX);
2581 dump_cfg_string(oLocalCommand, o->local_command);
2582 dump_cfg_string(oLogLevel, log_level_name(o->log_level));
2583 dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC);
Greg Hartman9768ca42017-06-22 20:49:52 -07002584#ifdef ENABLE_PKCS11
Adam Langleyd0592972015-03-30 14:49:51 -07002585 dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
Greg Hartman9768ca42017-06-22 20:49:52 -07002586#endif
Adam Langleyd0592972015-03-30 14:49:51 -07002587 dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
Greg Hartman9768ca42017-06-22 20:49:52 -07002588 dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types);
Adam Langleyd0592972015-03-30 14:49:51 -07002589 dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
2590 dump_cfg_string(oXAuthLocation, o->xauth_location);
2591
2592 /* Forwards */
2593 dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards);
2594 dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards);
2595 dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards);
2596
2597 /* String array options */
2598 dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files);
2599 dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains);
2600 dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles);
2601 dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
2602 dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
2603
2604 /* Special cases */
2605
2606 /* oConnectTimeout */
2607 if (o->connection_timeout == -1)
2608 printf("connecttimeout none\n");
2609 else
2610 dump_cfg_int(oConnectTimeout, o->connection_timeout);
2611
2612 /* oTunnelDevice */
2613 printf("tunneldevice");
2614 if (o->tun_local == SSH_TUNID_ANY)
2615 printf(" any");
2616 else
2617 printf(" %d", o->tun_local);
2618 if (o->tun_remote == SSH_TUNID_ANY)
2619 printf(":any");
2620 else
2621 printf(":%d", o->tun_remote);
2622 printf("\n");
2623
2624 /* oCanonicalizePermittedCNAMEs */
2625 if ( o->num_permitted_cnames > 0) {
2626 printf("canonicalizePermittedcnames");
2627 for (i = 0; i < o->num_permitted_cnames; i++) {
2628 printf(" %s:%s", o->permitted_cnames[i].source_list,
2629 o->permitted_cnames[i].target_list);
2630 }
2631 printf("\n");
2632 }
2633
2634 /* oCipher */
2635 if (o->cipher != SSH_CIPHER_NOT_SET)
2636 printf("Cipher %s\n", cipher_name(o->cipher));
2637
2638 /* oControlPersist */
2639 if (o->control_persist == 0 || o->control_persist_timeout == 0)
2640 dump_cfg_fmtint(oControlPersist, o->control_persist);
2641 else
2642 dump_cfg_int(oControlPersist, o->control_persist_timeout);
2643
2644 /* oEscapeChar */
2645 if (o->escape_char == SSH_ESCAPECHAR_NONE)
2646 printf("escapechar none\n");
2647 else {
Greg Hartman9768ca42017-06-22 20:49:52 -07002648 vis(buf, o->escape_char, VIS_WHITE, 0);
2649 printf("escapechar %s\n", buf);
Adam Langleyd0592972015-03-30 14:49:51 -07002650 }
2651
2652 /* oIPQoS */
2653 printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
2654 printf("%s\n", iptos2str(o->ip_qos_bulk));
2655
2656 /* oRekeyLimit */
Greg Hartman9768ca42017-06-22 20:49:52 -07002657 printf("rekeylimit %llu %d\n",
2658 (unsigned long long)o->rekey_limit, o->rekey_interval);
Adam Langleyd0592972015-03-30 14:49:51 -07002659
2660 /* oStreamLocalBindMask */
2661 printf("streamlocalbindmask 0%o\n",
2662 o->fwd_opts.streamlocal_bind_mask);
Greg Hartman9768ca42017-06-22 20:49:52 -07002663
2664 /* oProxyCommand / oProxyJump */
2665 if (o->jump_host == NULL)
2666 dump_cfg_string(oProxyCommand, o->proxy_command);
2667 else {
2668 /* Check for numeric addresses */
2669 i = strchr(o->jump_host, ':') != NULL ||
2670 strspn(o->jump_host, "1234567890.") == strlen(o->jump_host);
2671 snprintf(buf, sizeof(buf), "%d", o->jump_port);
2672 printf("proxyjump %s%s%s%s%s%s%s%s%s\n",
2673 /* optional additional jump spec */
2674 o->jump_extra == NULL ? "" : o->jump_extra,
2675 o->jump_extra == NULL ? "" : ",",
2676 /* optional user */
2677 o->jump_user == NULL ? "" : o->jump_user,
2678 o->jump_user == NULL ? "" : "@",
2679 /* opening [ if hostname is numeric */
2680 i ? "[" : "",
2681 /* mandatory hostname */
2682 o->jump_host,
2683 /* closing ] if hostname is numeric */
2684 i ? "]" : "",
2685 /* optional port number */
2686 o->jump_port <= 0 ? "" : ":",
2687 o->jump_port <= 0 ? "" : buf);
2688 }
Adam Langleyd0592972015-03-30 14:49:51 -07002689}