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