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