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