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