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