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