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