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