blob: 42a2961faead7dc72351133d8cb79f2a5bd2bcb7 [file] [log] [blame]
Adam Langleyd0592972015-03-30 14:49:51 -07001/* $OpenBSD: readconf.c,v 1.232 2015/02/16 22:13: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>
Adam Langleyd0592972015-03-30 14:49:51 -070042#ifdef HAVE_UTIL_H
43#include <util.h>
44#endif
45#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
46# include <vis.h>
47#endif
Greg Hartmanbd77cf72015-02-25 13:21:06 -080048
49#include "xmalloc.h"
50#include "ssh.h"
51#include "compat.h"
52#include "cipher.h"
53#include "pathnames.h"
54#include "log.h"
Adam Langleyd0592972015-03-30 14:49:51 -070055#include "sshkey.h"
56#include "misc.h"
Greg Hartmanbd77cf72015-02-25 13:21:06 -080057#include "readconf.h"
58#include "match.h"
Greg Hartmanbd77cf72015-02-25 13:21:06 -080059#include "kex.h"
60#include "mac.h"
Adam Langleyd0592972015-03-30 14:49:51 -070061#include "uidswap.h"
62#include "myproposal.h"
63#include "digest.h"
Greg Hartmanbd77cf72015-02-25 13:21:06 -080064
65/* Format of the configuration file:
66
67 # Configuration data is parsed as follows:
68 # 1. command line options
69 # 2. user-specific file
70 # 3. system-wide file
71 # Any configuration value is only changed the first time it is set.
72 # Thus, host-specific definitions should be at the beginning of the
73 # configuration file, and defaults at the end.
74
75 # Host-specific declarations. These may override anything above. A single
76 # host may match multiple declarations; these are processed in the order
77 # that they are given in.
78
79 Host *.ngs.fi ngs.fi
80 User foo
81
82 Host fake.com
83 HostName another.host.name.real.org
84 User blaah
85 Port 34289
86 ForwardX11 no
87 ForwardAgent no
88
89 Host books.com
90 RemoteForward 9999 shadows.cs.hut.fi:9999
91 Cipher 3des
92
93 Host fascist.blob.com
94 Port 23123
95 User tylonen
96 PasswordAuthentication no
97
98 Host puukko.hut.fi
99 User t35124p
100 ProxyCommand ssh-proxy %h %p
101
102 Host *.fr
103 PublicKeyAuthentication no
104
105 Host *.su
106 Cipher none
107 PasswordAuthentication no
108
109 Host vpn.fake.com
110 Tunnel yes
111 TunnelDevice 3
112
113 # Defaults for various options
114 Host *
115 ForwardAgent no
116 ForwardX11 no
117 PasswordAuthentication yes
118 RSAAuthentication yes
119 RhostsRSAAuthentication yes
120 StrictHostKeyChecking yes
121 TcpKeepAlive no
122 IdentityFile ~/.ssh/identity
123 Port 22
124 EscapeChar ~
125
126*/
127
128/* Keyword tokens. */
129
130typedef enum {
131 oBadOption,
Adam Langleyd0592972015-03-30 14:49:51 -0700132 oHost, oMatch,
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800133 oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
134 oGatewayPorts, oExitOnForwardFailure,
135 oPasswordAuthentication, oRSAAuthentication,
136 oChallengeResponseAuthentication, oXAuthLocation,
137 oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
Adam Langleyd0592972015-03-30 14:49:51 -0700138 oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800139 oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
140 oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
141 oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
142 oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
Adam Langleyd0592972015-03-30 14:49:51 -0700143 oPubkeyAuthentication,
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800144 oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
145 oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
146 oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
147 oClearAllForwardings, oNoHostAuthenticationForLocalhost,
148 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
149 oAddressFamily, oGssAuthentication, oGssDelegateCreds,
150 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
151 oSendEnv, oControlPath, oControlMaster, oControlPersist,
152 oHashKnownHosts,
153 oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
Adam Langleyd0592972015-03-30 14:49:51 -0700154 oVisualHostKey, oUseRoaming,
155 oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
156 oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
157 oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
158 oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
159 oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes,
160 oIgnoredUnknownOption, oDeprecated, oUnsupported
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800161} OpCodes;
162
163/* Textual representations of the tokens. */
164
165static struct {
166 const char *name;
167 OpCodes opcode;
168} keywords[] = {
169 { "forwardagent", oForwardAgent },
170 { "forwardx11", oForwardX11 },
171 { "forwardx11trusted", oForwardX11Trusted },
172 { "forwardx11timeout", oForwardX11Timeout },
173 { "exitonforwardfailure", oExitOnForwardFailure },
174 { "xauthlocation", oXAuthLocation },
175 { "gatewayports", oGatewayPorts },
176 { "useprivilegedport", oUsePrivilegedPort },
177 { "rhostsauthentication", oDeprecated },
178 { "passwordauthentication", oPasswordAuthentication },
179 { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
180 { "kbdinteractivedevices", oKbdInteractiveDevices },
181 { "rsaauthentication", oRSAAuthentication },
182 { "pubkeyauthentication", oPubkeyAuthentication },
183 { "dsaauthentication", oPubkeyAuthentication }, /* alias */
184 { "rhostsrsaauthentication", oRhostsRSAAuthentication },
185 { "hostbasedauthentication", oHostbasedAuthentication },
186 { "challengeresponseauthentication", oChallengeResponseAuthentication },
187 { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
188 { "tisauthentication", oChallengeResponseAuthentication }, /* alias */
189 { "kerberosauthentication", oUnsupported },
190 { "kerberostgtpassing", oUnsupported },
191 { "afstokenpassing", oUnsupported },
192#if defined(GSSAPI)
193 { "gssapiauthentication", oGssAuthentication },
194 { "gssapidelegatecredentials", oGssDelegateCreds },
195#else
196 { "gssapiauthentication", oUnsupported },
197 { "gssapidelegatecredentials", oUnsupported },
198#endif
199 { "fallbacktorsh", oDeprecated },
200 { "usersh", oDeprecated },
201 { "identityfile", oIdentityFile },
202 { "identityfile2", oIdentityFile }, /* obsolete */
203 { "identitiesonly", oIdentitiesOnly },
204 { "hostname", oHostName },
205 { "hostkeyalias", oHostKeyAlias },
206 { "proxycommand", oProxyCommand },
207 { "port", oPort },
208 { "cipher", oCipher },
209 { "ciphers", oCiphers },
210 { "macs", oMacs },
211 { "protocol", oProtocol },
212 { "remoteforward", oRemoteForward },
213 { "localforward", oLocalForward },
214 { "user", oUser },
215 { "host", oHost },
Adam Langleyd0592972015-03-30 14:49:51 -0700216 { "match", oMatch },
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800217 { "escapechar", oEscapeChar },
218 { "globalknownhostsfile", oGlobalKnownHostsFile },
219 { "globalknownhostsfile2", oDeprecated },
220 { "userknownhostsfile", oUserKnownHostsFile },
Adam Langleyd0592972015-03-30 14:49:51 -0700221 { "userknownhostsfile2", oDeprecated },
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800222 { "connectionattempts", oConnectionAttempts },
223 { "batchmode", oBatchMode },
224 { "checkhostip", oCheckHostIP },
225 { "stricthostkeychecking", oStrictHostKeyChecking },
226 { "compression", oCompression },
227 { "compressionlevel", oCompressionLevel },
228 { "tcpkeepalive", oTCPKeepAlive },
229 { "keepalive", oTCPKeepAlive }, /* obsolete */
230 { "numberofpasswordprompts", oNumberOfPasswordPrompts },
231 { "loglevel", oLogLevel },
232 { "dynamicforward", oDynamicForward },
233 { "preferredauthentications", oPreferredAuthentications },
234 { "hostkeyalgorithms", oHostKeyAlgorithms },
235 { "bindaddress", oBindAddress },
236#ifdef ENABLE_PKCS11
237 { "smartcarddevice", oPKCS11Provider },
238 { "pkcs11provider", oPKCS11Provider },
239#else
240 { "smartcarddevice", oUnsupported },
241 { "pkcs11provider", oUnsupported },
242#endif
243 { "clearallforwardings", oClearAllForwardings },
244 { "enablesshkeysign", oEnableSSHKeysign },
245 { "verifyhostkeydns", oVerifyHostKeyDNS },
246 { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
247 { "rekeylimit", oRekeyLimit },
248 { "connecttimeout", oConnectTimeout },
249 { "addressfamily", oAddressFamily },
250 { "serveraliveinterval", oServerAliveInterval },
251 { "serveralivecountmax", oServerAliveCountMax },
252 { "sendenv", oSendEnv },
253 { "controlpath", oControlPath },
254 { "controlmaster", oControlMaster },
255 { "controlpersist", oControlPersist },
256 { "hashknownhosts", oHashKnownHosts },
257 { "tunnel", oTunnel },
258 { "tunneldevice", oTunnelDevice },
259 { "localcommand", oLocalCommand },
260 { "permitlocalcommand", oPermitLocalCommand },
261 { "visualhostkey", oVisualHostKey },
262 { "useroaming", oUseRoaming },
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800263 { "kexalgorithms", oKexAlgorithms },
264 { "ipqos", oIPQoS },
265 { "requesttty", oRequestTTY },
Adam Langleyd0592972015-03-30 14:49:51 -0700266 { "proxyusefdpass", oProxyUseFdpass },
267 { "canonicaldomains", oCanonicalDomains },
268 { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
269 { "canonicalizehostname", oCanonicalizeHostname },
270 { "canonicalizemaxdots", oCanonicalizeMaxDots },
271 { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
272 { "streamlocalbindmask", oStreamLocalBindMask },
273 { "streamlocalbindunlink", oStreamLocalBindUnlink },
274 { "revokedhostkeys", oRevokedHostKeys },
275 { "fingerprinthash", oFingerprintHash },
276 { "updatehostkeys", oUpdateHostkeys },
277 { "hostbasedkeytypes", oHostbasedKeyTypes },
278 { "ignoreunknown", oIgnoreUnknown },
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800279
280 { NULL, oBadOption }
281};
282
283/*
284 * Adds a local TCP/IP port forward to options. Never returns if there is an
285 * error.
286 */
287
288void
Adam Langleyd0592972015-03-30 14:49:51 -0700289add_local_forward(Options *options, const struct Forward *newfwd)
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800290{
Adam Langleyd0592972015-03-30 14:49:51 -0700291 struct Forward *fwd;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800292#ifndef NO_IPPORT_RESERVED_CONCEPT
293 extern uid_t original_real_uid;
Adam Langleyd0592972015-03-30 14:49:51 -0700294 if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0 &&
295 newfwd->listen_path == NULL)
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800296 fatal("Privileged ports can only be forwarded by root.");
297#endif
298 options->local_forwards = xrealloc(options->local_forwards,
299 options->num_local_forwards + 1,
300 sizeof(*options->local_forwards));
301 fwd = &options->local_forwards[options->num_local_forwards++];
302
303 fwd->listen_host = newfwd->listen_host;
304 fwd->listen_port = newfwd->listen_port;
Adam Langleyd0592972015-03-30 14:49:51 -0700305 fwd->listen_path = newfwd->listen_path;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800306 fwd->connect_host = newfwd->connect_host;
307 fwd->connect_port = newfwd->connect_port;
Adam Langleyd0592972015-03-30 14:49:51 -0700308 fwd->connect_path = newfwd->connect_path;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800309}
310
311/*
312 * Adds a remote TCP/IP port forward to options. Never returns if there is
313 * an error.
314 */
315
316void
Adam Langleyd0592972015-03-30 14:49:51 -0700317add_remote_forward(Options *options, const struct Forward *newfwd)
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800318{
Adam Langleyd0592972015-03-30 14:49:51 -0700319 struct Forward *fwd;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800320
321 options->remote_forwards = xrealloc(options->remote_forwards,
322 options->num_remote_forwards + 1,
323 sizeof(*options->remote_forwards));
324 fwd = &options->remote_forwards[options->num_remote_forwards++];
325
326 fwd->listen_host = newfwd->listen_host;
327 fwd->listen_port = newfwd->listen_port;
Adam Langleyd0592972015-03-30 14:49:51 -0700328 fwd->listen_path = newfwd->listen_path;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800329 fwd->connect_host = newfwd->connect_host;
330 fwd->connect_port = newfwd->connect_port;
Adam Langleyd0592972015-03-30 14:49:51 -0700331 fwd->connect_path = newfwd->connect_path;
332 fwd->handle = newfwd->handle;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800333 fwd->allocated_port = 0;
334}
335
336static void
337clear_forwardings(Options *options)
338{
339 int i;
340
341 for (i = 0; i < options->num_local_forwards; i++) {
Adam Langleyd0592972015-03-30 14:49:51 -0700342 free(options->local_forwards[i].listen_host);
343 free(options->local_forwards[i].listen_path);
344 free(options->local_forwards[i].connect_host);
345 free(options->local_forwards[i].connect_path);
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800346 }
347 if (options->num_local_forwards > 0) {
Adam Langleyd0592972015-03-30 14:49:51 -0700348 free(options->local_forwards);
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800349 options->local_forwards = NULL;
350 }
351 options->num_local_forwards = 0;
352 for (i = 0; i < options->num_remote_forwards; i++) {
Adam Langleyd0592972015-03-30 14:49:51 -0700353 free(options->remote_forwards[i].listen_host);
354 free(options->remote_forwards[i].listen_path);
355 free(options->remote_forwards[i].connect_host);
356 free(options->remote_forwards[i].connect_path);
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800357 }
358 if (options->num_remote_forwards > 0) {
Adam Langleyd0592972015-03-30 14:49:51 -0700359 free(options->remote_forwards);
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800360 options->remote_forwards = NULL;
361 }
362 options->num_remote_forwards = 0;
363 options->tun_open = SSH_TUNMODE_NO;
364}
365
Adam Langleyd0592972015-03-30 14:49:51 -0700366void
367add_identity_file(Options *options, const char *dir, const char *filename,
368 int userprovided)
369{
370 char *path;
371 int i;
372
373 if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
374 fatal("Too many identity files specified (max %d)",
375 SSH_MAX_IDENTITY_FILES);
376
377 if (dir == NULL) /* no dir, filename is absolute */
378 path = xstrdup(filename);
379 else
380 (void)xasprintf(&path, "%.100s%.100s", dir, filename);
381
382 /* Avoid registering duplicates */
383 for (i = 0; i < options->num_identity_files; i++) {
384 if (options->identity_file_userprovided[i] == userprovided &&
385 strcmp(options->identity_files[i], path) == 0) {
386 debug2("%s: ignoring duplicate key %s", __func__, path);
387 free(path);
388 return;
389 }
390 }
391
392 options->identity_file_userprovided[options->num_identity_files] =
393 userprovided;
394 options->identity_files[options->num_identity_files++] = path;
395}
396
397int
398default_ssh_port(void)
399{
400 static int port;
401 struct servent *sp;
402
403 if (port == 0) {
404 sp = getservbyname(SSH_SERVICE_NAME, "tcp");
405 port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
406 }
407 return port;
408}
409
410/*
411 * Execute a command in a shell.
412 * Return its exit status or -1 on abnormal exit.
413 */
414static int
415execute_in_shell(const char *cmd)
416{
417 char *shell, *command_string;
418 pid_t pid;
419 int devnull, status;
420 extern uid_t original_real_uid;
421
422 if ((shell = getenv("SHELL")) == NULL)
423 shell = _PATH_BSHELL;
424
425 /*
426 * Use "exec" to avoid "sh -c" processes on some platforms
427 * (e.g. Solaris)
428 */
429 xasprintf(&command_string, "exec %s", cmd);
430
431 /* Need this to redirect subprocess stdin/out */
432 if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1)
433 fatal("open(/dev/null): %s", strerror(errno));
434
435 debug("Executing command: '%.500s'", cmd);
436
437 /* Fork and execute the command. */
438 if ((pid = fork()) == 0) {
439 char *argv[4];
440
441 /* Child. Permanently give up superuser privileges. */
442 permanently_drop_suid(original_real_uid);
443
444 /* Redirect child stdin and stdout. Leave stderr */
445 if (dup2(devnull, STDIN_FILENO) == -1)
446 fatal("dup2: %s", strerror(errno));
447 if (dup2(devnull, STDOUT_FILENO) == -1)
448 fatal("dup2: %s", strerror(errno));
449 if (devnull > STDERR_FILENO)
450 close(devnull);
451 closefrom(STDERR_FILENO + 1);
452
453 argv[0] = shell;
454 argv[1] = "-c";
455 argv[2] = command_string;
456 argv[3] = NULL;
457
458 execv(argv[0], argv);
459 error("Unable to execute '%.100s': %s", cmd, strerror(errno));
460 /* Die with signal to make this error apparent to parent. */
461 signal(SIGTERM, SIG_DFL);
462 kill(getpid(), SIGTERM);
463 _exit(1);
464 }
465 /* Parent. */
466 if (pid < 0)
467 fatal("%s: fork: %.100s", __func__, strerror(errno));
468
469 close(devnull);
470 free(command_string);
471
472 while (waitpid(pid, &status, 0) == -1) {
473 if (errno != EINTR && errno != EAGAIN)
474 fatal("%s: waitpid: %s", __func__, strerror(errno));
475 }
476 if (!WIFEXITED(status)) {
477 error("command '%.100s' exited abnormally", cmd);
478 return -1;
479 }
480 debug3("command returned status %d", WEXITSTATUS(status));
481 return WEXITSTATUS(status);
482}
483
484/*
485 * Parse and execute a Match directive.
486 */
487static int
488match_cfg_line(Options *options, char **condition, struct passwd *pw,
489 const char *host_arg, const char *original_host, int post_canon,
490 const char *filename, int linenum)
491{
492 char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria;
493 const char *ruser;
494 int r, port, this_result, result = 1, attributes = 0, negate;
495 size_t len;
496 char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
497
498 /*
499 * Configuration is likely to be incomplete at this point so we
500 * must be prepared to use default values.
501 */
502 port = options->port <= 0 ? default_ssh_port() : options->port;
503 ruser = options->user == NULL ? pw->pw_name : options->user;
504 if (options->hostname != NULL) {
505 /* NB. Please keep in sync with ssh.c:main() */
506 host = percent_expand(options->hostname,
507 "h", host_arg, (char *)NULL);
508 } else
509 host = xstrdup(host_arg);
510
511 debug2("checking match for '%s' host %s originally %s",
512 cp, host, original_host);
513 while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') {
514 criteria = NULL;
515 this_result = 1;
516 if ((negate = attrib[0] == '!'))
517 attrib++;
518 /* criteria "all" and "canonical" have no argument */
519 if (strcasecmp(attrib, "all") == 0) {
520 if (attributes > 1 ||
521 ((arg = strdelim(&cp)) != NULL && *arg != '\0')) {
522 error("%.200s line %d: '%s' cannot be combined "
523 "with other Match attributes",
524 filename, linenum, oattrib);
525 result = -1;
526 goto out;
527 }
528 if (result)
529 result = negate ? 0 : 1;
530 goto out;
531 }
532 attributes++;
533 if (strcasecmp(attrib, "canonical") == 0) {
534 r = !!post_canon; /* force bitmask member to boolean */
535 if (r == (negate ? 1 : 0))
536 this_result = result = 0;
537 debug3("%.200s line %d: %smatched '%s'",
538 filename, linenum,
539 this_result ? "" : "not ", oattrib);
540 continue;
541 }
542 /* All other criteria require an argument */
543 if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
544 error("Missing Match criteria for %s", attrib);
545 result = -1;
546 goto out;
547 }
548 len = strlen(arg);
549 if (strcasecmp(attrib, "host") == 0) {
550 criteria = xstrdup(host);
551 r = match_hostname(host, arg, len) == 1;
552 if (r == (negate ? 1 : 0))
553 this_result = result = 0;
554 } else if (strcasecmp(attrib, "originalhost") == 0) {
555 criteria = xstrdup(original_host);
556 r = match_hostname(original_host, arg, len) == 1;
557 if (r == (negate ? 1 : 0))
558 this_result = result = 0;
559 } else if (strcasecmp(attrib, "user") == 0) {
560 criteria = xstrdup(ruser);
561 r = match_pattern_list(ruser, arg, len, 0) == 1;
562 if (r == (negate ? 1 : 0))
563 this_result = result = 0;
564 } else if (strcasecmp(attrib, "localuser") == 0) {
565 criteria = xstrdup(pw->pw_name);
566 r = match_pattern_list(pw->pw_name, arg, len, 0) == 1;
567 if (r == (negate ? 1 : 0))
568 this_result = result = 0;
569 } else if (strcasecmp(attrib, "exec") == 0) {
570 if (gethostname(thishost, sizeof(thishost)) == -1)
571 fatal("gethostname: %s", strerror(errno));
572 strlcpy(shorthost, thishost, sizeof(shorthost));
573 shorthost[strcspn(thishost, ".")] = '\0';
574 snprintf(portstr, sizeof(portstr), "%d", port);
575
576 cmd = percent_expand(arg,
577 "L", shorthost,
578 "d", pw->pw_dir,
579 "h", host,
580 "l", thishost,
581 "n", original_host,
582 "p", portstr,
583 "r", ruser,
584 "u", pw->pw_name,
585 (char *)NULL);
586 if (result != 1) {
587 /* skip execution if prior predicate failed */
588 debug3("%.200s line %d: skipped exec "
589 "\"%.100s\"", filename, linenum, cmd);
590 free(cmd);
591 continue;
592 }
593 r = execute_in_shell(cmd);
594 if (r == -1) {
595 fatal("%.200s line %d: match exec "
596 "'%.100s' error", filename,
597 linenum, cmd);
598 }
599 criteria = xstrdup(cmd);
600 free(cmd);
601 /* Force exit status to boolean */
602 r = r == 0;
603 if (r == (negate ? 1 : 0))
604 this_result = result = 0;
605 } else {
606 error("Unsupported Match attribute %s", attrib);
607 result = -1;
608 goto out;
609 }
610 debug3("%.200s line %d: %smatched '%s \"%.100s\"' ",
611 filename, linenum, this_result ? "": "not ",
612 oattrib, criteria);
613 free(criteria);
614 }
615 if (attributes == 0) {
616 error("One or more attributes required for Match");
617 result = -1;
618 goto out;
619 }
620 out:
621 if (result != -1)
622 debug2("match %sfound", result ? "" : "not ");
623 *condition = cp;
624 free(host);
625 return result;
626}
627
628/* Check and prepare a domain name: removes trailing '.' and lowercases */
629static void
630valid_domain(char *name, const char *filename, int linenum)
631{
632 size_t i, l = strlen(name);
633 u_char c, last = '\0';
634
635 if (l == 0)
636 fatal("%s line %d: empty hostname suffix", filename, linenum);
637 if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0]))
638 fatal("%s line %d: hostname suffix \"%.100s\" "
639 "starts with invalid character", filename, linenum, name);
640 for (i = 0; i < l; i++) {
641 c = tolower((u_char)name[i]);
642 name[i] = (char)c;
643 if (last == '.' && c == '.')
644 fatal("%s line %d: hostname suffix \"%.100s\" contains "
645 "consecutive separators", filename, linenum, name);
646 if (c != '.' && c != '-' && !isalnum(c) &&
647 c != '_') /* technically invalid, but common */
648 fatal("%s line %d: hostname suffix \"%.100s\" contains "
649 "invalid characters", filename, linenum, name);
650 last = c;
651 }
652 if (name[l - 1] == '.')
653 name[l - 1] = '\0';
654}
655
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800656/*
657 * Returns the number of the token pointed to by cp or oBadOption.
658 */
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800659static OpCodes
Adam Langleyd0592972015-03-30 14:49:51 -0700660parse_token(const char *cp, const char *filename, int linenum,
661 const char *ignored_unknown)
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800662{
Adam Langleyd0592972015-03-30 14:49:51 -0700663 int i;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800664
665 for (i = 0; keywords[i].name; i++)
Adam Langleyd0592972015-03-30 14:49:51 -0700666 if (strcmp(cp, keywords[i].name) == 0)
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800667 return keywords[i].opcode;
Adam Langleyd0592972015-03-30 14:49:51 -0700668 if (ignored_unknown != NULL && match_pattern_list(cp, ignored_unknown,
669 strlen(ignored_unknown), 1) == 1)
670 return oIgnoredUnknownOption;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800671 error("%s: line %d: Bad configuration option: %s",
672 filename, linenum, cp);
673 return oBadOption;
674}
675
Adam Langleyd0592972015-03-30 14:49:51 -0700676/* Multistate option parsing */
677struct multistate {
678 char *key;
679 int value;
680};
681static const struct multistate multistate_flag[] = {
682 { "true", 1 },
683 { "false", 0 },
684 { "yes", 1 },
685 { "no", 0 },
686 { NULL, -1 }
687};
688static const struct multistate multistate_yesnoask[] = {
689 { "true", 1 },
690 { "false", 0 },
691 { "yes", 1 },
692 { "no", 0 },
693 { "ask", 2 },
694 { NULL, -1 }
695};
696static const struct multistate multistate_addressfamily[] = {
697 { "inet", AF_INET },
698 { "inet6", AF_INET6 },
699 { "any", AF_UNSPEC },
700 { NULL, -1 }
701};
702static const struct multistate multistate_controlmaster[] = {
703 { "true", SSHCTL_MASTER_YES },
704 { "yes", SSHCTL_MASTER_YES },
705 { "false", SSHCTL_MASTER_NO },
706 { "no", SSHCTL_MASTER_NO },
707 { "auto", SSHCTL_MASTER_AUTO },
708 { "ask", SSHCTL_MASTER_ASK },
709 { "autoask", SSHCTL_MASTER_AUTO_ASK },
710 { NULL, -1 }
711};
712static const struct multistate multistate_tunnel[] = {
713 { "ethernet", SSH_TUNMODE_ETHERNET },
714 { "point-to-point", SSH_TUNMODE_POINTOPOINT },
715 { "true", SSH_TUNMODE_DEFAULT },
716 { "yes", SSH_TUNMODE_DEFAULT },
717 { "false", SSH_TUNMODE_NO },
718 { "no", SSH_TUNMODE_NO },
719 { NULL, -1 }
720};
721static const struct multistate multistate_requesttty[] = {
722 { "true", REQUEST_TTY_YES },
723 { "yes", REQUEST_TTY_YES },
724 { "false", REQUEST_TTY_NO },
725 { "no", REQUEST_TTY_NO },
726 { "force", REQUEST_TTY_FORCE },
727 { "auto", REQUEST_TTY_AUTO },
728 { NULL, -1 }
729};
730static const struct multistate multistate_canonicalizehostname[] = {
731 { "true", SSH_CANONICALISE_YES },
732 { "false", SSH_CANONICALISE_NO },
733 { "yes", SSH_CANONICALISE_YES },
734 { "no", SSH_CANONICALISE_NO },
735 { "always", SSH_CANONICALISE_ALWAYS },
736 { NULL, -1 }
737};
738
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800739/*
740 * Processes a single option line as used in the configuration files. This
741 * only sets those values that have not already been set.
742 */
743#define WHITESPACE " \t\r\n"
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800744int
Adam Langleyd0592972015-03-30 14:49:51 -0700745process_config_line(Options *options, struct passwd *pw, const char *host,
746 const char *original_host, char *line, const char *filename,
747 int linenum, int *activep, int flags)
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800748{
749 char *s, **charptr, *endofnumber, *keyword, *arg, *arg2;
750 char **cpptr, fwdarg[256];
Adam Langleyd0592972015-03-30 14:49:51 -0700751 u_int i, *uintptr, max_entries = 0;
752 int negated, opcode, *intptr, value, value2, cmdline = 0;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800753 LogLevel *log_level_ptr;
Adam Langleyd0592972015-03-30 14:49:51 -0700754 long long val64;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800755 size_t len;
Adam Langleyd0592972015-03-30 14:49:51 -0700756 struct Forward fwd;
757 const struct multistate *multistate_ptr;
758 struct allowed_cname *cname;
759
760 if (activep == NULL) { /* We are processing a command line directive */
761 cmdline = 1;
762 activep = &cmdline;
763 }
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800764
765 /* Strip trailing whitespace */
766 for (len = strlen(line) - 1; len > 0; len--) {
767 if (strchr(WHITESPACE, line[len]) == NULL)
768 break;
769 line[len] = '\0';
770 }
771
772 s = line;
773 /* Get the keyword. (Each line is supposed to begin with a keyword). */
774 if ((keyword = strdelim(&s)) == NULL)
775 return 0;
776 /* Ignore leading whitespace. */
777 if (*keyword == '\0')
778 keyword = strdelim(&s);
779 if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
780 return 0;
Adam Langleyd0592972015-03-30 14:49:51 -0700781 /* Match lowercase keyword */
782 lowercase(keyword);
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800783
Adam Langleyd0592972015-03-30 14:49:51 -0700784 opcode = parse_token(keyword, filename, linenum,
785 options->ignored_unknown);
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800786
787 switch (opcode) {
788 case oBadOption:
789 /* don't panic, but count bad options */
790 return -1;
791 /* NOTREACHED */
Adam Langleyd0592972015-03-30 14:49:51 -0700792 case oIgnoredUnknownOption:
793 debug("%s line %d: Ignored unknown option \"%s\"",
794 filename, linenum, keyword);
795 return 0;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800796 case oConnectTimeout:
797 intptr = &options->connection_timeout;
798parse_time:
799 arg = strdelim(&s);
800 if (!arg || *arg == '\0')
801 fatal("%s line %d: missing time value.",
802 filename, linenum);
Adam Langleyd0592972015-03-30 14:49:51 -0700803 if (strcmp(arg, "none") == 0)
804 value = -1;
805 else if ((value = convtime(arg)) == -1)
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800806 fatal("%s line %d: invalid time value.",
807 filename, linenum);
808 if (*activep && *intptr == -1)
809 *intptr = value;
810 break;
811
812 case oForwardAgent:
813 intptr = &options->forward_agent;
Adam Langleyd0592972015-03-30 14:49:51 -0700814 parse_flag:
815 multistate_ptr = multistate_flag;
816 parse_multistate:
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800817 arg = strdelim(&s);
818 if (!arg || *arg == '\0')
Adam Langleyd0592972015-03-30 14:49:51 -0700819 fatal("%s line %d: missing argument.",
820 filename, linenum);
821 value = -1;
822 for (i = 0; multistate_ptr[i].key != NULL; i++) {
823 if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
824 value = multistate_ptr[i].value;
825 break;
826 }
827 }
828 if (value == -1)
829 fatal("%s line %d: unsupported option \"%s\".",
830 filename, linenum, arg);
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800831 if (*activep && *intptr == -1)
832 *intptr = value;
833 break;
834
835 case oForwardX11:
836 intptr = &options->forward_x11;
837 goto parse_flag;
838
839 case oForwardX11Trusted:
840 intptr = &options->forward_x11_trusted;
841 goto parse_flag;
Adam Langleyd0592972015-03-30 14:49:51 -0700842
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800843 case oForwardX11Timeout:
844 intptr = &options->forward_x11_timeout;
845 goto parse_time;
846
847 case oGatewayPorts:
Adam Langleyd0592972015-03-30 14:49:51 -0700848 intptr = &options->fwd_opts.gateway_ports;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800849 goto parse_flag;
850
851 case oExitOnForwardFailure:
852 intptr = &options->exit_on_forward_failure;
853 goto parse_flag;
854
855 case oUsePrivilegedPort:
856 intptr = &options->use_privileged_port;
857 goto parse_flag;
858
859 case oPasswordAuthentication:
860 intptr = &options->password_authentication;
861 goto parse_flag;
862
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800863 case oKbdInteractiveAuthentication:
864 intptr = &options->kbd_interactive_authentication;
865 goto parse_flag;
866
867 case oKbdInteractiveDevices:
868 charptr = &options->kbd_interactive_devices;
869 goto parse_string;
870
871 case oPubkeyAuthentication:
872 intptr = &options->pubkey_authentication;
873 goto parse_flag;
874
875 case oRSAAuthentication:
876 intptr = &options->rsa_authentication;
877 goto parse_flag;
878
879 case oRhostsRSAAuthentication:
880 intptr = &options->rhosts_rsa_authentication;
881 goto parse_flag;
882
883 case oHostbasedAuthentication:
884 intptr = &options->hostbased_authentication;
885 goto parse_flag;
886
887 case oChallengeResponseAuthentication:
888 intptr = &options->challenge_response_authentication;
889 goto parse_flag;
890
891 case oGssAuthentication:
892 intptr = &options->gss_authentication;
893 goto parse_flag;
894
895 case oGssDelegateCreds:
896 intptr = &options->gss_deleg_creds;
897 goto parse_flag;
898
899 case oBatchMode:
900 intptr = &options->batch_mode;
901 goto parse_flag;
902
903 case oCheckHostIP:
904 intptr = &options->check_host_ip;
905 goto parse_flag;
906
907 case oVerifyHostKeyDNS:
908 intptr = &options->verify_host_key_dns;
Adam Langleyd0592972015-03-30 14:49:51 -0700909 multistate_ptr = multistate_yesnoask;
910 goto parse_multistate;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800911
912 case oStrictHostKeyChecking:
913 intptr = &options->strict_host_key_checking;
Adam Langleyd0592972015-03-30 14:49:51 -0700914 multistate_ptr = multistate_yesnoask;
915 goto parse_multistate;
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800916
917 case oCompression:
918 intptr = &options->compression;
919 goto parse_flag;
920
921 case oTCPKeepAlive:
922 intptr = &options->tcp_keep_alive;
923 goto parse_flag;
924
925 case oNoHostAuthenticationForLocalhost:
926 intptr = &options->no_host_authentication_for_localhost;
927 goto parse_flag;
928
929 case oNumberOfPasswordPrompts:
930 intptr = &options->number_of_password_prompts;
931 goto parse_int;
932
933 case oCompressionLevel:
934 intptr = &options->compression_level;
935 goto parse_int;
936
937 case oRekeyLimit:
938 arg = strdelim(&s);
939 if (!arg || *arg == '\0')
Adam Langleyd0592972015-03-30 14:49:51 -0700940 fatal("%.200s line %d: Missing argument.", filename,
941 linenum);
942 if (strcmp(arg, "default") == 0) {
943 val64 = 0;
944 } else {
945 if (scan_scaled(arg, &val64) == -1)
946 fatal("%.200s line %d: Bad number '%s': %s",
947 filename, linenum, arg, strerror(errno));
948 /* check for too-large or too-small limits */
949 if (val64 > UINT_MAX)
950 fatal("%.200s line %d: RekeyLimit too large",
951 filename, linenum);
952 if (val64 != 0 && val64 < 16)
953 fatal("%.200s line %d: RekeyLimit too small",
954 filename, linenum);
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800955 }
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800956 if (*activep && options->rekey_limit == -1)
957 options->rekey_limit = (u_int32_t)val64;
Adam Langleyd0592972015-03-30 14:49:51 -0700958 if (s != NULL) { /* optional rekey interval present */
959 if (strcmp(s, "none") == 0) {
960 (void)strdelim(&s); /* discard */
961 break;
962 }
963 intptr = &options->rekey_interval;
964 goto parse_time;
965 }
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800966 break;
967
968 case oIdentityFile:
969 arg = strdelim(&s);
970 if (!arg || *arg == '\0')
971 fatal("%.200s line %d: Missing argument.", filename, linenum);
972 if (*activep) {
973 intptr = &options->num_identity_files;
974 if (*intptr >= SSH_MAX_IDENTITY_FILES)
975 fatal("%.200s line %d: Too many identity files specified (max %d).",
976 filename, linenum, SSH_MAX_IDENTITY_FILES);
Adam Langleyd0592972015-03-30 14:49:51 -0700977 add_identity_file(options, NULL,
978 arg, flags & SSHCONF_USERCONF);
Greg Hartmanbd77cf72015-02-25 13:21:06 -0800979 }
980 break;
981
982 case oXAuthLocation:
983 charptr=&options->xauth_location;
984 goto parse_string;
985
986 case oUser:
987 charptr = &options->user;
988parse_string:
989 arg = strdelim(&s);
990 if (!arg || *arg == '\0')
991 fatal("%.200s line %d: Missing argument.",
992 filename, linenum);
993 if (*activep && *charptr == NULL)
994 *charptr = xstrdup(arg);
995 break;
996
997 case oGlobalKnownHostsFile:
998 cpptr = (char **)&options->system_hostfiles;
999 uintptr = &options->num_system_hostfiles;
1000 max_entries = SSH_MAX_HOSTS_FILES;
1001parse_char_array:
1002 if (*activep && *uintptr == 0) {
1003 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1004 if ((*uintptr) >= max_entries)
1005 fatal("%s line %d: "
1006 "too many authorized keys files.",
1007 filename, linenum);
1008 cpptr[(*uintptr)++] = xstrdup(arg);
1009 }
1010 }
1011 return 0;
1012
1013 case oUserKnownHostsFile:
1014 cpptr = (char **)&options->user_hostfiles;
1015 uintptr = &options->num_user_hostfiles;
1016 max_entries = SSH_MAX_HOSTS_FILES;
1017 goto parse_char_array;
1018
1019 case oHostName:
1020 charptr = &options->hostname;
1021 goto parse_string;
1022
1023 case oHostKeyAlias:
1024 charptr = &options->host_key_alias;
1025 goto parse_string;
1026
1027 case oPreferredAuthentications:
1028 charptr = &options->preferred_authentications;
1029 goto parse_string;
1030
1031 case oBindAddress:
1032 charptr = &options->bind_address;
1033 goto parse_string;
1034
1035 case oPKCS11Provider:
1036 charptr = &options->pkcs11_provider;
1037 goto parse_string;
1038
1039 case oProxyCommand:
1040 charptr = &options->proxy_command;
1041parse_command:
1042 if (s == NULL)
1043 fatal("%.200s line %d: Missing argument.", filename, linenum);
1044 len = strspn(s, WHITESPACE "=");
1045 if (*activep && *charptr == NULL)
1046 *charptr = xstrdup(s + len);
1047 return 0;
1048
1049 case oPort:
1050 intptr = &options->port;
1051parse_int:
1052 arg = strdelim(&s);
1053 if (!arg || *arg == '\0')
1054 fatal("%.200s line %d: Missing argument.", filename, linenum);
1055 if (arg[0] < '0' || arg[0] > '9')
1056 fatal("%.200s line %d: Bad number.", filename, linenum);
1057
1058 /* Octal, decimal, or hex format? */
1059 value = strtol(arg, &endofnumber, 0);
1060 if (arg == endofnumber)
1061 fatal("%.200s line %d: Bad number.", filename, linenum);
1062 if (*activep && *intptr == -1)
1063 *intptr = value;
1064 break;
1065
1066 case oConnectionAttempts:
1067 intptr = &options->connection_attempts;
1068 goto parse_int;
1069
1070 case oCipher:
1071 intptr = &options->cipher;
1072 arg = strdelim(&s);
1073 if (!arg || *arg == '\0')
1074 fatal("%.200s line %d: Missing argument.", filename, linenum);
1075 value = cipher_number(arg);
1076 if (value == -1)
1077 fatal("%.200s line %d: Bad cipher '%s'.",
1078 filename, linenum, arg ? arg : "<NONE>");
1079 if (*activep && *intptr == -1)
1080 *intptr = value;
1081 break;
1082
1083 case oCiphers:
1084 arg = strdelim(&s);
1085 if (!arg || *arg == '\0')
1086 fatal("%.200s line %d: Missing argument.", filename, linenum);
1087 if (!ciphers_valid(arg))
1088 fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
1089 filename, linenum, arg ? arg : "<NONE>");
1090 if (*activep && options->ciphers == NULL)
1091 options->ciphers = xstrdup(arg);
1092 break;
1093
1094 case oMacs:
1095 arg = strdelim(&s);
1096 if (!arg || *arg == '\0')
1097 fatal("%.200s line %d: Missing argument.", filename, linenum);
1098 if (!mac_valid(arg))
1099 fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
1100 filename, linenum, arg ? arg : "<NONE>");
1101 if (*activep && options->macs == NULL)
1102 options->macs = xstrdup(arg);
1103 break;
1104
1105 case oKexAlgorithms:
1106 arg = strdelim(&s);
1107 if (!arg || *arg == '\0')
1108 fatal("%.200s line %d: Missing argument.",
1109 filename, linenum);
1110 if (!kex_names_valid(arg))
1111 fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
1112 filename, linenum, arg ? arg : "<NONE>");
1113 if (*activep && options->kex_algorithms == NULL)
1114 options->kex_algorithms = xstrdup(arg);
1115 break;
1116
1117 case oHostKeyAlgorithms:
1118 arg = strdelim(&s);
1119 if (!arg || *arg == '\0')
1120 fatal("%.200s line %d: Missing argument.", filename, linenum);
Adam Langleyd0592972015-03-30 14:49:51 -07001121 if (!sshkey_names_valid2(arg, 1))
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001122 fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
1123 filename, linenum, arg ? arg : "<NONE>");
1124 if (*activep && options->hostkeyalgorithms == NULL)
1125 options->hostkeyalgorithms = xstrdup(arg);
1126 break;
1127
1128 case oProtocol:
1129 intptr = &options->protocol;
1130 arg = strdelim(&s);
1131 if (!arg || *arg == '\0')
1132 fatal("%.200s line %d: Missing argument.", filename, linenum);
1133 value = proto_spec(arg);
1134 if (value == SSH_PROTO_UNKNOWN)
1135 fatal("%.200s line %d: Bad protocol spec '%s'.",
1136 filename, linenum, arg ? arg : "<NONE>");
1137 if (*activep && *intptr == SSH_PROTO_UNKNOWN)
1138 *intptr = value;
1139 break;
1140
1141 case oLogLevel:
1142 log_level_ptr = &options->log_level;
1143 arg = strdelim(&s);
1144 value = log_level_number(arg);
1145 if (value == SYSLOG_LEVEL_NOT_SET)
1146 fatal("%.200s line %d: unsupported log level '%s'",
1147 filename, linenum, arg ? arg : "<NONE>");
1148 if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
1149 *log_level_ptr = (LogLevel) value;
1150 break;
1151
1152 case oLocalForward:
1153 case oRemoteForward:
1154 case oDynamicForward:
1155 arg = strdelim(&s);
1156 if (arg == NULL || *arg == '\0')
1157 fatal("%.200s line %d: Missing port argument.",
1158 filename, linenum);
1159
1160 if (opcode == oLocalForward ||
1161 opcode == oRemoteForward) {
1162 arg2 = strdelim(&s);
1163 if (arg2 == NULL || *arg2 == '\0')
1164 fatal("%.200s line %d: Missing target argument.",
1165 filename, linenum);
1166
1167 /* construct a string for parse_forward */
1168 snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
1169 } else if (opcode == oDynamicForward) {
1170 strlcpy(fwdarg, arg, sizeof(fwdarg));
1171 }
1172
1173 if (parse_forward(&fwd, fwdarg,
1174 opcode == oDynamicForward ? 1 : 0,
1175 opcode == oRemoteForward ? 1 : 0) == 0)
1176 fatal("%.200s line %d: Bad forwarding specification.",
1177 filename, linenum);
1178
1179 if (*activep) {
1180 if (opcode == oLocalForward ||
1181 opcode == oDynamicForward)
1182 add_local_forward(options, &fwd);
1183 else if (opcode == oRemoteForward)
1184 add_remote_forward(options, &fwd);
1185 }
1186 break;
1187
1188 case oClearAllForwardings:
1189 intptr = &options->clear_forwardings;
1190 goto parse_flag;
1191
1192 case oHost:
Adam Langleyd0592972015-03-30 14:49:51 -07001193 if (cmdline)
1194 fatal("Host directive not supported as a command-line "
1195 "option");
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001196 *activep = 0;
1197 arg2 = NULL;
1198 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1199 negated = *arg == '!';
1200 if (negated)
1201 arg++;
1202 if (match_pattern(host, arg)) {
1203 if (negated) {
1204 debug("%.200s line %d: Skipping Host "
1205 "block because of negated match "
1206 "for %.100s", filename, linenum,
1207 arg);
1208 *activep = 0;
1209 break;
1210 }
1211 if (!*activep)
1212 arg2 = arg; /* logged below */
1213 *activep = 1;
1214 }
1215 }
1216 if (*activep)
1217 debug("%.200s line %d: Applying options for %.100s",
1218 filename, linenum, arg2);
1219 /* Avoid garbage check below, as strdelim is done. */
1220 return 0;
1221
Adam Langleyd0592972015-03-30 14:49:51 -07001222 case oMatch:
1223 if (cmdline)
1224 fatal("Host directive not supported as a command-line "
1225 "option");
1226 value = match_cfg_line(options, &s, pw, host, original_host,
1227 flags & SSHCONF_POSTCANON, filename, linenum);
1228 if (value < 0)
1229 fatal("%.200s line %d: Bad Match condition", filename,
1230 linenum);
1231 *activep = value;
1232 break;
1233
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001234 case oEscapeChar:
1235 intptr = &options->escape_char;
1236 arg = strdelim(&s);
1237 if (!arg || *arg == '\0')
1238 fatal("%.200s line %d: Missing argument.", filename, linenum);
1239 if (arg[0] == '^' && arg[2] == 0 &&
1240 (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
1241 value = (u_char) arg[1] & 31;
1242 else if (strlen(arg) == 1)
1243 value = (u_char) arg[0];
1244 else if (strcmp(arg, "none") == 0)
1245 value = SSH_ESCAPECHAR_NONE;
1246 else {
1247 fatal("%.200s line %d: Bad escape character.",
1248 filename, linenum);
1249 /* NOTREACHED */
1250 value = 0; /* Avoid compiler warning. */
1251 }
1252 if (*activep && *intptr == -1)
1253 *intptr = value;
1254 break;
1255
1256 case oAddressFamily:
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001257 intptr = &options->address_family;
Adam Langleyd0592972015-03-30 14:49:51 -07001258 multistate_ptr = multistate_addressfamily;
1259 goto parse_multistate;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001260
1261 case oEnableSSHKeysign:
1262 intptr = &options->enable_ssh_keysign;
1263 goto parse_flag;
1264
1265 case oIdentitiesOnly:
1266 intptr = &options->identities_only;
1267 goto parse_flag;
1268
1269 case oServerAliveInterval:
1270 intptr = &options->server_alive_interval;
1271 goto parse_time;
1272
1273 case oServerAliveCountMax:
1274 intptr = &options->server_alive_count_max;
1275 goto parse_int;
1276
1277 case oSendEnv:
1278 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1279 if (strchr(arg, '=') != NULL)
1280 fatal("%s line %d: Invalid environment name.",
1281 filename, linenum);
1282 if (!*activep)
1283 continue;
1284 if (options->num_send_env >= MAX_SEND_ENV)
1285 fatal("%s line %d: too many send env.",
1286 filename, linenum);
1287 options->send_env[options->num_send_env++] =
1288 xstrdup(arg);
1289 }
1290 break;
1291
1292 case oControlPath:
1293 charptr = &options->control_path;
1294 goto parse_string;
1295
1296 case oControlMaster:
1297 intptr = &options->control_master;
Adam Langleyd0592972015-03-30 14:49:51 -07001298 multistate_ptr = multistate_controlmaster;
1299 goto parse_multistate;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001300
1301 case oControlPersist:
1302 /* no/false/yes/true, or a time spec */
1303 intptr = &options->control_persist;
1304 arg = strdelim(&s);
1305 if (!arg || *arg == '\0')
1306 fatal("%.200s line %d: Missing ControlPersist"
1307 " argument.", filename, linenum);
1308 value = 0;
1309 value2 = 0; /* timeout */
1310 if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
1311 value = 0;
1312 else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
1313 value = 1;
1314 else if ((value2 = convtime(arg)) >= 0)
1315 value = 1;
1316 else
1317 fatal("%.200s line %d: Bad ControlPersist argument.",
1318 filename, linenum);
1319 if (*activep && *intptr == -1) {
1320 *intptr = value;
1321 options->control_persist_timeout = value2;
1322 }
1323 break;
1324
1325 case oHashKnownHosts:
1326 intptr = &options->hash_known_hosts;
1327 goto parse_flag;
1328
1329 case oTunnel:
1330 intptr = &options->tun_open;
Adam Langleyd0592972015-03-30 14:49:51 -07001331 multistate_ptr = multistate_tunnel;
1332 goto parse_multistate;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001333
1334 case oTunnelDevice:
1335 arg = strdelim(&s);
1336 if (!arg || *arg == '\0')
1337 fatal("%.200s line %d: Missing argument.", filename, linenum);
1338 value = a2tun(arg, &value2);
1339 if (value == SSH_TUNID_ERR)
1340 fatal("%.200s line %d: Bad tun device.", filename, linenum);
1341 if (*activep) {
1342 options->tun_local = value;
1343 options->tun_remote = value2;
1344 }
1345 break;
1346
1347 case oLocalCommand:
1348 charptr = &options->local_command;
1349 goto parse_command;
1350
1351 case oPermitLocalCommand:
1352 intptr = &options->permit_local_command;
1353 goto parse_flag;
1354
1355 case oVisualHostKey:
1356 intptr = &options->visual_host_key;
1357 goto parse_flag;
1358
1359 case oIPQoS:
1360 arg = strdelim(&s);
1361 if ((value = parse_ipqos(arg)) == -1)
1362 fatal("%s line %d: Bad IPQoS value: %s",
1363 filename, linenum, arg);
1364 arg = strdelim(&s);
1365 if (arg == NULL)
1366 value2 = value;
1367 else if ((value2 = parse_ipqos(arg)) == -1)
1368 fatal("%s line %d: Bad IPQoS value: %s",
1369 filename, linenum, arg);
1370 if (*activep) {
1371 options->ip_qos_interactive = value;
1372 options->ip_qos_bulk = value2;
1373 }
1374 break;
1375
1376 case oUseRoaming:
1377 intptr = &options->use_roaming;
1378 goto parse_flag;
1379
1380 case oRequestTTY:
Adam Langleyd0592972015-03-30 14:49:51 -07001381 intptr = &options->request_tty;
1382 multistate_ptr = multistate_requesttty;
1383 goto parse_multistate;
1384
1385 case oIgnoreUnknown:
1386 charptr = &options->ignored_unknown;
1387 goto parse_string;
1388
1389 case oProxyUseFdpass:
1390 intptr = &options->proxy_use_fdpass;
1391 goto parse_flag;
1392
1393 case oCanonicalDomains:
1394 value = options->num_canonical_domains != 0;
1395 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1396 valid_domain(arg, filename, linenum);
1397 if (!*activep || value)
1398 continue;
1399 if (options->num_canonical_domains >= MAX_CANON_DOMAINS)
1400 fatal("%s line %d: too many hostname suffixes.",
1401 filename, linenum);
1402 options->canonical_domains[
1403 options->num_canonical_domains++] = xstrdup(arg);
1404 }
1405 break;
1406
1407 case oCanonicalizePermittedCNAMEs:
1408 value = options->num_permitted_cnames != 0;
1409 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1410 /* Either '*' for everything or 'list:list' */
1411 if (strcmp(arg, "*") == 0)
1412 arg2 = arg;
1413 else {
1414 lowercase(arg);
1415 if ((arg2 = strchr(arg, ':')) == NULL ||
1416 arg2[1] == '\0') {
1417 fatal("%s line %d: "
1418 "Invalid permitted CNAME \"%s\"",
1419 filename, linenum, arg);
1420 }
1421 *arg2 = '\0';
1422 arg2++;
1423 }
1424 if (!*activep || value)
1425 continue;
1426 if (options->num_permitted_cnames >= MAX_CANON_DOMAINS)
1427 fatal("%s line %d: too many permitted CNAMEs.",
1428 filename, linenum);
1429 cname = options->permitted_cnames +
1430 options->num_permitted_cnames++;
1431 cname->source_list = xstrdup(arg);
1432 cname->target_list = xstrdup(arg2);
1433 }
1434 break;
1435
1436 case oCanonicalizeHostname:
1437 intptr = &options->canonicalize_hostname;
1438 multistate_ptr = multistate_canonicalizehostname;
1439 goto parse_multistate;
1440
1441 case oCanonicalizeMaxDots:
1442 intptr = &options->canonicalize_max_dots;
1443 goto parse_int;
1444
1445 case oCanonicalizeFallbackLocal:
1446 intptr = &options->canonicalize_fallback_local;
1447 goto parse_flag;
1448
1449 case oStreamLocalBindMask:
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001450 arg = strdelim(&s);
1451 if (!arg || *arg == '\0')
Adam Langleyd0592972015-03-30 14:49:51 -07001452 fatal("%.200s line %d: Missing StreamLocalBindMask argument.", filename, linenum);
1453 /* Parse mode in octal format */
1454 value = strtol(arg, &endofnumber, 8);
1455 if (arg == endofnumber || value < 0 || value > 0777)
1456 fatal("%.200s line %d: Bad mask.", filename, linenum);
1457 options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
1458 break;
1459
1460 case oStreamLocalBindUnlink:
1461 intptr = &options->fwd_opts.streamlocal_bind_unlink;
1462 goto parse_flag;
1463
1464 case oRevokedHostKeys:
1465 charptr = &options->revoked_host_keys;
1466 goto parse_string;
1467
1468 case oFingerprintHash:
1469 intptr = &options->fingerprint_hash;
1470 arg = strdelim(&s);
1471 if (!arg || *arg == '\0')
1472 fatal("%.200s line %d: Missing argument.",
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001473 filename, linenum);
Adam Langleyd0592972015-03-30 14:49:51 -07001474 if ((value = ssh_digest_alg_by_name(arg)) == -1)
1475 fatal("%.200s line %d: Invalid hash algorithm \"%s\".",
1476 filename, linenum, arg);
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001477 if (*activep && *intptr == -1)
1478 *intptr = value;
1479 break;
1480
Adam Langleyd0592972015-03-30 14:49:51 -07001481 case oUpdateHostkeys:
1482 intptr = &options->update_hostkeys;
1483 multistate_ptr = multistate_yesnoask;
1484 goto parse_multistate;
1485
1486 case oHostbasedKeyTypes:
1487 charptr = &options->hostbased_key_types;
1488 arg = strdelim(&s);
1489 if (!arg || *arg == '\0')
1490 fatal("%.200s line %d: Missing argument.",
1491 filename, linenum);
1492 if (!sshkey_names_valid2(arg, 1))
1493 fatal("%s line %d: Bad key types '%s'.",
1494 filename, linenum, arg ? arg : "<NONE>");
1495 if (*activep && *charptr == NULL)
1496 *charptr = xstrdup(arg);
1497 break;
1498
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001499 case oDeprecated:
1500 debug("%s line %d: Deprecated option \"%s\"",
1501 filename, linenum, keyword);
1502 return 0;
1503
1504 case oUnsupported:
1505 error("%s line %d: Unsupported option \"%s\"",
1506 filename, linenum, keyword);
1507 return 0;
1508
1509 default:
Adam Langleyd0592972015-03-30 14:49:51 -07001510 fatal("%s: Unimplemented opcode %d", __func__, opcode);
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001511 }
1512
1513 /* Check that there is no garbage at end of line. */
1514 if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1515 fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
1516 filename, linenum, arg);
1517 }
1518 return 0;
1519}
1520
1521
1522/*
1523 * Reads the config file and modifies the options accordingly. Options
1524 * should already be initialized before this call. This never returns if
1525 * there is an error. If the file does not exist, this returns 0.
1526 */
1527
1528int
Adam Langleyd0592972015-03-30 14:49:51 -07001529read_config_file(const char *filename, struct passwd *pw, const char *host,
1530 const char *original_host, Options *options, int flags)
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001531{
1532 FILE *f;
1533 char line[1024];
1534 int active, linenum;
1535 int bad_options = 0;
1536
1537 if ((f = fopen(filename, "r")) == NULL)
1538 return 0;
1539
Adam Langleyd0592972015-03-30 14:49:51 -07001540 if (flags & SSHCONF_CHECKPERM) {
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001541 struct stat sb;
1542
1543 if (fstat(fileno(f), &sb) == -1)
1544 fatal("fstat %s: %s", filename, strerror(errno));
1545 if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
1546 (sb.st_mode & 022) != 0))
1547 fatal("Bad owner or permissions on %s", filename);
1548 }
1549
1550 debug("Reading configuration data %.200s", filename);
1551
1552 /*
1553 * Mark that we are now processing the options. This flag is turned
1554 * on/off by Host specifications.
1555 */
1556 active = 1;
1557 linenum = 0;
1558 while (fgets(line, sizeof(line), f)) {
1559 /* Update line number counter. */
1560 linenum++;
Adam Langleyd0592972015-03-30 14:49:51 -07001561 if (process_config_line(options, pw, host, original_host,
1562 line, filename, linenum, &active, flags) != 0)
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001563 bad_options++;
1564 }
1565 fclose(f);
1566 if (bad_options > 0)
1567 fatal("%s: terminating, %d bad configuration options",
1568 filename, bad_options);
1569 return 1;
1570}
1571
Adam Langleyd0592972015-03-30 14:49:51 -07001572/* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
1573int
1574option_clear_or_none(const char *o)
1575{
1576 return o == NULL || strcasecmp(o, "none") == 0;
1577}
1578
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001579/*
1580 * Initializes options to special values that indicate that they have not yet
1581 * been set. Read_config_file will only set options with this value. Options
1582 * are processed in the following order: command line, user config file,
1583 * system config file. Last, fill_default_options is called.
1584 */
1585
1586void
1587initialize_options(Options * options)
1588{
1589 memset(options, 'X', sizeof(*options));
1590 options->forward_agent = -1;
1591 options->forward_x11 = -1;
1592 options->forward_x11_trusted = -1;
1593 options->forward_x11_timeout = -1;
1594 options->exit_on_forward_failure = -1;
1595 options->xauth_location = NULL;
Adam Langleyd0592972015-03-30 14:49:51 -07001596 options->fwd_opts.gateway_ports = -1;
1597 options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
1598 options->fwd_opts.streamlocal_bind_unlink = -1;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001599 options->use_privileged_port = -1;
1600 options->rsa_authentication = -1;
1601 options->pubkey_authentication = -1;
1602 options->challenge_response_authentication = -1;
1603 options->gss_authentication = -1;
1604 options->gss_deleg_creds = -1;
1605 options->password_authentication = -1;
1606 options->kbd_interactive_authentication = -1;
1607 options->kbd_interactive_devices = NULL;
1608 options->rhosts_rsa_authentication = -1;
1609 options->hostbased_authentication = -1;
1610 options->batch_mode = -1;
1611 options->check_host_ip = -1;
1612 options->strict_host_key_checking = -1;
1613 options->compression = -1;
1614 options->tcp_keep_alive = -1;
1615 options->compression_level = -1;
1616 options->port = -1;
1617 options->address_family = -1;
1618 options->connection_attempts = -1;
1619 options->connection_timeout = -1;
1620 options->number_of_password_prompts = -1;
1621 options->cipher = -1;
1622 options->ciphers = NULL;
1623 options->macs = NULL;
1624 options->kex_algorithms = NULL;
1625 options->hostkeyalgorithms = NULL;
1626 options->protocol = SSH_PROTO_UNKNOWN;
1627 options->num_identity_files = 0;
1628 options->hostname = NULL;
1629 options->host_key_alias = NULL;
1630 options->proxy_command = NULL;
1631 options->user = NULL;
1632 options->escape_char = -1;
1633 options->num_system_hostfiles = 0;
1634 options->num_user_hostfiles = 0;
1635 options->local_forwards = NULL;
1636 options->num_local_forwards = 0;
1637 options->remote_forwards = NULL;
1638 options->num_remote_forwards = 0;
1639 options->clear_forwardings = -1;
1640 options->log_level = SYSLOG_LEVEL_NOT_SET;
1641 options->preferred_authentications = NULL;
1642 options->bind_address = NULL;
1643 options->pkcs11_provider = NULL;
1644 options->enable_ssh_keysign = - 1;
1645 options->no_host_authentication_for_localhost = - 1;
1646 options->identities_only = - 1;
1647 options->rekey_limit = - 1;
Adam Langleyd0592972015-03-30 14:49:51 -07001648 options->rekey_interval = -1;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001649 options->verify_host_key_dns = -1;
1650 options->server_alive_interval = -1;
1651 options->server_alive_count_max = -1;
1652 options->num_send_env = 0;
1653 options->control_path = NULL;
1654 options->control_master = -1;
1655 options->control_persist = -1;
1656 options->control_persist_timeout = 0;
1657 options->hash_known_hosts = -1;
1658 options->tun_open = -1;
1659 options->tun_local = -1;
1660 options->tun_remote = -1;
1661 options->local_command = NULL;
1662 options->permit_local_command = -1;
1663 options->use_roaming = -1;
1664 options->visual_host_key = -1;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001665 options->ip_qos_interactive = -1;
1666 options->ip_qos_bulk = -1;
1667 options->request_tty = -1;
Adam Langleyd0592972015-03-30 14:49:51 -07001668 options->proxy_use_fdpass = -1;
1669 options->ignored_unknown = NULL;
1670 options->num_canonical_domains = 0;
1671 options->num_permitted_cnames = 0;
1672 options->canonicalize_max_dots = -1;
1673 options->canonicalize_fallback_local = -1;
1674 options->canonicalize_hostname = -1;
1675 options->revoked_host_keys = NULL;
1676 options->fingerprint_hash = -1;
1677 options->update_hostkeys = -1;
1678 options->hostbased_key_types = NULL;
1679}
1680
1681/*
1682 * A petite version of fill_default_options() that just fills the options
1683 * needed for hostname canonicalization to proceed.
1684 */
1685void
1686fill_default_options_for_canonicalization(Options *options)
1687{
1688 if (options->canonicalize_max_dots == -1)
1689 options->canonicalize_max_dots = 1;
1690 if (options->canonicalize_fallback_local == -1)
1691 options->canonicalize_fallback_local = 1;
1692 if (options->canonicalize_hostname == -1)
1693 options->canonicalize_hostname = SSH_CANONICALISE_NO;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001694}
1695
1696/*
1697 * Called after processing other sources of option data, this fills those
1698 * options for which no value has been specified with their default values.
1699 */
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001700void
1701fill_default_options(Options * options)
1702{
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001703 if (options->forward_agent == -1)
1704 options->forward_agent = 0;
1705 if (options->forward_x11 == -1)
1706 options->forward_x11 = 0;
1707 if (options->forward_x11_trusted == -1)
1708 options->forward_x11_trusted = 0;
1709 if (options->forward_x11_timeout == -1)
1710 options->forward_x11_timeout = 1200;
1711 if (options->exit_on_forward_failure == -1)
1712 options->exit_on_forward_failure = 0;
1713 if (options->xauth_location == NULL)
1714 options->xauth_location = _PATH_XAUTH;
Adam Langleyd0592972015-03-30 14:49:51 -07001715 if (options->fwd_opts.gateway_ports == -1)
1716 options->fwd_opts.gateway_ports = 0;
1717 if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
1718 options->fwd_opts.streamlocal_bind_mask = 0177;
1719 if (options->fwd_opts.streamlocal_bind_unlink == -1)
1720 options->fwd_opts.streamlocal_bind_unlink = 0;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001721 if (options->use_privileged_port == -1)
1722 options->use_privileged_port = 0;
1723 if (options->rsa_authentication == -1)
1724 options->rsa_authentication = 1;
1725 if (options->pubkey_authentication == -1)
1726 options->pubkey_authentication = 1;
1727 if (options->challenge_response_authentication == -1)
1728 options->challenge_response_authentication = 1;
1729 if (options->gss_authentication == -1)
1730 options->gss_authentication = 0;
1731 if (options->gss_deleg_creds == -1)
1732 options->gss_deleg_creds = 0;
1733 if (options->password_authentication == -1)
1734 options->password_authentication = 1;
1735 if (options->kbd_interactive_authentication == -1)
1736 options->kbd_interactive_authentication = 1;
1737 if (options->rhosts_rsa_authentication == -1)
1738 options->rhosts_rsa_authentication = 0;
1739 if (options->hostbased_authentication == -1)
1740 options->hostbased_authentication = 0;
1741 if (options->batch_mode == -1)
1742 options->batch_mode = 0;
1743 if (options->check_host_ip == -1)
1744 options->check_host_ip = 1;
1745 if (options->strict_host_key_checking == -1)
1746 options->strict_host_key_checking = 2; /* 2 is default */
1747 if (options->compression == -1)
1748 options->compression = 0;
1749 if (options->tcp_keep_alive == -1)
1750 options->tcp_keep_alive = 1;
1751 if (options->compression_level == -1)
1752 options->compression_level = 6;
1753 if (options->port == -1)
1754 options->port = 0; /* Filled in ssh_connect. */
1755 if (options->address_family == -1)
1756 options->address_family = AF_UNSPEC;
1757 if (options->connection_attempts == -1)
1758 options->connection_attempts = 1;
1759 if (options->number_of_password_prompts == -1)
1760 options->number_of_password_prompts = 3;
1761 /* Selected in ssh_login(). */
1762 if (options->cipher == -1)
1763 options->cipher = SSH_CIPHER_NOT_SET;
1764 /* options->ciphers, default set in myproposals.h */
1765 /* options->macs, default set in myproposals.h */
1766 /* options->kex_algorithms, default set in myproposals.h */
1767 /* options->hostkeyalgorithms, default set in myproposals.h */
1768 if (options->protocol == SSH_PROTO_UNKNOWN)
1769 options->protocol = SSH_PROTO_2;
1770 if (options->num_identity_files == 0) {
1771 if (options->protocol & SSH_PROTO_1) {
Adam Langleyd0592972015-03-30 14:49:51 -07001772 add_identity_file(options, "~/",
1773 _PATH_SSH_CLIENT_IDENTITY, 0);
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001774 }
1775 if (options->protocol & SSH_PROTO_2) {
Adam Langleyd0592972015-03-30 14:49:51 -07001776 add_identity_file(options, "~/",
1777 _PATH_SSH_CLIENT_ID_RSA, 0);
1778 add_identity_file(options, "~/",
1779 _PATH_SSH_CLIENT_ID_DSA, 0);
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001780#ifdef OPENSSL_HAS_ECC
Adam Langleyd0592972015-03-30 14:49:51 -07001781 add_identity_file(options, "~/",
1782 _PATH_SSH_CLIENT_ID_ECDSA, 0);
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001783#endif
Adam Langleyd0592972015-03-30 14:49:51 -07001784 add_identity_file(options, "~/",
1785 _PATH_SSH_CLIENT_ID_ED25519, 0);
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001786 }
1787 }
1788 if (options->escape_char == -1)
1789 options->escape_char = '~';
1790 if (options->num_system_hostfiles == 0) {
1791 options->system_hostfiles[options->num_system_hostfiles++] =
1792 xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
1793 options->system_hostfiles[options->num_system_hostfiles++] =
1794 xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
1795 }
1796 if (options->num_user_hostfiles == 0) {
1797 options->user_hostfiles[options->num_user_hostfiles++] =
1798 xstrdup(_PATH_SSH_USER_HOSTFILE);
1799 options->user_hostfiles[options->num_user_hostfiles++] =
1800 xstrdup(_PATH_SSH_USER_HOSTFILE2);
1801 }
1802 if (options->log_level == SYSLOG_LEVEL_NOT_SET)
1803 options->log_level = SYSLOG_LEVEL_INFO;
1804 if (options->clear_forwardings == 1)
1805 clear_forwardings(options);
1806 if (options->no_host_authentication_for_localhost == - 1)
1807 options->no_host_authentication_for_localhost = 0;
1808 if (options->identities_only == -1)
1809 options->identities_only = 0;
1810 if (options->enable_ssh_keysign == -1)
1811 options->enable_ssh_keysign = 0;
1812 if (options->rekey_limit == -1)
1813 options->rekey_limit = 0;
Adam Langleyd0592972015-03-30 14:49:51 -07001814 if (options->rekey_interval == -1)
1815 options->rekey_interval = 0;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001816 if (options->verify_host_key_dns == -1)
1817 options->verify_host_key_dns = 0;
1818 if (options->server_alive_interval == -1)
1819 options->server_alive_interval = 0;
1820 if (options->server_alive_count_max == -1)
1821 options->server_alive_count_max = 3;
1822 if (options->control_master == -1)
1823 options->control_master = 0;
1824 if (options->control_persist == -1) {
1825 options->control_persist = 0;
1826 options->control_persist_timeout = 0;
1827 }
1828 if (options->hash_known_hosts == -1)
1829 options->hash_known_hosts = 0;
1830 if (options->tun_open == -1)
1831 options->tun_open = SSH_TUNMODE_NO;
1832 if (options->tun_local == -1)
1833 options->tun_local = SSH_TUNID_ANY;
1834 if (options->tun_remote == -1)
1835 options->tun_remote = SSH_TUNID_ANY;
1836 if (options->permit_local_command == -1)
1837 options->permit_local_command = 0;
1838 if (options->use_roaming == -1)
1839 options->use_roaming = 1;
1840 if (options->visual_host_key == -1)
1841 options->visual_host_key = 0;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001842 if (options->ip_qos_interactive == -1)
1843 options->ip_qos_interactive = IPTOS_LOWDELAY;
1844 if (options->ip_qos_bulk == -1)
1845 options->ip_qos_bulk = IPTOS_THROUGHPUT;
1846 if (options->request_tty == -1)
1847 options->request_tty = REQUEST_TTY_AUTO;
Adam Langleyd0592972015-03-30 14:49:51 -07001848 if (options->proxy_use_fdpass == -1)
1849 options->proxy_use_fdpass = 0;
1850 if (options->canonicalize_max_dots == -1)
1851 options->canonicalize_max_dots = 1;
1852 if (options->canonicalize_fallback_local == -1)
1853 options->canonicalize_fallback_local = 1;
1854 if (options->canonicalize_hostname == -1)
1855 options->canonicalize_hostname = SSH_CANONICALISE_NO;
1856 if (options->fingerprint_hash == -1)
1857 options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
1858 if (options->update_hostkeys == -1)
1859 options->update_hostkeys = 0;
1860 if (options->hostbased_key_types == NULL)
1861 options->hostbased_key_types = xstrdup("*");
1862
1863#define CLEAR_ON_NONE(v) \
1864 do { \
1865 if (option_clear_or_none(v)) { \
1866 free(v); \
1867 v = NULL; \
1868 } \
1869 } while(0)
1870 CLEAR_ON_NONE(options->local_command);
1871 CLEAR_ON_NONE(options->proxy_command);
1872 CLEAR_ON_NONE(options->control_path);
1873 CLEAR_ON_NONE(options->revoked_host_keys);
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001874 /* options->user will be set in the main program if appropriate */
1875 /* options->hostname will be set in the main program if appropriate */
1876 /* options->host_key_alias should not be set by default */
1877 /* options->preferred_authentications will be set in ssh */
1878}
1879
Adam Langleyd0592972015-03-30 14:49:51 -07001880struct fwdarg {
1881 char *arg;
1882 int ispath;
1883};
1884
1885/*
1886 * parse_fwd_field
1887 * parses the next field in a port forwarding specification.
1888 * sets fwd to the parsed field and advances p past the colon
1889 * or sets it to NULL at end of string.
1890 * returns 0 on success, else non-zero.
1891 */
1892static int
1893parse_fwd_field(char **p, struct fwdarg *fwd)
1894{
1895 char *ep, *cp = *p;
1896 int ispath = 0;
1897
1898 if (*cp == '\0') {
1899 *p = NULL;
1900 return -1; /* end of string */
1901 }
1902
1903 /*
1904 * A field escaped with square brackets is used literally.
1905 * XXX - allow ']' to be escaped via backslash?
1906 */
1907 if (*cp == '[') {
1908 /* find matching ']' */
1909 for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
1910 if (*ep == '/')
1911 ispath = 1;
1912 }
1913 /* no matching ']' or not at end of field. */
1914 if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
1915 return -1;
1916 /* NUL terminate the field and advance p past the colon */
1917 *ep++ = '\0';
1918 if (*ep != '\0')
1919 *ep++ = '\0';
1920 fwd->arg = cp + 1;
1921 fwd->ispath = ispath;
1922 *p = ep;
1923 return 0;
1924 }
1925
1926 for (cp = *p; *cp != '\0'; cp++) {
1927 switch (*cp) {
1928 case '\\':
1929 memmove(cp, cp + 1, strlen(cp + 1) + 1);
1930 cp++;
1931 break;
1932 case '/':
1933 ispath = 1;
1934 break;
1935 case ':':
1936 *cp++ = '\0';
1937 goto done;
1938 }
1939 }
1940done:
1941 fwd->arg = *p;
1942 fwd->ispath = ispath;
1943 *p = cp;
1944 return 0;
1945}
1946
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001947/*
1948 * parse_forward
1949 * parses a string containing a port forwarding specification of the form:
1950 * dynamicfwd == 0
Adam Langleyd0592972015-03-30 14:49:51 -07001951 * [listenhost:]listenport|listenpath:connecthost:connectport|connectpath
1952 * listenpath:connectpath
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001953 * dynamicfwd == 1
1954 * [listenhost:]listenport
1955 * returns number of arguments parsed or zero on error
1956 */
1957int
Adam Langleyd0592972015-03-30 14:49:51 -07001958parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001959{
Adam Langleyd0592972015-03-30 14:49:51 -07001960 struct fwdarg fwdargs[4];
1961 char *p, *cp;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001962 int i;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001963
Adam Langleyd0592972015-03-30 14:49:51 -07001964 memset(fwd, 0, sizeof(*fwd));
1965 memset(fwdargs, 0, sizeof(fwdargs));
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001966
1967 cp = p = xstrdup(fwdspec);
1968
1969 /* skip leading spaces */
Adam Langleyd0592972015-03-30 14:49:51 -07001970 while (isspace((u_char)*cp))
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001971 cp++;
1972
Adam Langleyd0592972015-03-30 14:49:51 -07001973 for (i = 0; i < 4; ++i) {
1974 if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001975 break;
Adam Langleyd0592972015-03-30 14:49:51 -07001976 }
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001977
1978 /* Check for trailing garbage */
Adam Langleyd0592972015-03-30 14:49:51 -07001979 if (cp != NULL && *cp != '\0') {
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001980 i = 0; /* failure */
Adam Langleyd0592972015-03-30 14:49:51 -07001981 }
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001982
1983 switch (i) {
1984 case 1:
Adam Langleyd0592972015-03-30 14:49:51 -07001985 if (fwdargs[0].ispath) {
1986 fwd->listen_path = xstrdup(fwdargs[0].arg);
1987 fwd->listen_port = PORT_STREAMLOCAL;
1988 } else {
1989 fwd->listen_host = NULL;
1990 fwd->listen_port = a2port(fwdargs[0].arg);
1991 }
Greg Hartmanbd77cf72015-02-25 13:21:06 -08001992 fwd->connect_host = xstrdup("socks");
1993 break;
1994
1995 case 2:
Adam Langleyd0592972015-03-30 14:49:51 -07001996 if (fwdargs[0].ispath && fwdargs[1].ispath) {
1997 fwd->listen_path = xstrdup(fwdargs[0].arg);
1998 fwd->listen_port = PORT_STREAMLOCAL;
1999 fwd->connect_path = xstrdup(fwdargs[1].arg);
2000 fwd->connect_port = PORT_STREAMLOCAL;
2001 } else if (fwdargs[1].ispath) {
2002 fwd->listen_host = NULL;
2003 fwd->listen_port = a2port(fwdargs[0].arg);
2004 fwd->connect_path = xstrdup(fwdargs[1].arg);
2005 fwd->connect_port = PORT_STREAMLOCAL;
2006 } else {
2007 fwd->listen_host = xstrdup(fwdargs[0].arg);
2008 fwd->listen_port = a2port(fwdargs[1].arg);
2009 fwd->connect_host = xstrdup("socks");
2010 }
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002011 break;
2012
2013 case 3:
Adam Langleyd0592972015-03-30 14:49:51 -07002014 if (fwdargs[0].ispath) {
2015 fwd->listen_path = xstrdup(fwdargs[0].arg);
2016 fwd->listen_port = PORT_STREAMLOCAL;
2017 fwd->connect_host = xstrdup(fwdargs[1].arg);
2018 fwd->connect_port = a2port(fwdargs[2].arg);
2019 } else if (fwdargs[2].ispath) {
2020 fwd->listen_host = xstrdup(fwdargs[0].arg);
2021 fwd->listen_port = a2port(fwdargs[1].arg);
2022 fwd->connect_path = xstrdup(fwdargs[2].arg);
2023 fwd->connect_port = PORT_STREAMLOCAL;
2024 } else {
2025 fwd->listen_host = NULL;
2026 fwd->listen_port = a2port(fwdargs[0].arg);
2027 fwd->connect_host = xstrdup(fwdargs[1].arg);
2028 fwd->connect_port = a2port(fwdargs[2].arg);
2029 }
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002030 break;
2031
2032 case 4:
Adam Langleyd0592972015-03-30 14:49:51 -07002033 fwd->listen_host = xstrdup(fwdargs[0].arg);
2034 fwd->listen_port = a2port(fwdargs[1].arg);
2035 fwd->connect_host = xstrdup(fwdargs[2].arg);
2036 fwd->connect_port = a2port(fwdargs[3].arg);
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002037 break;
2038 default:
2039 i = 0; /* failure */
2040 }
2041
Adam Langleyd0592972015-03-30 14:49:51 -07002042 free(p);
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002043
2044 if (dynamicfwd) {
2045 if (!(i == 1 || i == 2))
2046 goto fail_free;
2047 } else {
Adam Langleyd0592972015-03-30 14:49:51 -07002048 if (!(i == 3 || i == 4)) {
2049 if (fwd->connect_path == NULL &&
2050 fwd->listen_path == NULL)
2051 goto fail_free;
2052 }
2053 if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002054 goto fail_free;
2055 }
2056
Adam Langleyd0592972015-03-30 14:49:51 -07002057 if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
2058 (!remotefwd && fwd->listen_port == 0))
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002059 goto fail_free;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002060 if (fwd->connect_host != NULL &&
2061 strlen(fwd->connect_host) >= NI_MAXHOST)
2062 goto fail_free;
Adam Langleyd0592972015-03-30 14:49:51 -07002063 /* XXX - if connecting to a remote socket, max sun len may not match this host */
2064 if (fwd->connect_path != NULL &&
2065 strlen(fwd->connect_path) >= PATH_MAX_SUN)
2066 goto fail_free;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002067 if (fwd->listen_host != NULL &&
2068 strlen(fwd->listen_host) >= NI_MAXHOST)
2069 goto fail_free;
Adam Langleyd0592972015-03-30 14:49:51 -07002070 if (fwd->listen_path != NULL &&
2071 strlen(fwd->listen_path) >= PATH_MAX_SUN)
2072 goto fail_free;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002073
2074 return (i);
2075
2076 fail_free:
Adam Langleyd0592972015-03-30 14:49:51 -07002077 free(fwd->connect_host);
2078 fwd->connect_host = NULL;
2079 free(fwd->connect_path);
2080 fwd->connect_path = NULL;
2081 free(fwd->listen_host);
2082 fwd->listen_host = NULL;
2083 free(fwd->listen_path);
2084 fwd->listen_path = NULL;
Greg Hartmanbd77cf72015-02-25 13:21:06 -08002085 return (0);
2086}
Adam Langleyd0592972015-03-30 14:49:51 -07002087
2088/* XXX the following is a near-vebatim copy from servconf.c; refactor */
2089static const char *
2090fmt_multistate_int(int val, const struct multistate *m)
2091{
2092 u_int i;
2093
2094 for (i = 0; m[i].key != NULL; i++) {
2095 if (m[i].value == val)
2096 return m[i].key;
2097 }
2098 return "UNKNOWN";
2099}
2100
2101static const char *
2102fmt_intarg(OpCodes code, int val)
2103{
2104 if (val == -1)
2105 return "unset";
2106 switch (code) {
2107 case oAddressFamily:
2108 return fmt_multistate_int(val, multistate_addressfamily);
2109 case oVerifyHostKeyDNS:
2110 case oStrictHostKeyChecking:
2111 case oUpdateHostkeys:
2112 return fmt_multistate_int(val, multistate_yesnoask);
2113 case oControlMaster:
2114 return fmt_multistate_int(val, multistate_controlmaster);
2115 case oTunnel:
2116 return fmt_multistate_int(val, multistate_tunnel);
2117 case oRequestTTY:
2118 return fmt_multistate_int(val, multistate_requesttty);
2119 case oCanonicalizeHostname:
2120 return fmt_multistate_int(val, multistate_canonicalizehostname);
2121 case oFingerprintHash:
2122 return ssh_digest_alg_name(val);
2123 case oProtocol:
2124 switch (val) {
2125 case SSH_PROTO_1:
2126 return "1";
2127 case SSH_PROTO_2:
2128 return "2";
2129 case (SSH_PROTO_1|SSH_PROTO_2):
2130 return "2,1";
2131 default:
2132 return "UNKNOWN";
2133 }
2134 default:
2135 switch (val) {
2136 case 0:
2137 return "no";
2138 case 1:
2139 return "yes";
2140 default:
2141 return "UNKNOWN";
2142 }
2143 }
2144}
2145
2146static const char *
2147lookup_opcode_name(OpCodes code)
2148{
2149 u_int i;
2150
2151 for (i = 0; keywords[i].name != NULL; i++)
2152 if (keywords[i].opcode == code)
2153 return(keywords[i].name);
2154 return "UNKNOWN";
2155}
2156
2157static void
2158dump_cfg_int(OpCodes code, int val)
2159{
2160 printf("%s %d\n", lookup_opcode_name(code), val);
2161}
2162
2163static void
2164dump_cfg_fmtint(OpCodes code, int val)
2165{
2166 printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
2167}
2168
2169static void
2170dump_cfg_string(OpCodes code, const char *val)
2171{
2172 if (val == NULL)
2173 return;
2174 printf("%s %s\n", lookup_opcode_name(code), val);
2175}
2176
2177static void
2178dump_cfg_strarray(OpCodes code, u_int count, char **vals)
2179{
2180 u_int i;
2181
2182 for (i = 0; i < count; i++)
2183 printf("%s %s\n", lookup_opcode_name(code), vals[i]);
2184}
2185
2186static void
2187dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
2188{
2189 u_int i;
2190
2191 printf("%s", lookup_opcode_name(code));
2192 for (i = 0; i < count; i++)
2193 printf(" %s", vals[i]);
2194 printf("\n");
2195}
2196
2197static void
2198dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
2199{
2200 const struct Forward *fwd;
2201 u_int i;
2202
2203 /* oDynamicForward */
2204 for (i = 0; i < count; i++) {
2205 fwd = &fwds[i];
2206 if (code == oDynamicForward &&
2207 strcmp(fwd->connect_host, "socks") != 0)
2208 continue;
2209 if (code == oLocalForward &&
2210 strcmp(fwd->connect_host, "socks") == 0)
2211 continue;
2212 printf("%s", lookup_opcode_name(code));
2213 if (fwd->listen_port == PORT_STREAMLOCAL)
2214 printf(" %s", fwd->listen_path);
2215 else if (fwd->listen_host == NULL)
2216 printf(" %d", fwd->listen_port);
2217 else {
2218 printf(" [%s]:%d",
2219 fwd->listen_host, fwd->listen_port);
2220 }
2221 if (code != oDynamicForward) {
2222 if (fwd->connect_port == PORT_STREAMLOCAL)
2223 printf(" %s", fwd->connect_path);
2224 else if (fwd->connect_host == NULL)
2225 printf(" %d", fwd->connect_port);
2226 else {
2227 printf(" [%s]:%d",
2228 fwd->connect_host, fwd->connect_port);
2229 }
2230 }
2231 printf("\n");
2232 }
2233}
2234
2235void
2236dump_client_config(Options *o, const char *host)
2237{
2238 int i;
2239 char vbuf[5];
2240
2241 /* Most interesting options first: user, host, port */
2242 dump_cfg_string(oUser, o->user);
2243 dump_cfg_string(oHostName, host);
2244 dump_cfg_int(oPort, o->port);
2245
2246 /* Flag options */
2247 dump_cfg_fmtint(oAddressFamily, o->address_family);
2248 dump_cfg_fmtint(oBatchMode, o->batch_mode);
2249 dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local);
2250 dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname);
2251 dump_cfg_fmtint(oChallengeResponseAuthentication, o->challenge_response_authentication);
2252 dump_cfg_fmtint(oCheckHostIP, o->check_host_ip);
2253 dump_cfg_fmtint(oCompression, o->compression);
2254 dump_cfg_fmtint(oControlMaster, o->control_master);
2255 dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
2256 dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
2257 dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
2258 dump_cfg_fmtint(oForwardAgent, o->forward_agent);
2259 dump_cfg_fmtint(oForwardX11, o->forward_x11);
2260 dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
2261 dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
2262#ifdef GSSAPI
2263 dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
2264 dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
2265#endif /* GSSAPI */
2266 dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
2267 dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
2268 dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
2269 dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication);
2270 dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost);
2271 dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication);
2272 dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command);
2273 dump_cfg_fmtint(oProtocol, o->protocol);
2274 dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
2275 dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
2276 dump_cfg_fmtint(oRequestTTY, o->request_tty);
2277 dump_cfg_fmtint(oRhostsRSAAuthentication, o->rhosts_rsa_authentication);
2278 dump_cfg_fmtint(oRSAAuthentication, o->rsa_authentication);
2279 dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
2280 dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking);
2281 dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive);
2282 dump_cfg_fmtint(oTunnel, o->tun_open);
2283 dump_cfg_fmtint(oUsePrivilegedPort, o->use_privileged_port);
2284 dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns);
2285 dump_cfg_fmtint(oVisualHostKey, o->visual_host_key);
2286 dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys);
2287
2288 /* Integer options */
2289 dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots);
2290 dump_cfg_int(oCompressionLevel, o->compression_level);
2291 dump_cfg_int(oConnectionAttempts, o->connection_attempts);
2292 dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout);
2293 dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
2294 dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
2295 dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
2296
2297 /* String options */
2298 dump_cfg_string(oBindAddress, o->bind_address);
2299 dump_cfg_string(oCiphers, o->ciphers ? o->ciphers : KEX_CLIENT_ENCRYPT);
2300 dump_cfg_string(oControlPath, o->control_path);
2301 dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms ? o->hostkeyalgorithms : KEX_DEFAULT_PK_ALG);
2302 dump_cfg_string(oHostKeyAlias, o->host_key_alias);
2303 dump_cfg_string(oHostbasedKeyTypes, o->hostbased_key_types);
2304 dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
2305 dump_cfg_string(oKexAlgorithms, o->kex_algorithms ? o->kex_algorithms : KEX_CLIENT_KEX);
2306 dump_cfg_string(oLocalCommand, o->local_command);
2307 dump_cfg_string(oLogLevel, log_level_name(o->log_level));
2308 dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC);
2309 dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
2310 dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
2311 dump_cfg_string(oProxyCommand, o->proxy_command);
2312 dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
2313 dump_cfg_string(oXAuthLocation, o->xauth_location);
2314
2315 /* Forwards */
2316 dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards);
2317 dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards);
2318 dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards);
2319
2320 /* String array options */
2321 dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files);
2322 dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains);
2323 dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles);
2324 dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
2325 dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
2326
2327 /* Special cases */
2328
2329 /* oConnectTimeout */
2330 if (o->connection_timeout == -1)
2331 printf("connecttimeout none\n");
2332 else
2333 dump_cfg_int(oConnectTimeout, o->connection_timeout);
2334
2335 /* oTunnelDevice */
2336 printf("tunneldevice");
2337 if (o->tun_local == SSH_TUNID_ANY)
2338 printf(" any");
2339 else
2340 printf(" %d", o->tun_local);
2341 if (o->tun_remote == SSH_TUNID_ANY)
2342 printf(":any");
2343 else
2344 printf(":%d", o->tun_remote);
2345 printf("\n");
2346
2347 /* oCanonicalizePermittedCNAMEs */
2348 if ( o->num_permitted_cnames > 0) {
2349 printf("canonicalizePermittedcnames");
2350 for (i = 0; i < o->num_permitted_cnames; i++) {
2351 printf(" %s:%s", o->permitted_cnames[i].source_list,
2352 o->permitted_cnames[i].target_list);
2353 }
2354 printf("\n");
2355 }
2356
2357 /* oCipher */
2358 if (o->cipher != SSH_CIPHER_NOT_SET)
2359 printf("Cipher %s\n", cipher_name(o->cipher));
2360
2361 /* oControlPersist */
2362 if (o->control_persist == 0 || o->control_persist_timeout == 0)
2363 dump_cfg_fmtint(oControlPersist, o->control_persist);
2364 else
2365 dump_cfg_int(oControlPersist, o->control_persist_timeout);
2366
2367 /* oEscapeChar */
2368 if (o->escape_char == SSH_ESCAPECHAR_NONE)
2369 printf("escapechar none\n");
2370 else {
2371 vis(vbuf, o->escape_char, VIS_WHITE, 0);
2372 printf("escapechar %s\n", vbuf);
2373 }
2374
2375 /* oIPQoS */
2376 printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
2377 printf("%s\n", iptos2str(o->ip_qos_bulk));
2378
2379 /* oRekeyLimit */
2380 printf("rekeylimit %lld %d\n",
2381 (long long)o->rekey_limit, o->rekey_interval);
2382
2383 /* oStreamLocalBindMask */
2384 printf("streamlocalbindmask 0%o\n",
2385 o->fwd_opts.streamlocal_bind_mask);
2386}