Merge branch 'vendor/ZLIB'
[dragonfly.git] / crypto / openssh / readconf.c
1 /* $OpenBSD: readconf.c,v 1.304 2019/03/01 02:08:50 djm Exp $ */
2 /*
3  * Author: Tatu Ylonen <ylo@cs.hut.fi>
4  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5  *                    All rights reserved
6  * Functions for reading the configuration files.
7  *
8  * As far as I am concerned, the code I have written for this software
9  * can be used freely for any purpose.  Any derived versions of this
10  * software must be clearly marked as such, and if the derived work is
11  * incompatible with the protocol description in the RFC file, it must be
12  * called by a name other than "ssh" or "Secure Shell".
13  */
14
15 #include "includes.h"
16
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 <stdarg.h>
39 #include <stdio.h>
40 #include <string.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 "compat.h"
58 #include "cipher.h"
59 #include "pathnames.h"
60 #include "log.h"
61 #include "sshkey.h"
62 #include "misc.h"
63 #include "readconf.h"
64 #include "match.h"
65 #include "kex.h"
66 #include "mac.h"
67 #include "uidswap.h"
68 #include "myproposal.h"
69 #include "digest.h"
70
71 /* Format of the configuration file:
72
73    # Configuration data is parsed as follows:
74    #  1. command line options
75    #  2. user-specific file
76    #  3. system-wide file
77    # Any configuration value is only changed the first time it is set.
78    # Thus, host-specific definitions should be at the beginning of the
79    # configuration file, and defaults at the end.
80
81    # Host-specific declarations.  These may override anything above.  A single
82    # host may match multiple declarations; these are processed in the order
83    # that they are given in.
84
85    Host *.ngs.fi ngs.fi
86      User foo
87
88    Host fake.com
89      HostName another.host.name.real.org
90      User blaah
91      Port 34289
92      ForwardX11 no
93      ForwardAgent no
94
95    Host books.com
96      RemoteForward 9999 shadows.cs.hut.fi:9999
97      Ciphers 3des-cbc
98
99    Host fascist.blob.com
100      Port 23123
101      User tylonen
102      PasswordAuthentication no
103
104    Host puukko.hut.fi
105      User t35124p
106      ProxyCommand ssh-proxy %h %p
107
108    Host *.fr
109      PublicKeyAuthentication no
110
111    Host *.su
112      Ciphers aes128-ctr
113      PasswordAuthentication no
114
115    Host vpn.fake.com
116      Tunnel yes
117      TunnelDevice 3
118
119    # Defaults for various options
120    Host *
121      ForwardAgent no
122      ForwardX11 no
123      PasswordAuthentication yes
124      RSAAuthentication yes
125      RhostsRSAAuthentication yes
126      StrictHostKeyChecking yes
127      TcpKeepAlive no
128      IdentityFile ~/.ssh/identity
129      Port 22
130      EscapeChar ~
131
132 */
133
134 static int read_config_file_depth(const char *filename, struct passwd *pw,
135     const char *host, const char *original_host, Options *options,
136     int flags, int *activep, int *want_final_pass, int depth);
137 static int process_config_line_depth(Options *options, struct passwd *pw,
138     const char *host, const char *original_host, char *line,
139     const char *filename, int linenum, int *activep, int flags,
140     int *want_final_pass, int depth);
141
142 /* Keyword tokens. */
143
144 typedef enum {
145         oBadOption,
146         oHost, oMatch, oInclude,
147         oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
148         oGatewayPorts, oExitOnForwardFailure,
149         oPasswordAuthentication, oRSAAuthentication,
150         oChallengeResponseAuthentication, oXAuthLocation,
151         oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
152         oCertificateFile, oAddKeysToAgent, oIdentityAgent,
153         oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
154         oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
155         oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
156         oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
157         oUsePrivilegedPort, oLogFacility, oLogLevel, oCiphers, oMacs,
158         oPubkeyAuthentication,
159         oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
160         oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
161         oHostKeyAlgorithms, oBindAddress, oBindInterface, oPKCS11Provider,
162         oClearAllForwardings, oNoHostAuthenticationForLocalhost,
163         oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
164         oAddressFamily, oGssAuthentication, oGssDelegateCreds,
165         oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
166         oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist,
167         oHashKnownHosts,
168         oTunnel, oTunnelDevice,
169         oLocalCommand, oPermitLocalCommand, oRemoteCommand,
170         oVisualHostKey,
171         oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
172         oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
173         oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
174         oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
175         oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes,
176         oPubkeyAcceptedKeyTypes, oCASignatureAlgorithms, oProxyJump,
177         oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
178 } OpCodes;
179
180 /* Textual representations of the tokens. */
181
182 static struct {
183         const char *name;
184         OpCodes opcode;
185 } keywords[] = {
186         /* Deprecated options */
187         { "protocol", oIgnore }, /* NB. silently ignored */
188         { "cipher", oDeprecated },
189         { "fallbacktorsh", oDeprecated },
190         { "globalknownhostsfile2", oDeprecated },
191         { "rhostsauthentication", oDeprecated },
192         { "userknownhostsfile2", oDeprecated },
193         { "useroaming", oDeprecated },
194         { "usersh", oDeprecated },
195         { "useprivilegedport", oDeprecated },
196
197         /* Unsupported options */
198         { "afstokenpassing", oUnsupported },
199         { "kerberosauthentication", oUnsupported },
200         { "kerberostgtpassing", oUnsupported },
201
202         /* Sometimes-unsupported options */
203 #if defined(GSSAPI)
204         { "gssapiauthentication", oGssAuthentication },
205         { "gssapidelegatecredentials", oGssDelegateCreds },
206 # else
207         { "gssapiauthentication", oUnsupported },
208         { "gssapidelegatecredentials", oUnsupported },
209 #endif
210 #ifdef ENABLE_PKCS11
211         { "pkcs11provider", oPKCS11Provider },
212         { "smartcarddevice", oPKCS11Provider },
213 # else
214         { "smartcarddevice", oUnsupported },
215         { "pkcs11provider", oUnsupported },
216 #endif
217         { "rsaauthentication", oUnsupported },
218         { "rhostsrsaauthentication", oUnsupported },
219         { "compressionlevel", oUnsupported },
220
221         { "forwardagent", oForwardAgent },
222         { "forwardx11", oForwardX11 },
223         { "forwardx11trusted", oForwardX11Trusted },
224         { "forwardx11timeout", oForwardX11Timeout },
225         { "exitonforwardfailure", oExitOnForwardFailure },
226         { "xauthlocation", oXAuthLocation },
227         { "gatewayports", oGatewayPorts },
228         { "passwordauthentication", oPasswordAuthentication },
229         { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
230         { "kbdinteractivedevices", oKbdInteractiveDevices },
231         { "pubkeyauthentication", oPubkeyAuthentication },
232         { "dsaauthentication", oPubkeyAuthentication },             /* alias */
233         { "hostbasedauthentication", oHostbasedAuthentication },
234         { "challengeresponseauthentication", oChallengeResponseAuthentication },
235         { "skeyauthentication", oUnsupported },
236         { "tisauthentication", oChallengeResponseAuthentication },  /* alias */
237         { "identityfile", oIdentityFile },
238         { "identityfile2", oIdentityFile },                     /* obsolete */
239         { "identitiesonly", oIdentitiesOnly },
240         { "certificatefile", oCertificateFile },
241         { "addkeystoagent", oAddKeysToAgent },
242         { "identityagent", oIdentityAgent },
243         { "hostname", oHostName },
244         { "hostkeyalias", oHostKeyAlias },
245         { "proxycommand", oProxyCommand },
246         { "port", oPort },
247         { "ciphers", oCiphers },
248         { "macs", oMacs },
249         { "remoteforward", oRemoteForward },
250         { "localforward", oLocalForward },
251         { "user", oUser },
252         { "host", oHost },
253         { "match", oMatch },
254         { "escapechar", oEscapeChar },
255         { "globalknownhostsfile", oGlobalKnownHostsFile },
256         { "userknownhostsfile", oUserKnownHostsFile },
257         { "connectionattempts", oConnectionAttempts },
258         { "batchmode", oBatchMode },
259         { "checkhostip", oCheckHostIP },
260         { "stricthostkeychecking", oStrictHostKeyChecking },
261         { "compression", oCompression },
262         { "tcpkeepalive", oTCPKeepAlive },
263         { "keepalive", oTCPKeepAlive },                         /* obsolete */
264         { "numberofpasswordprompts", oNumberOfPasswordPrompts },
265         { "syslogfacility", oLogFacility },
266         { "loglevel", oLogLevel },
267         { "dynamicforward", oDynamicForward },
268         { "preferredauthentications", oPreferredAuthentications },
269         { "hostkeyalgorithms", oHostKeyAlgorithms },
270         { "casignaturealgorithms", oCASignatureAlgorithms },
271         { "bindaddress", oBindAddress },
272         { "bindinterface", oBindInterface },
273         { "clearallforwardings", oClearAllForwardings },
274         { "enablesshkeysign", oEnableSSHKeysign },
275         { "verifyhostkeydns", oVerifyHostKeyDNS },
276         { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
277         { "rekeylimit", oRekeyLimit },
278         { "connecttimeout", oConnectTimeout },
279         { "addressfamily", oAddressFamily },
280         { "serveraliveinterval", oServerAliveInterval },
281         { "serveralivecountmax", oServerAliveCountMax },
282         { "sendenv", oSendEnv },
283         { "setenv", oSetEnv },
284         { "controlpath", oControlPath },
285         { "controlmaster", oControlMaster },
286         { "controlpersist", oControlPersist },
287         { "hashknownhosts", oHashKnownHosts },
288         { "include", oInclude },
289         { "tunnel", oTunnel },
290         { "tunneldevice", oTunnelDevice },
291         { "localcommand", oLocalCommand },
292         { "permitlocalcommand", oPermitLocalCommand },
293         { "remotecommand", oRemoteCommand },
294         { "visualhostkey", oVisualHostKey },
295         { "kexalgorithms", oKexAlgorithms },
296         { "ipqos", oIPQoS },
297         { "requesttty", oRequestTTY },
298         { "proxyusefdpass", oProxyUseFdpass },
299         { "canonicaldomains", oCanonicalDomains },
300         { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
301         { "canonicalizehostname", oCanonicalizeHostname },
302         { "canonicalizemaxdots", oCanonicalizeMaxDots },
303         { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
304         { "streamlocalbindmask", oStreamLocalBindMask },
305         { "streamlocalbindunlink", oStreamLocalBindUnlink },
306         { "revokedhostkeys", oRevokedHostKeys },
307         { "fingerprinthash", oFingerprintHash },
308         { "updatehostkeys", oUpdateHostkeys },
309         { "hostbasedkeytypes", oHostbasedKeyTypes },
310         { "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes },
311         { "ignoreunknown", oIgnoreUnknown },
312         { "proxyjump", oProxyJump },
313
314         { NULL, oBadOption }
315 };
316
317 /*
318  * Adds a local TCP/IP port forward to options.  Never returns if there is an
319  * error.
320  */
321
322 void
323 add_local_forward(Options *options, const struct Forward *newfwd)
324 {
325         struct Forward *fwd;
326         int i;
327
328         /* Don't add duplicates */
329         for (i = 0; i < options->num_local_forwards; i++) {
330                 if (forward_equals(newfwd, options->local_forwards + i))
331                         return;
332         }
333         options->local_forwards = xreallocarray(options->local_forwards,
334             options->num_local_forwards + 1,
335             sizeof(*options->local_forwards));
336         fwd = &options->local_forwards[options->num_local_forwards++];
337
338         fwd->listen_host = newfwd->listen_host;
339         fwd->listen_port = newfwd->listen_port;
340         fwd->listen_path = newfwd->listen_path;
341         fwd->connect_host = newfwd->connect_host;
342         fwd->connect_port = newfwd->connect_port;
343         fwd->connect_path = newfwd->connect_path;
344 }
345
346 /*
347  * Adds a remote TCP/IP port forward to options.  Never returns if there is
348  * an error.
349  */
350
351 void
352 add_remote_forward(Options *options, const struct Forward *newfwd)
353 {
354         struct Forward *fwd;
355         int i;
356
357         /* Don't add duplicates */
358         for (i = 0; i < options->num_remote_forwards; i++) {
359                 if (forward_equals(newfwd, options->remote_forwards + i))
360                         return;
361         }
362         options->remote_forwards = xreallocarray(options->remote_forwards,
363             options->num_remote_forwards + 1,
364             sizeof(*options->remote_forwards));
365         fwd = &options->remote_forwards[options->num_remote_forwards++];
366
367         fwd->listen_host = newfwd->listen_host;
368         fwd->listen_port = newfwd->listen_port;
369         fwd->listen_path = newfwd->listen_path;
370         fwd->connect_host = newfwd->connect_host;
371         fwd->connect_port = newfwd->connect_port;
372         fwd->connect_path = newfwd->connect_path;
373         fwd->handle = newfwd->handle;
374         fwd->allocated_port = 0;
375 }
376
377 static void
378 clear_forwardings(Options *options)
379 {
380         int i;
381
382         for (i = 0; i < options->num_local_forwards; i++) {
383                 free(options->local_forwards[i].listen_host);
384                 free(options->local_forwards[i].listen_path);
385                 free(options->local_forwards[i].connect_host);
386                 free(options->local_forwards[i].connect_path);
387         }
388         if (options->num_local_forwards > 0) {
389                 free(options->local_forwards);
390                 options->local_forwards = NULL;
391         }
392         options->num_local_forwards = 0;
393         for (i = 0; i < options->num_remote_forwards; i++) {
394                 free(options->remote_forwards[i].listen_host);
395                 free(options->remote_forwards[i].listen_path);
396                 free(options->remote_forwards[i].connect_host);
397                 free(options->remote_forwards[i].connect_path);
398         }
399         if (options->num_remote_forwards > 0) {
400                 free(options->remote_forwards);
401                 options->remote_forwards = NULL;
402         }
403         options->num_remote_forwards = 0;
404         options->tun_open = SSH_TUNMODE_NO;
405 }
406
407 void
408 add_certificate_file(Options *options, const char *path, int userprovided)
409 {
410         int i;
411
412         if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES)
413                 fatal("Too many certificate files specified (max %d)",
414                     SSH_MAX_CERTIFICATE_FILES);
415
416         /* Avoid registering duplicates */
417         for (i = 0; i < options->num_certificate_files; i++) {
418                 if (options->certificate_file_userprovided[i] == userprovided &&
419                     strcmp(options->certificate_files[i], path) == 0) {
420                         debug2("%s: ignoring duplicate key %s", __func__, path);
421                         return;
422                 }
423         }
424
425         options->certificate_file_userprovided[options->num_certificate_files] =
426             userprovided;
427         options->certificate_files[options->num_certificate_files++] =
428             xstrdup(path);
429 }
430
431 void
432 add_identity_file(Options *options, const char *dir, const char *filename,
433     int userprovided)
434 {
435         char *path;
436         int i;
437
438         if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
439                 fatal("Too many identity files specified (max %d)",
440                     SSH_MAX_IDENTITY_FILES);
441
442         if (dir == NULL) /* no dir, filename is absolute */
443                 path = xstrdup(filename);
444         else if (xasprintf(&path, "%s%s", dir, filename) >= PATH_MAX)
445                 fatal("Identity file path %s too long", path);
446
447         /* Avoid registering duplicates */
448         for (i = 0; i < options->num_identity_files; i++) {
449                 if (options->identity_file_userprovided[i] == userprovided &&
450                     strcmp(options->identity_files[i], path) == 0) {
451                         debug2("%s: ignoring duplicate key %s", __func__, path);
452                         free(path);
453                         return;
454                 }
455         }
456
457         options->identity_file_userprovided[options->num_identity_files] =
458             userprovided;
459         options->identity_files[options->num_identity_files++] = path;
460 }
461
462 int
463 default_ssh_port(void)
464 {
465         static int port;
466         struct servent *sp;
467
468         if (port == 0) {
469                 sp = getservbyname(SSH_SERVICE_NAME, "tcp");
470                 port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
471         }
472         return port;
473 }
474
475 /*
476  * Execute a command in a shell.
477  * Return its exit status or -1 on abnormal exit.
478  */
479 static int
480 execute_in_shell(const char *cmd)
481 {
482         char *shell;
483         pid_t pid;
484         int devnull, status;
485
486         if ((shell = getenv("SHELL")) == NULL)
487                 shell = _PATH_BSHELL;
488
489         /* Need this to redirect subprocess stdin/out */
490         if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1)
491                 fatal("open(/dev/null): %s", strerror(errno));
492
493         debug("Executing command: '%.500s'", cmd);
494
495         /* Fork and execute the command. */
496         if ((pid = fork()) == 0) {
497                 char *argv[4];
498
499                 /* Redirect child stdin and stdout. Leave stderr */
500                 if (dup2(devnull, STDIN_FILENO) == -1)
501                         fatal("dup2: %s", strerror(errno));
502                 if (dup2(devnull, STDOUT_FILENO) == -1)
503                         fatal("dup2: %s", strerror(errno));
504                 if (devnull > STDERR_FILENO)
505                         close(devnull);
506                 closefrom(STDERR_FILENO + 1);
507
508                 argv[0] = shell;
509                 argv[1] = "-c";
510                 argv[2] = xstrdup(cmd);
511                 argv[3] = NULL;
512
513                 execv(argv[0], argv);
514                 error("Unable to execute '%.100s': %s", cmd, strerror(errno));
515                 /* Die with signal to make this error apparent to parent. */
516                 signal(SIGTERM, SIG_DFL);
517                 kill(getpid(), SIGTERM);
518                 _exit(1);
519         }
520         /* Parent. */
521         if (pid < 0)
522                 fatal("%s: fork: %.100s", __func__, strerror(errno));
523
524         close(devnull);
525
526         while (waitpid(pid, &status, 0) == -1) {
527                 if (errno != EINTR && errno != EAGAIN)
528                         fatal("%s: waitpid: %s", __func__, strerror(errno));
529         }
530         if (!WIFEXITED(status)) {
531                 error("command '%.100s' exited abnormally", cmd);
532                 return -1;
533         }
534         debug3("command returned status %d", WEXITSTATUS(status));
535         return WEXITSTATUS(status);
536 }
537
538 /*
539  * Parse and execute a Match directive.
540  */
541 static int
542 match_cfg_line(Options *options, char **condition, struct passwd *pw,
543     const char *host_arg, const char *original_host, int final_pass,
544     int *want_final_pass, const char *filename, int linenum)
545 {
546         char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria;
547         const char *ruser;
548         int r, port, this_result, result = 1, attributes = 0, negate;
549         char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
550         char uidstr[32];
551
552         /*
553          * Configuration is likely to be incomplete at this point so we
554          * must be prepared to use default values.
555          */
556         port = options->port <= 0 ? default_ssh_port() : options->port;
557         ruser = options->user == NULL ? pw->pw_name : options->user;
558         if (final_pass) {
559                 host = xstrdup(options->hostname);
560         } else if (options->hostname != NULL) {
561                 /* NB. Please keep in sync with ssh.c:main() */
562                 host = percent_expand(options->hostname,
563                     "h", host_arg, (char *)NULL);
564         } else {
565                 host = xstrdup(host_arg);
566         }
567
568         debug2("checking match for '%s' host %s originally %s",
569             cp, host, original_host);
570         while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') {
571                 criteria = NULL;
572                 this_result = 1;
573                 if ((negate = attrib[0] == '!'))
574                         attrib++;
575                 /* criteria "all" and "canonical" have no argument */
576                 if (strcasecmp(attrib, "all") == 0) {
577                         if (attributes > 1 ||
578                             ((arg = strdelim(&cp)) != NULL && *arg != '\0')) {
579                                 error("%.200s line %d: '%s' cannot be combined "
580                                     "with other Match attributes",
581                                     filename, linenum, oattrib);
582                                 result = -1;
583                                 goto out;
584                         }
585                         if (result)
586                                 result = negate ? 0 : 1;
587                         goto out;
588                 }
589                 attributes++;
590                 if (strcasecmp(attrib, "canonical") == 0 ||
591                     strcasecmp(attrib, "final") == 0) {
592                         /*
593                          * If the config requests "Match final" then remember
594                          * this so we can perform a second pass later.
595                          */
596                         if (strcasecmp(attrib, "final") == 0 &&
597                             want_final_pass != NULL)
598                                 *want_final_pass = 1;
599                         r = !!final_pass;  /* force bitmask member to boolean */
600                         if (r == (negate ? 1 : 0))
601                                 this_result = result = 0;
602                         debug3("%.200s line %d: %smatched '%s'",
603                             filename, linenum,
604                             this_result ? "" : "not ", oattrib);
605                         continue;
606                 }
607                 /* All other criteria require an argument */
608                 if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
609                         error("Missing Match criteria for %s", attrib);
610                         result = -1;
611                         goto out;
612                 }
613                 if (strcasecmp(attrib, "host") == 0) {
614                         criteria = xstrdup(host);
615                         r = match_hostname(host, arg) == 1;
616                         if (r == (negate ? 1 : 0))
617                                 this_result = result = 0;
618                 } else if (strcasecmp(attrib, "originalhost") == 0) {
619                         criteria = xstrdup(original_host);
620                         r = match_hostname(original_host, arg) == 1;
621                         if (r == (negate ? 1 : 0))
622                                 this_result = result = 0;
623                 } else if (strcasecmp(attrib, "user") == 0) {
624                         criteria = xstrdup(ruser);
625                         r = match_pattern_list(ruser, arg, 0) == 1;
626                         if (r == (negate ? 1 : 0))
627                                 this_result = result = 0;
628                 } else if (strcasecmp(attrib, "localuser") == 0) {
629                         criteria = xstrdup(pw->pw_name);
630                         r = match_pattern_list(pw->pw_name, arg, 0) == 1;
631                         if (r == (negate ? 1 : 0))
632                                 this_result = result = 0;
633                 } else if (strcasecmp(attrib, "exec") == 0) {
634                         if (gethostname(thishost, sizeof(thishost)) == -1)
635                                 fatal("gethostname: %s", strerror(errno));
636                         strlcpy(shorthost, thishost, sizeof(shorthost));
637                         shorthost[strcspn(thishost, ".")] = '\0';
638                         snprintf(portstr, sizeof(portstr), "%d", port);
639                         snprintf(uidstr, sizeof(uidstr), "%llu",
640                             (unsigned long long)pw->pw_uid);
641
642                         cmd = percent_expand(arg,
643                             "L", shorthost,
644                             "d", pw->pw_dir,
645                             "h", host,
646                             "l", thishost,
647                             "n", original_host,
648                             "p", portstr,
649                             "r", ruser,
650                             "u", pw->pw_name,
651                             "i", uidstr,
652                             (char *)NULL);
653                         if (result != 1) {
654                                 /* skip execution if prior predicate failed */
655                                 debug3("%.200s line %d: skipped exec "
656                                     "\"%.100s\"", filename, linenum, cmd);
657                                 free(cmd);
658                                 continue;
659                         }
660                         r = execute_in_shell(cmd);
661                         if (r == -1) {
662                                 fatal("%.200s line %d: match exec "
663                                     "'%.100s' error", filename,
664                                     linenum, cmd);
665                         }
666                         criteria = xstrdup(cmd);
667                         free(cmd);
668                         /* Force exit status to boolean */
669                         r = r == 0;
670                         if (r == (negate ? 1 : 0))
671                                 this_result = result = 0;
672                 } else {
673                         error("Unsupported Match attribute %s", attrib);
674                         result = -1;
675                         goto out;
676                 }
677                 debug3("%.200s line %d: %smatched '%s \"%.100s\"' ",
678                     filename, linenum, this_result ? "": "not ",
679                     oattrib, criteria);
680                 free(criteria);
681         }
682         if (attributes == 0) {
683                 error("One or more attributes required for Match");
684                 result = -1;
685                 goto out;
686         }
687  out:
688         if (result != -1)
689                 debug2("match %sfound", result ? "" : "not ");
690         *condition = cp;
691         free(host);
692         return result;
693 }
694
695 /* Remove environment variable by pattern */
696 static void
697 rm_env(Options *options, const char *arg, const char *filename, int linenum)
698 {
699         int i, j;
700         char *cp;
701
702         /* Remove an environment variable */
703         for (i = 0; i < options->num_send_env; ) {
704                 cp = xstrdup(options->send_env[i]);
705                 if (!match_pattern(cp, arg + 1)) {
706                         free(cp);
707                         i++;
708                         continue;
709                 }
710                 debug3("%s line %d: removing environment %s",
711                     filename, linenum, cp);
712                 free(cp);
713                 free(options->send_env[i]);
714                 options->send_env[i] = NULL;
715                 for (j = i; j < options->num_send_env - 1; j++) {
716                         options->send_env[j] = options->send_env[j + 1];
717                         options->send_env[j + 1] = NULL;
718                 }
719                 options->num_send_env--;
720                 /* NB. don't increment i */
721         }
722 }
723
724 /*
725  * Returns the number of the token pointed to by cp or oBadOption.
726  */
727 static OpCodes
728 parse_token(const char *cp, const char *filename, int linenum,
729     const char *ignored_unknown)
730 {
731         int i;
732
733         for (i = 0; keywords[i].name; i++)
734                 if (strcmp(cp, keywords[i].name) == 0)
735                         return keywords[i].opcode;
736         if (ignored_unknown != NULL &&
737             match_pattern_list(cp, ignored_unknown, 1) == 1)
738                 return oIgnoredUnknownOption;
739         error("%s: line %d: Bad configuration option: %s",
740             filename, linenum, cp);
741         return oBadOption;
742 }
743
744 /* Multistate option parsing */
745 struct multistate {
746         char *key;
747         int value;
748 };
749 static const struct multistate multistate_flag[] = {
750         { "true",                       1 },
751         { "false",                      0 },
752         { "yes",                        1 },
753         { "no",                         0 },
754         { NULL, -1 }
755 };
756 static const struct multistate multistate_yesnoask[] = {
757         { "true",                       1 },
758         { "false",                      0 },
759         { "yes",                        1 },
760         { "no",                         0 },
761         { "ask",                        2 },
762         { NULL, -1 }
763 };
764 static const struct multistate multistate_strict_hostkey[] = {
765         { "true",                       SSH_STRICT_HOSTKEY_YES },
766         { "false",                      SSH_STRICT_HOSTKEY_OFF },
767         { "yes",                        SSH_STRICT_HOSTKEY_YES },
768         { "no",                         SSH_STRICT_HOSTKEY_OFF },
769         { "ask",                        SSH_STRICT_HOSTKEY_ASK },
770         { "off",                        SSH_STRICT_HOSTKEY_OFF },
771         { "accept-new",                 SSH_STRICT_HOSTKEY_NEW },
772         { NULL, -1 }
773 };
774 static const struct multistate multistate_yesnoaskconfirm[] = {
775         { "true",                       1 },
776         { "false",                      0 },
777         { "yes",                        1 },
778         { "no",                         0 },
779         { "ask",                        2 },
780         { "confirm",                    3 },
781         { NULL, -1 }
782 };
783 static const struct multistate multistate_addressfamily[] = {
784         { "inet",                       AF_INET },
785         { "inet6",                      AF_INET6 },
786         { "any",                        AF_UNSPEC },
787         { NULL, -1 }
788 };
789 static const struct multistate multistate_controlmaster[] = {
790         { "true",                       SSHCTL_MASTER_YES },
791         { "yes",                        SSHCTL_MASTER_YES },
792         { "false",                      SSHCTL_MASTER_NO },
793         { "no",                         SSHCTL_MASTER_NO },
794         { "auto",                       SSHCTL_MASTER_AUTO },
795         { "ask",                        SSHCTL_MASTER_ASK },
796         { "autoask",                    SSHCTL_MASTER_AUTO_ASK },
797         { NULL, -1 }
798 };
799 static const struct multistate multistate_tunnel[] = {
800         { "ethernet",                   SSH_TUNMODE_ETHERNET },
801         { "point-to-point",             SSH_TUNMODE_POINTOPOINT },
802         { "true",                       SSH_TUNMODE_DEFAULT },
803         { "yes",                        SSH_TUNMODE_DEFAULT },
804         { "false",                      SSH_TUNMODE_NO },
805         { "no",                         SSH_TUNMODE_NO },
806         { NULL, -1 }
807 };
808 static const struct multistate multistate_requesttty[] = {
809         { "true",                       REQUEST_TTY_YES },
810         { "yes",                        REQUEST_TTY_YES },
811         { "false",                      REQUEST_TTY_NO },
812         { "no",                         REQUEST_TTY_NO },
813         { "force",                      REQUEST_TTY_FORCE },
814         { "auto",                       REQUEST_TTY_AUTO },
815         { NULL, -1 }
816 };
817 static const struct multistate multistate_canonicalizehostname[] = {
818         { "true",                       SSH_CANONICALISE_YES },
819         { "false",                      SSH_CANONICALISE_NO },
820         { "yes",                        SSH_CANONICALISE_YES },
821         { "no",                         SSH_CANONICALISE_NO },
822         { "always",                     SSH_CANONICALISE_ALWAYS },
823         { NULL, -1 }
824 };
825
826 /*
827  * Processes a single option line as used in the configuration files. This
828  * only sets those values that have not already been set.
829  */
830 int
831 process_config_line(Options *options, struct passwd *pw, const char *host,
832     const char *original_host, char *line, const char *filename,
833     int linenum, int *activep, int flags)
834 {
835         return process_config_line_depth(options, pw, host, original_host,
836             line, filename, linenum, activep, flags, NULL, 0);
837 }
838
839 #define WHITESPACE " \t\r\n"
840 static int
841 process_config_line_depth(Options *options, struct passwd *pw, const char *host,
842     const char *original_host, char *line, const char *filename,
843     int linenum, int *activep, int flags, int *want_final_pass, int depth)
844 {
845         char *s, **charptr, *endofnumber, *keyword, *arg, *arg2;
846         char **cpptr, fwdarg[256];
847         u_int i, *uintptr, max_entries = 0;
848         int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0;
849         int remotefwd, dynamicfwd;
850         LogLevel *log_level_ptr;
851         SyslogFacility *log_facility_ptr;
852         long long val64;
853         size_t len;
854         struct Forward fwd;
855         const struct multistate *multistate_ptr;
856         struct allowed_cname *cname;
857         glob_t gl;
858         const char *errstr;
859
860         if (activep == NULL) { /* We are processing a command line directive */
861                 cmdline = 1;
862                 activep = &cmdline;
863         }
864
865         /* Strip trailing whitespace. Allow \f (form feed) at EOL only */
866         if ((len = strlen(line)) == 0)
867                 return 0;
868         for (len--; len > 0; len--) {
869                 if (strchr(WHITESPACE "\f", line[len]) == NULL)
870                         break;
871                 line[len] = '\0';
872         }
873
874         s = line;
875         /* Get the keyword. (Each line is supposed to begin with a keyword). */
876         if ((keyword = strdelim(&s)) == NULL)
877                 return 0;
878         /* Ignore leading whitespace. */
879         if (*keyword == '\0')
880                 keyword = strdelim(&s);
881         if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
882                 return 0;
883         /* Match lowercase keyword */
884         lowercase(keyword);
885
886         opcode = parse_token(keyword, filename, linenum,
887             options->ignored_unknown);
888
889         switch (opcode) {
890         case oBadOption:
891                 /* don't panic, but count bad options */
892                 return -1;
893         case oIgnore:
894                 return 0;
895         case oIgnoredUnknownOption:
896                 debug("%s line %d: Ignored unknown option \"%s\"",
897                     filename, linenum, keyword);
898                 return 0;
899         case oConnectTimeout:
900                 intptr = &options->connection_timeout;
901 parse_time:
902                 arg = strdelim(&s);
903                 if (!arg || *arg == '\0')
904                         fatal("%s line %d: missing time value.",
905                             filename, linenum);
906                 if (strcmp(arg, "none") == 0)
907                         value = -1;
908                 else if ((value = convtime(arg)) == -1)
909                         fatal("%s line %d: invalid time value.",
910                             filename, linenum);
911                 if (*activep && *intptr == -1)
912                         *intptr = value;
913                 break;
914
915         case oForwardAgent:
916                 intptr = &options->forward_agent;
917  parse_flag:
918                 multistate_ptr = multistate_flag;
919  parse_multistate:
920                 arg = strdelim(&s);
921                 if (!arg || *arg == '\0')
922                         fatal("%s line %d: missing argument.",
923                             filename, linenum);
924                 value = -1;
925                 for (i = 0; multistate_ptr[i].key != NULL; i++) {
926                         if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
927                                 value = multistate_ptr[i].value;
928                                 break;
929                         }
930                 }
931                 if (value == -1)
932                         fatal("%s line %d: unsupported option \"%s\".",
933                             filename, linenum, arg);
934                 if (*activep && *intptr == -1)
935                         *intptr = value;
936                 break;
937
938         case oForwardX11:
939                 intptr = &options->forward_x11;
940                 goto parse_flag;
941
942         case oForwardX11Trusted:
943                 intptr = &options->forward_x11_trusted;
944                 goto parse_flag;
945
946         case oForwardX11Timeout:
947                 intptr = &options->forward_x11_timeout;
948                 goto parse_time;
949
950         case oGatewayPorts:
951                 intptr = &options->fwd_opts.gateway_ports;
952                 goto parse_flag;
953
954         case oExitOnForwardFailure:
955                 intptr = &options->exit_on_forward_failure;
956                 goto parse_flag;
957
958         case oPasswordAuthentication:
959                 intptr = &options->password_authentication;
960                 goto parse_flag;
961
962         case oKbdInteractiveAuthentication:
963                 intptr = &options->kbd_interactive_authentication;
964                 goto parse_flag;
965
966         case oKbdInteractiveDevices:
967                 charptr = &options->kbd_interactive_devices;
968                 goto parse_string;
969
970         case oPubkeyAuthentication:
971                 intptr = &options->pubkey_authentication;
972                 goto parse_flag;
973
974         case oHostbasedAuthentication:
975                 intptr = &options->hostbased_authentication;
976                 goto parse_flag;
977
978         case oChallengeResponseAuthentication:
979                 intptr = &options->challenge_response_authentication;
980                 goto parse_flag;
981
982         case oGssAuthentication:
983                 intptr = &options->gss_authentication;
984                 goto parse_flag;
985
986         case oGssDelegateCreds:
987                 intptr = &options->gss_deleg_creds;
988                 goto parse_flag;
989
990         case oBatchMode:
991                 intptr = &options->batch_mode;
992                 goto parse_flag;
993
994         case oCheckHostIP:
995                 intptr = &options->check_host_ip;
996                 goto parse_flag;
997
998         case oVerifyHostKeyDNS:
999                 intptr = &options->verify_host_key_dns;
1000                 multistate_ptr = multistate_yesnoask;
1001                 goto parse_multistate;
1002
1003         case oStrictHostKeyChecking:
1004                 intptr = &options->strict_host_key_checking;
1005                 multistate_ptr = multistate_strict_hostkey;
1006                 goto parse_multistate;
1007
1008         case oCompression:
1009                 intptr = &options->compression;
1010                 goto parse_flag;
1011
1012         case oTCPKeepAlive:
1013                 intptr = &options->tcp_keep_alive;
1014                 goto parse_flag;
1015
1016         case oNoHostAuthenticationForLocalhost:
1017                 intptr = &options->no_host_authentication_for_localhost;
1018                 goto parse_flag;
1019
1020         case oNumberOfPasswordPrompts:
1021                 intptr = &options->number_of_password_prompts;
1022                 goto parse_int;
1023
1024         case oRekeyLimit:
1025                 arg = strdelim(&s);
1026                 if (!arg || *arg == '\0')
1027                         fatal("%.200s line %d: Missing argument.", filename,
1028                             linenum);
1029                 if (strcmp(arg, "default") == 0) {
1030                         val64 = 0;
1031                 } else {
1032                         if (scan_scaled(arg, &val64) == -1)
1033                                 fatal("%.200s line %d: Bad number '%s': %s",
1034                                     filename, linenum, arg, strerror(errno));
1035                         if (val64 != 0 && val64 < 16)
1036                                 fatal("%.200s line %d: RekeyLimit too small",
1037                                     filename, linenum);
1038                 }
1039                 if (*activep && options->rekey_limit == -1)
1040                         options->rekey_limit = val64;
1041                 if (s != NULL) { /* optional rekey interval present */
1042                         if (strcmp(s, "none") == 0) {
1043                                 (void)strdelim(&s);     /* discard */
1044                                 break;
1045                         }
1046                         intptr = &options->rekey_interval;
1047                         goto parse_time;
1048                 }
1049                 break;
1050
1051         case oIdentityFile:
1052                 arg = strdelim(&s);
1053                 if (!arg || *arg == '\0')
1054                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1055                 if (*activep) {
1056                         intptr = &options->num_identity_files;
1057                         if (*intptr >= SSH_MAX_IDENTITY_FILES)
1058                                 fatal("%.200s line %d: Too many identity files specified (max %d).",
1059                                     filename, linenum, SSH_MAX_IDENTITY_FILES);
1060                         add_identity_file(options, NULL,
1061                             arg, flags & SSHCONF_USERCONF);
1062                 }
1063                 break;
1064
1065         case oCertificateFile:
1066                 arg = strdelim(&s);
1067                 if (!arg || *arg == '\0')
1068                         fatal("%.200s line %d: Missing argument.",
1069                             filename, linenum);
1070                 if (*activep) {
1071                         intptr = &options->num_certificate_files;
1072                         if (*intptr >= SSH_MAX_CERTIFICATE_FILES) {
1073                                 fatal("%.200s line %d: Too many certificate "
1074                                     "files specified (max %d).",
1075                                     filename, linenum,
1076                                     SSH_MAX_CERTIFICATE_FILES);
1077                         }
1078                         add_certificate_file(options, arg,
1079                             flags & SSHCONF_USERCONF);
1080                 }
1081                 break;
1082
1083         case oXAuthLocation:
1084                 charptr=&options->xauth_location;
1085                 goto parse_string;
1086
1087         case oUser:
1088                 charptr = &options->user;
1089 parse_string:
1090                 arg = strdelim(&s);
1091                 if (!arg || *arg == '\0')
1092                         fatal("%.200s line %d: Missing argument.",
1093                             filename, linenum);
1094                 if (*activep && *charptr == NULL)
1095                         *charptr = xstrdup(arg);
1096                 break;
1097
1098         case oGlobalKnownHostsFile:
1099                 cpptr = (char **)&options->system_hostfiles;
1100                 uintptr = &options->num_system_hostfiles;
1101                 max_entries = SSH_MAX_HOSTS_FILES;
1102 parse_char_array:
1103                 if (*activep && *uintptr == 0) {
1104                         while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1105                                 if ((*uintptr) >= max_entries)
1106                                         fatal("%s line %d: "
1107                                             "too many authorized keys files.",
1108                                             filename, linenum);
1109                                 cpptr[(*uintptr)++] = xstrdup(arg);
1110                         }
1111                 }
1112                 return 0;
1113
1114         case oUserKnownHostsFile:
1115                 cpptr = (char **)&options->user_hostfiles;
1116                 uintptr = &options->num_user_hostfiles;
1117                 max_entries = SSH_MAX_HOSTS_FILES;
1118                 goto parse_char_array;
1119
1120         case oHostName:
1121                 charptr = &options->hostname;
1122                 goto parse_string;
1123
1124         case oHostKeyAlias:
1125                 charptr = &options->host_key_alias;
1126                 goto parse_string;
1127
1128         case oPreferredAuthentications:
1129                 charptr = &options->preferred_authentications;
1130                 goto parse_string;
1131
1132         case oBindAddress:
1133                 charptr = &options->bind_address;
1134                 goto parse_string;
1135
1136         case oBindInterface:
1137                 charptr = &options->bind_interface;
1138                 goto parse_string;
1139
1140         case oPKCS11Provider:
1141                 charptr = &options->pkcs11_provider;
1142                 goto parse_string;
1143
1144         case oProxyCommand:
1145                 charptr = &options->proxy_command;
1146                 /* Ignore ProxyCommand if ProxyJump already specified */
1147                 if (options->jump_host != NULL)
1148                         charptr = &options->jump_host; /* Skip below */
1149 parse_command:
1150                 if (s == NULL)
1151                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1152                 len = strspn(s, WHITESPACE "=");
1153                 if (*activep && *charptr == NULL)
1154                         *charptr = xstrdup(s + len);
1155                 return 0;
1156
1157         case oProxyJump:
1158                 if (s == NULL) {
1159                         fatal("%.200s line %d: Missing argument.",
1160                             filename, linenum);
1161                 }
1162                 len = strspn(s, WHITESPACE "=");
1163                 if (parse_jump(s + len, options, *activep) == -1) {
1164                         fatal("%.200s line %d: Invalid ProxyJump \"%s\"",
1165                             filename, linenum, s + len);
1166                 }
1167                 return 0;
1168
1169         case oPort:
1170                 arg = strdelim(&s);
1171                 if (!arg || *arg == '\0')
1172                         fatal("%.200s line %d: Missing argument.",
1173                             filename, linenum);
1174                 value = a2port(arg);
1175                 if (value <= 0)
1176                         fatal("%.200s line %d: Bad port '%s'.",
1177                             filename, linenum, arg);
1178                 if (*activep && options->port == -1)
1179                         options->port = value;
1180                 break;
1181
1182         case oConnectionAttempts:
1183                 intptr = &options->connection_attempts;
1184 parse_int:
1185                 arg = strdelim(&s);
1186                 if ((errstr = atoi_err(arg, &value)) != NULL)
1187                         fatal("%s line %d: integer value %s.",
1188                             filename, linenum, errstr);
1189                 if (*activep && *intptr == -1)
1190                         *intptr = value;
1191                 break;
1192
1193         case oCiphers:
1194                 arg = strdelim(&s);
1195                 if (!arg || *arg == '\0')
1196                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1197                 if (*arg != '-' && !ciphers_valid(*arg == '+' ? arg + 1 : arg))
1198                         fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
1199                             filename, linenum, arg ? arg : "<NONE>");
1200                 if (*activep && options->ciphers == NULL)
1201                         options->ciphers = xstrdup(arg);
1202                 break;
1203
1204         case oMacs:
1205                 arg = strdelim(&s);
1206                 if (!arg || *arg == '\0')
1207                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1208                 if (*arg != '-' && !mac_valid(*arg == '+' ? arg + 1 : arg))
1209                         fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
1210                             filename, linenum, arg ? arg : "<NONE>");
1211                 if (*activep && options->macs == NULL)
1212                         options->macs = xstrdup(arg);
1213                 break;
1214
1215         case oKexAlgorithms:
1216                 arg = strdelim(&s);
1217                 if (!arg || *arg == '\0')
1218                         fatal("%.200s line %d: Missing argument.",
1219                             filename, linenum);
1220                 if (*arg != '-' &&
1221                     !kex_names_valid(*arg == '+' ? arg + 1 : arg))
1222                         fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
1223                             filename, linenum, arg ? arg : "<NONE>");
1224                 if (*activep && options->kex_algorithms == NULL)
1225                         options->kex_algorithms = xstrdup(arg);
1226                 break;
1227
1228         case oHostKeyAlgorithms:
1229                 charptr = &options->hostkeyalgorithms;
1230 parse_keytypes:
1231                 arg = strdelim(&s);
1232                 if (!arg || *arg == '\0')
1233                         fatal("%.200s line %d: Missing argument.",
1234                             filename, linenum);
1235                 if (*arg != '-' &&
1236                     !sshkey_names_valid2(*arg == '+' ? arg + 1 : arg, 1))
1237                         fatal("%s line %d: Bad key types '%s'.",
1238                                 filename, linenum, arg ? arg : "<NONE>");
1239                 if (*activep && *charptr == NULL)
1240                         *charptr = xstrdup(arg);
1241                 break;
1242
1243         case oCASignatureAlgorithms:
1244                 charptr = &options->ca_sign_algorithms;
1245                 goto parse_keytypes;
1246
1247         case oLogLevel:
1248                 log_level_ptr = &options->log_level;
1249                 arg = strdelim(&s);
1250                 value = log_level_number(arg);
1251                 if (value == SYSLOG_LEVEL_NOT_SET)
1252                         fatal("%.200s line %d: unsupported log level '%s'",
1253                             filename, linenum, arg ? arg : "<NONE>");
1254                 if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
1255                         *log_level_ptr = (LogLevel) value;
1256                 break;
1257
1258         case oLogFacility:
1259                 log_facility_ptr = &options->log_facility;
1260                 arg = strdelim(&s);
1261                 value = log_facility_number(arg);
1262                 if (value == SYSLOG_FACILITY_NOT_SET)
1263                         fatal("%.200s line %d: unsupported log facility '%s'",
1264                             filename, linenum, arg ? arg : "<NONE>");
1265                 if (*log_facility_ptr == -1)
1266                         *log_facility_ptr = (SyslogFacility) value;
1267                 break;
1268
1269         case oLocalForward:
1270         case oRemoteForward:
1271         case oDynamicForward:
1272                 arg = strdelim(&s);
1273                 if (arg == NULL || *arg == '\0')
1274                         fatal("%.200s line %d: Missing port argument.",
1275                             filename, linenum);
1276
1277                 remotefwd = (opcode == oRemoteForward);
1278                 dynamicfwd = (opcode == oDynamicForward);
1279
1280                 if (!dynamicfwd) {
1281                         arg2 = strdelim(&s);
1282                         if (arg2 == NULL || *arg2 == '\0') {
1283                                 if (remotefwd)
1284                                         dynamicfwd = 1;
1285                                 else
1286                                         fatal("%.200s line %d: Missing target "
1287                                             "argument.", filename, linenum);
1288                         } else {
1289                                 /* construct a string for parse_forward */
1290                                 snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg,
1291                                     arg2);
1292                         }
1293                 }
1294                 if (dynamicfwd)
1295                         strlcpy(fwdarg, arg, sizeof(fwdarg));
1296
1297                 if (parse_forward(&fwd, fwdarg, dynamicfwd, remotefwd) == 0)
1298                         fatal("%.200s line %d: Bad forwarding specification.",
1299                             filename, linenum);
1300
1301                 if (*activep) {
1302                         if (remotefwd) {
1303                                 add_remote_forward(options, &fwd);
1304                         } else {
1305                                 add_local_forward(options, &fwd);
1306                         }
1307                 }
1308                 break;
1309
1310         case oClearAllForwardings:
1311                 intptr = &options->clear_forwardings;
1312                 goto parse_flag;
1313
1314         case oHost:
1315                 if (cmdline)
1316                         fatal("Host directive not supported as a command-line "
1317                             "option");
1318                 *activep = 0;
1319                 arg2 = NULL;
1320                 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1321                         if ((flags & SSHCONF_NEVERMATCH) != 0)
1322                                 break;
1323                         negated = *arg == '!';
1324                         if (negated)
1325                                 arg++;
1326                         if (match_pattern(host, arg)) {
1327                                 if (negated) {
1328                                         debug("%.200s line %d: Skipping Host "
1329                                             "block because of negated match "
1330                                             "for %.100s", filename, linenum,
1331                                             arg);
1332                                         *activep = 0;
1333                                         break;
1334                                 }
1335                                 if (!*activep)
1336                                         arg2 = arg; /* logged below */
1337                                 *activep = 1;
1338                         }
1339                 }
1340                 if (*activep)
1341                         debug("%.200s line %d: Applying options for %.100s",
1342                             filename, linenum, arg2);
1343                 /* Avoid garbage check below, as strdelim is done. */
1344                 return 0;
1345
1346         case oMatch:
1347                 if (cmdline)
1348                         fatal("Host directive not supported as a command-line "
1349                             "option");
1350                 value = match_cfg_line(options, &s, pw, host, original_host,
1351                     flags & SSHCONF_FINAL, want_final_pass,
1352                     filename, linenum);
1353                 if (value < 0)
1354                         fatal("%.200s line %d: Bad Match condition", filename,
1355                             linenum);
1356                 *activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value;
1357                 break;
1358
1359         case oEscapeChar:
1360                 intptr = &options->escape_char;
1361                 arg = strdelim(&s);
1362                 if (!arg || *arg == '\0')
1363                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1364                 if (strcmp(arg, "none") == 0)
1365                         value = SSH_ESCAPECHAR_NONE;
1366                 else if (arg[1] == '\0')
1367                         value = (u_char) arg[0];
1368                 else if (arg[0] == '^' && arg[2] == 0 &&
1369                     (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
1370                         value = (u_char) arg[1] & 31;
1371                 else {
1372                         fatal("%.200s line %d: Bad escape character.",
1373                             filename, linenum);
1374                         /* NOTREACHED */
1375                         value = 0;      /* Avoid compiler warning. */
1376                 }
1377                 if (*activep && *intptr == -1)
1378                         *intptr = value;
1379                 break;
1380
1381         case oAddressFamily:
1382                 intptr = &options->address_family;
1383                 multistate_ptr = multistate_addressfamily;
1384                 goto parse_multistate;
1385
1386         case oEnableSSHKeysign:
1387                 intptr = &options->enable_ssh_keysign;
1388                 goto parse_flag;
1389
1390         case oIdentitiesOnly:
1391                 intptr = &options->identities_only;
1392                 goto parse_flag;
1393
1394         case oServerAliveInterval:
1395                 intptr = &options->server_alive_interval;
1396                 goto parse_time;
1397
1398         case oServerAliveCountMax:
1399                 intptr = &options->server_alive_count_max;
1400                 goto parse_int;
1401
1402         case oSendEnv:
1403                 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1404                         if (strchr(arg, '=') != NULL)
1405                                 fatal("%s line %d: Invalid environment name.",
1406                                     filename, linenum);
1407                         if (!*activep)
1408                                 continue;
1409                         if (*arg == '-') {
1410                                 /* Removing an env var */
1411                                 rm_env(options, arg, filename, linenum);
1412                                 continue;
1413                         } else {
1414                                 /* Adding an env var */
1415                                 if (options->num_send_env >= INT_MAX)
1416                                         fatal("%s line %d: too many send env.",
1417                                             filename, linenum);
1418                                 options->send_env = xrecallocarray(
1419                                     options->send_env, options->num_send_env,
1420                                     options->num_send_env + 1,
1421                                     sizeof(*options->send_env));
1422                                 options->send_env[options->num_send_env++] =
1423                                     xstrdup(arg);
1424                         }
1425                 }
1426                 break;
1427
1428         case oSetEnv:
1429                 value = options->num_setenv;
1430                 while ((arg = strdelimw(&s)) != NULL && *arg != '\0') {
1431                         if (strchr(arg, '=') == NULL)
1432                                 fatal("%s line %d: Invalid SetEnv.",
1433                                     filename, linenum);
1434                         if (!*activep || value != 0)
1435                                 continue;
1436                         /* Adding a setenv var */
1437                         if (options->num_setenv >= INT_MAX)
1438                                 fatal("%s line %d: too many SetEnv.",
1439                                     filename, linenum);
1440                         options->setenv = xrecallocarray(
1441                             options->setenv, options->num_setenv,
1442                             options->num_setenv + 1, sizeof(*options->setenv));
1443                         options->setenv[options->num_setenv++] = xstrdup(arg);
1444                 }
1445                 break;
1446
1447         case oControlPath:
1448                 charptr = &options->control_path;
1449                 goto parse_string;
1450
1451         case oControlMaster:
1452                 intptr = &options->control_master;
1453                 multistate_ptr = multistate_controlmaster;
1454                 goto parse_multistate;
1455
1456         case oControlPersist:
1457                 /* no/false/yes/true, or a time spec */
1458                 intptr = &options->control_persist;
1459                 arg = strdelim(&s);
1460                 if (!arg || *arg == '\0')
1461                         fatal("%.200s line %d: Missing ControlPersist"
1462                             " argument.", filename, linenum);
1463                 value = 0;
1464                 value2 = 0;     /* timeout */
1465                 if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
1466                         value = 0;
1467                 else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
1468                         value = 1;
1469                 else if ((value2 = convtime(arg)) >= 0)
1470                         value = 1;
1471                 else
1472                         fatal("%.200s line %d: Bad ControlPersist argument.",
1473                             filename, linenum);
1474                 if (*activep && *intptr == -1) {
1475                         *intptr = value;
1476                         options->control_persist_timeout = value2;
1477                 }
1478                 break;
1479
1480         case oHashKnownHosts:
1481                 intptr = &options->hash_known_hosts;
1482                 goto parse_flag;
1483
1484         case oTunnel:
1485                 intptr = &options->tun_open;
1486                 multistate_ptr = multistate_tunnel;
1487                 goto parse_multistate;
1488
1489         case oTunnelDevice:
1490                 arg = strdelim(&s);
1491                 if (!arg || *arg == '\0')
1492                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1493                 value = a2tun(arg, &value2);
1494                 if (value == SSH_TUNID_ERR)
1495                         fatal("%.200s line %d: Bad tun device.", filename, linenum);
1496                 if (*activep) {
1497                         options->tun_local = value;
1498                         options->tun_remote = value2;
1499                 }
1500                 break;
1501
1502         case oLocalCommand:
1503                 charptr = &options->local_command;
1504                 goto parse_command;
1505
1506         case oPermitLocalCommand:
1507                 intptr = &options->permit_local_command;
1508                 goto parse_flag;
1509
1510         case oRemoteCommand:
1511                 charptr = &options->remote_command;
1512                 goto parse_command;
1513
1514         case oVisualHostKey:
1515                 intptr = &options->visual_host_key;
1516                 goto parse_flag;
1517
1518         case oInclude:
1519                 if (cmdline)
1520                         fatal("Include directive not supported as a "
1521                             "command-line option");
1522                 value = 0;
1523                 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1524                         /*
1525                          * Ensure all paths are anchored. User configuration
1526                          * files may begin with '~/' but system configurations
1527                          * must not. If the path is relative, then treat it
1528                          * as living in ~/.ssh for user configurations or
1529                          * /etc/ssh for system ones.
1530                          */
1531                         if (*arg == '~' && (flags & SSHCONF_USERCONF) == 0)
1532                                 fatal("%.200s line %d: bad include path %s.",
1533                                     filename, linenum, arg);
1534                         if (!path_absolute(arg) && *arg != '~') {
1535                                 xasprintf(&arg2, "%s/%s",
1536                                     (flags & SSHCONF_USERCONF) ?
1537                                     "~/" _PATH_SSH_USER_DIR : SSHDIR, arg);
1538                         } else
1539                                 arg2 = xstrdup(arg);
1540                         memset(&gl, 0, sizeof(gl));
1541                         r = glob(arg2, GLOB_TILDE, NULL, &gl);
1542                         if (r == GLOB_NOMATCH) {
1543                                 debug("%.200s line %d: include %s matched no "
1544                                     "files",filename, linenum, arg2);
1545                                 free(arg2);
1546                                 continue;
1547                         } else if (r != 0 || gl.gl_pathc < 0)
1548                                 fatal("%.200s line %d: glob failed for %s.",
1549                                     filename, linenum, arg2);
1550                         free(arg2);
1551                         oactive = *activep;
1552                         for (i = 0; i < (u_int)gl.gl_pathc; i++) {
1553                                 debug3("%.200s line %d: Including file %s "
1554                                     "depth %d%s", filename, linenum,
1555                                     gl.gl_pathv[i], depth,
1556                                     oactive ? "" : " (parse only)");
1557                                 r = read_config_file_depth(gl.gl_pathv[i],
1558                                     pw, host, original_host, options,
1559                                     flags | SSHCONF_CHECKPERM |
1560                                     (oactive ? 0 : SSHCONF_NEVERMATCH),
1561                                     activep, want_final_pass, depth + 1);
1562                                 if (r != 1 && errno != ENOENT) {
1563                                         fatal("Can't open user config file "
1564                                             "%.100s: %.100s", gl.gl_pathv[i],
1565                                             strerror(errno));
1566                                 }
1567                                 /*
1568                                  * don't let Match in includes clobber the
1569                                  * containing file's Match state.
1570                                  */
1571                                 *activep = oactive;
1572                                 if (r != 1)
1573                                         value = -1;
1574                         }
1575                         globfree(&gl);
1576                 }
1577                 if (value != 0)
1578                         return value;
1579                 break;
1580
1581         case oIPQoS:
1582                 arg = strdelim(&s);
1583                 if ((value = parse_ipqos(arg)) == -1)
1584                         fatal("%s line %d: Bad IPQoS value: %s",
1585                             filename, linenum, arg);
1586                 arg = strdelim(&s);
1587                 if (arg == NULL)
1588                         value2 = value;
1589                 else if ((value2 = parse_ipqos(arg)) == -1)
1590                         fatal("%s line %d: Bad IPQoS value: %s",
1591                             filename, linenum, arg);
1592                 if (*activep) {
1593                         options->ip_qos_interactive = value;
1594                         options->ip_qos_bulk = value2;
1595                 }
1596                 break;
1597
1598         case oRequestTTY:
1599                 intptr = &options->request_tty;
1600                 multistate_ptr = multistate_requesttty;
1601                 goto parse_multistate;
1602
1603         case oIgnoreUnknown:
1604                 charptr = &options->ignored_unknown;
1605                 goto parse_string;
1606
1607         case oProxyUseFdpass:
1608                 intptr = &options->proxy_use_fdpass;
1609                 goto parse_flag;
1610
1611         case oCanonicalDomains:
1612                 value = options->num_canonical_domains != 0;
1613                 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1614                         if (!valid_domain(arg, 1, &errstr)) {
1615                                 fatal("%s line %d: %s", filename, linenum,
1616                                     errstr);
1617                         }
1618                         if (!*activep || value)
1619                                 continue;
1620                         if (options->num_canonical_domains >= MAX_CANON_DOMAINS)
1621                                 fatal("%s line %d: too many hostname suffixes.",
1622                                     filename, linenum);
1623                         options->canonical_domains[
1624                             options->num_canonical_domains++] = xstrdup(arg);
1625                 }
1626                 break;
1627
1628         case oCanonicalizePermittedCNAMEs:
1629                 value = options->num_permitted_cnames != 0;
1630                 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1631                         /* Either '*' for everything or 'list:list' */
1632                         if (strcmp(arg, "*") == 0)
1633                                 arg2 = arg;
1634                         else {
1635                                 lowercase(arg);
1636                                 if ((arg2 = strchr(arg, ':')) == NULL ||
1637                                     arg2[1] == '\0') {
1638                                         fatal("%s line %d: "
1639                                             "Invalid permitted CNAME \"%s\"",
1640                                             filename, linenum, arg);
1641                                 }
1642                                 *arg2 = '\0';
1643                                 arg2++;
1644                         }
1645                         if (!*activep || value)
1646                                 continue;
1647                         if (options->num_permitted_cnames >= MAX_CANON_DOMAINS)
1648                                 fatal("%s line %d: too many permitted CNAMEs.",
1649                                     filename, linenum);
1650                         cname = options->permitted_cnames +
1651                             options->num_permitted_cnames++;
1652                         cname->source_list = xstrdup(arg);
1653                         cname->target_list = xstrdup(arg2);
1654                 }
1655                 break;
1656
1657         case oCanonicalizeHostname:
1658                 intptr = &options->canonicalize_hostname;
1659                 multistate_ptr = multistate_canonicalizehostname;
1660                 goto parse_multistate;
1661
1662         case oCanonicalizeMaxDots:
1663                 intptr = &options->canonicalize_max_dots;
1664                 goto parse_int;
1665
1666         case oCanonicalizeFallbackLocal:
1667                 intptr = &options->canonicalize_fallback_local;
1668                 goto parse_flag;
1669
1670         case oStreamLocalBindMask:
1671                 arg = strdelim(&s);
1672                 if (!arg || *arg == '\0')
1673                         fatal("%.200s line %d: Missing StreamLocalBindMask argument.", filename, linenum);
1674                 /* Parse mode in octal format */
1675                 value = strtol(arg, &endofnumber, 8);
1676                 if (arg == endofnumber || value < 0 || value > 0777)
1677                         fatal("%.200s line %d: Bad mask.", filename, linenum);
1678                 options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
1679                 break;
1680
1681         case oStreamLocalBindUnlink:
1682                 intptr = &options->fwd_opts.streamlocal_bind_unlink;
1683                 goto parse_flag;
1684
1685         case oRevokedHostKeys:
1686                 charptr = &options->revoked_host_keys;
1687                 goto parse_string;
1688
1689         case oFingerprintHash:
1690                 intptr = &options->fingerprint_hash;
1691                 arg = strdelim(&s);
1692                 if (!arg || *arg == '\0')
1693                         fatal("%.200s line %d: Missing argument.",
1694                             filename, linenum);
1695                 if ((value = ssh_digest_alg_by_name(arg)) == -1)
1696                         fatal("%.200s line %d: Invalid hash algorithm \"%s\".",
1697                             filename, linenum, arg);
1698                 if (*activep && *intptr == -1)
1699                         *intptr = value;
1700                 break;
1701
1702         case oUpdateHostkeys:
1703                 intptr = &options->update_hostkeys;
1704                 multistate_ptr = multistate_yesnoask;
1705                 goto parse_multistate;
1706
1707         case oHostbasedKeyTypes:
1708                 charptr = &options->hostbased_key_types;
1709                 goto parse_keytypes;
1710
1711         case oPubkeyAcceptedKeyTypes:
1712                 charptr = &options->pubkey_key_types;
1713                 goto parse_keytypes;
1714
1715         case oAddKeysToAgent:
1716                 intptr = &options->add_keys_to_agent;
1717                 multistate_ptr = multistate_yesnoaskconfirm;
1718                 goto parse_multistate;
1719
1720         case oIdentityAgent:
1721                 charptr = &options->identity_agent;
1722                 arg = strdelim(&s);
1723                 if (!arg || *arg == '\0')
1724                         fatal("%.200s line %d: Missing argument.",
1725                             filename, linenum);
1726                 /* Extra validation if the string represents an env var. */
1727                 if (arg[0] == '$' && !valid_env_name(arg + 1)) {
1728                         fatal("%.200s line %d: Invalid environment name %s.",
1729                             filename, linenum, arg);
1730                 }
1731                 if (*activep && *charptr == NULL)
1732                         *charptr = xstrdup(arg);
1733                 break;
1734
1735         case oDeprecated:
1736                 debug("%s line %d: Deprecated option \"%s\"",
1737                     filename, linenum, keyword);
1738                 return 0;
1739
1740         case oUnsupported:
1741                 error("%s line %d: Unsupported option \"%s\"",
1742                     filename, linenum, keyword);
1743                 return 0;
1744
1745         default:
1746                 fatal("%s: Unimplemented opcode %d", __func__, opcode);
1747         }
1748
1749         /* Check that there is no garbage at end of line. */
1750         if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1751                 fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
1752                     filename, linenum, arg);
1753         }
1754         return 0;
1755 }
1756
1757 /*
1758  * Reads the config file and modifies the options accordingly.  Options
1759  * should already be initialized before this call.  This never returns if
1760  * there is an error.  If the file does not exist, this returns 0.
1761  */
1762 int
1763 read_config_file(const char *filename, struct passwd *pw, const char *host,
1764     const char *original_host, Options *options, int flags,
1765     int *want_final_pass)
1766 {
1767         int active = 1;
1768
1769         return read_config_file_depth(filename, pw, host, original_host,
1770             options, flags, &active, want_final_pass, 0);
1771 }
1772
1773 #define READCONF_MAX_DEPTH      16
1774 static int
1775 read_config_file_depth(const char *filename, struct passwd *pw,
1776     const char *host, const char *original_host, Options *options,
1777     int flags, int *activep, int *want_final_pass, int depth)
1778 {
1779         FILE *f;
1780         char *line = NULL;
1781         size_t linesize = 0;
1782         int linenum;
1783         int bad_options = 0;
1784
1785         if (depth < 0 || depth > READCONF_MAX_DEPTH)
1786                 fatal("Too many recursive configuration includes");
1787
1788         if ((f = fopen(filename, "r")) == NULL)
1789                 return 0;
1790
1791         if (flags & SSHCONF_CHECKPERM) {
1792                 struct stat sb;
1793
1794                 if (fstat(fileno(f), &sb) == -1)
1795                         fatal("fstat %s: %s", filename, strerror(errno));
1796                 if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
1797                     (sb.st_mode & 022) != 0))
1798                         fatal("Bad owner or permissions on %s", filename);
1799         }
1800
1801         debug("Reading configuration data %.200s", filename);
1802
1803         /*
1804          * Mark that we are now processing the options.  This flag is turned
1805          * on/off by Host specifications.
1806          */
1807         linenum = 0;
1808         while (getline(&line, &linesize, f) != -1) {
1809                 /* Update line number counter. */
1810                 linenum++;
1811                 if (process_config_line_depth(options, pw, host, original_host,
1812                     line, filename, linenum, activep, flags, want_final_pass,
1813                     depth) != 0)
1814                         bad_options++;
1815         }
1816         free(line);
1817         fclose(f);
1818         if (bad_options > 0)
1819                 fatal("%s: terminating, %d bad configuration options",
1820                     filename, bad_options);
1821         return 1;
1822 }
1823
1824 /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
1825 int
1826 option_clear_or_none(const char *o)
1827 {
1828         return o == NULL || strcasecmp(o, "none") == 0;
1829 }
1830
1831 /*
1832  * Initializes options to special values that indicate that they have not yet
1833  * been set.  Read_config_file will only set options with this value. Options
1834  * are processed in the following order: command line, user config file,
1835  * system config file.  Last, fill_default_options is called.
1836  */
1837
1838 void
1839 initialize_options(Options * options)
1840 {
1841         memset(options, 'X', sizeof(*options));
1842         options->forward_agent = -1;
1843         options->forward_x11 = -1;
1844         options->forward_x11_trusted = -1;
1845         options->forward_x11_timeout = -1;
1846         options->stdio_forward_host = NULL;
1847         options->stdio_forward_port = 0;
1848         options->clear_forwardings = -1;
1849         options->exit_on_forward_failure = -1;
1850         options->xauth_location = NULL;
1851         options->fwd_opts.gateway_ports = -1;
1852         options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
1853         options->fwd_opts.streamlocal_bind_unlink = -1;
1854         options->pubkey_authentication = -1;
1855         options->challenge_response_authentication = -1;
1856         options->gss_authentication = -1;
1857         options->gss_deleg_creds = -1;
1858         options->password_authentication = -1;
1859         options->kbd_interactive_authentication = -1;
1860         options->kbd_interactive_devices = NULL;
1861         options->hostbased_authentication = -1;
1862         options->batch_mode = -1;
1863         options->check_host_ip = -1;
1864         options->strict_host_key_checking = -1;
1865         options->compression = -1;
1866         options->tcp_keep_alive = -1;
1867         options->port = -1;
1868         options->address_family = -1;
1869         options->connection_attempts = -1;
1870         options->connection_timeout = -1;
1871         options->number_of_password_prompts = -1;
1872         options->ciphers = NULL;
1873         options->macs = NULL;
1874         options->kex_algorithms = NULL;
1875         options->hostkeyalgorithms = NULL;
1876         options->ca_sign_algorithms = NULL;
1877         options->num_identity_files = 0;
1878         options->num_certificate_files = 0;
1879         options->hostname = NULL;
1880         options->host_key_alias = NULL;
1881         options->proxy_command = NULL;
1882         options->jump_user = NULL;
1883         options->jump_host = NULL;
1884         options->jump_port = -1;
1885         options->jump_extra = NULL;
1886         options->user = NULL;
1887         options->escape_char = -1;
1888         options->num_system_hostfiles = 0;
1889         options->num_user_hostfiles = 0;
1890         options->local_forwards = NULL;
1891         options->num_local_forwards = 0;
1892         options->remote_forwards = NULL;
1893         options->num_remote_forwards = 0;
1894         options->log_facility = SYSLOG_FACILITY_NOT_SET;
1895         options->log_level = SYSLOG_LEVEL_NOT_SET;
1896         options->preferred_authentications = NULL;
1897         options->bind_address = NULL;
1898         options->bind_interface = NULL;
1899         options->pkcs11_provider = NULL;
1900         options->enable_ssh_keysign = - 1;
1901         options->no_host_authentication_for_localhost = - 1;
1902         options->identities_only = - 1;
1903         options->rekey_limit = - 1;
1904         options->rekey_interval = -1;
1905         options->verify_host_key_dns = -1;
1906         options->server_alive_interval = -1;
1907         options->server_alive_count_max = -1;
1908         options->send_env = NULL;
1909         options->num_send_env = 0;
1910         options->setenv = NULL;
1911         options->num_setenv = 0;
1912         options->control_path = NULL;
1913         options->control_master = -1;
1914         options->control_persist = -1;
1915         options->control_persist_timeout = 0;
1916         options->hash_known_hosts = -1;
1917         options->tun_open = -1;
1918         options->tun_local = -1;
1919         options->tun_remote = -1;
1920         options->local_command = NULL;
1921         options->permit_local_command = -1;
1922         options->remote_command = NULL;
1923         options->add_keys_to_agent = -1;
1924         options->identity_agent = NULL;
1925         options->visual_host_key = -1;
1926         options->ip_qos_interactive = -1;
1927         options->ip_qos_bulk = -1;
1928         options->request_tty = -1;
1929         options->proxy_use_fdpass = -1;
1930         options->ignored_unknown = NULL;
1931         options->num_canonical_domains = 0;
1932         options->num_permitted_cnames = 0;
1933         options->canonicalize_max_dots = -1;
1934         options->canonicalize_fallback_local = -1;
1935         options->canonicalize_hostname = -1;
1936         options->revoked_host_keys = NULL;
1937         options->fingerprint_hash = -1;
1938         options->update_hostkeys = -1;
1939         options->hostbased_key_types = NULL;
1940         options->pubkey_key_types = NULL;
1941 }
1942
1943 /*
1944  * A petite version of fill_default_options() that just fills the options
1945  * needed for hostname canonicalization to proceed.
1946  */
1947 void
1948 fill_default_options_for_canonicalization(Options *options)
1949 {
1950         if (options->canonicalize_max_dots == -1)
1951                 options->canonicalize_max_dots = 1;
1952         if (options->canonicalize_fallback_local == -1)
1953                 options->canonicalize_fallback_local = 1;
1954         if (options->canonicalize_hostname == -1)
1955                 options->canonicalize_hostname = SSH_CANONICALISE_NO;
1956 }
1957
1958 /*
1959  * Called after processing other sources of option data, this fills those
1960  * options for which no value has been specified with their default values.
1961  */
1962 void
1963 fill_default_options(Options * options)
1964 {
1965         char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
1966         int r;
1967
1968         if (options->forward_agent == -1)
1969                 options->forward_agent = 0;
1970         if (options->forward_x11 == -1)
1971                 options->forward_x11 = 0;
1972         if (options->forward_x11_trusted == -1)
1973                 options->forward_x11_trusted = 0;
1974         if (options->forward_x11_timeout == -1)
1975                 options->forward_x11_timeout = 1200;
1976         /*
1977          * stdio forwarding (-W) changes the default for these but we defer
1978          * setting the values so they can be overridden.
1979          */
1980         if (options->exit_on_forward_failure == -1)
1981                 options->exit_on_forward_failure =
1982                     options->stdio_forward_host != NULL ? 1 : 0;
1983         if (options->clear_forwardings == -1)
1984                 options->clear_forwardings =
1985                     options->stdio_forward_host != NULL ? 1 : 0;
1986         if (options->clear_forwardings == 1)
1987                 clear_forwardings(options);
1988
1989         if (options->xauth_location == NULL)
1990                 options->xauth_location = _PATH_XAUTH;
1991         if (options->fwd_opts.gateway_ports == -1)
1992                 options->fwd_opts.gateway_ports = 0;
1993         if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
1994                 options->fwd_opts.streamlocal_bind_mask = 0177;
1995         if (options->fwd_opts.streamlocal_bind_unlink == -1)
1996                 options->fwd_opts.streamlocal_bind_unlink = 0;
1997         if (options->pubkey_authentication == -1)
1998                 options->pubkey_authentication = 1;
1999         if (options->challenge_response_authentication == -1)
2000                 options->challenge_response_authentication = 1;
2001         if (options->gss_authentication == -1)
2002                 options->gss_authentication = 0;
2003         if (options->gss_deleg_creds == -1)
2004                 options->gss_deleg_creds = 0;
2005         if (options->password_authentication == -1)
2006                 options->password_authentication = 1;
2007         if (options->kbd_interactive_authentication == -1)
2008                 options->kbd_interactive_authentication = 1;
2009         if (options->hostbased_authentication == -1)
2010                 options->hostbased_authentication = 0;
2011         if (options->batch_mode == -1)
2012                 options->batch_mode = 0;
2013         if (options->check_host_ip == -1)
2014                 options->check_host_ip = 1;
2015         if (options->strict_host_key_checking == -1)
2016                 options->strict_host_key_checking = SSH_STRICT_HOSTKEY_ASK;
2017         if (options->compression == -1)
2018                 options->compression = 0;
2019         if (options->tcp_keep_alive == -1)
2020                 options->tcp_keep_alive = 1;
2021         if (options->port == -1)
2022                 options->port = 0;      /* Filled in ssh_connect. */
2023         if (options->address_family == -1)
2024                 options->address_family = AF_UNSPEC;
2025         if (options->connection_attempts == -1)
2026                 options->connection_attempts = 1;
2027         if (options->number_of_password_prompts == -1)
2028                 options->number_of_password_prompts = 3;
2029         /* options->hostkeyalgorithms, default set in myproposals.h */
2030         if (options->add_keys_to_agent == -1)
2031                 options->add_keys_to_agent = 0;
2032         if (options->num_identity_files == 0) {
2033                 add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_RSA, 0);
2034                 add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0);
2035 #ifdef OPENSSL_HAS_ECC
2036                 add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0);
2037 #endif
2038                 add_identity_file(options, "~/",
2039                     _PATH_SSH_CLIENT_ID_ED25519, 0);
2040                 add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_XMSS, 0);
2041         }
2042         if (options->escape_char == -1)
2043                 options->escape_char = '~';
2044         if (options->num_system_hostfiles == 0) {
2045                 options->system_hostfiles[options->num_system_hostfiles++] =
2046                     xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
2047                 options->system_hostfiles[options->num_system_hostfiles++] =
2048                     xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
2049         }
2050         if (options->num_user_hostfiles == 0) {
2051                 options->user_hostfiles[options->num_user_hostfiles++] =
2052                     xstrdup(_PATH_SSH_USER_HOSTFILE);
2053                 options->user_hostfiles[options->num_user_hostfiles++] =
2054                     xstrdup(_PATH_SSH_USER_HOSTFILE2);
2055         }
2056         if (options->log_level == SYSLOG_LEVEL_NOT_SET)
2057                 options->log_level = SYSLOG_LEVEL_INFO;
2058         if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
2059                 options->log_facility = SYSLOG_FACILITY_USER;
2060         if (options->no_host_authentication_for_localhost == - 1)
2061                 options->no_host_authentication_for_localhost = 0;
2062         if (options->identities_only == -1)
2063                 options->identities_only = 0;
2064         if (options->enable_ssh_keysign == -1)
2065                 options->enable_ssh_keysign = 0;
2066         if (options->rekey_limit == -1)
2067                 options->rekey_limit = 0;
2068         if (options->rekey_interval == -1)
2069                 options->rekey_interval = 0;
2070         if (options->verify_host_key_dns == -1)
2071                 options->verify_host_key_dns = 0;
2072         if (options->server_alive_interval == -1)
2073                 options->server_alive_interval = 0;
2074         if (options->server_alive_count_max == -1)
2075                 options->server_alive_count_max = 3;
2076         if (options->control_master == -1)
2077                 options->control_master = 0;
2078         if (options->control_persist == -1) {
2079                 options->control_persist = 0;
2080                 options->control_persist_timeout = 0;
2081         }
2082         if (options->hash_known_hosts == -1)
2083                 options->hash_known_hosts = 0;
2084         if (options->tun_open == -1)
2085                 options->tun_open = SSH_TUNMODE_NO;
2086         if (options->tun_local == -1)
2087                 options->tun_local = SSH_TUNID_ANY;
2088         if (options->tun_remote == -1)
2089                 options->tun_remote = SSH_TUNID_ANY;
2090         if (options->permit_local_command == -1)
2091                 options->permit_local_command = 0;
2092         if (options->visual_host_key == -1)
2093                 options->visual_host_key = 0;
2094         if (options->ip_qos_interactive == -1)
2095                 options->ip_qos_interactive = IPTOS_DSCP_AF21;
2096         if (options->ip_qos_bulk == -1)
2097                 options->ip_qos_bulk = IPTOS_DSCP_CS1;
2098         if (options->request_tty == -1)
2099                 options->request_tty = REQUEST_TTY_AUTO;
2100         if (options->proxy_use_fdpass == -1)
2101                 options->proxy_use_fdpass = 0;
2102         if (options->canonicalize_max_dots == -1)
2103                 options->canonicalize_max_dots = 1;
2104         if (options->canonicalize_fallback_local == -1)
2105                 options->canonicalize_fallback_local = 1;
2106         if (options->canonicalize_hostname == -1)
2107                 options->canonicalize_hostname = SSH_CANONICALISE_NO;
2108         if (options->fingerprint_hash == -1)
2109                 options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
2110         if (options->update_hostkeys == -1)
2111                 options->update_hostkeys = 0;
2112
2113         /* Expand KEX name lists */
2114         all_cipher = cipher_alg_list(',', 0);
2115         all_mac = mac_alg_list(',');
2116         all_kex = kex_alg_list(',');
2117         all_key = sshkey_alg_list(0, 0, 1, ',');
2118         all_sig = sshkey_alg_list(0, 1, 1, ',');
2119 #define ASSEMBLE(what, defaults, all) \
2120         do { \
2121                 if ((r = kex_assemble_names(&options->what, \
2122                     defaults, all)) != 0) \
2123                         fatal("%s: %s: %s", __func__, #what, ssh_err(r)); \
2124         } while (0)
2125         ASSEMBLE(ciphers, KEX_CLIENT_ENCRYPT, all_cipher);
2126         ASSEMBLE(macs, KEX_CLIENT_MAC, all_mac);
2127         ASSEMBLE(kex_algorithms, KEX_CLIENT_KEX, all_kex);
2128         ASSEMBLE(hostbased_key_types, KEX_DEFAULT_PK_ALG, all_key);
2129         ASSEMBLE(pubkey_key_types, KEX_DEFAULT_PK_ALG, all_key);
2130         ASSEMBLE(ca_sign_algorithms, SSH_ALLOWED_CA_SIGALGS, all_sig);
2131 #undef ASSEMBLE
2132         free(all_cipher);
2133         free(all_mac);
2134         free(all_kex);
2135         free(all_key);
2136         free(all_sig);
2137
2138 #define CLEAR_ON_NONE(v) \
2139         do { \
2140                 if (option_clear_or_none(v)) { \
2141                         free(v); \
2142                         v = NULL; \
2143                 } \
2144         } while(0)
2145         CLEAR_ON_NONE(options->local_command);
2146         CLEAR_ON_NONE(options->remote_command);
2147         CLEAR_ON_NONE(options->proxy_command);
2148         CLEAR_ON_NONE(options->control_path);
2149         CLEAR_ON_NONE(options->revoked_host_keys);
2150         CLEAR_ON_NONE(options->pkcs11_provider);
2151         if (options->jump_host != NULL &&
2152             strcmp(options->jump_host, "none") == 0 &&
2153             options->jump_port == 0 && options->jump_user == NULL) {
2154                 free(options->jump_host);
2155                 options->jump_host = NULL;
2156         }
2157         /* options->identity_agent distinguishes NULL from 'none' */
2158         /* options->user will be set in the main program if appropriate */
2159         /* options->hostname will be set in the main program if appropriate */
2160         /* options->host_key_alias should not be set by default */
2161         /* options->preferred_authentications will be set in ssh */
2162 }
2163
2164 struct fwdarg {
2165         char *arg;
2166         int ispath;
2167 };
2168
2169 /*
2170  * parse_fwd_field
2171  * parses the next field in a port forwarding specification.
2172  * sets fwd to the parsed field and advances p past the colon
2173  * or sets it to NULL at end of string.
2174  * returns 0 on success, else non-zero.
2175  */
2176 static int
2177 parse_fwd_field(char **p, struct fwdarg *fwd)
2178 {
2179         char *ep, *cp = *p;
2180         int ispath = 0;
2181
2182         if (*cp == '\0') {
2183                 *p = NULL;
2184                 return -1;      /* end of string */
2185         }
2186
2187         /*
2188          * A field escaped with square brackets is used literally.
2189          * XXX - allow ']' to be escaped via backslash?
2190          */
2191         if (*cp == '[') {
2192                 /* find matching ']' */
2193                 for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
2194                         if (*ep == '/')
2195                                 ispath = 1;
2196                 }
2197                 /* no matching ']' or not at end of field. */
2198                 if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
2199                         return -1;
2200                 /* NUL terminate the field and advance p past the colon */
2201                 *ep++ = '\0';
2202                 if (*ep != '\0')
2203                         *ep++ = '\0';
2204                 fwd->arg = cp + 1;
2205                 fwd->ispath = ispath;
2206                 *p = ep;
2207                 return 0;
2208         }
2209
2210         for (cp = *p; *cp != '\0'; cp++) {
2211                 switch (*cp) {
2212                 case '\\':
2213                         memmove(cp, cp + 1, strlen(cp + 1) + 1);
2214                         if (*cp == '\0')
2215                                 return -1;
2216                         break;
2217                 case '/':
2218                         ispath = 1;
2219                         break;
2220                 case ':':
2221                         *cp++ = '\0';
2222                         goto done;
2223                 }
2224         }
2225 done:
2226         fwd->arg = *p;
2227         fwd->ispath = ispath;
2228         *p = cp;
2229         return 0;
2230 }
2231
2232 /*
2233  * parse_forward
2234  * parses a string containing a port forwarding specification of the form:
2235  *   dynamicfwd == 0
2236  *      [listenhost:]listenport|listenpath:connecthost:connectport|connectpath
2237  *      listenpath:connectpath
2238  *   dynamicfwd == 1
2239  *      [listenhost:]listenport
2240  * returns number of arguments parsed or zero on error
2241  */
2242 int
2243 parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
2244 {
2245         struct fwdarg fwdargs[4];
2246         char *p, *cp;
2247         int i;
2248
2249         memset(fwd, 0, sizeof(*fwd));
2250         memset(fwdargs, 0, sizeof(fwdargs));
2251
2252         cp = p = xstrdup(fwdspec);
2253
2254         /* skip leading spaces */
2255         while (isspace((u_char)*cp))
2256                 cp++;
2257
2258         for (i = 0; i < 4; ++i) {
2259                 if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
2260                         break;
2261         }
2262
2263         /* Check for trailing garbage */
2264         if (cp != NULL && *cp != '\0') {
2265                 i = 0;  /* failure */
2266         }
2267
2268         switch (i) {
2269         case 1:
2270                 if (fwdargs[0].ispath) {
2271                         fwd->listen_path = xstrdup(fwdargs[0].arg);
2272                         fwd->listen_port = PORT_STREAMLOCAL;
2273                 } else {
2274                         fwd->listen_host = NULL;
2275                         fwd->listen_port = a2port(fwdargs[0].arg);
2276                 }
2277                 fwd->connect_host = xstrdup("socks");
2278                 break;
2279
2280         case 2:
2281                 if (fwdargs[0].ispath && fwdargs[1].ispath) {
2282                         fwd->listen_path = xstrdup(fwdargs[0].arg);
2283                         fwd->listen_port = PORT_STREAMLOCAL;
2284                         fwd->connect_path = xstrdup(fwdargs[1].arg);
2285                         fwd->connect_port = PORT_STREAMLOCAL;
2286                 } else if (fwdargs[1].ispath) {
2287                         fwd->listen_host = NULL;
2288                         fwd->listen_port = a2port(fwdargs[0].arg);
2289                         fwd->connect_path = xstrdup(fwdargs[1].arg);
2290                         fwd->connect_port = PORT_STREAMLOCAL;
2291                 } else {
2292                         fwd->listen_host = xstrdup(fwdargs[0].arg);
2293                         fwd->listen_port = a2port(fwdargs[1].arg);
2294                         fwd->connect_host = xstrdup("socks");
2295                 }
2296                 break;
2297
2298         case 3:
2299                 if (fwdargs[0].ispath) {
2300                         fwd->listen_path = xstrdup(fwdargs[0].arg);
2301                         fwd->listen_port = PORT_STREAMLOCAL;
2302                         fwd->connect_host = xstrdup(fwdargs[1].arg);
2303                         fwd->connect_port = a2port(fwdargs[2].arg);
2304                 } else if (fwdargs[2].ispath) {
2305                         fwd->listen_host = xstrdup(fwdargs[0].arg);
2306                         fwd->listen_port = a2port(fwdargs[1].arg);
2307                         fwd->connect_path = xstrdup(fwdargs[2].arg);
2308                         fwd->connect_port = PORT_STREAMLOCAL;
2309                 } else {
2310                         fwd->listen_host = NULL;
2311                         fwd->listen_port = a2port(fwdargs[0].arg);
2312                         fwd->connect_host = xstrdup(fwdargs[1].arg);
2313                         fwd->connect_port = a2port(fwdargs[2].arg);
2314                 }
2315                 break;
2316
2317         case 4:
2318                 fwd->listen_host = xstrdup(fwdargs[0].arg);
2319                 fwd->listen_port = a2port(fwdargs[1].arg);
2320                 fwd->connect_host = xstrdup(fwdargs[2].arg);
2321                 fwd->connect_port = a2port(fwdargs[3].arg);
2322                 break;
2323         default:
2324                 i = 0; /* failure */
2325         }
2326
2327         free(p);
2328
2329         if (dynamicfwd) {
2330                 if (!(i == 1 || i == 2))
2331                         goto fail_free;
2332         } else {
2333                 if (!(i == 3 || i == 4)) {
2334                         if (fwd->connect_path == NULL &&
2335                             fwd->listen_path == NULL)
2336                                 goto fail_free;
2337                 }
2338                 if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
2339                         goto fail_free;
2340         }
2341
2342         if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
2343             (!remotefwd && fwd->listen_port == 0))
2344                 goto fail_free;
2345         if (fwd->connect_host != NULL &&
2346             strlen(fwd->connect_host) >= NI_MAXHOST)
2347                 goto fail_free;
2348         /* XXX - if connecting to a remote socket, max sun len may not match this host */
2349         if (fwd->connect_path != NULL &&
2350             strlen(fwd->connect_path) >= PATH_MAX_SUN)
2351                 goto fail_free;
2352         if (fwd->listen_host != NULL &&
2353             strlen(fwd->listen_host) >= NI_MAXHOST)
2354                 goto fail_free;
2355         if (fwd->listen_path != NULL &&
2356             strlen(fwd->listen_path) >= PATH_MAX_SUN)
2357                 goto fail_free;
2358
2359         return (i);
2360
2361  fail_free:
2362         free(fwd->connect_host);
2363         fwd->connect_host = NULL;
2364         free(fwd->connect_path);
2365         fwd->connect_path = NULL;
2366         free(fwd->listen_host);
2367         fwd->listen_host = NULL;
2368         free(fwd->listen_path);
2369         fwd->listen_path = NULL;
2370         return (0);
2371 }
2372
2373 int
2374 parse_jump(const char *s, Options *o, int active)
2375 {
2376         char *orig, *sdup, *cp;
2377         char *host = NULL, *user = NULL;
2378         int ret = -1, port = -1, first;
2379
2380         active &= o->proxy_command == NULL && o->jump_host == NULL;
2381
2382         orig = sdup = xstrdup(s);
2383         first = active;
2384         do {
2385                 if (strcasecmp(s, "none") == 0)
2386                         break;
2387                 if ((cp = strrchr(sdup, ',')) == NULL)
2388                         cp = sdup; /* last */
2389                 else
2390                         *cp++ = '\0';
2391
2392                 if (first) {
2393                         /* First argument and configuration is active */
2394                         if (parse_ssh_uri(cp, &user, &host, &port) == -1 ||
2395                             parse_user_host_port(cp, &user, &host, &port) != 0)
2396                                 goto out;
2397                 } else {
2398                         /* Subsequent argument or inactive configuration */
2399                         if (parse_ssh_uri(cp, NULL, NULL, NULL) == -1 ||
2400                             parse_user_host_port(cp, NULL, NULL, NULL) != 0)
2401                                 goto out;
2402                 }
2403                 first = 0; /* only check syntax for subsequent hosts */
2404         } while (cp != sdup);
2405         /* success */
2406         if (active) {
2407                 if (strcasecmp(s, "none") == 0) {
2408                         o->jump_host = xstrdup("none");
2409                         o->jump_port = 0;
2410                 } else {
2411                         o->jump_user = user;
2412                         o->jump_host = host;
2413                         o->jump_port = port;
2414                         o->proxy_command = xstrdup("none");
2415                         user = host = NULL;
2416                         if ((cp = strrchr(s, ',')) != NULL && cp != s) {
2417                                 o->jump_extra = xstrdup(s);
2418                                 o->jump_extra[cp - s] = '\0';
2419                         }
2420                 }
2421         }
2422         ret = 0;
2423  out:
2424         free(orig);
2425         free(user);
2426         free(host);
2427         return ret;
2428 }
2429
2430 int
2431 parse_ssh_uri(const char *uri, char **userp, char **hostp, int *portp)
2432 {
2433         char *path;
2434         int r;
2435
2436         r = parse_uri("ssh", uri, userp, hostp, portp, &path);
2437         if (r == 0 && path != NULL)
2438                 r = -1;         /* path not allowed */
2439         return r;
2440 }
2441
2442 /* XXX the following is a near-vebatim copy from servconf.c; refactor */
2443 static const char *
2444 fmt_multistate_int(int val, const struct multistate *m)
2445 {
2446         u_int i;
2447
2448         for (i = 0; m[i].key != NULL; i++) {
2449                 if (m[i].value == val)
2450                         return m[i].key;
2451         }
2452         return "UNKNOWN";
2453 }
2454
2455 static const char *
2456 fmt_intarg(OpCodes code, int val)
2457 {
2458         if (val == -1)
2459                 return "unset";
2460         switch (code) {
2461         case oAddressFamily:
2462                 return fmt_multistate_int(val, multistate_addressfamily);
2463         case oVerifyHostKeyDNS:
2464         case oUpdateHostkeys:
2465                 return fmt_multistate_int(val, multistate_yesnoask);
2466         case oStrictHostKeyChecking:
2467                 return fmt_multistate_int(val, multistate_strict_hostkey);
2468         case oControlMaster:
2469                 return fmt_multistate_int(val, multistate_controlmaster);
2470         case oTunnel:
2471                 return fmt_multistate_int(val, multistate_tunnel);
2472         case oRequestTTY:
2473                 return fmt_multistate_int(val, multistate_requesttty);
2474         case oCanonicalizeHostname:
2475                 return fmt_multistate_int(val, multistate_canonicalizehostname);
2476         case oAddKeysToAgent:
2477                 return fmt_multistate_int(val, multistate_yesnoaskconfirm);
2478         case oFingerprintHash:
2479                 return ssh_digest_alg_name(val);
2480         default:
2481                 switch (val) {
2482                 case 0:
2483                         return "no";
2484                 case 1:
2485                         return "yes";
2486                 default:
2487                         return "UNKNOWN";
2488                 }
2489         }
2490 }
2491
2492 static const char *
2493 lookup_opcode_name(OpCodes code)
2494 {
2495         u_int i;
2496
2497         for (i = 0; keywords[i].name != NULL; i++)
2498                 if (keywords[i].opcode == code)
2499                         return(keywords[i].name);
2500         return "UNKNOWN";
2501 }
2502
2503 static void
2504 dump_cfg_int(OpCodes code, int val)
2505 {
2506         printf("%s %d\n", lookup_opcode_name(code), val);
2507 }
2508
2509 static void
2510 dump_cfg_fmtint(OpCodes code, int val)
2511 {
2512         printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
2513 }
2514
2515 static void
2516 dump_cfg_string(OpCodes code, const char *val)
2517 {
2518         if (val == NULL)
2519                 return;
2520         printf("%s %s\n", lookup_opcode_name(code), val);
2521 }
2522
2523 static void
2524 dump_cfg_strarray(OpCodes code, u_int count, char **vals)
2525 {
2526         u_int i;
2527
2528         for (i = 0; i < count; i++)
2529                 printf("%s %s\n", lookup_opcode_name(code), vals[i]);
2530 }
2531
2532 static void
2533 dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
2534 {
2535         u_int i;
2536
2537         printf("%s", lookup_opcode_name(code));
2538         for (i = 0; i < count; i++)
2539                 printf(" %s",  vals[i]);
2540         printf("\n");
2541 }
2542
2543 static void
2544 dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
2545 {
2546         const struct Forward *fwd;
2547         u_int i;
2548
2549         /* oDynamicForward */
2550         for (i = 0; i < count; i++) {
2551                 fwd = &fwds[i];
2552                 if (code == oDynamicForward && fwd->connect_host != NULL &&
2553                     strcmp(fwd->connect_host, "socks") != 0)
2554                         continue;
2555                 if (code == oLocalForward && fwd->connect_host != NULL &&
2556                     strcmp(fwd->connect_host, "socks") == 0)
2557                         continue;
2558                 printf("%s", lookup_opcode_name(code));
2559                 if (fwd->listen_port == PORT_STREAMLOCAL)
2560                         printf(" %s", fwd->listen_path);
2561                 else if (fwd->listen_host == NULL)
2562                         printf(" %d", fwd->listen_port);
2563                 else {
2564                         printf(" [%s]:%d",
2565                             fwd->listen_host, fwd->listen_port);
2566                 }
2567                 if (code != oDynamicForward) {
2568                         if (fwd->connect_port == PORT_STREAMLOCAL)
2569                                 printf(" %s", fwd->connect_path);
2570                         else if (fwd->connect_host == NULL)
2571                                 printf(" %d", fwd->connect_port);
2572                         else {
2573                                 printf(" [%s]:%d",
2574                                     fwd->connect_host, fwd->connect_port);
2575                         }
2576                 }
2577                 printf("\n");
2578         }
2579 }
2580
2581 void
2582 dump_client_config(Options *o, const char *host)
2583 {
2584         int i;
2585         char buf[8], *all_key;
2586
2587         /* This is normally prepared in ssh_kex2 */
2588         all_key = sshkey_alg_list(0, 0, 1, ',');
2589         if (kex_assemble_names( &o->hostkeyalgorithms,
2590             KEX_DEFAULT_PK_ALG, all_key) != 0)
2591                 fatal("%s: kex_assemble_names failed", __func__);
2592         free(all_key);
2593
2594         /* Most interesting options first: user, host, port */
2595         dump_cfg_string(oUser, o->user);
2596         dump_cfg_string(oHostName, host);
2597         dump_cfg_int(oPort, o->port);
2598
2599         /* Flag options */
2600         dump_cfg_fmtint(oAddKeysToAgent, o->add_keys_to_agent);
2601         dump_cfg_fmtint(oAddressFamily, o->address_family);
2602         dump_cfg_fmtint(oBatchMode, o->batch_mode);
2603         dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local);
2604         dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname);
2605         dump_cfg_fmtint(oChallengeResponseAuthentication, o->challenge_response_authentication);
2606         dump_cfg_fmtint(oCheckHostIP, o->check_host_ip);
2607         dump_cfg_fmtint(oCompression, o->compression);
2608         dump_cfg_fmtint(oControlMaster, o->control_master);
2609         dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
2610         dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings);
2611         dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
2612         dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
2613         dump_cfg_fmtint(oForwardAgent, o->forward_agent);
2614         dump_cfg_fmtint(oForwardX11, o->forward_x11);
2615         dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
2616         dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
2617 #ifdef GSSAPI
2618         dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
2619         dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
2620 #endif /* GSSAPI */
2621         dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
2622         dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
2623         dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
2624         dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication);
2625         dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost);
2626         dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication);
2627         dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command);
2628         dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
2629         dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
2630         dump_cfg_fmtint(oRequestTTY, o->request_tty);
2631         dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
2632         dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking);
2633         dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive);
2634         dump_cfg_fmtint(oTunnel, o->tun_open);
2635         dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns);
2636         dump_cfg_fmtint(oVisualHostKey, o->visual_host_key);
2637         dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys);
2638
2639         /* Integer options */
2640         dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots);
2641         dump_cfg_int(oConnectionAttempts, o->connection_attempts);
2642         dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout);
2643         dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
2644         dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
2645         dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
2646
2647         /* String options */
2648         dump_cfg_string(oBindAddress, o->bind_address);
2649         dump_cfg_string(oBindInterface, o->bind_interface);
2650         dump_cfg_string(oCiphers, o->ciphers ? o->ciphers : KEX_CLIENT_ENCRYPT);
2651         dump_cfg_string(oControlPath, o->control_path);
2652         dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms);
2653         dump_cfg_string(oHostKeyAlias, o->host_key_alias);
2654         dump_cfg_string(oHostbasedKeyTypes, o->hostbased_key_types);
2655         dump_cfg_string(oIdentityAgent, o->identity_agent);
2656         dump_cfg_string(oIgnoreUnknown, o->ignored_unknown);
2657         dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
2658         dump_cfg_string(oKexAlgorithms, o->kex_algorithms ? o->kex_algorithms : KEX_CLIENT_KEX);
2659         dump_cfg_string(oCASignatureAlgorithms, o->ca_sign_algorithms ? o->ca_sign_algorithms : SSH_ALLOWED_CA_SIGALGS);
2660         dump_cfg_string(oLocalCommand, o->local_command);
2661         dump_cfg_string(oRemoteCommand, o->remote_command);
2662         dump_cfg_string(oLogLevel, log_level_name(o->log_level));
2663         dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC);
2664 #ifdef ENABLE_PKCS11
2665         dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
2666 #endif
2667         dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
2668         dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types);
2669         dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
2670         dump_cfg_string(oXAuthLocation, o->xauth_location);
2671
2672         /* Forwards */
2673         dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards);
2674         dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards);
2675         dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards);
2676
2677         /* String array options */
2678         dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files);
2679         dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains);
2680         dump_cfg_strarray(oCertificateFile, o->num_certificate_files, o->certificate_files);
2681         dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles);
2682         dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
2683         dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
2684         dump_cfg_strarray(oSetEnv, o->num_setenv, o->setenv);
2685
2686         /* Special cases */
2687
2688         /* oConnectTimeout */
2689         if (o->connection_timeout == -1)
2690                 printf("connecttimeout none\n");
2691         else
2692                 dump_cfg_int(oConnectTimeout, o->connection_timeout);
2693
2694         /* oTunnelDevice */
2695         printf("tunneldevice");
2696         if (o->tun_local == SSH_TUNID_ANY)
2697                 printf(" any");
2698         else
2699                 printf(" %d", o->tun_local);
2700         if (o->tun_remote == SSH_TUNID_ANY)
2701                 printf(":any");
2702         else
2703                 printf(":%d", o->tun_remote);
2704         printf("\n");
2705
2706         /* oCanonicalizePermittedCNAMEs */
2707         if ( o->num_permitted_cnames > 0) {
2708                 printf("canonicalizePermittedcnames");
2709                 for (i = 0; i < o->num_permitted_cnames; i++) {
2710                         printf(" %s:%s", o->permitted_cnames[i].source_list,
2711                             o->permitted_cnames[i].target_list);
2712                 }
2713                 printf("\n");
2714         }
2715
2716         /* oControlPersist */
2717         if (o->control_persist == 0 || o->control_persist_timeout == 0)
2718                 dump_cfg_fmtint(oControlPersist, o->control_persist);
2719         else
2720                 dump_cfg_int(oControlPersist, o->control_persist_timeout);
2721
2722         /* oEscapeChar */
2723         if (o->escape_char == SSH_ESCAPECHAR_NONE)
2724                 printf("escapechar none\n");
2725         else {
2726                 vis(buf, o->escape_char, VIS_WHITE, 0);
2727                 printf("escapechar %s\n", buf);
2728         }
2729
2730         /* oIPQoS */
2731         printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
2732         printf("%s\n", iptos2str(o->ip_qos_bulk));
2733
2734         /* oRekeyLimit */
2735         printf("rekeylimit %llu %d\n",
2736             (unsigned long long)o->rekey_limit, o->rekey_interval);
2737
2738         /* oStreamLocalBindMask */
2739         printf("streamlocalbindmask 0%o\n",
2740             o->fwd_opts.streamlocal_bind_mask);
2741
2742         /* oLogFacility */
2743         printf("syslogfacility %s\n", log_facility_name(o->log_facility));
2744
2745         /* oProxyCommand / oProxyJump */
2746         if (o->jump_host == NULL)
2747                 dump_cfg_string(oProxyCommand, o->proxy_command);
2748         else {
2749                 /* Check for numeric addresses */
2750                 i = strchr(o->jump_host, ':') != NULL ||
2751                     strspn(o->jump_host, "1234567890.") == strlen(o->jump_host);
2752                 snprintf(buf, sizeof(buf), "%d", o->jump_port);
2753                 printf("proxyjump %s%s%s%s%s%s%s%s%s\n",
2754                     /* optional additional jump spec */
2755                     o->jump_extra == NULL ? "" : o->jump_extra,
2756                     o->jump_extra == NULL ? "" : ",",
2757                     /* optional user */
2758                     o->jump_user == NULL ? "" : o->jump_user,
2759                     o->jump_user == NULL ? "" : "@",
2760                     /* opening [ if hostname is numeric */
2761                     i ? "[" : "",
2762                     /* mandatory hostname */
2763                     o->jump_host,
2764                     /* closing ] if hostname is numeric */
2765                     i ? "]" : "",
2766                     /* optional port number */
2767                     o->jump_port <= 0 ? "" : ":",
2768                     o->jump_port <= 0 ? "" : buf);
2769         }
2770 }