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