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