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