]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - crypto/openssh/readconf.c
tcp: Rack compressed ack path updates the recv window too easily
[FreeBSD/FreeBSD.git] / crypto / openssh / readconf.c
1 /* $OpenBSD: readconf.c,v 1.361 2021/07/23 04:04:52 djm Exp $ */
2 /*
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 __RCSID("$FreeBSD$");
17
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <sys/socket.h>
21 #include <sys/wait.h>
22 #include <sys/un.h>
23
24 #include <netinet/in.h>
25 #include <netinet/in_systm.h>
26 #include <netinet/ip.h>
27 #include <arpa/inet.h>
28
29 #include <ctype.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <limits.h>
33 #include <netdb.h>
34 #ifdef HAVE_PATHS_H
35 # include <paths.h>
36 #endif
37 #include <pwd.h>
38 #include <signal.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <stdarg.h>
42 #include <unistd.h>
43 #ifdef USE_SYSTEM_GLOB
44 # include <glob.h>
45 #else
46 # include "openbsd-compat/glob.h"
47 #endif
48 #ifdef HAVE_UTIL_H
49 #include <util.h>
50 #endif
51 #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
52 # include <vis.h>
53 #endif
54
55 #include "xmalloc.h"
56 #include "ssh.h"
57 #include "ssherr.h"
58 #include "compat.h"
59 #include "cipher.h"
60 #include "pathnames.h"
61 #include "log.h"
62 #include "sshkey.h"
63 #include "misc.h"
64 #include "readconf.h"
65 #include "match.h"
66 #include "kex.h"
67 #include "mac.h"
68 #include "uidswap.h"
69 #include "myproposal.h"
70 #include "digest.h"
71 #include "version.h"
72
73 /* Format of the configuration file:
74
75    # Configuration data is parsed as follows:
76    #  1. command line options
77    #  2. user-specific file
78    #  3. system-wide file
79    # Any configuration value is only changed the first time it is set.
80    # Thus, host-specific definitions should be at the beginning of the
81    # configuration file, and defaults at the end.
82
83    # Host-specific declarations.  These may override anything above.  A single
84    # host may match multiple declarations; these are processed in the order
85    # that they are given in.
86
87    Host *.ngs.fi ngs.fi
88      User foo
89
90    Host fake.com
91      Hostname another.host.name.real.org
92      User blaah
93      Port 34289
94      ForwardX11 no
95      ForwardAgent no
96
97    Host books.com
98      RemoteForward 9999 shadows.cs.hut.fi:9999
99      Ciphers 3des-cbc
100
101    Host fascist.blob.com
102      Port 23123
103      User tylonen
104      PasswordAuthentication no
105
106    Host puukko.hut.fi
107      User t35124p
108      ProxyCommand ssh-proxy %h %p
109
110    Host *.fr
111      PublicKeyAuthentication no
112
113    Host *.su
114      Ciphers aes128-ctr
115      PasswordAuthentication no
116
117    Host vpn.fake.com
118      Tunnel yes
119      TunnelDevice 3
120
121    # Defaults for various options
122    Host *
123      ForwardAgent no
124      ForwardX11 no
125      PasswordAuthentication yes
126      StrictHostKeyChecking yes
127      TcpKeepAlive no
128      IdentityFile ~/.ssh/identity
129      Port 22
130      EscapeChar ~
131
132 */
133
134 static int read_config_file_depth(const char *filename, struct passwd *pw,
135     const char *host, const char *original_host, Options *options,
136     int flags, int *activep, int *want_final_pass, int depth);
137 static int process_config_line_depth(Options *options, struct passwd *pw,
138     const char *host, const char *original_host, char *line,
139     const char *filename, int linenum, int *activep, int flags,
140     int *want_final_pass, int depth);
141
142 /* Keyword tokens. */
143
144 typedef enum {
145         oBadOption,
146         oVersionAddendum,
147         oHost, oMatch, oInclude,
148         oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
149         oGatewayPorts, oExitOnForwardFailure,
150         oPasswordAuthentication,
151         oXAuthLocation,
152         oIdentityFile, oHostname, oPort, oRemoteForward, oLocalForward,
153         oPermitRemoteOpen,
154         oCertificateFile, oAddKeysToAgent, oIdentityAgent,
155         oUser, oEscapeChar, oProxyCommand,
156         oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
157         oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
158         oTCPKeepAlive, oNumberOfPasswordPrompts,
159         oLogFacility, oLogLevel, oLogVerbose, oCiphers, oMacs,
160         oPubkeyAuthentication,
161         oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
162         oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
163         oHostKeyAlgorithms, oBindAddress, oBindInterface, oPKCS11Provider,
164         oClearAllForwardings, oNoHostAuthenticationForLocalhost,
165         oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
166         oAddressFamily, oGssAuthentication, oGssDelegateCreds,
167         oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
168         oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist,
169         oHashKnownHosts,
170         oTunnel, oTunnelDevice,
171         oLocalCommand, oPermitLocalCommand, oRemoteCommand,
172         oVisualHostKey,
173         oKexAlgorithms, oIPQoS, oRequestTTY, oSessionType, oStdinNull,
174         oForkAfterAuthentication, oIgnoreUnknown, oProxyUseFdpass,
175         oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
176         oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
177         oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
178         oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms,
179         oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump,
180         oSecurityKeyProvider, oKnownHostsCommand,
181         oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
182 } OpCodes;
183
184 /* Textual representations of the tokens. */
185
186 static struct {
187         const char *name;
188         OpCodes opcode;
189 } keywords[] = {
190         /* Deprecated options */
191         { "protocol", oIgnore }, /* NB. silently ignored */
192         { "cipher", oDeprecated },
193         { "fallbacktorsh", oDeprecated },
194         { "globalknownhostsfile2", oDeprecated },
195         { "rhostsauthentication", oDeprecated },
196         { "userknownhostsfile2", oDeprecated },
197         { "useroaming", oDeprecated },
198         { "usersh", oDeprecated },
199         { "useprivilegedport", oDeprecated },
200
201         /* Unsupported options */
202         { "afstokenpassing", oUnsupported },
203         { "kerberosauthentication", oUnsupported },
204         { "kerberostgtpassing", oUnsupported },
205         { "rsaauthentication", oUnsupported },
206         { "rhostsrsaauthentication", oUnsupported },
207         { "compressionlevel", oUnsupported },
208
209         /* Sometimes-unsupported options */
210 #if defined(GSSAPI)
211         { "gssapiauthentication", oGssAuthentication },
212         { "gssapidelegatecredentials", oGssDelegateCreds },
213 # else
214         { "gssapiauthentication", oUnsupported },
215         { "gssapidelegatecredentials", oUnsupported },
216 #endif
217 #ifdef ENABLE_PKCS11
218         { "pkcs11provider", oPKCS11Provider },
219         { "smartcarddevice", oPKCS11Provider },
220 # else
221         { "smartcarddevice", oUnsupported },
222         { "pkcs11provider", oUnsupported },
223 #endif
224
225         { "forwardagent", oForwardAgent },
226         { "forwardx11", oForwardX11 },
227         { "forwardx11trusted", oForwardX11Trusted },
228         { "forwardx11timeout", oForwardX11Timeout },
229         { "exitonforwardfailure", oExitOnForwardFailure },
230         { "xauthlocation", oXAuthLocation },
231         { "gatewayports", oGatewayPorts },
232         { "passwordauthentication", oPasswordAuthentication },
233         { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
234         { "kbdinteractivedevices", oKbdInteractiveDevices },
235         { "challengeresponseauthentication", oKbdInteractiveAuthentication }, /* alias */
236         { "skeyauthentication", oKbdInteractiveAuthentication }, /* alias */
237         { "tisauthentication", oKbdInteractiveAuthentication },  /* alias */
238         { "pubkeyauthentication", oPubkeyAuthentication },
239         { "dsaauthentication", oPubkeyAuthentication },             /* alias */
240         { "hostbasedauthentication", oHostbasedAuthentication },
241         { "identityfile", oIdentityFile },
242         { "identityfile2", oIdentityFile },                     /* obsolete */
243         { "identitiesonly", oIdentitiesOnly },
244         { "certificatefile", oCertificateFile },
245         { "addkeystoagent", oAddKeysToAgent },
246         { "identityagent", oIdentityAgent },
247         { "hostname", oHostname },
248         { "hostkeyalias", oHostKeyAlias },
249         { "proxycommand", oProxyCommand },
250         { "port", oPort },
251         { "ciphers", oCiphers },
252         { "macs", oMacs },
253         { "remoteforward", oRemoteForward },
254         { "localforward", oLocalForward },
255         { "permitremoteopen", oPermitRemoteOpen },
256         { "user", oUser },
257         { "host", oHost },
258         { "match", oMatch },
259         { "escapechar", oEscapeChar },
260         { "globalknownhostsfile", oGlobalKnownHostsFile },
261         { "userknownhostsfile", oUserKnownHostsFile },
262         { "connectionattempts", oConnectionAttempts },
263         { "batchmode", oBatchMode },
264         { "checkhostip", oCheckHostIP },
265         { "stricthostkeychecking", oStrictHostKeyChecking },
266         { "compression", oCompression },
267         { "tcpkeepalive", oTCPKeepAlive },
268         { "keepalive", oTCPKeepAlive },                         /* obsolete */
269         { "numberofpasswordprompts", oNumberOfPasswordPrompts },
270         { "syslogfacility", oLogFacility },
271         { "loglevel", oLogLevel },
272         { "logverbose", oLogVerbose },
273         { "dynamicforward", oDynamicForward },
274         { "preferredauthentications", oPreferredAuthentications },
275         { "hostkeyalgorithms", oHostKeyAlgorithms },
276         { "casignaturealgorithms", oCASignatureAlgorithms },
277         { "bindaddress", oBindAddress },
278         { "bindinterface", oBindInterface },
279         { "clearallforwardings", oClearAllForwardings },
280         { "enablesshkeysign", oEnableSSHKeysign },
281         { "verifyhostkeydns", oVerifyHostKeyDNS },
282         { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
283         { "rekeylimit", oRekeyLimit },
284         { "connecttimeout", oConnectTimeout },
285         { "addressfamily", oAddressFamily },
286         { "serveraliveinterval", oServerAliveInterval },
287         { "serveralivecountmax", oServerAliveCountMax },
288         { "sendenv", oSendEnv },
289         { "setenv", oSetEnv },
290         { "controlpath", oControlPath },
291         { "controlmaster", oControlMaster },
292         { "controlpersist", oControlPersist },
293         { "hashknownhosts", oHashKnownHosts },
294         { "include", oInclude },
295         { "tunnel", oTunnel },
296         { "tunneldevice", oTunnelDevice },
297         { "localcommand", oLocalCommand },
298         { "permitlocalcommand", oPermitLocalCommand },
299         { "remotecommand", oRemoteCommand },
300         { "visualhostkey", oVisualHostKey },
301         { "kexalgorithms", oKexAlgorithms },
302         { "ipqos", oIPQoS },
303         { "requesttty", oRequestTTY },
304         { "sessiontype", oSessionType },
305         { "stdinnull", oStdinNull },
306         { "forkafterauthentication", oForkAfterAuthentication },
307         { "proxyusefdpass", oProxyUseFdpass },
308         { "canonicaldomains", oCanonicalDomains },
309         { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
310         { "canonicalizehostname", oCanonicalizeHostname },
311         { "canonicalizemaxdots", oCanonicalizeMaxDots },
312         { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
313         { "streamlocalbindmask", oStreamLocalBindMask },
314         { "streamlocalbindunlink", oStreamLocalBindUnlink },
315         { "revokedhostkeys", oRevokedHostKeys },
316         { "fingerprinthash", oFingerprintHash },
317         { "updatehostkeys", oUpdateHostkeys },
318         { "hostbasedacceptedalgorithms", oHostbasedAcceptedAlgorithms },
319         { "hostbasedkeytypes", oHostbasedAcceptedAlgorithms }, /* obsolete */
320         { "pubkeyacceptedalgorithms", oPubkeyAcceptedAlgorithms },
321         { "pubkeyacceptedkeytypes", oPubkeyAcceptedAlgorithms }, /* obsolete */
322         { "ignoreunknown", oIgnoreUnknown },
323         { "proxyjump", oProxyJump },
324         { "securitykeyprovider", oSecurityKeyProvider },
325         { "knownhostscommand", oKnownHostsCommand },
326
327         { "hpndisabled", oDeprecated },
328         { "hpnbuffersize", oDeprecated },
329         { "tcprcvbufpoll", oDeprecated },
330         { "tcprcvbuf", oDeprecated },
331         { "noneenabled", oUnsupported },
332         { "noneswitch", oUnsupported },
333         { "versionaddendum", oVersionAddendum },
334
335         { NULL, oBadOption }
336 };
337
338 static const char *lookup_opcode_name(OpCodes code);
339
340 const char *
341 kex_default_pk_alg(void)
342 {
343         static char *pkalgs;
344
345         if (pkalgs == NULL) {
346                 char *all_key;
347
348                 all_key = sshkey_alg_list(0, 0, 1, ',');
349                 pkalgs = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
350                 free(all_key);
351         }
352         return pkalgs;
353 }
354
355 char *
356 ssh_connection_hash(const char *thishost, const char *host, const char *portstr,
357     const char *user)
358 {
359         struct ssh_digest_ctx *md;
360         u_char conn_hash[SSH_DIGEST_MAX_LENGTH];
361
362         if ((md = ssh_digest_start(SSH_DIGEST_SHA1)) == NULL ||
363             ssh_digest_update(md, thishost, strlen(thishost)) < 0 ||
364             ssh_digest_update(md, host, strlen(host)) < 0 ||
365             ssh_digest_update(md, portstr, strlen(portstr)) < 0 ||
366             ssh_digest_update(md, user, strlen(user)) < 0 ||
367             ssh_digest_final(md, conn_hash, sizeof(conn_hash)) < 0)
368                 fatal_f("mux digest failed");
369         ssh_digest_free(md);
370         return tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1));
371 }
372
373 /*
374  * Adds a local TCP/IP port forward to options.  Never returns if there is an
375  * error.
376  */
377
378 void
379 add_local_forward(Options *options, const struct Forward *newfwd)
380 {
381         struct Forward *fwd;
382         int i;
383
384         /* Don't add duplicates */
385         for (i = 0; i < options->num_local_forwards; i++) {
386                 if (forward_equals(newfwd, options->local_forwards + i))
387                         return;
388         }
389         options->local_forwards = xreallocarray(options->local_forwards,
390             options->num_local_forwards + 1,
391             sizeof(*options->local_forwards));
392         fwd = &options->local_forwards[options->num_local_forwards++];
393
394         fwd->listen_host = newfwd->listen_host;
395         fwd->listen_port = newfwd->listen_port;
396         fwd->listen_path = newfwd->listen_path;
397         fwd->connect_host = newfwd->connect_host;
398         fwd->connect_port = newfwd->connect_port;
399         fwd->connect_path = newfwd->connect_path;
400 }
401
402 /*
403  * Adds a remote TCP/IP port forward to options.  Never returns if there is
404  * an error.
405  */
406
407 void
408 add_remote_forward(Options *options, const struct Forward *newfwd)
409 {
410         struct Forward *fwd;
411         int i;
412
413         /* Don't add duplicates */
414         for (i = 0; i < options->num_remote_forwards; i++) {
415                 if (forward_equals(newfwd, options->remote_forwards + i))
416                         return;
417         }
418         options->remote_forwards = xreallocarray(options->remote_forwards,
419             options->num_remote_forwards + 1,
420             sizeof(*options->remote_forwards));
421         fwd = &options->remote_forwards[options->num_remote_forwards++];
422
423         fwd->listen_host = newfwd->listen_host;
424         fwd->listen_port = newfwd->listen_port;
425         fwd->listen_path = newfwd->listen_path;
426         fwd->connect_host = newfwd->connect_host;
427         fwd->connect_port = newfwd->connect_port;
428         fwd->connect_path = newfwd->connect_path;
429         fwd->handle = newfwd->handle;
430         fwd->allocated_port = 0;
431 }
432
433 static void
434 clear_forwardings(Options *options)
435 {
436         int i;
437
438         for (i = 0; i < options->num_local_forwards; i++) {
439                 free(options->local_forwards[i].listen_host);
440                 free(options->local_forwards[i].listen_path);
441                 free(options->local_forwards[i].connect_host);
442                 free(options->local_forwards[i].connect_path);
443         }
444         if (options->num_local_forwards > 0) {
445                 free(options->local_forwards);
446                 options->local_forwards = NULL;
447         }
448         options->num_local_forwards = 0;
449         for (i = 0; i < options->num_remote_forwards; i++) {
450                 free(options->remote_forwards[i].listen_host);
451                 free(options->remote_forwards[i].listen_path);
452                 free(options->remote_forwards[i].connect_host);
453                 free(options->remote_forwards[i].connect_path);
454         }
455         if (options->num_remote_forwards > 0) {
456                 free(options->remote_forwards);
457                 options->remote_forwards = NULL;
458         }
459         options->num_remote_forwards = 0;
460         options->tun_open = SSH_TUNMODE_NO;
461 }
462
463 void
464 add_certificate_file(Options *options, const char *path, int userprovided)
465 {
466         int i;
467
468         if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES)
469                 fatal("Too many certificate files specified (max %d)",
470                     SSH_MAX_CERTIFICATE_FILES);
471
472         /* Avoid registering duplicates */
473         for (i = 0; i < options->num_certificate_files; i++) {
474                 if (options->certificate_file_userprovided[i] == userprovided &&
475                     strcmp(options->certificate_files[i], path) == 0) {
476                         debug2_f("ignoring duplicate key %s", path);
477                         return;
478                 }
479         }
480
481         options->certificate_file_userprovided[options->num_certificate_files] =
482             userprovided;
483         options->certificate_files[options->num_certificate_files++] =
484             xstrdup(path);
485 }
486
487 void
488 add_identity_file(Options *options, const char *dir, const char *filename,
489     int userprovided)
490 {
491         char *path;
492         int i;
493
494         if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
495                 fatal("Too many identity files specified (max %d)",
496                     SSH_MAX_IDENTITY_FILES);
497
498         if (dir == NULL) /* no dir, filename is absolute */
499                 path = xstrdup(filename);
500         else if (xasprintf(&path, "%s%s", dir, filename) >= PATH_MAX)
501                 fatal("Identity file path %s too long", path);
502
503         /* Avoid registering duplicates */
504         for (i = 0; i < options->num_identity_files; i++) {
505                 if (options->identity_file_userprovided[i] == userprovided &&
506                     strcmp(options->identity_files[i], path) == 0) {
507                         debug2_f("ignoring duplicate key %s", path);
508                         free(path);
509                         return;
510                 }
511         }
512
513         options->identity_file_userprovided[options->num_identity_files] =
514             userprovided;
515         options->identity_files[options->num_identity_files++] = path;
516 }
517
518 int
519 default_ssh_port(void)
520 {
521         static int port;
522         struct servent *sp;
523
524         if (port == 0) {
525                 sp = getservbyname(SSH_SERVICE_NAME, "tcp");
526                 port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
527         }
528         return port;
529 }
530
531 /*
532  * Execute a command in a shell.
533  * Return its exit status or -1 on abnormal exit.
534  */
535 static int
536 execute_in_shell(const char *cmd)
537 {
538         char *shell;
539         pid_t pid;
540         int status;
541
542         if ((shell = getenv("SHELL")) == NULL)
543                 shell = _PATH_BSHELL;
544
545         if (access(shell, X_OK) == -1) {
546                 fatal("Shell \"%s\" is not executable: %s",
547                     shell, strerror(errno));
548         }
549
550         debug("Executing command: '%.500s'", cmd);
551
552         /* Fork and execute the command. */
553         if ((pid = fork()) == 0) {
554                 char *argv[4];
555
556                 if (stdfd_devnull(1, 1, 0) == -1)
557                         fatal_f("stdfd_devnull failed");
558                 closefrom(STDERR_FILENO + 1);
559
560                 argv[0] = shell;
561                 argv[1] = "-c";
562                 argv[2] = xstrdup(cmd);
563                 argv[3] = NULL;
564
565                 execv(argv[0], argv);
566                 error("Unable to execute '%.100s': %s", cmd, strerror(errno));
567                 /* Die with signal to make this error apparent to parent. */
568                 ssh_signal(SIGTERM, SIG_DFL);
569                 kill(getpid(), SIGTERM);
570                 _exit(1);
571         }
572         /* Parent. */
573         if (pid == -1)
574                 fatal_f("fork: %.100s", strerror(errno));
575
576         while (waitpid(pid, &status, 0) == -1) {
577                 if (errno != EINTR && errno != EAGAIN)
578                         fatal_f("waitpid: %s", strerror(errno));
579         }
580         if (!WIFEXITED(status)) {
581                 error("command '%.100s' exited abnormally", cmd);
582                 return -1;
583         }
584         debug3("command returned status %d", WEXITSTATUS(status));
585         return WEXITSTATUS(status);
586 }
587
588 /*
589  * Parse and execute a Match directive.
590  */
591 static int
592 match_cfg_line(Options *options, char **condition, struct passwd *pw,
593     const char *host_arg, const char *original_host, int final_pass,
594     int *want_final_pass, const char *filename, int linenum)
595 {
596         char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria;
597         const char *ruser;
598         int r, port, this_result, result = 1, attributes = 0, negate;
599         char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
600         char uidstr[32];
601
602         /*
603          * Configuration is likely to be incomplete at this point so we
604          * must be prepared to use default values.
605          */
606         port = options->port <= 0 ? default_ssh_port() : options->port;
607         ruser = options->user == NULL ? pw->pw_name : options->user;
608         if (final_pass) {
609                 host = xstrdup(options->hostname);
610         } else if (options->hostname != NULL) {
611                 /* NB. Please keep in sync with ssh.c:main() */
612                 host = percent_expand(options->hostname,
613                     "h", host_arg, (char *)NULL);
614         } else {
615                 host = xstrdup(host_arg);
616         }
617
618         debug2("checking match for '%s' host %s originally %s",
619             cp, host, original_host);
620         while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') {
621                 /* Terminate on comment */
622                 if (*attrib == '#') {
623                         cp = NULL; /* mark all arguments consumed */
624                         break;
625                 }
626                 arg = criteria = NULL;
627                 this_result = 1;
628                 if ((negate = attrib[0] == '!'))
629                         attrib++;
630                 /* Criterion "all" has no argument and must appear alone */
631                 if (strcasecmp(attrib, "all") == 0) {
632                         if (attributes > 1 || ((arg = strdelim(&cp)) != NULL &&
633                             *arg != '\0' && *arg != '#')) {
634                                 error("%.200s line %d: '%s' cannot be combined "
635                                     "with other Match attributes",
636                                     filename, linenum, oattrib);
637                                 result = -1;
638                                 goto out;
639                         }
640                         if (arg != NULL && *arg == '#')
641                                 cp = NULL; /* mark all arguments consumed */
642                         if (result)
643                                 result = negate ? 0 : 1;
644                         goto out;
645                 }
646                 attributes++;
647                 /* criteria "final" and "canonical" have no argument */
648                 if (strcasecmp(attrib, "canonical") == 0 ||
649                     strcasecmp(attrib, "final") == 0) {
650                         /*
651                          * If the config requests "Match final" then remember
652                          * this so we can perform a second pass later.
653                          */
654                         if (strcasecmp(attrib, "final") == 0 &&
655                             want_final_pass != NULL)
656                                 *want_final_pass = 1;
657                         r = !!final_pass;  /* force bitmask member to boolean */
658                         if (r == (negate ? 1 : 0))
659                                 this_result = result = 0;
660                         debug3("%.200s line %d: %smatched '%s'",
661                             filename, linenum,
662                             this_result ? "" : "not ", oattrib);
663                         continue;
664                 }
665                 /* All other criteria require an argument */
666                 if ((arg = strdelim(&cp)) == NULL ||
667                     *arg == '\0' || *arg == '#') {
668                         error("Missing Match criteria for %s", attrib);
669                         result = -1;
670                         goto out;
671                 }
672                 if (strcasecmp(attrib, "host") == 0) {
673                         criteria = xstrdup(host);
674                         r = match_hostname(host, arg) == 1;
675                         if (r == (negate ? 1 : 0))
676                                 this_result = result = 0;
677                 } else if (strcasecmp(attrib, "originalhost") == 0) {
678                         criteria = xstrdup(original_host);
679                         r = match_hostname(original_host, arg) == 1;
680                         if (r == (negate ? 1 : 0))
681                                 this_result = result = 0;
682                 } else if (strcasecmp(attrib, "user") == 0) {
683                         criteria = xstrdup(ruser);
684                         r = match_pattern_list(ruser, arg, 0) == 1;
685                         if (r == (negate ? 1 : 0))
686                                 this_result = result = 0;
687                 } else if (strcasecmp(attrib, "localuser") == 0) {
688                         criteria = xstrdup(pw->pw_name);
689                         r = match_pattern_list(pw->pw_name, arg, 0) == 1;
690                         if (r == (negate ? 1 : 0))
691                                 this_result = result = 0;
692                 } else if (strcasecmp(attrib, "exec") == 0) {
693                         char *conn_hash_hex, *keyalias;
694
695                         if (gethostname(thishost, sizeof(thishost)) == -1)
696                                 fatal("gethostname: %s", strerror(errno));
697                         strlcpy(shorthost, thishost, sizeof(shorthost));
698                         shorthost[strcspn(thishost, ".")] = '\0';
699                         snprintf(portstr, sizeof(portstr), "%d", port);
700                         snprintf(uidstr, sizeof(uidstr), "%llu",
701                             (unsigned long long)pw->pw_uid);
702                         conn_hash_hex = ssh_connection_hash(thishost, host,
703                             portstr, ruser);
704                         keyalias = options->host_key_alias ?
705                             options->host_key_alias : host;
706
707                         cmd = percent_expand(arg,
708                             "C", conn_hash_hex,
709                             "L", shorthost,
710                             "d", pw->pw_dir,
711                             "h", host,
712                             "k", keyalias,
713                             "l", thishost,
714                             "n", original_host,
715                             "p", portstr,
716                             "r", ruser,
717                             "u", pw->pw_name,
718                             "i", uidstr,
719                             (char *)NULL);
720                         free(conn_hash_hex);
721                         if (result != 1) {
722                                 /* skip execution if prior predicate failed */
723                                 debug3("%.200s line %d: skipped exec "
724                                     "\"%.100s\"", filename, linenum, cmd);
725                                 free(cmd);
726                                 continue;
727                         }
728                         r = execute_in_shell(cmd);
729                         if (r == -1) {
730                                 fatal("%.200s line %d: match exec "
731                                     "'%.100s' error", filename,
732                                     linenum, cmd);
733                         }
734                         criteria = xstrdup(cmd);
735                         free(cmd);
736                         /* Force exit status to boolean */
737                         r = r == 0;
738                         if (r == (negate ? 1 : 0))
739                                 this_result = result = 0;
740                 } else {
741                         error("Unsupported Match attribute %s", attrib);
742                         result = -1;
743                         goto out;
744                 }
745                 debug3("%.200s line %d: %smatched '%s \"%.100s\"' ",
746                     filename, linenum, this_result ? "": "not ",
747                     oattrib, criteria);
748                 free(criteria);
749         }
750         if (attributes == 0) {
751                 error("One or more attributes required for Match");
752                 result = -1;
753                 goto out;
754         }
755  out:
756         if (result != -1)
757                 debug2("match %sfound", result ? "" : "not ");
758         *condition = cp;
759         free(host);
760         return result;
761 }
762
763 /* Remove environment variable by pattern */
764 static void
765 rm_env(Options *options, const char *arg, const char *filename, int linenum)
766 {
767         int i, j, onum_send_env = options->num_send_env;
768         char *cp;
769
770         /* Remove an environment variable */
771         for (i = 0; i < options->num_send_env; ) {
772                 cp = xstrdup(options->send_env[i]);
773                 if (!match_pattern(cp, arg + 1)) {
774                         free(cp);
775                         i++;
776                         continue;
777                 }
778                 debug3("%s line %d: removing environment %s",
779                     filename, linenum, cp);
780                 free(cp);
781                 free(options->send_env[i]);
782                 options->send_env[i] = NULL;
783                 for (j = i; j < options->num_send_env - 1; j++) {
784                         options->send_env[j] = options->send_env[j + 1];
785                         options->send_env[j + 1] = NULL;
786                 }
787                 options->num_send_env--;
788                 /* NB. don't increment i */
789         }
790         if (onum_send_env != options->num_send_env) {
791                 options->send_env = xrecallocarray(options->send_env,
792                     onum_send_env, options->num_send_env,
793                     sizeof(*options->send_env));
794         }
795 }
796
797 /*
798  * Returns the number of the token pointed to by cp or oBadOption.
799  */
800 static OpCodes
801 parse_token(const char *cp, const char *filename, int linenum,
802     const char *ignored_unknown)
803 {
804         int i;
805
806         for (i = 0; keywords[i].name; i++)
807                 if (strcmp(cp, keywords[i].name) == 0)
808                         return keywords[i].opcode;
809         if (ignored_unknown != NULL &&
810             match_pattern_list(cp, ignored_unknown, 1) == 1)
811                 return oIgnoredUnknownOption;
812         error("%s: line %d: Bad configuration option: %s",
813             filename, linenum, cp);
814         return oBadOption;
815 }
816
817 /* Multistate option parsing */
818 struct multistate {
819         char *key;
820         int value;
821 };
822 static const struct multistate multistate_flag[] = {
823         { "true",                       1 },
824         { "false",                      0 },
825         { "yes",                        1 },
826         { "no",                         0 },
827         { NULL, -1 }
828 };
829 static const struct multistate multistate_yesnoask[] = {
830         { "true",                       1 },
831         { "false",                      0 },
832         { "yes",                        1 },
833         { "no",                         0 },
834         { "ask",                        2 },
835         { NULL, -1 }
836 };
837 static const struct multistate multistate_strict_hostkey[] = {
838         { "true",                       SSH_STRICT_HOSTKEY_YES },
839         { "false",                      SSH_STRICT_HOSTKEY_OFF },
840         { "yes",                        SSH_STRICT_HOSTKEY_YES },
841         { "no",                         SSH_STRICT_HOSTKEY_OFF },
842         { "ask",                        SSH_STRICT_HOSTKEY_ASK },
843         { "off",                        SSH_STRICT_HOSTKEY_OFF },
844         { "accept-new",                 SSH_STRICT_HOSTKEY_NEW },
845         { NULL, -1 }
846 };
847 static const struct multistate multistate_yesnoaskconfirm[] = {
848         { "true",                       1 },
849         { "false",                      0 },
850         { "yes",                        1 },
851         { "no",                         0 },
852         { "ask",                        2 },
853         { "confirm",                    3 },
854         { NULL, -1 }
855 };
856 static const struct multistate multistate_addressfamily[] = {
857         { "inet",                       AF_INET },
858         { "inet6",                      AF_INET6 },
859         { "any",                        AF_UNSPEC },
860         { NULL, -1 }
861 };
862 static const struct multistate multistate_controlmaster[] = {
863         { "true",                       SSHCTL_MASTER_YES },
864         { "yes",                        SSHCTL_MASTER_YES },
865         { "false",                      SSHCTL_MASTER_NO },
866         { "no",                         SSHCTL_MASTER_NO },
867         { "auto",                       SSHCTL_MASTER_AUTO },
868         { "ask",                        SSHCTL_MASTER_ASK },
869         { "autoask",                    SSHCTL_MASTER_AUTO_ASK },
870         { NULL, -1 }
871 };
872 static const struct multistate multistate_tunnel[] = {
873         { "ethernet",                   SSH_TUNMODE_ETHERNET },
874         { "point-to-point",             SSH_TUNMODE_POINTOPOINT },
875         { "true",                       SSH_TUNMODE_DEFAULT },
876         { "yes",                        SSH_TUNMODE_DEFAULT },
877         { "false",                      SSH_TUNMODE_NO },
878         { "no",                         SSH_TUNMODE_NO },
879         { NULL, -1 }
880 };
881 static const struct multistate multistate_requesttty[] = {
882         { "true",                       REQUEST_TTY_YES },
883         { "yes",                        REQUEST_TTY_YES },
884         { "false",                      REQUEST_TTY_NO },
885         { "no",                         REQUEST_TTY_NO },
886         { "force",                      REQUEST_TTY_FORCE },
887         { "auto",                       REQUEST_TTY_AUTO },
888         { NULL, -1 }
889 };
890 static const struct multistate multistate_sessiontype[] = {
891         { "none",                       SESSION_TYPE_NONE },
892         { "subsystem",                  SESSION_TYPE_SUBSYSTEM },
893         { "default",                    SESSION_TYPE_DEFAULT },
894         { NULL, -1 }
895 };
896 static const struct multistate multistate_canonicalizehostname[] = {
897         { "true",                       SSH_CANONICALISE_YES },
898         { "false",                      SSH_CANONICALISE_NO },
899         { "yes",                        SSH_CANONICALISE_YES },
900         { "no",                         SSH_CANONICALISE_NO },
901         { "always",                     SSH_CANONICALISE_ALWAYS },
902         { NULL, -1 }
903 };
904 static const struct multistate multistate_compression[] = {
905 #ifdef WITH_ZLIB
906         { "yes",                        COMP_ZLIB },
907 #endif
908         { "no",                         COMP_NONE },
909         { NULL, -1 }
910 };
911
912 static int
913 parse_multistate_value(const char *arg, const char *filename, int linenum,
914     const struct multistate *multistate_ptr)
915 {
916         int i;
917
918         if (!arg || *arg == '\0') {
919                 error("%s line %d: missing argument.", filename, linenum);
920                 return -1;
921         }
922         for (i = 0; multistate_ptr[i].key != NULL; i++) {
923                 if (strcasecmp(arg, multistate_ptr[i].key) == 0)
924                         return multistate_ptr[i].value;
925         }
926         return -1;
927 }
928
929 /*
930  * Processes a single option line as used in the configuration files. This
931  * only sets those values that have not already been set.
932  */
933 int
934 process_config_line(Options *options, struct passwd *pw, const char *host,
935     const char *original_host, char *line, const char *filename,
936     int linenum, int *activep, int flags)
937 {
938         return process_config_line_depth(options, pw, host, original_host,
939             line, filename, linenum, activep, flags, NULL, 0);
940 }
941
942 #define WHITESPACE " \t\r\n"
943 static int
944 process_config_line_depth(Options *options, struct passwd *pw, const char *host,
945     const char *original_host, char *line, const char *filename,
946     int linenum, int *activep, int flags, int *want_final_pass, int depth)
947 {
948         char *str, **charptr, *endofnumber, *keyword, *arg, *arg2, *p, ch;
949         char **cpptr, ***cppptr, fwdarg[256];
950         u_int i, *uintptr, uvalue, max_entries = 0;
951         int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0;
952         int remotefwd, dynamicfwd;
953         LogLevel *log_level_ptr;
954         SyslogFacility *log_facility_ptr;
955         long long val64;
956         size_t len;
957         struct Forward fwd;
958         const struct multistate *multistate_ptr;
959         struct allowed_cname *cname;
960         glob_t gl;
961         const char *errstr;
962         char **oav = NULL, **av;
963         int oac = 0, ac;
964         int ret = -1;
965
966         if (activep == NULL) { /* We are processing a command line directive */
967                 cmdline = 1;
968                 activep = &cmdline;
969         }
970
971         /* Strip trailing whitespace. Allow \f (form feed) at EOL only */
972         if ((len = strlen(line)) == 0)
973                 return 0;
974         for (len--; len > 0; len--) {
975                 if (strchr(WHITESPACE "\f", line[len]) == NULL)
976                         break;
977                 line[len] = '\0';
978         }
979
980         str = line;
981         /* Get the keyword. (Each line is supposed to begin with a keyword). */
982         if ((keyword = strdelim(&str)) == NULL)
983                 return 0;
984         /* Ignore leading whitespace. */
985         if (*keyword == '\0')
986                 keyword = strdelim(&str);
987         if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
988                 return 0;
989         /* Match lowercase keyword */
990         lowercase(keyword);
991
992         /* Prepare to parse remainder of line */
993         if (str != NULL)
994                 str += strspn(str, WHITESPACE);
995         if (str == NULL || *str == '\0') {
996                 error("%s line %d: no argument after keyword \"%s\"",
997                     filename, linenum, keyword);
998                 return -1;
999         }
1000         opcode = parse_token(keyword, filename, linenum,
1001             options->ignored_unknown);
1002         if (argv_split(str, &oac, &oav, 1) != 0) {
1003                 error("%s line %d: invalid quotes", filename, linenum);
1004                 return -1;
1005         }
1006         ac = oac;
1007         av = oav;
1008
1009         switch (opcode) {
1010         case oBadOption:
1011                 /* don't panic, but count bad options */
1012                 goto out;
1013         case oIgnore:
1014                 argv_consume(&ac);
1015                 break;
1016         case oIgnoredUnknownOption:
1017                 debug("%s line %d: Ignored unknown option \"%s\"",
1018                     filename, linenum, keyword);
1019                 argv_consume(&ac);
1020                 break;
1021         case oConnectTimeout:
1022                 intptr = &options->connection_timeout;
1023 parse_time:
1024                 arg = argv_next(&ac, &av);
1025                 if (!arg || *arg == '\0') {
1026                         error("%s line %d: missing time value.",
1027                             filename, linenum);
1028                         goto out;
1029                 }
1030                 if (strcmp(arg, "none") == 0)
1031                         value = -1;
1032                 else if ((value = convtime(arg)) == -1) {
1033                         error("%s line %d: invalid time value.",
1034                             filename, linenum);
1035                         goto out;
1036                 }
1037                 if (*activep && *intptr == -1)
1038                         *intptr = value;
1039                 break;
1040
1041         case oForwardAgent:
1042                 intptr = &options->forward_agent;
1043
1044                 arg = argv_next(&ac, &av);
1045                 if (!arg || *arg == '\0') {
1046                         error("%s line %d: missing argument.",
1047                             filename, linenum);
1048                         goto out;
1049                 }
1050
1051                 value = -1;
1052                 multistate_ptr = multistate_flag;
1053                 for (i = 0; multistate_ptr[i].key != NULL; i++) {
1054                         if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
1055                                 value = multistate_ptr[i].value;
1056                                 break;
1057                         }
1058                 }
1059                 if (value != -1) {
1060                         if (*activep && *intptr == -1)
1061                                 *intptr = value;
1062                         break;
1063                 }
1064                 /* ForwardAgent wasn't 'yes' or 'no', assume a path */
1065                 if (*activep && *intptr == -1)
1066                         *intptr = 1;
1067
1068                 charptr = &options->forward_agent_sock_path;
1069                 goto parse_agent_path;
1070
1071         case oForwardX11:
1072                 intptr = &options->forward_x11;
1073  parse_flag:
1074                 multistate_ptr = multistate_flag;
1075  parse_multistate:
1076                 arg = argv_next(&ac, &av);
1077                 if ((value = parse_multistate_value(arg, filename, linenum,
1078                     multistate_ptr)) == -1) {
1079                         error("%s line %d: unsupported option \"%s\".",
1080                             filename, linenum, arg);
1081                         goto out;
1082                 }
1083                 if (*activep && *intptr == -1)
1084                         *intptr = value;
1085                 break;
1086
1087         case oForwardX11Trusted:
1088                 intptr = &options->forward_x11_trusted;
1089                 goto parse_flag;
1090
1091         case oForwardX11Timeout:
1092                 intptr = &options->forward_x11_timeout;
1093                 goto parse_time;
1094
1095         case oGatewayPorts:
1096                 intptr = &options->fwd_opts.gateway_ports;
1097                 goto parse_flag;
1098
1099         case oExitOnForwardFailure:
1100                 intptr = &options->exit_on_forward_failure;
1101                 goto parse_flag;
1102
1103         case oPasswordAuthentication:
1104                 intptr = &options->password_authentication;
1105                 goto parse_flag;
1106
1107         case oKbdInteractiveAuthentication:
1108                 intptr = &options->kbd_interactive_authentication;
1109                 goto parse_flag;
1110
1111         case oKbdInteractiveDevices:
1112                 charptr = &options->kbd_interactive_devices;
1113                 goto parse_string;
1114
1115         case oPubkeyAuthentication:
1116                 intptr = &options->pubkey_authentication;
1117                 goto parse_flag;
1118
1119         case oHostbasedAuthentication:
1120                 intptr = &options->hostbased_authentication;
1121                 goto parse_flag;
1122
1123         case oGssAuthentication:
1124                 intptr = &options->gss_authentication;
1125                 goto parse_flag;
1126
1127         case oGssDelegateCreds:
1128                 intptr = &options->gss_deleg_creds;
1129                 goto parse_flag;
1130
1131         case oBatchMode:
1132                 intptr = &options->batch_mode;
1133                 goto parse_flag;
1134
1135         case oCheckHostIP:
1136                 intptr = &options->check_host_ip;
1137                 goto parse_flag;
1138
1139         case oVerifyHostKeyDNS:
1140                 intptr = &options->verify_host_key_dns;
1141                 multistate_ptr = multistate_yesnoask;
1142                 goto parse_multistate;
1143
1144         case oStrictHostKeyChecking:
1145                 intptr = &options->strict_host_key_checking;
1146                 multistate_ptr = multistate_strict_hostkey;
1147                 goto parse_multistate;
1148
1149         case oCompression:
1150                 intptr = &options->compression;
1151                 multistate_ptr = multistate_compression;
1152                 goto parse_multistate;
1153
1154         case oTCPKeepAlive:
1155                 intptr = &options->tcp_keep_alive;
1156                 goto parse_flag;
1157
1158         case oNoHostAuthenticationForLocalhost:
1159                 intptr = &options->no_host_authentication_for_localhost;
1160                 goto parse_flag;
1161
1162         case oNumberOfPasswordPrompts:
1163                 intptr = &options->number_of_password_prompts;
1164                 goto parse_int;
1165
1166         case oRekeyLimit:
1167                 arg = argv_next(&ac, &av);
1168                 if (!arg || *arg == '\0') {
1169                         error("%.200s line %d: Missing argument.", filename,
1170                             linenum);
1171                         goto out;
1172                 }
1173                 if (strcmp(arg, "default") == 0) {
1174                         val64 = 0;
1175                 } else {
1176                         if (scan_scaled(arg, &val64) == -1) {
1177                                 error("%.200s line %d: Bad number '%s': %s",
1178                                     filename, linenum, arg, strerror(errno));
1179                                 goto out;
1180                         }
1181                         if (val64 != 0 && val64 < 16) {
1182                                 error("%.200s line %d: RekeyLimit too small",
1183                                     filename, linenum);
1184                                 goto out;
1185                         }
1186                 }
1187                 if (*activep && options->rekey_limit == -1)
1188                         options->rekey_limit = val64;
1189                 if (ac != 0) { /* optional rekey interval present */
1190                         if (strcmp(av[0], "none") == 0) {
1191                                 (void)argv_next(&ac, &av);      /* discard */
1192                                 break;
1193                         }
1194                         intptr = &options->rekey_interval;
1195                         goto parse_time;
1196                 }
1197                 break;
1198
1199         case oIdentityFile:
1200                 arg = argv_next(&ac, &av);
1201                 if (!arg || *arg == '\0') {
1202                         error("%.200s line %d: Missing argument.",
1203                             filename, linenum);
1204                         goto out;
1205                 }
1206                 if (*activep) {
1207                         intptr = &options->num_identity_files;
1208                         if (*intptr >= SSH_MAX_IDENTITY_FILES) {
1209                                 error("%.200s line %d: Too many identity files "
1210                                     "specified (max %d).", filename, linenum,
1211                                     SSH_MAX_IDENTITY_FILES);
1212                                 goto out;
1213                         }
1214                         add_identity_file(options, NULL,
1215                             arg, flags & SSHCONF_USERCONF);
1216                 }
1217                 break;
1218
1219         case oCertificateFile:
1220                 arg = argv_next(&ac, &av);
1221                 if (!arg || *arg == '\0') {
1222                         error("%.200s line %d: Missing argument.",
1223                             filename, linenum);
1224                         goto out;
1225                 }
1226                 if (*activep) {
1227                         intptr = &options->num_certificate_files;
1228                         if (*intptr >= SSH_MAX_CERTIFICATE_FILES) {
1229                                 error("%.200s line %d: Too many certificate "
1230                                     "files specified (max %d).",
1231                                     filename, linenum,
1232                                     SSH_MAX_CERTIFICATE_FILES);
1233                                 goto out;
1234                         }
1235                         add_certificate_file(options, arg,
1236                             flags & SSHCONF_USERCONF);
1237                 }
1238                 break;
1239
1240         case oXAuthLocation:
1241                 charptr=&options->xauth_location;
1242                 goto parse_string;
1243
1244         case oUser:
1245                 charptr = &options->user;
1246 parse_string:
1247                 arg = argv_next(&ac, &av);
1248                 if (!arg || *arg == '\0') {
1249                         error("%.200s line %d: Missing argument.",
1250                             filename, linenum);
1251                         goto out;
1252                 }
1253                 if (*activep && *charptr == NULL)
1254                         *charptr = xstrdup(arg);
1255                 break;
1256
1257         case oGlobalKnownHostsFile:
1258                 cpptr = (char **)&options->system_hostfiles;
1259                 uintptr = &options->num_system_hostfiles;
1260                 max_entries = SSH_MAX_HOSTS_FILES;
1261 parse_char_array:
1262                 i = 0;
1263                 value = *uintptr == 0; /* was array empty when we started? */
1264                 while ((arg = argv_next(&ac, &av)) != NULL) {
1265                         if (*arg == '\0') {
1266                                 error("%s line %d: keyword %s empty argument",
1267                                     filename, linenum, keyword);
1268                                 goto out;
1269                         }
1270                         /* Allow "none" only in first position */
1271                         if (strcasecmp(arg, "none") == 0) {
1272                                 if (i > 0 || ac > 0) {
1273                                         error("%s line %d: keyword %s \"none\" "
1274                                             "argument must appear alone.",
1275                                             filename, linenum, keyword);
1276                                         goto out;
1277                                 }
1278                         }
1279                         i++;
1280                         if (*activep && value) {
1281                                 if ((*uintptr) >= max_entries) {
1282                                         error("%s line %d: too many %s "
1283                                             "entries.", filename, linenum,
1284                                             keyword);
1285                                         goto out;
1286                                 }
1287                                 cpptr[(*uintptr)++] = xstrdup(arg);
1288                         }
1289                 }
1290                 break;
1291
1292         case oUserKnownHostsFile:
1293                 cpptr = (char **)&options->user_hostfiles;
1294                 uintptr = &options->num_user_hostfiles;
1295                 max_entries = SSH_MAX_HOSTS_FILES;
1296                 goto parse_char_array;
1297
1298         case oHostname:
1299                 charptr = &options->hostname;
1300                 goto parse_string;
1301
1302         case oHostKeyAlias:
1303                 charptr = &options->host_key_alias;
1304                 goto parse_string;
1305
1306         case oPreferredAuthentications:
1307                 charptr = &options->preferred_authentications;
1308                 goto parse_string;
1309
1310         case oBindAddress:
1311                 charptr = &options->bind_address;
1312                 goto parse_string;
1313
1314         case oBindInterface:
1315                 charptr = &options->bind_interface;
1316                 goto parse_string;
1317
1318         case oPKCS11Provider:
1319                 charptr = &options->pkcs11_provider;
1320                 goto parse_string;
1321
1322         case oSecurityKeyProvider:
1323                 charptr = &options->sk_provider;
1324                 goto parse_string;
1325
1326         case oKnownHostsCommand:
1327                 charptr = &options->known_hosts_command;
1328                 goto parse_command;
1329
1330         case oProxyCommand:
1331                 charptr = &options->proxy_command;
1332                 /* Ignore ProxyCommand if ProxyJump already specified */
1333                 if (options->jump_host != NULL)
1334                         charptr = &options->jump_host; /* Skip below */
1335 parse_command:
1336                 if (str == NULL) {
1337                         error("%.200s line %d: Missing argument.",
1338                             filename, linenum);
1339                         goto out;
1340                 }
1341                 len = strspn(str, WHITESPACE "=");
1342                 if (*activep && *charptr == NULL)
1343                         *charptr = xstrdup(str + len);
1344                 argv_consume(&ac);
1345                 break;
1346
1347         case oProxyJump:
1348                 if (str == NULL) {
1349                         error("%.200s line %d: Missing argument.",
1350                             filename, linenum);
1351                         goto out;
1352                 }
1353                 len = strspn(str, WHITESPACE "=");
1354                 /* XXX use argv? */
1355                 if (parse_jump(str + len, options, *activep) == -1) {
1356                         error("%.200s line %d: Invalid ProxyJump \"%s\"",
1357                             filename, linenum, str + len);
1358                         goto out;
1359                 }
1360                 argv_consume(&ac);
1361                 break;
1362
1363         case oPort:
1364                 arg = argv_next(&ac, &av);
1365                 if (!arg || *arg == '\0') {
1366                         error("%.200s line %d: Missing argument.",
1367                             filename, linenum);
1368                         goto out;
1369                 }
1370                 value = a2port(arg);
1371                 if (value <= 0) {
1372                         error("%.200s line %d: Bad port '%s'.",
1373                             filename, linenum, arg);
1374                         goto out;
1375                 }
1376                 if (*activep && options->port == -1)
1377                         options->port = value;
1378                 break;
1379
1380         case oConnectionAttempts:
1381                 intptr = &options->connection_attempts;
1382 parse_int:
1383                 arg = argv_next(&ac, &av);
1384                 if ((errstr = atoi_err(arg, &value)) != NULL) {
1385                         error("%s line %d: integer value %s.",
1386                             filename, linenum, errstr);
1387                         goto out;
1388                 }
1389                 if (*activep && *intptr == -1)
1390                         *intptr = value;
1391                 break;
1392
1393         case oCiphers:
1394                 arg = argv_next(&ac, &av);
1395                 if (!arg || *arg == '\0') {
1396                         error("%.200s line %d: Missing argument.",
1397                             filename, linenum);
1398                         goto out;
1399                 }
1400                 if (*arg != '-' &&
1401                     !ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)){
1402                         error("%.200s line %d: Bad SSH2 cipher spec '%s'.",
1403                             filename, linenum, arg ? arg : "<NONE>");
1404                         goto out;
1405                 }
1406                 if (*activep && options->ciphers == NULL)
1407                         options->ciphers = xstrdup(arg);
1408                 break;
1409
1410         case oMacs:
1411                 arg = argv_next(&ac, &av);
1412                 if (!arg || *arg == '\0') {
1413                         error("%.200s line %d: Missing argument.",
1414                             filename, linenum);
1415                         goto out;
1416                 }
1417                 if (*arg != '-' &&
1418                     !mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)) {
1419                         error("%.200s line %d: Bad SSH2 MAC spec '%s'.",
1420                             filename, linenum, arg ? arg : "<NONE>");
1421                         goto out;
1422                 }
1423                 if (*activep && options->macs == NULL)
1424                         options->macs = xstrdup(arg);
1425                 break;
1426
1427         case oKexAlgorithms:
1428                 arg = argv_next(&ac, &av);
1429                 if (!arg || *arg == '\0') {
1430                         error("%.200s line %d: Missing argument.",
1431                             filename, linenum);
1432                         goto out;
1433                 }
1434                 if (*arg != '-' &&
1435                     !kex_names_valid(*arg == '+' || *arg == '^' ?
1436                     arg + 1 : arg)) {
1437                         error("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
1438                             filename, linenum, arg ? arg : "<NONE>");
1439                         goto out;
1440                 }
1441                 if (*activep && options->kex_algorithms == NULL)
1442                         options->kex_algorithms = xstrdup(arg);
1443                 break;
1444
1445         case oHostKeyAlgorithms:
1446                 charptr = &options->hostkeyalgorithms;
1447 parse_pubkey_algos:
1448                 arg = argv_next(&ac, &av);
1449                 if (!arg || *arg == '\0') {
1450                         error("%.200s line %d: Missing argument.",
1451                             filename, linenum);
1452                         goto out;
1453                 }
1454                 if (*arg != '-' &&
1455                     !sshkey_names_valid2(*arg == '+' || *arg == '^' ?
1456                     arg + 1 : arg, 1)) {
1457                         error("%s line %d: Bad key types '%s'.",
1458                             filename, linenum, arg ? arg : "<NONE>");
1459                         goto out;
1460                 }
1461                 if (*activep && *charptr == NULL)
1462                         *charptr = xstrdup(arg);
1463                 break;
1464
1465         case oCASignatureAlgorithms:
1466                 charptr = &options->ca_sign_algorithms;
1467                 goto parse_pubkey_algos;
1468
1469         case oLogLevel:
1470                 log_level_ptr = &options->log_level;
1471                 arg = argv_next(&ac, &av);
1472                 value = log_level_number(arg);
1473                 if (value == SYSLOG_LEVEL_NOT_SET) {
1474                         error("%.200s line %d: unsupported log level '%s'",
1475                             filename, linenum, arg ? arg : "<NONE>");
1476                         goto out;
1477                 }
1478                 if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
1479                         *log_level_ptr = (LogLevel) value;
1480                 break;
1481
1482         case oLogFacility:
1483                 log_facility_ptr = &options->log_facility;
1484                 arg = argv_next(&ac, &av);
1485                 value = log_facility_number(arg);
1486                 if (value == SYSLOG_FACILITY_NOT_SET) {
1487                         error("%.200s line %d: unsupported log facility '%s'",
1488                             filename, linenum, arg ? arg : "<NONE>");
1489                         goto out;
1490                 }
1491                 if (*log_facility_ptr == -1)
1492                         *log_facility_ptr = (SyslogFacility) value;
1493                 break;
1494
1495         case oLogVerbose:
1496                 cppptr = &options->log_verbose;
1497                 uintptr = &options->num_log_verbose;
1498                 i = 0;
1499                 while ((arg = argv_next(&ac, &av)) != NULL) {
1500                         if (*arg == '\0') {
1501                                 error("%s line %d: keyword %s empty argument",
1502                                     filename, linenum, keyword);
1503                                 goto out;
1504                         }
1505                         /* Allow "none" only in first position */
1506                         if (strcasecmp(arg, "none") == 0) {
1507                                 if (i > 0 || ac > 0) {
1508                                         error("%s line %d: keyword %s \"none\" "
1509                                             "argument must appear alone.",
1510                                             filename, linenum, keyword);
1511                                         goto out;
1512                                 }
1513                         }
1514                         i++;
1515                         if (*activep && *uintptr == 0) {
1516                                 *cppptr = xrecallocarray(*cppptr, *uintptr,
1517                                     *uintptr + 1, sizeof(**cppptr));
1518                                 (*cppptr)[(*uintptr)++] = xstrdup(arg);
1519                         }
1520                 }
1521                 break;
1522
1523         case oLocalForward:
1524         case oRemoteForward:
1525         case oDynamicForward:
1526                 arg = argv_next(&ac, &av);
1527                 if (!arg || *arg == '\0') {
1528                         error("%.200s line %d: Missing argument.",
1529                             filename, linenum);
1530                         goto out;
1531                 }
1532
1533                 remotefwd = (opcode == oRemoteForward);
1534                 dynamicfwd = (opcode == oDynamicForward);
1535
1536                 if (!dynamicfwd) {
1537                         arg2 = argv_next(&ac, &av);
1538                         if (arg2 == NULL || *arg2 == '\0') {
1539                                 if (remotefwd)
1540                                         dynamicfwd = 1;
1541                                 else {
1542                                         error("%.200s line %d: Missing target "
1543                                             "argument.", filename, linenum);
1544                                         goto out;
1545                                 }
1546                         } else {
1547                                 /* construct a string for parse_forward */
1548                                 snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg,
1549                                     arg2);
1550                         }
1551                 }
1552                 if (dynamicfwd)
1553                         strlcpy(fwdarg, arg, sizeof(fwdarg));
1554
1555                 if (parse_forward(&fwd, fwdarg, dynamicfwd, remotefwd) == 0) {
1556                         error("%.200s line %d: Bad forwarding specification.",
1557                             filename, linenum);
1558                         goto out;
1559                 }
1560
1561                 if (*activep) {
1562                         if (remotefwd) {
1563                                 add_remote_forward(options, &fwd);
1564                         } else {
1565                                 add_local_forward(options, &fwd);
1566                         }
1567                 }
1568                 break;
1569
1570         case oPermitRemoteOpen:
1571                 uintptr = &options->num_permitted_remote_opens;
1572                 cppptr = &options->permitted_remote_opens;
1573                 arg = argv_next(&ac, &av);
1574                 if (!arg || *arg == '\0')
1575                         fatal("%s line %d: missing %s specification",
1576                             filename, linenum, lookup_opcode_name(opcode));
1577                 uvalue = *uintptr;      /* modified later */
1578                 if (strcmp(arg, "any") == 0 || strcmp(arg, "none") == 0) {
1579                         if (*activep && uvalue == 0) {
1580                                 *uintptr = 1;
1581                                 *cppptr = xcalloc(1, sizeof(**cppptr));
1582                                 (*cppptr)[0] = xstrdup(arg);
1583                         }
1584                         break;
1585                 }
1586                 while ((arg = argv_next(&ac, &av)) != NULL) {
1587                         arg2 = xstrdup(arg);
1588                         ch = '\0';
1589                         p = hpdelim2(&arg, &ch);
1590                         if (p == NULL || ch == '/') {
1591                                 fatal("%s line %d: missing host in %s",
1592                                     filename, linenum,
1593                                     lookup_opcode_name(opcode));
1594                         }
1595                         p = cleanhostname(p);
1596                         /*
1597                          * don't want to use permitopen_port to avoid
1598                          * dependency on channels.[ch] here.
1599                          */
1600                         if (arg == NULL ||
1601                             (strcmp(arg, "*") != 0 && a2port(arg) <= 0)) {
1602                                 fatal("%s line %d: bad port number in %s",
1603                                     filename, linenum,
1604                                     lookup_opcode_name(opcode));
1605                         }
1606                         if (*activep && uvalue == 0) {
1607                                 opt_array_append(filename, linenum,
1608                                     lookup_opcode_name(opcode),
1609                                     cppptr, uintptr, arg2);
1610                         }
1611                         free(arg2);
1612                 }
1613                 break;
1614
1615         case oClearAllForwardings:
1616                 intptr = &options->clear_forwardings;
1617                 goto parse_flag;
1618
1619         case oHost:
1620                 if (cmdline) {
1621                         error("Host directive not supported as a command-line "
1622                             "option");
1623                         goto out;
1624                 }
1625                 *activep = 0;
1626                 arg2 = NULL;
1627                 while ((arg = argv_next(&ac, &av)) != NULL) {
1628                         if (*arg == '\0') {
1629                                 error("%s line %d: keyword %s empty argument",
1630                                     filename, linenum, keyword);
1631                                 goto out;
1632                         }
1633                         if ((flags & SSHCONF_NEVERMATCH) != 0) {
1634                                 argv_consume(&ac);
1635                                 break;
1636                         }
1637                         negated = *arg == '!';
1638                         if (negated)
1639                                 arg++;
1640                         if (match_pattern(host, arg)) {
1641                                 if (negated) {
1642                                         debug("%.200s line %d: Skipping Host "
1643                                             "block because of negated match "
1644                                             "for %.100s", filename, linenum,
1645                                             arg);
1646                                         *activep = 0;
1647                                         argv_consume(&ac);
1648                                         break;
1649                                 }
1650                                 if (!*activep)
1651                                         arg2 = arg; /* logged below */
1652                                 *activep = 1;
1653                         }
1654                 }
1655                 if (*activep)
1656                         debug("%.200s line %d: Applying options for %.100s",
1657                             filename, linenum, arg2);
1658                 break;
1659
1660         case oMatch:
1661                 if (cmdline) {
1662                         error("Host directive not supported as a command-line "
1663                             "option");
1664                         goto out;
1665                 }
1666                 value = match_cfg_line(options, &str, pw, host, original_host,
1667                     flags & SSHCONF_FINAL, want_final_pass,
1668                     filename, linenum);
1669                 if (value < 0) {
1670                         error("%.200s line %d: Bad Match condition", filename,
1671                             linenum);
1672                         goto out;
1673                 }
1674                 *activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value;
1675                 /*
1676                  * If match_cfg_line() didn't consume all its arguments then
1677                  * arrange for the extra arguments check below to fail.
1678                  */
1679
1680                 if (str == NULL || *str == '\0')
1681                         argv_consume(&ac);
1682                 break;
1683
1684         case oEscapeChar:
1685                 intptr = &options->escape_char;
1686                 arg = argv_next(&ac, &av);
1687                 if (!arg || *arg == '\0') {
1688                         error("%.200s line %d: Missing argument.",
1689                             filename, linenum);
1690                         goto out;
1691                 }
1692                 if (strcmp(arg, "none") == 0)
1693                         value = SSH_ESCAPECHAR_NONE;
1694                 else if (arg[1] == '\0')
1695                         value = (u_char) arg[0];
1696                 else if (arg[0] == '^' && arg[2] == 0 &&
1697                     (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
1698                         value = (u_char) arg[1] & 31;
1699                 else {
1700                         error("%.200s line %d: Bad escape character.",
1701                             filename, linenum);
1702                         goto out;
1703                 }
1704                 if (*activep && *intptr == -1)
1705                         *intptr = value;
1706                 break;
1707
1708         case oAddressFamily:
1709                 intptr = &options->address_family;
1710                 multistate_ptr = multistate_addressfamily;
1711                 goto parse_multistate;
1712
1713         case oEnableSSHKeysign:
1714                 intptr = &options->enable_ssh_keysign;
1715                 goto parse_flag;
1716
1717         case oIdentitiesOnly:
1718                 intptr = &options->identities_only;
1719                 goto parse_flag;
1720
1721         case oServerAliveInterval:
1722                 intptr = &options->server_alive_interval;
1723                 goto parse_time;
1724
1725         case oServerAliveCountMax:
1726                 intptr = &options->server_alive_count_max;
1727                 goto parse_int;
1728
1729         case oSendEnv:
1730                 while ((arg = argv_next(&ac, &av)) != NULL) {
1731                         if (*arg == '\0' || strchr(arg, '=') != NULL) {
1732                                 error("%s line %d: Invalid environment name.",
1733                                     filename, linenum);
1734                                 goto out;
1735                         }
1736                         if (!*activep)
1737                                 continue;
1738                         if (*arg == '-') {
1739                                 /* Removing an env var */
1740                                 rm_env(options, arg, filename, linenum);
1741                                 continue;
1742                         } else {
1743                                 /* Adding an env var */
1744                                 if (options->num_send_env >= INT_MAX) {
1745                                         error("%s line %d: too many send env.",
1746                                             filename, linenum);
1747                                         goto out;
1748                                 }
1749                                 options->send_env = xrecallocarray(
1750                                     options->send_env, options->num_send_env,
1751                                     options->num_send_env + 1,
1752                                     sizeof(*options->send_env));
1753                                 options->send_env[options->num_send_env++] =
1754                                     xstrdup(arg);
1755                         }
1756                 }
1757                 break;
1758
1759         case oSetEnv:
1760                 value = options->num_setenv;
1761                 while ((arg = argv_next(&ac, &av)) != NULL) {
1762                         if (strchr(arg, '=') == NULL) {
1763                                 error("%s line %d: Invalid SetEnv.",
1764                                     filename, linenum);
1765                                 goto out;
1766                         }
1767                         if (!*activep || value != 0)
1768                                 continue;
1769                         /* Adding a setenv var */
1770                         if (options->num_setenv >= INT_MAX) {
1771                                 error("%s line %d: too many SetEnv.",
1772                                     filename, linenum);
1773                                 goto out;
1774                         }
1775                         options->setenv = xrecallocarray(
1776                             options->setenv, options->num_setenv,
1777                             options->num_setenv + 1, sizeof(*options->setenv));
1778                         options->setenv[options->num_setenv++] = xstrdup(arg);
1779                 }
1780                 break;
1781
1782         case oControlPath:
1783                 charptr = &options->control_path;
1784                 goto parse_string;
1785
1786         case oControlMaster:
1787                 intptr = &options->control_master;
1788                 multistate_ptr = multistate_controlmaster;
1789                 goto parse_multistate;
1790
1791         case oControlPersist:
1792                 /* no/false/yes/true, or a time spec */
1793                 intptr = &options->control_persist;
1794                 arg = argv_next(&ac, &av);
1795                 if (!arg || *arg == '\0') {
1796                         error("%.200s line %d: Missing ControlPersist"
1797                             " argument.", filename, linenum);
1798                         goto out;
1799                 }
1800                 value = 0;
1801                 value2 = 0;     /* timeout */
1802                 if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
1803                         value = 0;
1804                 else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
1805                         value = 1;
1806                 else if ((value2 = convtime(arg)) >= 0)
1807                         value = 1;
1808                 else {
1809                         error("%.200s line %d: Bad ControlPersist argument.",
1810                             filename, linenum);
1811                         goto out;
1812                 }
1813                 if (*activep && *intptr == -1) {
1814                         *intptr = value;
1815                         options->control_persist_timeout = value2;
1816                 }
1817                 break;
1818
1819         case oHashKnownHosts:
1820                 intptr = &options->hash_known_hosts;
1821                 goto parse_flag;
1822
1823         case oTunnel:
1824                 intptr = &options->tun_open;
1825                 multistate_ptr = multistate_tunnel;
1826                 goto parse_multistate;
1827
1828         case oTunnelDevice:
1829                 arg = argv_next(&ac, &av);
1830                 if (!arg || *arg == '\0') {
1831                         error("%.200s line %d: Missing argument.",
1832                             filename, linenum);
1833                         goto out;
1834                 }
1835                 value = a2tun(arg, &value2);
1836                 if (value == SSH_TUNID_ERR) {
1837                         error("%.200s line %d: Bad tun device.",
1838                             filename, linenum);
1839                         goto out;
1840                 }
1841                 if (*activep && options->tun_local == -1) {
1842                         options->tun_local = value;
1843                         options->tun_remote = value2;
1844                 }
1845                 break;
1846
1847         case oLocalCommand:
1848                 charptr = &options->local_command;
1849                 goto parse_command;
1850
1851         case oPermitLocalCommand:
1852                 intptr = &options->permit_local_command;
1853                 goto parse_flag;
1854
1855         case oRemoteCommand:
1856                 charptr = &options->remote_command;
1857                 goto parse_command;
1858
1859         case oVisualHostKey:
1860                 intptr = &options->visual_host_key;
1861                 goto parse_flag;
1862
1863         case oInclude:
1864                 if (cmdline) {
1865                         error("Include directive not supported as a "
1866                             "command-line option");
1867                         goto out;
1868                 }
1869                 value = 0;
1870                 while ((arg = argv_next(&ac, &av)) != NULL) {
1871                         if (*arg == '\0') {
1872                                 error("%s line %d: keyword %s empty argument",
1873                                     filename, linenum, keyword);
1874                                 goto out;
1875                         }
1876                         /*
1877                          * Ensure all paths are anchored. User configuration
1878                          * files may begin with '~/' but system configurations
1879                          * must not. If the path is relative, then treat it
1880                          * as living in ~/.ssh for user configurations or
1881                          * /etc/ssh for system ones.
1882                          */
1883                         if (*arg == '~' && (flags & SSHCONF_USERCONF) == 0) {
1884                                 error("%.200s line %d: bad include path %s.",
1885                                     filename, linenum, arg);
1886                                 goto out;
1887                         }
1888                         if (!path_absolute(arg) && *arg != '~') {
1889                                 xasprintf(&arg2, "%s/%s",
1890                                     (flags & SSHCONF_USERCONF) ?
1891                                     "~/" _PATH_SSH_USER_DIR : SSHDIR, arg);
1892                         } else
1893                                 arg2 = xstrdup(arg);
1894                         memset(&gl, 0, sizeof(gl));
1895                         r = glob(arg2, GLOB_TILDE, NULL, &gl);
1896                         if (r == GLOB_NOMATCH) {
1897                                 debug("%.200s line %d: include %s matched no "
1898                                     "files",filename, linenum, arg2);
1899                                 free(arg2);
1900                                 continue;
1901                         } else if (r != 0) {
1902                                 error("%.200s line %d: glob failed for %s.",
1903                                     filename, linenum, arg2);
1904                                 goto out;
1905                         }
1906                         free(arg2);
1907                         oactive = *activep;
1908                         for (i = 0; i < gl.gl_pathc; i++) {
1909                                 debug3("%.200s line %d: Including file %s "
1910                                     "depth %d%s", filename, linenum,
1911                                     gl.gl_pathv[i], depth,
1912                                     oactive ? "" : " (parse only)");
1913                                 r = read_config_file_depth(gl.gl_pathv[i],
1914                                     pw, host, original_host, options,
1915                                     flags | SSHCONF_CHECKPERM |
1916                                     (oactive ? 0 : SSHCONF_NEVERMATCH),
1917                                     activep, want_final_pass, depth + 1);
1918                                 if (r != 1 && errno != ENOENT) {
1919                                         error("Can't open user config file "
1920                                             "%.100s: %.100s", gl.gl_pathv[i],
1921                                             strerror(errno));
1922                                         globfree(&gl);
1923                                         goto out;
1924                                 }
1925                                 /*
1926                                  * don't let Match in includes clobber the
1927                                  * containing file's Match state.
1928                                  */
1929                                 *activep = oactive;
1930                                 if (r != 1)
1931                                         value = -1;
1932                         }
1933                         globfree(&gl);
1934                 }
1935                 if (value != 0)
1936                         ret = value;
1937                 break;
1938
1939         case oIPQoS:
1940                 arg = argv_next(&ac, &av);
1941                 if ((value = parse_ipqos(arg)) == -1) {
1942                         error("%s line %d: Bad IPQoS value: %s",
1943                             filename, linenum, arg);
1944                         goto out;
1945                 }
1946                 arg = argv_next(&ac, &av);
1947                 if (arg == NULL)
1948                         value2 = value;
1949                 else if ((value2 = parse_ipqos(arg)) == -1) {
1950                         error("%s line %d: Bad IPQoS value: %s",
1951                             filename, linenum, arg);
1952                         goto out;
1953                 }
1954                 if (*activep && options->ip_qos_interactive == -1) {
1955                         options->ip_qos_interactive = value;
1956                         options->ip_qos_bulk = value2;
1957                 }
1958                 break;
1959
1960         case oRequestTTY:
1961                 intptr = &options->request_tty;
1962                 multistate_ptr = multistate_requesttty;
1963                 goto parse_multistate;
1964
1965         case oSessionType:
1966                 intptr = &options->session_type;
1967                 multistate_ptr = multistate_sessiontype;
1968                 goto parse_multistate;
1969
1970         case oStdinNull:
1971                 intptr = &options->stdin_null;
1972                 goto parse_flag;
1973
1974         case oForkAfterAuthentication:
1975                 intptr = &options->fork_after_authentication;
1976                 goto parse_flag;
1977
1978         case oVersionAddendum:
1979                 if (str == NULL)
1980                         fatal("%.200s line %d: Missing argument.", filename,
1981                             linenum);
1982                 len = strspn(str, WHITESPACE);
1983                 if (*activep && options->version_addendum == NULL) {
1984                         if (strcasecmp(str + len, "none") == 0)
1985                                 options->version_addendum = xstrdup("");
1986                         else if (strchr(str + len, '\r') != NULL)
1987                                 fatal("%.200s line %d: Invalid argument",
1988                                     filename, linenum);
1989                         else
1990                                 options->version_addendum = xstrdup(str + len);
1991                 }
1992                 return 0;
1993
1994         case oIgnoreUnknown:
1995                 charptr = &options->ignored_unknown;
1996                 goto parse_string;
1997
1998         case oProxyUseFdpass:
1999                 intptr = &options->proxy_use_fdpass;
2000                 goto parse_flag;
2001
2002         case oCanonicalDomains:
2003                 value = options->num_canonical_domains != 0;
2004                 i = 0;
2005                 while ((arg = argv_next(&ac, &av)) != NULL) {
2006                         if (*arg == '\0') {
2007                                 error("%s line %d: keyword %s empty argument",
2008                                     filename, linenum, keyword);
2009                                 goto out;
2010                         }
2011                         /* Allow "none" only in first position */
2012                         if (strcasecmp(arg, "none") == 0) {
2013                                 if (i > 0 || ac > 0) {
2014                                         error("%s line %d: keyword %s \"none\" "
2015                                             "argument must appear alone.",
2016                                             filename, linenum, keyword);
2017                                         goto out;
2018                                 }
2019                         }
2020                         i++;
2021                         if (!valid_domain(arg, 1, &errstr)) {
2022                                 error("%s line %d: %s", filename, linenum,
2023                                     errstr);
2024                                 goto out;
2025                         }
2026                         if (!*activep || value)
2027                                 continue;
2028                         if (options->num_canonical_domains >=
2029                             MAX_CANON_DOMAINS) {
2030                                 error("%s line %d: too many hostname suffixes.",
2031                                     filename, linenum);
2032                                 goto out;
2033                         }
2034                         options->canonical_domains[
2035                             options->num_canonical_domains++] = xstrdup(arg);
2036                 }
2037                 break;
2038
2039         case oCanonicalizePermittedCNAMEs:
2040                 value = options->num_permitted_cnames != 0;
2041                 while ((arg = argv_next(&ac, &av)) != NULL) {
2042                         /* Either '*' for everything or 'list:list' */
2043                         if (strcmp(arg, "*") == 0)
2044                                 arg2 = arg;
2045                         else {
2046                                 lowercase(arg);
2047                                 if ((arg2 = strchr(arg, ':')) == NULL ||
2048                                     arg2[1] == '\0') {
2049                                         error("%s line %d: "
2050                                             "Invalid permitted CNAME \"%s\"",
2051                                             filename, linenum, arg);
2052                                         goto out;
2053                                 }
2054                                 *arg2 = '\0';
2055                                 arg2++;
2056                         }
2057                         if (!*activep || value)
2058                                 continue;
2059                         if (options->num_permitted_cnames >=
2060                             MAX_CANON_DOMAINS) {
2061                                 error("%s line %d: too many permitted CNAMEs.",
2062                                     filename, linenum);
2063                                 goto out;
2064                         }
2065                         cname = options->permitted_cnames +
2066                             options->num_permitted_cnames++;
2067                         cname->source_list = xstrdup(arg);
2068                         cname->target_list = xstrdup(arg2);
2069                 }
2070                 break;
2071
2072         case oCanonicalizeHostname:
2073                 intptr = &options->canonicalize_hostname;
2074                 multistate_ptr = multistate_canonicalizehostname;
2075                 goto parse_multistate;
2076
2077         case oCanonicalizeMaxDots:
2078                 intptr = &options->canonicalize_max_dots;
2079                 goto parse_int;
2080
2081         case oCanonicalizeFallbackLocal:
2082                 intptr = &options->canonicalize_fallback_local;
2083                 goto parse_flag;
2084
2085         case oStreamLocalBindMask:
2086                 arg = argv_next(&ac, &av);
2087                 if (!arg || *arg == '\0') {
2088                         error("%.200s line %d: Missing StreamLocalBindMask "
2089                             "argument.", filename, linenum);
2090                         goto out;
2091                 }
2092                 /* Parse mode in octal format */
2093                 value = strtol(arg, &endofnumber, 8);
2094                 if (arg == endofnumber || value < 0 || value > 0777) {
2095                         error("%.200s line %d: Bad mask.", filename, linenum);
2096                         goto out;
2097                 }
2098                 options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
2099                 break;
2100
2101         case oStreamLocalBindUnlink:
2102                 intptr = &options->fwd_opts.streamlocal_bind_unlink;
2103                 goto parse_flag;
2104
2105         case oRevokedHostKeys:
2106                 charptr = &options->revoked_host_keys;
2107                 goto parse_string;
2108
2109         case oFingerprintHash:
2110                 intptr = &options->fingerprint_hash;
2111                 arg = argv_next(&ac, &av);
2112                 if (!arg || *arg == '\0') {
2113                         error("%.200s line %d: Missing argument.",
2114                             filename, linenum);
2115                         goto out;
2116                 }
2117                 if ((value = ssh_digest_alg_by_name(arg)) == -1) {
2118                         error("%.200s line %d: Invalid hash algorithm \"%s\".",
2119                             filename, linenum, arg);
2120                         goto out;
2121                 }
2122                 if (*activep && *intptr == -1)
2123                         *intptr = value;
2124                 break;
2125
2126         case oUpdateHostkeys:
2127                 intptr = &options->update_hostkeys;
2128                 multistate_ptr = multistate_yesnoask;
2129                 goto parse_multistate;
2130
2131         case oHostbasedAcceptedAlgorithms:
2132                 charptr = &options->hostbased_accepted_algos;
2133                 goto parse_pubkey_algos;
2134
2135         case oPubkeyAcceptedAlgorithms:
2136                 charptr = &options->pubkey_accepted_algos;
2137                 goto parse_pubkey_algos;
2138
2139         case oAddKeysToAgent:
2140                 arg = argv_next(&ac, &av);
2141                 arg2 = argv_next(&ac, &av);
2142                 value = parse_multistate_value(arg, filename, linenum,
2143                     multistate_yesnoaskconfirm);
2144                 value2 = 0; /* unlimited lifespan by default */
2145                 if (value == 3 && arg2 != NULL) {
2146                         /* allow "AddKeysToAgent confirm 5m" */
2147                         if ((value2 = convtime(arg2)) == -1 ||
2148                             value2 > INT_MAX) {
2149                                 error("%s line %d: invalid time value.",
2150                                     filename, linenum);
2151                                 goto out;
2152                         }
2153                 } else if (value == -1 && arg2 == NULL) {
2154                         if ((value2 = convtime(arg)) == -1 ||
2155                             value2 > INT_MAX) {
2156                                 error("%s line %d: unsupported option",
2157                                     filename, linenum);
2158                                 goto out;
2159                         }
2160                         value = 1; /* yes */
2161                 } else if (value == -1 || arg2 != NULL) {
2162                         error("%s line %d: unsupported option",
2163                             filename, linenum);
2164                         goto out;
2165                 }
2166                 if (*activep && options->add_keys_to_agent == -1) {
2167                         options->add_keys_to_agent = value;
2168                         options->add_keys_to_agent_lifespan = value2;
2169                 }
2170                 break;
2171
2172         case oIdentityAgent:
2173                 charptr = &options->identity_agent;
2174                 arg = argv_next(&ac, &av);
2175                 if (!arg || *arg == '\0') {
2176                         error("%.200s line %d: Missing argument.",
2177                             filename, linenum);
2178                         goto out;
2179                 }
2180   parse_agent_path:
2181                 /* Extra validation if the string represents an env var. */
2182                 if ((arg2 = dollar_expand(&r, arg)) == NULL || r) {
2183                         error("%.200s line %d: Invalid environment expansion "
2184                             "%s.", filename, linenum, arg);
2185                         goto out;
2186                 }
2187                 free(arg2);
2188                 /* check for legacy environment format */
2189                 if (arg[0] == '$' && arg[1] != '{' &&
2190                     !valid_env_name(arg + 1)) {
2191                         error("%.200s line %d: Invalid environment name %s.",
2192                             filename, linenum, arg);
2193                         goto out;
2194                 }
2195                 if (*activep && *charptr == NULL)
2196                         *charptr = xstrdup(arg);
2197                 break;
2198
2199         case oDeprecated:
2200                 debug("%s line %d: Deprecated option \"%s\"",
2201                     filename, linenum, keyword);
2202                 argv_consume(&ac);
2203                 break;
2204
2205         case oUnsupported:
2206                 error("%s line %d: Unsupported option \"%s\"",
2207                     filename, linenum, keyword);
2208                 argv_consume(&ac);
2209                 break;
2210
2211         default:
2212                 error("%s line %d: Unimplemented opcode %d",
2213                     filename, linenum, opcode);
2214                 goto out;
2215         }
2216
2217         /* Check that there is no garbage at end of line. */
2218         if (ac > 0) {
2219                 error("%.200s line %d: keyword %s extra arguments "
2220                     "at end of line", filename, linenum, keyword);
2221                 goto out;
2222         }
2223
2224         /* success */
2225         ret = 0;
2226  out:
2227         argv_free(oav, oac);
2228         return ret;
2229 }
2230
2231 /*
2232  * Reads the config file and modifies the options accordingly.  Options
2233  * should already be initialized before this call.  This never returns if
2234  * there is an error.  If the file does not exist, this returns 0.
2235  */
2236 int
2237 read_config_file(const char *filename, struct passwd *pw, const char *host,
2238     const char *original_host, Options *options, int flags,
2239     int *want_final_pass)
2240 {
2241         int active = 1;
2242
2243         return read_config_file_depth(filename, pw, host, original_host,
2244             options, flags, &active, want_final_pass, 0);
2245 }
2246
2247 #define READCONF_MAX_DEPTH      16
2248 static int
2249 read_config_file_depth(const char *filename, struct passwd *pw,
2250     const char *host, const char *original_host, Options *options,
2251     int flags, int *activep, int *want_final_pass, int depth)
2252 {
2253         FILE *f;
2254         char *line = NULL;
2255         size_t linesize = 0;
2256         int linenum;
2257         int bad_options = 0;
2258
2259         if (depth < 0 || depth > READCONF_MAX_DEPTH)
2260                 fatal("Too many recursive configuration includes");
2261
2262         if ((f = fopen(filename, "r")) == NULL)
2263                 return 0;
2264
2265         if (flags & SSHCONF_CHECKPERM) {
2266                 struct stat sb;
2267
2268                 if (fstat(fileno(f), &sb) == -1)
2269                         fatal("fstat %s: %s", filename, strerror(errno));
2270                 if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
2271                     (sb.st_mode & 022) != 0))
2272                         fatal("Bad owner or permissions on %s", filename);
2273         }
2274
2275         debug("Reading configuration data %.200s", filename);
2276
2277         /*
2278          * Mark that we are now processing the options.  This flag is turned
2279          * on/off by Host specifications.
2280          */
2281         linenum = 0;
2282         while (getline(&line, &linesize, f) != -1) {
2283                 /* Update line number counter. */
2284                 linenum++;
2285                 /*
2286                  * Trim out comments and strip whitespace.
2287                  * NB - preserve newlines, they are needed to reproduce
2288                  * line numbers later for error messages.
2289                  */
2290                 if (process_config_line_depth(options, pw, host, original_host,
2291                     line, filename, linenum, activep, flags, want_final_pass,
2292                     depth) != 0)
2293                         bad_options++;
2294         }
2295         free(line);
2296         fclose(f);
2297         if (bad_options > 0)
2298                 fatal("%s: terminating, %d bad configuration options",
2299                     filename, bad_options);
2300         return 1;
2301 }
2302
2303 /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
2304 int
2305 option_clear_or_none(const char *o)
2306 {
2307         return o == NULL || strcasecmp(o, "none") == 0;
2308 }
2309
2310 /*
2311  * Initializes options to special values that indicate that they have not yet
2312  * been set.  Read_config_file will only set options with this value. Options
2313  * are processed in the following order: command line, user config file,
2314  * system config file.  Last, fill_default_options is called.
2315  */
2316
2317 void
2318 initialize_options(Options * options)
2319 {
2320         memset(options, 'X', sizeof(*options));
2321         options->version_addendum = NULL;
2322         options->forward_agent = -1;
2323         options->forward_agent_sock_path = NULL;
2324         options->forward_x11 = -1;
2325         options->forward_x11_trusted = -1;
2326         options->forward_x11_timeout = -1;
2327         options->stdio_forward_host = NULL;
2328         options->stdio_forward_port = 0;
2329         options->clear_forwardings = -1;
2330         options->exit_on_forward_failure = -1;
2331         options->xauth_location = NULL;
2332         options->fwd_opts.gateway_ports = -1;
2333         options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
2334         options->fwd_opts.streamlocal_bind_unlink = -1;
2335         options->pubkey_authentication = -1;
2336         options->gss_authentication = -1;
2337         options->gss_deleg_creds = -1;
2338         options->password_authentication = -1;
2339         options->kbd_interactive_authentication = -1;
2340         options->kbd_interactive_devices = NULL;
2341         options->hostbased_authentication = -1;
2342         options->batch_mode = -1;
2343         options->check_host_ip = -1;
2344         options->strict_host_key_checking = -1;
2345         options->compression = -1;
2346         options->tcp_keep_alive = -1;
2347         options->port = -1;
2348         options->address_family = -1;
2349         options->connection_attempts = -1;
2350         options->connection_timeout = -1;
2351         options->number_of_password_prompts = -1;
2352         options->ciphers = NULL;
2353         options->macs = NULL;
2354         options->kex_algorithms = NULL;
2355         options->hostkeyalgorithms = NULL;
2356         options->ca_sign_algorithms = NULL;
2357         options->num_identity_files = 0;
2358         memset(options->identity_keys, 0, sizeof(options->identity_keys));
2359         options->num_certificate_files = 0;
2360         memset(options->certificates, 0, sizeof(options->certificates));
2361         options->hostname = NULL;
2362         options->host_key_alias = NULL;
2363         options->proxy_command = NULL;
2364         options->jump_user = NULL;
2365         options->jump_host = NULL;
2366         options->jump_port = -1;
2367         options->jump_extra = NULL;
2368         options->user = NULL;
2369         options->escape_char = -1;
2370         options->num_system_hostfiles = 0;
2371         options->num_user_hostfiles = 0;
2372         options->local_forwards = NULL;
2373         options->num_local_forwards = 0;
2374         options->remote_forwards = NULL;
2375         options->num_remote_forwards = 0;
2376         options->permitted_remote_opens = NULL;
2377         options->num_permitted_remote_opens = 0;
2378         options->log_facility = SYSLOG_FACILITY_NOT_SET;
2379         options->log_level = SYSLOG_LEVEL_NOT_SET;
2380         options->num_log_verbose = 0;
2381         options->log_verbose = NULL;
2382         options->preferred_authentications = NULL;
2383         options->bind_address = NULL;
2384         options->bind_interface = NULL;
2385         options->pkcs11_provider = NULL;
2386         options->sk_provider = NULL;
2387         options->enable_ssh_keysign = - 1;
2388         options->no_host_authentication_for_localhost = - 1;
2389         options->identities_only = - 1;
2390         options->rekey_limit = - 1;
2391         options->rekey_interval = -1;
2392         options->verify_host_key_dns = -1;
2393         options->server_alive_interval = -1;
2394         options->server_alive_count_max = -1;
2395         options->send_env = NULL;
2396         options->num_send_env = 0;
2397         options->setenv = NULL;
2398         options->num_setenv = 0;
2399         options->control_path = NULL;
2400         options->control_master = -1;
2401         options->control_persist = -1;
2402         options->control_persist_timeout = 0;
2403         options->hash_known_hosts = -1;
2404         options->tun_open = -1;
2405         options->tun_local = -1;
2406         options->tun_remote = -1;
2407         options->local_command = NULL;
2408         options->permit_local_command = -1;
2409         options->remote_command = NULL;
2410         options->add_keys_to_agent = -1;
2411         options->add_keys_to_agent_lifespan = -1;
2412         options->identity_agent = NULL;
2413         options->visual_host_key = -1;
2414         options->ip_qos_interactive = -1;
2415         options->ip_qos_bulk = -1;
2416         options->request_tty = -1;
2417         options->session_type = -1;
2418         options->stdin_null = -1;
2419         options->fork_after_authentication = -1;
2420         options->proxy_use_fdpass = -1;
2421         options->ignored_unknown = NULL;
2422         options->num_canonical_domains = 0;
2423         options->num_permitted_cnames = 0;
2424         options->canonicalize_max_dots = -1;
2425         options->canonicalize_fallback_local = -1;
2426         options->canonicalize_hostname = -1;
2427         options->revoked_host_keys = NULL;
2428         options->fingerprint_hash = -1;
2429         options->update_hostkeys = -1;
2430         options->hostbased_accepted_algos = NULL;
2431         options->pubkey_accepted_algos = NULL;
2432         options->known_hosts_command = NULL;
2433 }
2434
2435 /*
2436  * A petite version of fill_default_options() that just fills the options
2437  * needed for hostname canonicalization to proceed.
2438  */
2439 void
2440 fill_default_options_for_canonicalization(Options *options)
2441 {
2442         if (options->canonicalize_max_dots == -1)
2443                 options->canonicalize_max_dots = 1;
2444         if (options->canonicalize_fallback_local == -1)
2445                 options->canonicalize_fallback_local = 1;
2446         if (options->canonicalize_hostname == -1)
2447                 options->canonicalize_hostname = SSH_CANONICALISE_NO;
2448 }
2449
2450 /*
2451  * Called after processing other sources of option data, this fills those
2452  * options for which no value has been specified with their default values.
2453  */
2454 int
2455 fill_default_options(Options * options)
2456 {
2457         char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
2458         char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig;
2459         int ret = 0, r;
2460
2461         if (options->forward_agent == -1)
2462                 options->forward_agent = 0;
2463         if (options->forward_x11 == -1)
2464                 options->forward_x11 = 0;
2465         if (options->forward_x11_trusted == -1)
2466                 options->forward_x11_trusted = 0;
2467         if (options->forward_x11_timeout == -1)
2468                 options->forward_x11_timeout = 1200;
2469         /*
2470          * stdio forwarding (-W) changes the default for these but we defer
2471          * setting the values so they can be overridden.
2472          */
2473         if (options->exit_on_forward_failure == -1)
2474                 options->exit_on_forward_failure =
2475                     options->stdio_forward_host != NULL ? 1 : 0;
2476         if (options->clear_forwardings == -1)
2477                 options->clear_forwardings =
2478                     options->stdio_forward_host != NULL ? 1 : 0;
2479         if (options->clear_forwardings == 1)
2480                 clear_forwardings(options);
2481
2482         if (options->xauth_location == NULL)
2483                 options->xauth_location = xstrdup(_PATH_XAUTH);
2484         if (options->fwd_opts.gateway_ports == -1)
2485                 options->fwd_opts.gateway_ports = 0;
2486         if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
2487                 options->fwd_opts.streamlocal_bind_mask = 0177;
2488         if (options->fwd_opts.streamlocal_bind_unlink == -1)
2489                 options->fwd_opts.streamlocal_bind_unlink = 0;
2490         if (options->pubkey_authentication == -1)
2491                 options->pubkey_authentication = 1;
2492         if (options->gss_authentication == -1)
2493                 options->gss_authentication = 0;
2494         if (options->gss_deleg_creds == -1)
2495                 options->gss_deleg_creds = 0;
2496         if (options->password_authentication == -1)
2497                 options->password_authentication = 1;
2498         if (options->kbd_interactive_authentication == -1)
2499                 options->kbd_interactive_authentication = 1;
2500         if (options->hostbased_authentication == -1)
2501                 options->hostbased_authentication = 0;
2502         if (options->batch_mode == -1)
2503                 options->batch_mode = 0;
2504         if (options->check_host_ip == -1)
2505                 options->check_host_ip = 0;
2506         if (options->strict_host_key_checking == -1)
2507                 options->strict_host_key_checking = SSH_STRICT_HOSTKEY_ASK;
2508         if (options->compression == -1)
2509                 options->compression = 0;
2510         if (options->tcp_keep_alive == -1)
2511                 options->tcp_keep_alive = 1;
2512         if (options->port == -1)
2513                 options->port = 0;      /* Filled in ssh_connect. */
2514         if (options->address_family == -1)
2515                 options->address_family = AF_UNSPEC;
2516         if (options->connection_attempts == -1)
2517                 options->connection_attempts = 1;
2518         if (options->number_of_password_prompts == -1)
2519                 options->number_of_password_prompts = 3;
2520         /* options->hostkeyalgorithms, default set in myproposals.h */
2521         if (options->add_keys_to_agent == -1) {
2522                 options->add_keys_to_agent = 0;
2523                 options->add_keys_to_agent_lifespan = 0;
2524         }
2525         if (options->num_identity_files == 0) {
2526                 add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_RSA, 0);
2527                 add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0);
2528 #ifdef OPENSSL_HAS_ECC
2529                 add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0);
2530                 add_identity_file(options, "~/",
2531                     _PATH_SSH_CLIENT_ID_ECDSA_SK, 0);
2532 #endif
2533                 add_identity_file(options, "~/",
2534                     _PATH_SSH_CLIENT_ID_ED25519, 0);
2535                 add_identity_file(options, "~/",
2536                     _PATH_SSH_CLIENT_ID_ED25519_SK, 0);
2537                 add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_XMSS, 0);
2538         }
2539         if (options->escape_char == -1)
2540                 options->escape_char = '~';
2541         if (options->num_system_hostfiles == 0) {
2542                 options->system_hostfiles[options->num_system_hostfiles++] =
2543                     xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
2544                 options->system_hostfiles[options->num_system_hostfiles++] =
2545                     xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
2546         }
2547         if (options->update_hostkeys == -1) {
2548                 if (options->verify_host_key_dns <= 0 &&
2549                     (options->num_user_hostfiles == 0 ||
2550                     (options->num_user_hostfiles == 1 && strcmp(options->
2551                     user_hostfiles[0], _PATH_SSH_USER_HOSTFILE) == 0)))
2552                         options->update_hostkeys = SSH_UPDATE_HOSTKEYS_YES;
2553                 else
2554                         options->update_hostkeys = SSH_UPDATE_HOSTKEYS_NO;
2555         }
2556         if (options->num_user_hostfiles == 0) {
2557                 options->user_hostfiles[options->num_user_hostfiles++] =
2558                     xstrdup(_PATH_SSH_USER_HOSTFILE);
2559                 options->user_hostfiles[options->num_user_hostfiles++] =
2560                     xstrdup(_PATH_SSH_USER_HOSTFILE2);
2561         }
2562         if (options->log_level == SYSLOG_LEVEL_NOT_SET)
2563                 options->log_level = SYSLOG_LEVEL_INFO;
2564         if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
2565                 options->log_facility = SYSLOG_FACILITY_USER;
2566         if (options->no_host_authentication_for_localhost == - 1)
2567                 options->no_host_authentication_for_localhost = 0;
2568         if (options->identities_only == -1)
2569                 options->identities_only = 0;
2570         if (options->enable_ssh_keysign == -1)
2571                 options->enable_ssh_keysign = 0;
2572         if (options->rekey_limit == -1)
2573                 options->rekey_limit = 0;
2574         if (options->rekey_interval == -1)
2575                 options->rekey_interval = 0;
2576 #if HAVE_LDNS
2577         if (options->verify_host_key_dns == -1)
2578                 /* automatically trust a verified SSHFP record */
2579                 options->verify_host_key_dns = 1;
2580 #else
2581         if (options->verify_host_key_dns == -1)
2582                 options->verify_host_key_dns = 0;
2583 #endif
2584         if (options->server_alive_interval == -1)
2585                 options->server_alive_interval = 0;
2586         if (options->server_alive_count_max == -1)
2587                 options->server_alive_count_max = 3;
2588         if (options->control_master == -1)
2589                 options->control_master = 0;
2590         if (options->control_persist == -1) {
2591                 options->control_persist = 0;
2592                 options->control_persist_timeout = 0;
2593         }
2594         if (options->hash_known_hosts == -1)
2595                 options->hash_known_hosts = 0;
2596         if (options->tun_open == -1)
2597                 options->tun_open = SSH_TUNMODE_NO;
2598         if (options->tun_local == -1)
2599                 options->tun_local = SSH_TUNID_ANY;
2600         if (options->tun_remote == -1)
2601                 options->tun_remote = SSH_TUNID_ANY;
2602         if (options->permit_local_command == -1)
2603                 options->permit_local_command = 0;
2604         if (options->visual_host_key == -1)
2605                 options->visual_host_key = 0;
2606         if (options->ip_qos_interactive == -1)
2607                 options->ip_qos_interactive = IPTOS_DSCP_AF21;
2608         if (options->ip_qos_bulk == -1)
2609                 options->ip_qos_bulk = IPTOS_DSCP_CS1;
2610         if (options->request_tty == -1)
2611                 options->request_tty = REQUEST_TTY_AUTO;
2612         if (options->session_type == -1)
2613                 options->session_type = SESSION_TYPE_DEFAULT;
2614         if (options->stdin_null == -1)
2615                 options->stdin_null = 0;
2616         if (options->fork_after_authentication == -1)
2617                 options->fork_after_authentication = 0;
2618         if (options->proxy_use_fdpass == -1)
2619                 options->proxy_use_fdpass = 0;
2620         if (options->canonicalize_max_dots == -1)
2621                 options->canonicalize_max_dots = 1;
2622         if (options->canonicalize_fallback_local == -1)
2623                 options->canonicalize_fallback_local = 1;
2624         if (options->canonicalize_hostname == -1)
2625                 options->canonicalize_hostname = SSH_CANONICALISE_NO;
2626         if (options->fingerprint_hash == -1)
2627                 options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
2628 #ifdef ENABLE_SK_INTERNAL
2629         if (options->sk_provider == NULL)
2630                 options->sk_provider = xstrdup("internal");
2631 #else
2632         if (options->sk_provider == NULL)
2633                 options->sk_provider = xstrdup("$SSH_SK_PROVIDER");
2634 #endif
2635
2636         /* Expand KEX name lists */
2637         all_cipher = cipher_alg_list(',', 0);
2638         all_mac = mac_alg_list(',');
2639         all_kex = kex_alg_list(',');
2640         all_key = sshkey_alg_list(0, 0, 1, ',');
2641         all_sig = sshkey_alg_list(0, 1, 1, ',');
2642         /* remove unsupported algos from default lists */
2643         def_cipher = match_filter_allowlist(KEX_CLIENT_ENCRYPT, all_cipher);
2644         def_mac = match_filter_allowlist(KEX_CLIENT_MAC, all_mac);
2645         def_kex = match_filter_allowlist(KEX_CLIENT_KEX, all_kex);
2646         def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
2647         def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig);
2648 #define ASSEMBLE(what, defaults, all) \
2649         do { \
2650                 if ((r = kex_assemble_names(&options->what, \
2651                     defaults, all)) != 0) { \
2652                         error_fr(r, "%s", #what); \
2653                         goto fail; \
2654                 } \
2655         } while (0)
2656         ASSEMBLE(ciphers, def_cipher, all_cipher);
2657         ASSEMBLE(macs, def_mac, all_mac);
2658         ASSEMBLE(kex_algorithms, def_kex, all_kex);
2659         ASSEMBLE(hostbased_accepted_algos, def_key, all_key);
2660         ASSEMBLE(pubkey_accepted_algos, def_key, all_key);
2661         ASSEMBLE(ca_sign_algorithms, def_sig, all_sig);
2662 #undef ASSEMBLE
2663
2664 #define CLEAR_ON_NONE(v) \
2665         do { \
2666                 if (option_clear_or_none(v)) { \
2667                         free(v); \
2668                         v = NULL; \
2669                 } \
2670         } while(0)
2671         CLEAR_ON_NONE(options->local_command);
2672         CLEAR_ON_NONE(options->remote_command);
2673         CLEAR_ON_NONE(options->proxy_command);
2674         CLEAR_ON_NONE(options->control_path);
2675         CLEAR_ON_NONE(options->revoked_host_keys);
2676         CLEAR_ON_NONE(options->pkcs11_provider);
2677         CLEAR_ON_NONE(options->sk_provider);
2678         CLEAR_ON_NONE(options->known_hosts_command);
2679         if (options->jump_host != NULL &&
2680             strcmp(options->jump_host, "none") == 0 &&
2681             options->jump_port == 0 && options->jump_user == NULL) {
2682                 free(options->jump_host);
2683                 options->jump_host = NULL;
2684         }
2685         /* options->identity_agent distinguishes NULL from 'none' */
2686         /* options->user will be set in the main program if appropriate */
2687         /* options->hostname will be set in the main program if appropriate */
2688         /* options->host_key_alias should not be set by default */
2689         /* options->preferred_authentications will be set in ssh */
2690         if (options->version_addendum == NULL)
2691                 options->version_addendum = xstrdup(SSH_VERSION_FREEBSD);
2692
2693         /* success */
2694         ret = 0;
2695  fail:
2696         free(all_cipher);
2697         free(all_mac);
2698         free(all_kex);
2699         free(all_key);
2700         free(all_sig);
2701         free(def_cipher);
2702         free(def_mac);
2703         free(def_kex);
2704         free(def_key);
2705         free(def_sig);
2706         return ret;
2707 }
2708
2709 void
2710 free_options(Options *o)
2711 {
2712         int i;
2713
2714         if (o == NULL)
2715                 return;
2716
2717 #define FREE_ARRAY(type, n, a) \
2718         do { \
2719                 type _i; \
2720                 for (_i = 0; _i < (n); _i++) \
2721                         free((a)[_i]); \
2722         } while (0)
2723
2724         free(o->forward_agent_sock_path);
2725         free(o->xauth_location);
2726         FREE_ARRAY(u_int, o->num_log_verbose, o->log_verbose);
2727         free(o->log_verbose);
2728         free(o->ciphers);
2729         free(o->macs);
2730         free(o->hostkeyalgorithms);
2731         free(o->kex_algorithms);
2732         free(o->ca_sign_algorithms);
2733         free(o->hostname);
2734         free(o->host_key_alias);
2735         free(o->proxy_command);
2736         free(o->user);
2737         FREE_ARRAY(u_int, o->num_system_hostfiles, o->system_hostfiles);
2738         FREE_ARRAY(u_int, o->num_user_hostfiles, o->user_hostfiles);
2739         free(o->preferred_authentications);
2740         free(o->bind_address);
2741         free(o->bind_interface);
2742         free(o->pkcs11_provider);
2743         free(o->sk_provider);
2744         for (i = 0; i < o->num_identity_files; i++) {
2745                 free(o->identity_files[i]);
2746                 sshkey_free(o->identity_keys[i]);
2747         }
2748         for (i = 0; i < o->num_certificate_files; i++) {
2749                 free(o->certificate_files[i]);
2750                 sshkey_free(o->certificates[i]);
2751         }
2752         free(o->identity_agent);
2753         for (i = 0; i < o->num_local_forwards; i++) {
2754                 free(o->local_forwards[i].listen_host);
2755                 free(o->local_forwards[i].listen_path);
2756                 free(o->local_forwards[i].connect_host);
2757                 free(o->local_forwards[i].connect_path);
2758         }
2759         free(o->local_forwards);
2760         for (i = 0; i < o->num_remote_forwards; i++) {
2761                 free(o->remote_forwards[i].listen_host);
2762                 free(o->remote_forwards[i].listen_path);
2763                 free(o->remote_forwards[i].connect_host);
2764                 free(o->remote_forwards[i].connect_path);
2765         }
2766         free(o->remote_forwards);
2767         free(o->stdio_forward_host);
2768         FREE_ARRAY(int, o->num_send_env, o->send_env);
2769         free(o->send_env);
2770         FREE_ARRAY(int, o->num_setenv, o->setenv);
2771         free(o->setenv);
2772         free(o->control_path);
2773         free(o->local_command);
2774         free(o->remote_command);
2775         FREE_ARRAY(int, o->num_canonical_domains, o->canonical_domains);
2776         for (i = 0; i < o->num_permitted_cnames; i++) {
2777                 free(o->permitted_cnames[i].source_list);
2778                 free(o->permitted_cnames[i].target_list);
2779         }
2780         free(o->revoked_host_keys);
2781         free(o->hostbased_accepted_algos);
2782         free(o->pubkey_accepted_algos);
2783         free(o->jump_user);
2784         free(o->jump_host);
2785         free(o->jump_extra);
2786         free(o->ignored_unknown);
2787         explicit_bzero(o, sizeof(*o));
2788 #undef FREE_ARRAY
2789 }
2790
2791 struct fwdarg {
2792         char *arg;
2793         int ispath;
2794 };
2795
2796 /*
2797  * parse_fwd_field
2798  * parses the next field in a port forwarding specification.
2799  * sets fwd to the parsed field and advances p past the colon
2800  * or sets it to NULL at end of string.
2801  * returns 0 on success, else non-zero.
2802  */
2803 static int
2804 parse_fwd_field(char **p, struct fwdarg *fwd)
2805 {
2806         char *ep, *cp = *p;
2807         int ispath = 0;
2808
2809         if (*cp == '\0') {
2810                 *p = NULL;
2811                 return -1;      /* end of string */
2812         }
2813
2814         /*
2815          * A field escaped with square brackets is used literally.
2816          * XXX - allow ']' to be escaped via backslash?
2817          */
2818         if (*cp == '[') {
2819                 /* find matching ']' */
2820                 for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
2821                         if (*ep == '/')
2822                                 ispath = 1;
2823                 }
2824                 /* no matching ']' or not at end of field. */
2825                 if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
2826                         return -1;
2827                 /* NUL terminate the field and advance p past the colon */
2828                 *ep++ = '\0';
2829                 if (*ep != '\0')
2830                         *ep++ = '\0';
2831                 fwd->arg = cp + 1;
2832                 fwd->ispath = ispath;
2833                 *p = ep;
2834                 return 0;
2835         }
2836
2837         for (cp = *p; *cp != '\0'; cp++) {
2838                 switch (*cp) {
2839                 case '\\':
2840                         memmove(cp, cp + 1, strlen(cp + 1) + 1);
2841                         if (*cp == '\0')
2842                                 return -1;
2843                         break;
2844                 case '/':
2845                         ispath = 1;
2846                         break;
2847                 case ':':
2848                         *cp++ = '\0';
2849                         goto done;
2850                 }
2851         }
2852 done:
2853         fwd->arg = *p;
2854         fwd->ispath = ispath;
2855         *p = cp;
2856         return 0;
2857 }
2858
2859 /*
2860  * parse_forward
2861  * parses a string containing a port forwarding specification of the form:
2862  *   dynamicfwd == 0
2863  *      [listenhost:]listenport|listenpath:connecthost:connectport|connectpath
2864  *      listenpath:connectpath
2865  *   dynamicfwd == 1
2866  *      [listenhost:]listenport
2867  * returns number of arguments parsed or zero on error
2868  */
2869 int
2870 parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
2871 {
2872         struct fwdarg fwdargs[4];
2873         char *p, *cp;
2874         int i, err;
2875
2876         memset(fwd, 0, sizeof(*fwd));
2877         memset(fwdargs, 0, sizeof(fwdargs));
2878
2879         /*
2880          * We expand environment variables before checking if we think they're
2881          * paths so that if ${VAR} expands to a fully qualified path it is
2882          * treated as a path.
2883          */
2884         cp = p = dollar_expand(&err, fwdspec);
2885         if (p == NULL || err)
2886                 return 0;
2887
2888         /* skip leading spaces */
2889         while (isspace((u_char)*cp))
2890                 cp++;
2891
2892         for (i = 0; i < 4; ++i) {
2893                 if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
2894                         break;
2895         }
2896
2897         /* Check for trailing garbage */
2898         if (cp != NULL && *cp != '\0') {
2899                 i = 0;  /* failure */
2900         }
2901
2902         switch (i) {
2903         case 1:
2904                 if (fwdargs[0].ispath) {
2905                         fwd->listen_path = xstrdup(fwdargs[0].arg);
2906                         fwd->listen_port = PORT_STREAMLOCAL;
2907                 } else {
2908                         fwd->listen_host = NULL;
2909                         fwd->listen_port = a2port(fwdargs[0].arg);
2910                 }
2911                 fwd->connect_host = xstrdup("socks");
2912                 break;
2913
2914         case 2:
2915                 if (fwdargs[0].ispath && fwdargs[1].ispath) {
2916                         fwd->listen_path = xstrdup(fwdargs[0].arg);
2917                         fwd->listen_port = PORT_STREAMLOCAL;
2918                         fwd->connect_path = xstrdup(fwdargs[1].arg);
2919                         fwd->connect_port = PORT_STREAMLOCAL;
2920                 } else if (fwdargs[1].ispath) {
2921                         fwd->listen_host = NULL;
2922                         fwd->listen_port = a2port(fwdargs[0].arg);
2923                         fwd->connect_path = xstrdup(fwdargs[1].arg);
2924                         fwd->connect_port = PORT_STREAMLOCAL;
2925                 } else {
2926                         fwd->listen_host = xstrdup(fwdargs[0].arg);
2927                         fwd->listen_port = a2port(fwdargs[1].arg);
2928                         fwd->connect_host = xstrdup("socks");
2929                 }
2930                 break;
2931
2932         case 3:
2933                 if (fwdargs[0].ispath) {
2934                         fwd->listen_path = xstrdup(fwdargs[0].arg);
2935                         fwd->listen_port = PORT_STREAMLOCAL;
2936                         fwd->connect_host = xstrdup(fwdargs[1].arg);
2937                         fwd->connect_port = a2port(fwdargs[2].arg);
2938                 } else if (fwdargs[2].ispath) {
2939                         fwd->listen_host = xstrdup(fwdargs[0].arg);
2940                         fwd->listen_port = a2port(fwdargs[1].arg);
2941                         fwd->connect_path = xstrdup(fwdargs[2].arg);
2942                         fwd->connect_port = PORT_STREAMLOCAL;
2943                 } else {
2944                         fwd->listen_host = NULL;
2945                         fwd->listen_port = a2port(fwdargs[0].arg);
2946                         fwd->connect_host = xstrdup(fwdargs[1].arg);
2947                         fwd->connect_port = a2port(fwdargs[2].arg);
2948                 }
2949                 break;
2950
2951         case 4:
2952                 fwd->listen_host = xstrdup(fwdargs[0].arg);
2953                 fwd->listen_port = a2port(fwdargs[1].arg);
2954                 fwd->connect_host = xstrdup(fwdargs[2].arg);
2955                 fwd->connect_port = a2port(fwdargs[3].arg);
2956                 break;
2957         default:
2958                 i = 0; /* failure */
2959         }
2960
2961         free(p);
2962
2963         if (dynamicfwd) {
2964                 if (!(i == 1 || i == 2))
2965                         goto fail_free;
2966         } else {
2967                 if (!(i == 3 || i == 4)) {
2968                         if (fwd->connect_path == NULL &&
2969                             fwd->listen_path == NULL)
2970                                 goto fail_free;
2971                 }
2972                 if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
2973                         goto fail_free;
2974         }
2975
2976         if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
2977             (!remotefwd && fwd->listen_port == 0))
2978                 goto fail_free;
2979         if (fwd->connect_host != NULL &&
2980             strlen(fwd->connect_host) >= NI_MAXHOST)
2981                 goto fail_free;
2982         /*
2983          * XXX - if connecting to a remote socket, max sun len may not
2984          * match this host
2985          */
2986         if (fwd->connect_path != NULL &&
2987             strlen(fwd->connect_path) >= PATH_MAX_SUN)
2988                 goto fail_free;
2989         if (fwd->listen_host != NULL &&
2990             strlen(fwd->listen_host) >= NI_MAXHOST)
2991                 goto fail_free;
2992         if (fwd->listen_path != NULL &&
2993             strlen(fwd->listen_path) >= PATH_MAX_SUN)
2994                 goto fail_free;
2995
2996         return (i);
2997
2998  fail_free:
2999         free(fwd->connect_host);
3000         fwd->connect_host = NULL;
3001         free(fwd->connect_path);
3002         fwd->connect_path = NULL;
3003         free(fwd->listen_host);
3004         fwd->listen_host = NULL;
3005         free(fwd->listen_path);
3006         fwd->listen_path = NULL;
3007         return (0);
3008 }
3009
3010 int
3011 parse_jump(const char *s, Options *o, int active)
3012 {
3013         char *orig, *sdup, *cp;
3014         char *host = NULL, *user = NULL;
3015         int r, ret = -1, port = -1, first;
3016
3017         active &= o->proxy_command == NULL && o->jump_host == NULL;
3018
3019         orig = sdup = xstrdup(s);
3020
3021         /* Remove comment and trailing whitespace */
3022         if ((cp = strchr(orig, '#')) != NULL)
3023                 *cp = '\0';
3024         rtrim(orig);
3025
3026         first = active;
3027         do {
3028                 if (strcasecmp(s, "none") == 0)
3029                         break;
3030                 if ((cp = strrchr(sdup, ',')) == NULL)
3031                         cp = sdup; /* last */
3032                 else
3033                         *cp++ = '\0';
3034
3035                 if (first) {
3036                         /* First argument and configuration is active */
3037                         r = parse_ssh_uri(cp, &user, &host, &port);
3038                         if (r == -1 || (r == 1 &&
3039                             parse_user_host_port(cp, &user, &host, &port) != 0))
3040                                 goto out;
3041                 } else {
3042                         /* Subsequent argument or inactive configuration */
3043                         r = parse_ssh_uri(cp, NULL, NULL, NULL);
3044                         if (r == -1 || (r == 1 &&
3045                             parse_user_host_port(cp, NULL, NULL, NULL) != 0))
3046                                 goto out;
3047                 }
3048                 first = 0; /* only check syntax for subsequent hosts */
3049         } while (cp != sdup);
3050         /* success */
3051         if (active) {
3052                 if (strcasecmp(s, "none") == 0) {
3053                         o->jump_host = xstrdup("none");
3054                         o->jump_port = 0;
3055                 } else {
3056                         o->jump_user = user;
3057                         o->jump_host = host;
3058                         o->jump_port = port;
3059                         o->proxy_command = xstrdup("none");
3060                         user = host = NULL;
3061                         if ((cp = strrchr(s, ',')) != NULL && cp != s) {
3062                                 o->jump_extra = xstrdup(s);
3063                                 o->jump_extra[cp - s] = '\0';
3064                         }
3065                 }
3066         }
3067         ret = 0;
3068  out:
3069         free(orig);
3070         free(user);
3071         free(host);
3072         return ret;
3073 }
3074
3075 int
3076 parse_ssh_uri(const char *uri, char **userp, char **hostp, int *portp)
3077 {
3078         char *user = NULL, *host = NULL, *path = NULL;
3079         int r, port;
3080
3081         r = parse_uri("ssh", uri, &user, &host, &port, &path);
3082         if (r == 0 && path != NULL)
3083                 r = -1;         /* path not allowed */
3084         if (r == 0) {
3085                 if (userp != NULL) {
3086                         *userp = user;
3087                         user = NULL;
3088                 }
3089                 if (hostp != NULL) {
3090                         *hostp = host;
3091                         host = NULL;
3092                 }
3093                 if (portp != NULL)
3094                         *portp = port;
3095         }
3096         free(user);
3097         free(host);
3098         free(path);
3099         return r;
3100 }
3101
3102 /* XXX the following is a near-vebatim copy from servconf.c; refactor */
3103 static const char *
3104 fmt_multistate_int(int val, const struct multistate *m)
3105 {
3106         u_int i;
3107
3108         for (i = 0; m[i].key != NULL; i++) {
3109                 if (m[i].value == val)
3110                         return m[i].key;
3111         }
3112         return "UNKNOWN";
3113 }
3114
3115 static const char *
3116 fmt_intarg(OpCodes code, int val)
3117 {
3118         if (val == -1)
3119                 return "unset";
3120         switch (code) {
3121         case oAddressFamily:
3122                 return fmt_multistate_int(val, multistate_addressfamily);
3123         case oVerifyHostKeyDNS:
3124         case oUpdateHostkeys:
3125                 return fmt_multistate_int(val, multistate_yesnoask);
3126         case oStrictHostKeyChecking:
3127                 return fmt_multistate_int(val, multistate_strict_hostkey);
3128         case oControlMaster:
3129                 return fmt_multistate_int(val, multistate_controlmaster);
3130         case oTunnel:
3131                 return fmt_multistate_int(val, multistate_tunnel);
3132         case oRequestTTY:
3133                 return fmt_multistate_int(val, multistate_requesttty);
3134         case oSessionType:
3135                 return fmt_multistate_int(val, multistate_sessiontype);
3136         case oCanonicalizeHostname:
3137                 return fmt_multistate_int(val, multistate_canonicalizehostname);
3138         case oAddKeysToAgent:
3139                 return fmt_multistate_int(val, multistate_yesnoaskconfirm);
3140         case oFingerprintHash:
3141                 return ssh_digest_alg_name(val);
3142         default:
3143                 switch (val) {
3144                 case 0:
3145                         return "no";
3146                 case 1:
3147                         return "yes";
3148                 default:
3149                         return "UNKNOWN";
3150                 }
3151         }
3152 }
3153
3154 static const char *
3155 lookup_opcode_name(OpCodes code)
3156 {
3157         u_int i;
3158
3159         for (i = 0; keywords[i].name != NULL; i++)
3160                 if (keywords[i].opcode == code)
3161                         return(keywords[i].name);
3162         return "UNKNOWN";
3163 }
3164
3165 static void
3166 dump_cfg_int(OpCodes code, int val)
3167 {
3168         printf("%s %d\n", lookup_opcode_name(code), val);
3169 }
3170
3171 static void
3172 dump_cfg_fmtint(OpCodes code, int val)
3173 {
3174         printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
3175 }
3176
3177 static void
3178 dump_cfg_string(OpCodes code, const char *val)
3179 {
3180         if (val == NULL)
3181                 return;
3182         printf("%s %s\n", lookup_opcode_name(code), val);
3183 }
3184
3185 static void
3186 dump_cfg_strarray(OpCodes code, u_int count, char **vals)
3187 {
3188         u_int i;
3189
3190         for (i = 0; i < count; i++)
3191                 printf("%s %s\n", lookup_opcode_name(code), vals[i]);
3192 }
3193
3194 static void
3195 dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
3196 {
3197         u_int i;
3198
3199         printf("%s", lookup_opcode_name(code));
3200         if (count == 0)
3201                 printf(" none");
3202         for (i = 0; i < count; i++)
3203                 printf(" %s",  vals[i]);
3204         printf("\n");
3205 }
3206
3207 static void
3208 dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
3209 {
3210         const struct Forward *fwd;
3211         u_int i;
3212
3213         /* oDynamicForward */
3214         for (i = 0; i < count; i++) {
3215                 fwd = &fwds[i];
3216                 if (code == oDynamicForward && fwd->connect_host != NULL &&
3217                     strcmp(fwd->connect_host, "socks") != 0)
3218                         continue;
3219                 if (code == oLocalForward && fwd->connect_host != NULL &&
3220                     strcmp(fwd->connect_host, "socks") == 0)
3221                         continue;
3222                 printf("%s", lookup_opcode_name(code));
3223                 if (fwd->listen_port == PORT_STREAMLOCAL)
3224                         printf(" %s", fwd->listen_path);
3225                 else if (fwd->listen_host == NULL)
3226                         printf(" %d", fwd->listen_port);
3227                 else {
3228                         printf(" [%s]:%d",
3229                             fwd->listen_host, fwd->listen_port);
3230                 }
3231                 if (code != oDynamicForward) {
3232                         if (fwd->connect_port == PORT_STREAMLOCAL)
3233                                 printf(" %s", fwd->connect_path);
3234                         else if (fwd->connect_host == NULL)
3235                                 printf(" %d", fwd->connect_port);
3236                         else {
3237                                 printf(" [%s]:%d",
3238                                     fwd->connect_host, fwd->connect_port);
3239                         }
3240                 }
3241                 printf("\n");
3242         }
3243 }
3244
3245 void
3246 dump_client_config(Options *o, const char *host)
3247 {
3248         int i, r;
3249         char buf[8], *all_key;
3250
3251         /*
3252          * Expand HostKeyAlgorithms name lists. This isn't handled in
3253          * fill_default_options() like the other algorithm lists because
3254          * the host key algorithms are by default dynamically chosen based
3255          * on the host's keys found in known_hosts.
3256          */
3257         all_key = sshkey_alg_list(0, 0, 1, ',');
3258         if ((r = kex_assemble_names(&o->hostkeyalgorithms, kex_default_pk_alg(),
3259             all_key)) != 0)
3260                 fatal_fr(r, "expand HostKeyAlgorithms");
3261         free(all_key);
3262
3263         /* Most interesting options first: user, host, port */
3264         dump_cfg_string(oUser, o->user);
3265         dump_cfg_string(oHostname, host);
3266         dump_cfg_int(oPort, o->port);
3267
3268         /* Flag options */
3269         dump_cfg_fmtint(oAddressFamily, o->address_family);
3270         dump_cfg_fmtint(oBatchMode, o->batch_mode);
3271         dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local);
3272         dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname);
3273         dump_cfg_fmtint(oCheckHostIP, o->check_host_ip);
3274         dump_cfg_fmtint(oCompression, o->compression);
3275         dump_cfg_fmtint(oControlMaster, o->control_master);
3276         dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
3277         dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings);
3278         dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
3279         dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
3280         dump_cfg_fmtint(oForwardX11, o->forward_x11);
3281         dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
3282         dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
3283 #ifdef GSSAPI
3284         dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
3285         dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
3286 #endif /* GSSAPI */
3287         dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
3288         dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
3289         dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
3290         dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication);
3291         dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost);
3292         dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication);
3293         dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command);
3294         dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
3295         dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
3296         dump_cfg_fmtint(oRequestTTY, o->request_tty);
3297         dump_cfg_fmtint(oSessionType, o->session_type);
3298         dump_cfg_fmtint(oStdinNull, o->stdin_null);
3299         dump_cfg_fmtint(oForkAfterAuthentication, o->fork_after_authentication);
3300         dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
3301         dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking);
3302         dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive);
3303         dump_cfg_fmtint(oTunnel, o->tun_open);
3304         dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns);
3305         dump_cfg_fmtint(oVisualHostKey, o->visual_host_key);
3306         dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys);
3307
3308         /* Integer options */
3309         dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots);
3310         dump_cfg_int(oConnectionAttempts, o->connection_attempts);
3311         dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout);
3312         dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
3313         dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
3314         dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
3315
3316         /* String options */
3317         dump_cfg_string(oBindAddress, o->bind_address);
3318         dump_cfg_string(oBindInterface, o->bind_interface);
3319         dump_cfg_string(oCiphers, o->ciphers);
3320         dump_cfg_string(oControlPath, o->control_path);
3321         dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms);
3322         dump_cfg_string(oHostKeyAlias, o->host_key_alias);
3323         dump_cfg_string(oHostbasedAcceptedAlgorithms, o->hostbased_accepted_algos);
3324         dump_cfg_string(oIdentityAgent, o->identity_agent);
3325         dump_cfg_string(oIgnoreUnknown, o->ignored_unknown);
3326         dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
3327         dump_cfg_string(oKexAlgorithms, o->kex_algorithms);
3328         dump_cfg_string(oCASignatureAlgorithms, o->ca_sign_algorithms);
3329         dump_cfg_string(oLocalCommand, o->local_command);
3330         dump_cfg_string(oRemoteCommand, o->remote_command);
3331         dump_cfg_string(oLogLevel, log_level_name(o->log_level));
3332         dump_cfg_string(oMacs, o->macs);
3333 #ifdef ENABLE_PKCS11
3334         dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
3335 #endif
3336         dump_cfg_string(oSecurityKeyProvider, o->sk_provider);
3337         dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
3338         dump_cfg_string(oPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos);
3339         dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
3340         dump_cfg_string(oXAuthLocation, o->xauth_location);
3341         dump_cfg_string(oKnownHostsCommand, o->known_hosts_command);
3342
3343         /* Forwards */
3344         dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards);
3345         dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards);
3346         dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards);
3347
3348         /* String array options */
3349         dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files);
3350         dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains);
3351         dump_cfg_strarray(oCertificateFile, o->num_certificate_files, o->certificate_files);
3352         dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles);
3353         dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
3354         dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
3355         dump_cfg_strarray(oSetEnv, o->num_setenv, o->setenv);
3356         dump_cfg_strarray_oneline(oLogVerbose,
3357             o->num_log_verbose, o->log_verbose);
3358
3359         /* Special cases */
3360
3361         /* PermitRemoteOpen */
3362         if (o->num_permitted_remote_opens == 0)
3363                 printf("%s any\n", lookup_opcode_name(oPermitRemoteOpen));
3364         else
3365                 dump_cfg_strarray_oneline(oPermitRemoteOpen,
3366                     o->num_permitted_remote_opens, o->permitted_remote_opens);
3367
3368         /* AddKeysToAgent */
3369         if (o->add_keys_to_agent_lifespan <= 0)
3370                 dump_cfg_fmtint(oAddKeysToAgent, o->add_keys_to_agent);
3371         else {
3372                 printf("addkeystoagent%s %d\n",
3373                     o->add_keys_to_agent == 3 ? " confirm" : "",
3374                     o->add_keys_to_agent_lifespan);
3375         }
3376
3377         /* oForwardAgent */
3378         if (o->forward_agent_sock_path == NULL)
3379                 dump_cfg_fmtint(oForwardAgent, o->forward_agent);
3380         else
3381                 dump_cfg_string(oForwardAgent, o->forward_agent_sock_path);
3382
3383         /* oConnectTimeout */
3384         if (o->connection_timeout == -1)
3385                 printf("connecttimeout none\n");
3386         else
3387                 dump_cfg_int(oConnectTimeout, o->connection_timeout);
3388
3389         /* oTunnelDevice */
3390         printf("tunneldevice");
3391         if (o->tun_local == SSH_TUNID_ANY)
3392                 printf(" any");
3393         else
3394                 printf(" %d", o->tun_local);
3395         if (o->tun_remote == SSH_TUNID_ANY)
3396                 printf(":any");
3397         else
3398                 printf(":%d", o->tun_remote);
3399         printf("\n");
3400
3401         /* oCanonicalizePermittedCNAMEs */
3402         if ( o->num_permitted_cnames > 0) {
3403                 printf("canonicalizePermittedcnames");
3404                 for (i = 0; i < o->num_permitted_cnames; i++) {
3405                         printf(" %s:%s", o->permitted_cnames[i].source_list,
3406                             o->permitted_cnames[i].target_list);
3407                 }
3408                 printf("\n");
3409         }
3410
3411         /* oControlPersist */
3412         if (o->control_persist == 0 || o->control_persist_timeout == 0)
3413                 dump_cfg_fmtint(oControlPersist, o->control_persist);
3414         else
3415                 dump_cfg_int(oControlPersist, o->control_persist_timeout);
3416
3417         /* oEscapeChar */
3418         if (o->escape_char == SSH_ESCAPECHAR_NONE)
3419                 printf("escapechar none\n");
3420         else {
3421                 vis(buf, o->escape_char, VIS_WHITE, 0);
3422                 printf("escapechar %s\n", buf);
3423         }
3424
3425         /* oIPQoS */
3426         printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
3427         printf("%s\n", iptos2str(o->ip_qos_bulk));
3428
3429         /* oRekeyLimit */
3430         printf("rekeylimit %llu %d\n",
3431             (unsigned long long)o->rekey_limit, o->rekey_interval);
3432
3433         /* oStreamLocalBindMask */
3434         printf("streamlocalbindmask 0%o\n",
3435             o->fwd_opts.streamlocal_bind_mask);
3436
3437         /* oLogFacility */
3438         printf("syslogfacility %s\n", log_facility_name(o->log_facility));
3439
3440         /* oProxyCommand / oProxyJump */
3441         if (o->jump_host == NULL)
3442                 dump_cfg_string(oProxyCommand, o->proxy_command);
3443         else {
3444                 /* Check for numeric addresses */
3445                 i = strchr(o->jump_host, ':') != NULL ||
3446                     strspn(o->jump_host, "1234567890.") == strlen(o->jump_host);
3447                 snprintf(buf, sizeof(buf), "%d", o->jump_port);
3448                 printf("proxyjump %s%s%s%s%s%s%s%s%s\n",
3449                     /* optional additional jump spec */
3450                     o->jump_extra == NULL ? "" : o->jump_extra,
3451                     o->jump_extra == NULL ? "" : ",",
3452                     /* optional user */
3453                     o->jump_user == NULL ? "" : o->jump_user,
3454                     o->jump_user == NULL ? "" : "@",
3455                     /* opening [ if hostname is numeric */
3456                     i ? "[" : "",
3457                     /* mandatory hostname */
3458                     o->jump_host,
3459                     /* closing ] if hostname is numeric */
3460                     i ? "]" : "",
3461                     /* optional port number */
3462                     o->jump_port <= 0 ? "" : ":",
3463                     o->jump_port <= 0 ? "" : buf);
3464         }
3465 }