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