]> andersk Git - gssapi-openssh.git/blame - openssh/readconf.c
Import of OpenSSH 4.9p1
[gssapi-openssh.git] / openssh / readconf.c
CommitLineData
47686178 1/* $OpenBSD: readconf.c,v 1.165 2008/01/19 23:09:49 djm Exp $ */
3c0ef626 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"
3c0ef626 16
9108f8d9 17#include <sys/types.h>
18#include <sys/stat.h>
19#include <sys/socket.h>
20
21#include <netinet/in.h>
22
23#include <ctype.h>
24#include <errno.h>
25#include <netdb.h>
26#include <signal.h>
27#include <stdarg.h>
28#include <stdio.h>
29#include <string.h>
30#include <unistd.h>
31
3c0ef626 32#include "xmalloc.h"
9108f8d9 33#include "ssh.h"
3c0ef626 34#include "compat.h"
35#include "cipher.h"
36#include "pathnames.h"
37#include "log.h"
9108f8d9 38#include "key.h"
3c0ef626 39#include "readconf.h"
40#include "match.h"
41#include "misc.h"
9108f8d9 42#include "buffer.h"
3c0ef626 43#include "kex.h"
44#include "mac.h"
45
46/* Format of the configuration file:
47
48 # Configuration data is parsed as follows:
49 # 1. command line options
50 # 2. user-specific file
51 # 3. system-wide file
52 # Any configuration value is only changed the first time it is set.
53 # Thus, host-specific definitions should be at the beginning of the
54 # configuration file, and defaults at the end.
55
56 # Host-specific declarations. These may override anything above. A single
57 # host may match multiple declarations; these are processed in the order
58 # that they are given in.
59
60 Host *.ngs.fi ngs.fi
f5799ae1 61 User foo
3c0ef626 62
63 Host fake.com
64 HostName another.host.name.real.org
65 User blaah
66 Port 34289
67 ForwardX11 no
68 ForwardAgent no
69
70 Host books.com
71 RemoteForward 9999 shadows.cs.hut.fi:9999
72 Cipher 3des
73
74 Host fascist.blob.com
75 Port 23123
76 User tylonen
3c0ef626 77 PasswordAuthentication no
78
79 Host puukko.hut.fi
80 User t35124p
81 ProxyCommand ssh-proxy %h %p
82
83 Host *.fr
f5799ae1 84 PublicKeyAuthentication no
3c0ef626 85
86 Host *.su
87 Cipher none
88 PasswordAuthentication no
89
2c06c99b 90 Host vpn.fake.com
91 Tunnel yes
92 TunnelDevice 3
93
3c0ef626 94 # Defaults for various options
95 Host *
96 ForwardAgent no
97 ForwardX11 no
3c0ef626 98 PasswordAuthentication yes
99 RSAAuthentication yes
100 RhostsRSAAuthentication yes
3c0ef626 101 StrictHostKeyChecking yes
cdd66111 102 TcpKeepAlive no
3c0ef626 103 IdentityFile ~/.ssh/identity
104 Port 22
105 EscapeChar ~
106
107*/
108
109/* Keyword tokens. */
110
111typedef enum {
112 oBadOption,
cdd66111 113 oForwardAgent, oForwardX11, oForwardX11Trusted, oGatewayPorts,
9108f8d9 114 oExitOnForwardFailure,
f5799ae1 115 oPasswordAuthentication, oRSAAuthentication,
3c0ef626 116 oChallengeResponseAuthentication, oXAuthLocation,
3c0ef626 117 oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
118 oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
119 oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
120 oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
cdd66111 121 oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
3c0ef626 122 oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
123 oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
124 oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
125 oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
126 oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
f5799ae1 127 oClearAllForwardings, oNoHostAuthenticationForLocalhost,
0fff78ff 128 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
129 oAddressFamily, oGssAuthentication, oGssDelegateCreds,
99be0775 130 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
996d5e62 131 oSendEnv, oControlPath, oControlMaster, oHashKnownHosts,
2c06c99b 132 oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
0fff78ff 133 oDeprecated, oUnsupported
3c0ef626 134} OpCodes;
135
136/* Textual representations of the tokens. */
137
138static struct {
139 const char *name;
140 OpCodes opcode;
141} keywords[] = {
142 { "forwardagent", oForwardAgent },
143 { "forwardx11", oForwardX11 },
cdd66111 144 { "forwardx11trusted", oForwardX11Trusted },
9108f8d9 145 { "exitonforwardfailure", oExitOnForwardFailure },
3c0ef626 146 { "xauthlocation", oXAuthLocation },
147 { "gatewayports", oGatewayPorts },
148 { "useprivilegedport", oUsePrivilegedPort },
0fff78ff 149 { "rhostsauthentication", oDeprecated },
3c0ef626 150 { "passwordauthentication", oPasswordAuthentication },
151 { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
152 { "kbdinteractivedevices", oKbdInteractiveDevices },
153 { "rsaauthentication", oRSAAuthentication },
154 { "pubkeyauthentication", oPubkeyAuthentication },
155 { "dsaauthentication", oPubkeyAuthentication }, /* alias */
156 { "rhostsrsaauthentication", oRhostsRSAAuthentication },
157 { "hostbasedauthentication", oHostbasedAuthentication },
158 { "challengeresponseauthentication", oChallengeResponseAuthentication },
159 { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
160 { "tisauthentication", oChallengeResponseAuthentication }, /* alias */
0fff78ff 161 { "kerberosauthentication", oUnsupported },
162 { "kerberostgtpassing", oUnsupported },
163 { "afstokenpassing", oUnsupported },
164#if defined(GSSAPI)
165 { "gssapiauthentication", oGssAuthentication },
166 { "gssapidelegatecredentials", oGssDelegateCreds },
167#else
168 { "gssapiauthentication", oUnsupported },
169 { "gssapidelegatecredentials", oUnsupported },
3c0ef626 170#endif
f5799ae1 171 { "fallbacktorsh", oDeprecated },
172 { "usersh", oDeprecated },
3c0ef626 173 { "identityfile", oIdentityFile },
174 { "identityfile2", oIdentityFile }, /* alias */
99be0775 175 { "identitiesonly", oIdentitiesOnly },
3c0ef626 176 { "hostname", oHostName },
177 { "hostkeyalias", oHostKeyAlias },
178 { "proxycommand", oProxyCommand },
179 { "port", oPort },
180 { "cipher", oCipher },
181 { "ciphers", oCiphers },
182 { "macs", oMacs },
183 { "protocol", oProtocol },
184 { "remoteforward", oRemoteForward },
185 { "localforward", oLocalForward },
186 { "user", oUser },
187 { "host", oHost },
188 { "escapechar", oEscapeChar },
189 { "globalknownhostsfile", oGlobalKnownHostsFile },
190 { "userknownhostsfile", oUserKnownHostsFile }, /* obsolete */
191 { "globalknownhostsfile2", oGlobalKnownHostsFile2 },
192 { "userknownhostsfile2", oUserKnownHostsFile2 }, /* obsolete */
193 { "connectionattempts", oConnectionAttempts },
194 { "batchmode", oBatchMode },
195 { "checkhostip", oCheckHostIP },
196 { "stricthostkeychecking", oStrictHostKeyChecking },
197 { "compression", oCompression },
198 { "compressionlevel", oCompressionLevel },
cdd66111 199 { "tcpkeepalive", oTCPKeepAlive },
200 { "keepalive", oTCPKeepAlive }, /* obsolete */
3c0ef626 201 { "numberofpasswordprompts", oNumberOfPasswordPrompts },
202 { "loglevel", oLogLevel },
203 { "dynamicforward", oDynamicForward },
204 { "preferredauthentications", oPreferredAuthentications },
205 { "hostkeyalgorithms", oHostKeyAlgorithms },
206 { "bindaddress", oBindAddress },
0fff78ff 207#ifdef SMARTCARD
3c0ef626 208 { "smartcarddevice", oSmartcardDevice },
0fff78ff 209#else
210 { "smartcarddevice", oUnsupported },
211#endif
e9a17296 212 { "clearallforwardings", oClearAllForwardings },
6a9b3198 213 { "enablesshkeysign", oEnableSSHKeysign },
0fff78ff 214 { "verifyhostkeydns", oVerifyHostKeyDNS },
e9a17296 215 { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
0fff78ff 216 { "rekeylimit", oRekeyLimit },
217 { "connecttimeout", oConnectTimeout },
218 { "addressfamily", oAddressFamily },
cdd66111 219 { "serveraliveinterval", oServerAliveInterval },
220 { "serveralivecountmax", oServerAliveCountMax },
c9f39d2c 221 { "sendenv", oSendEnv },
222 { "controlpath", oControlPath },
223 { "controlmaster", oControlMaster },
996d5e62 224 { "hashknownhosts", oHashKnownHosts },
2c06c99b 225 { "tunnel", oTunnel },
226 { "tunneldevice", oTunnelDevice },
227 { "localcommand", oLocalCommand },
228 { "permitlocalcommand", oPermitLocalCommand },
e9a17296 229 { NULL, oBadOption }
3c0ef626 230};
231
232/*
233 * Adds a local TCP/IP port forward to options. Never returns if there is an
234 * error.
235 */
236
237void
996d5e62 238add_local_forward(Options *options, const Forward *newfwd)
3c0ef626 239{
240 Forward *fwd;
41b2f314 241#ifndef NO_IPPORT_RESERVED_CONCEPT
3c0ef626 242 extern uid_t original_real_uid;
996d5e62 243 if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0)
3c0ef626 244 fatal("Privileged ports can only be forwarded by root.");
245#endif
246 if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
247 fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
248 fwd = &options->local_forwards[options->num_local_forwards++];
996d5e62 249
250 fwd->listen_host = (newfwd->listen_host == NULL) ?
251 NULL : xstrdup(newfwd->listen_host);
252 fwd->listen_port = newfwd->listen_port;
253 fwd->connect_host = xstrdup(newfwd->connect_host);
254 fwd->connect_port = newfwd->connect_port;
3c0ef626 255}
256
257/*
258 * Adds a remote TCP/IP port forward to options. Never returns if there is
259 * an error.
260 */
261
262void
996d5e62 263add_remote_forward(Options *options, const Forward *newfwd)
3c0ef626 264{
265 Forward *fwd;
266 if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
267 fatal("Too many remote forwards (max %d).",
e9a17296 268 SSH_MAX_FORWARDS_PER_DIRECTION);
3c0ef626 269 fwd = &options->remote_forwards[options->num_remote_forwards++];
996d5e62 270
271 fwd->listen_host = (newfwd->listen_host == NULL) ?
272 NULL : xstrdup(newfwd->listen_host);
273 fwd->listen_port = newfwd->listen_port;
274 fwd->connect_host = xstrdup(newfwd->connect_host);
275 fwd->connect_port = newfwd->connect_port;
3c0ef626 276}
277
278static void
279clear_forwardings(Options *options)
280{
281 int i;
282
996d5e62 283 for (i = 0; i < options->num_local_forwards; i++) {
dec6d9fe 284 if (options->local_forwards[i].listen_host != NULL)
285 xfree(options->local_forwards[i].listen_host);
996d5e62 286 xfree(options->local_forwards[i].connect_host);
287 }
3c0ef626 288 options->num_local_forwards = 0;
996d5e62 289 for (i = 0; i < options->num_remote_forwards; i++) {
dec6d9fe 290 if (options->remote_forwards[i].listen_host != NULL)
291 xfree(options->remote_forwards[i].listen_host);
996d5e62 292 xfree(options->remote_forwards[i].connect_host);
293 }
3c0ef626 294 options->num_remote_forwards = 0;
2c06c99b 295 options->tun_open = SSH_TUNMODE_NO;
3c0ef626 296}
297
298/*
299 * Returns the number of the token pointed to by cp or oBadOption.
300 */
301
302static OpCodes
303parse_token(const char *cp, const char *filename, int linenum)
304{
305 u_int i;
306
307 for (i = 0; keywords[i].name; i++)
308 if (strcasecmp(cp, keywords[i].name) == 0)
309 return keywords[i].opcode;
310
311 error("%s: line %d: Bad configuration option: %s",
312 filename, linenum, cp);
313 return oBadOption;
314}
315
316/*
317 * Processes a single option line as used in the configuration files. This
318 * only sets those values that have not already been set.
319 */
6a9b3198 320#define WHITESPACE " \t\r\n"
3c0ef626 321
322int
323process_config_line(Options *options, const char *host,
324 char *line, const char *filename, int linenum,
325 int *activep)
326{
996d5e62 327 char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256];
9108f8d9 328 int opcode, *intptr, value, value2, scale;
47686178 329 LogLevel *log_level_ptr;
9108f8d9 330 long long orig, val64;
6a9b3198 331 size_t len;
996d5e62 332 Forward fwd;
3c0ef626 333
0fff78ff 334 /* Strip trailing whitespace */
dec6d9fe 335 for (len = strlen(line) - 1; len > 0; len--) {
0fff78ff 336 if (strchr(WHITESPACE, line[len]) == NULL)
337 break;
338 line[len] = '\0';
339 }
340
3c0ef626 341 s = line;
342 /* Get the keyword. (Each line is supposed to begin with a keyword). */
9108f8d9 343 if ((keyword = strdelim(&s)) == NULL)
344 return 0;
3c0ef626 345 /* Ignore leading whitespace. */
346 if (*keyword == '\0')
347 keyword = strdelim(&s);
348 if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
349 return 0;
350
351 opcode = parse_token(keyword, filename, linenum);
352
353 switch (opcode) {
354 case oBadOption:
355 /* don't panic, but count bad options */
356 return -1;
357 /* NOTREACHED */
0fff78ff 358 case oConnectTimeout:
359 intptr = &options->connection_timeout;
cdd66111 360parse_time:
0fff78ff 361 arg = strdelim(&s);
362 if (!arg || *arg == '\0')
363 fatal("%s line %d: missing time value.",
364 filename, linenum);
365 if ((value = convtime(arg)) == -1)
366 fatal("%s line %d: invalid time value.",
367 filename, linenum);
799ae497 368 if (*activep && *intptr == -1)
0fff78ff 369 *intptr = value;
370 break;
371
3c0ef626 372 case oForwardAgent:
373 intptr = &options->forward_agent;
374parse_flag:
375 arg = strdelim(&s);
376 if (!arg || *arg == '\0')
377 fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
378 value = 0; /* To avoid compiler warning... */
379 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
380 value = 1;
381 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
382 value = 0;
383 else
384 fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
385 if (*activep && *intptr == -1)
386 *intptr = value;
387 break;
388
389 case oForwardX11:
390 intptr = &options->forward_x11;
391 goto parse_flag;
392
cdd66111 393 case oForwardX11Trusted:
394 intptr = &options->forward_x11_trusted;
395 goto parse_flag;
396
3c0ef626 397 case oGatewayPorts:
398 intptr = &options->gateway_ports;
399 goto parse_flag;
400
9108f8d9 401 case oExitOnForwardFailure:
402 intptr = &options->exit_on_forward_failure;
403 goto parse_flag;
404
3c0ef626 405 case oUsePrivilegedPort:
406 intptr = &options->use_privileged_port;
407 goto parse_flag;
408
3c0ef626 409 case oPasswordAuthentication:
410 intptr = &options->password_authentication;
411 goto parse_flag;
412
413 case oKbdInteractiveAuthentication:
414 intptr = &options->kbd_interactive_authentication;
415 goto parse_flag;
416
417 case oKbdInteractiveDevices:
418 charptr = &options->kbd_interactive_devices;
419 goto parse_string;
420
421 case oPubkeyAuthentication:
422 intptr = &options->pubkey_authentication;
423 goto parse_flag;
424
425 case oRSAAuthentication:
426 intptr = &options->rsa_authentication;
427 goto parse_flag;
428
429 case oRhostsRSAAuthentication:
430 intptr = &options->rhosts_rsa_authentication;
431 goto parse_flag;
432
433 case oHostbasedAuthentication:
434 intptr = &options->hostbased_authentication;
435 goto parse_flag;
436
437 case oChallengeResponseAuthentication:
438 intptr = &options->challenge_response_authentication;
439 goto parse_flag;
0fff78ff 440
441 case oGssAuthentication:
442 intptr = &options->gss_authentication;
3c0ef626 443 goto parse_flag;
0fff78ff 444
445 case oGssDelegateCreds:
446 intptr = &options->gss_deleg_creds;
3c0ef626 447 goto parse_flag;
0fff78ff 448
3c0ef626 449 case oBatchMode:
450 intptr = &options->batch_mode;
451 goto parse_flag;
452
453 case oCheckHostIP:
454 intptr = &options->check_host_ip;
455 goto parse_flag;
456
0fff78ff 457 case oVerifyHostKeyDNS:
458 intptr = &options->verify_host_key_dns;
cdd66111 459 goto parse_yesnoask;
0fff78ff 460
3c0ef626 461 case oStrictHostKeyChecking:
462 intptr = &options->strict_host_key_checking;
cdd66111 463parse_yesnoask:
3c0ef626 464 arg = strdelim(&s);
465 if (!arg || *arg == '\0')
466 fatal("%.200s line %d: Missing yes/no/ask argument.",
e9a17296 467 filename, linenum);
3c0ef626 468 value = 0; /* To avoid compiler warning... */
469 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
470 value = 1;
471 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
472 value = 0;
473 else if (strcmp(arg, "ask") == 0)
474 value = 2;
475 else
476 fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
477 if (*activep && *intptr == -1)
478 *intptr = value;
479 break;
480
481 case oCompression:
482 intptr = &options->compression;
483 goto parse_flag;
484
cdd66111 485 case oTCPKeepAlive:
486 intptr = &options->tcp_keep_alive;
3c0ef626 487 goto parse_flag;
488
489 case oNoHostAuthenticationForLocalhost:
490 intptr = &options->no_host_authentication_for_localhost;
491 goto parse_flag;
492
493 case oNumberOfPasswordPrompts:
494 intptr = &options->number_of_password_prompts;
495 goto parse_int;
496
497 case oCompressionLevel:
498 intptr = &options->compression_level;
499 goto parse_int;
500
0fff78ff 501 case oRekeyLimit:
0fff78ff 502 arg = strdelim(&s);
503 if (!arg || *arg == '\0')
504 fatal("%.200s line %d: Missing argument.", filename, linenum);
505 if (arg[0] < '0' || arg[0] > '9')
506 fatal("%.200s line %d: Bad number.", filename, linenum);
9108f8d9 507 orig = val64 = strtoll(arg, &endofnumber, 10);
0fff78ff 508 if (arg == endofnumber)
509 fatal("%.200s line %d: Bad number.", filename, linenum);
510 switch (toupper(*endofnumber)) {
9108f8d9 511 case '\0':
512 scale = 1;
513 break;
0fff78ff 514 case 'K':
9108f8d9 515 scale = 1<<10;
0fff78ff 516 break;
517 case 'M':
9108f8d9 518 scale = 1<<20;
0fff78ff 519 break;
520 case 'G':
9108f8d9 521 scale = 1<<30;
0fff78ff 522 break;
9108f8d9 523 default:
524 fatal("%.200s line %d: Invalid RekeyLimit suffix",
525 filename, linenum);
0fff78ff 526 }
9108f8d9 527 val64 *= scale;
528 /* detect integer wrap and too-large limits */
47686178 529 if ((val64 / scale) != orig || val64 > UINT_MAX)
9108f8d9 530 fatal("%.200s line %d: RekeyLimit too large",
531 filename, linenum);
532 if (val64 < 16)
533 fatal("%.200s line %d: RekeyLimit too small",
534 filename, linenum);
47686178 535 if (*activep && options->rekey_limit == -1)
536 options->rekey_limit = (u_int32_t)val64;
0fff78ff 537 break;
538
3c0ef626 539 case oIdentityFile:
540 arg = strdelim(&s);
541 if (!arg || *arg == '\0')
542 fatal("%.200s line %d: Missing argument.", filename, linenum);
543 if (*activep) {
544 intptr = &options->num_identity_files;
545 if (*intptr >= SSH_MAX_IDENTITY_FILES)
546 fatal("%.200s line %d: Too many identity files specified (max %d).",
e9a17296 547 filename, linenum, SSH_MAX_IDENTITY_FILES);
799ae497 548 charptr = &options->identity_files[*intptr];
3c0ef626 549 *charptr = xstrdup(arg);
550 *intptr = *intptr + 1;
551 }
552 break;
553
554 case oXAuthLocation:
555 charptr=&options->xauth_location;
556 goto parse_string;
557
558 case oUser:
559 charptr = &options->user;
560parse_string:
561 arg = strdelim(&s);
562 if (!arg || *arg == '\0')
563 fatal("%.200s line %d: Missing argument.", filename, linenum);
564 if (*activep && *charptr == NULL)
565 *charptr = xstrdup(arg);
566 break;
567
568 case oGlobalKnownHostsFile:
569 charptr = &options->system_hostfile;
570 goto parse_string;
571
572 case oUserKnownHostsFile:
573 charptr = &options->user_hostfile;
574 goto parse_string;
575
576 case oGlobalKnownHostsFile2:
577 charptr = &options->system_hostfile2;
578 goto parse_string;
579
580 case oUserKnownHostsFile2:
581 charptr = &options->user_hostfile2;
582 goto parse_string;
583
584 case oHostName:
585 charptr = &options->hostname;
586 goto parse_string;
587
588 case oHostKeyAlias:
589 charptr = &options->host_key_alias;
590 goto parse_string;
591
592 case oPreferredAuthentications:
593 charptr = &options->preferred_authentications;
594 goto parse_string;
595
596 case oBindAddress:
597 charptr = &options->bind_address;
598 goto parse_string;
599
600 case oSmartcardDevice:
601 charptr = &options->smartcard_device;
602 goto parse_string;
603
604 case oProxyCommand:
2c06c99b 605 charptr = &options->proxy_command;
606parse_command:
0fff78ff 607 if (s == NULL)
608 fatal("%.200s line %d: Missing argument.", filename, linenum);
6a9b3198 609 len = strspn(s, WHITESPACE "=");
3c0ef626 610 if (*activep && *charptr == NULL)
6a9b3198 611 *charptr = xstrdup(s + len);
3c0ef626 612 return 0;
613
614 case oPort:
615 intptr = &options->port;
616parse_int:
617 arg = strdelim(&s);
618 if (!arg || *arg == '\0')
619 fatal("%.200s line %d: Missing argument.", filename, linenum);
620 if (arg[0] < '0' || arg[0] > '9')
621 fatal("%.200s line %d: Bad number.", filename, linenum);
622
623 /* Octal, decimal, or hex format? */
624 value = strtol(arg, &endofnumber, 0);
625 if (arg == endofnumber)
626 fatal("%.200s line %d: Bad number.", filename, linenum);
627 if (*activep && *intptr == -1)
628 *intptr = value;
629 break;
630
631 case oConnectionAttempts:
632 intptr = &options->connection_attempts;
633 goto parse_int;
634
635 case oCipher:
636 intptr = &options->cipher;
637 arg = strdelim(&s);
638 if (!arg || *arg == '\0')
639 fatal("%.200s line %d: Missing argument.", filename, linenum);
640 value = cipher_number(arg);
641 if (value == -1)
642 fatal("%.200s line %d: Bad cipher '%s'.",
e9a17296 643 filename, linenum, arg ? arg : "<NONE>");
3c0ef626 644 if (*activep && *intptr == -1)
645 *intptr = value;
646 break;
647
648 case oCiphers:
649 arg = strdelim(&s);
650 if (!arg || *arg == '\0')
651 fatal("%.200s line %d: Missing argument.", filename, linenum);
652 if (!ciphers_valid(arg))
653 fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
e9a17296 654 filename, linenum, arg ? arg : "<NONE>");
3c0ef626 655 if (*activep && options->ciphers == NULL)
656 options->ciphers = xstrdup(arg);
657 break;
658
659 case oMacs:
660 arg = strdelim(&s);
661 if (!arg || *arg == '\0')
662 fatal("%.200s line %d: Missing argument.", filename, linenum);
663 if (!mac_valid(arg))
664 fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
e9a17296 665 filename, linenum, arg ? arg : "<NONE>");
3c0ef626 666 if (*activep && options->macs == NULL)
667 options->macs = xstrdup(arg);
668 break;
669
670 case oHostKeyAlgorithms:
671 arg = strdelim(&s);
672 if (!arg || *arg == '\0')
673 fatal("%.200s line %d: Missing argument.", filename, linenum);
674 if (!key_names_valid2(arg))
675 fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
e9a17296 676 filename, linenum, arg ? arg : "<NONE>");
3c0ef626 677 if (*activep && options->hostkeyalgorithms == NULL)
678 options->hostkeyalgorithms = xstrdup(arg);
679 break;
680
681 case oProtocol:
682 intptr = &options->protocol;
683 arg = strdelim(&s);
684 if (!arg || *arg == '\0')
685 fatal("%.200s line %d: Missing argument.", filename, linenum);
686 value = proto_spec(arg);
687 if (value == SSH_PROTO_UNKNOWN)
688 fatal("%.200s line %d: Bad protocol spec '%s'.",
e9a17296 689 filename, linenum, arg ? arg : "<NONE>");
3c0ef626 690 if (*activep && *intptr == SSH_PROTO_UNKNOWN)
691 *intptr = value;
692 break;
693
694 case oLogLevel:
47686178 695 log_level_ptr = &options->log_level;
3c0ef626 696 arg = strdelim(&s);
697 value = log_level_number(arg);
e9a17296 698 if (value == SYSLOG_LEVEL_NOT_SET)
3c0ef626 699 fatal("%.200s line %d: unsupported log level '%s'",
e9a17296 700 filename, linenum, arg ? arg : "<NONE>");
47686178 701 if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
702 *log_level_ptr = (LogLevel) value;
3c0ef626 703 break;
704
705 case oLocalForward:
706 case oRemoteForward:
707 arg = strdelim(&s);
996d5e62 708 if (arg == NULL || *arg == '\0')
3c0ef626 709 fatal("%.200s line %d: Missing port argument.",
710 filename, linenum);
996d5e62 711 arg2 = strdelim(&s);
712 if (arg2 == NULL || *arg2 == '\0')
713 fatal("%.200s line %d: Missing target argument.",
3c0ef626 714 filename, linenum);
996d5e62 715
716 /* construct a string for parse_forward */
717 snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
718
719 if (parse_forward(&fwd, fwdarg) == 0)
3c0ef626 720 fatal("%.200s line %d: Bad forwarding specification.",
721 filename, linenum);
996d5e62 722
3c0ef626 723 if (*activep) {
724 if (opcode == oLocalForward)
996d5e62 725 add_local_forward(options, &fwd);
3c0ef626 726 else if (opcode == oRemoteForward)
996d5e62 727 add_remote_forward(options, &fwd);
3c0ef626 728 }
729 break;
730
731 case oDynamicForward:
732 arg = strdelim(&s);
733 if (!arg || *arg == '\0')
734 fatal("%.200s line %d: Missing port argument.",
735 filename, linenum);
996d5e62 736 memset(&fwd, '\0', sizeof(fwd));
737 fwd.connect_host = "socks";
738 fwd.listen_host = hpdelim(&arg);
739 if (fwd.listen_host == NULL ||
740 strlen(fwd.listen_host) >= NI_MAXHOST)
741 fatal("%.200s line %d: Bad forwarding specification.",
742 filename, linenum);
743 if (arg) {
744 fwd.listen_port = a2port(arg);
745 fwd.listen_host = cleanhostname(fwd.listen_host);
746 } else {
747 fwd.listen_port = a2port(fwd.listen_host);
665a873d 748 fwd.listen_host = NULL;
996d5e62 749 }
750 if (fwd.listen_port == 0)
3c0ef626 751 fatal("%.200s line %d: Badly formatted port number.",
752 filename, linenum);
753 if (*activep)
996d5e62 754 add_local_forward(options, &fwd);
3c0ef626 755 break;
756
757 case oClearAllForwardings:
758 intptr = &options->clear_forwardings;
759 goto parse_flag;
760
761 case oHost:
762 *activep = 0;
763 while ((arg = strdelim(&s)) != NULL && *arg != '\0')
764 if (match_pattern(host, arg)) {
765 debug("Applying options for %.100s", arg);
766 *activep = 1;
767 break;
768 }
769 /* Avoid garbage check below, as strdelim is done. */
770 return 0;
771
772 case oEscapeChar:
773 intptr = &options->escape_char;
774 arg = strdelim(&s);
775 if (!arg || *arg == '\0')
776 fatal("%.200s line %d: Missing argument.", filename, linenum);
777 if (arg[0] == '^' && arg[2] == 0 &&
778 (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
779 value = (u_char) arg[1] & 31;
780 else if (strlen(arg) == 1)
781 value = (u_char) arg[0];
782 else if (strcmp(arg, "none") == 0)
783 value = SSH_ESCAPECHAR_NONE;
784 else {
785 fatal("%.200s line %d: Bad escape character.",
e9a17296 786 filename, linenum);
3c0ef626 787 /* NOTREACHED */
788 value = 0; /* Avoid compiler warning. */
789 }
790 if (*activep && *intptr == -1)
791 *intptr = value;
792 break;
793
0fff78ff 794 case oAddressFamily:
795 arg = strdelim(&s);
665a873d 796 if (!arg || *arg == '\0')
797 fatal("%s line %d: missing address family.",
798 filename, linenum);
0fff78ff 799 intptr = &options->address_family;
800 if (strcasecmp(arg, "inet") == 0)
801 value = AF_INET;
802 else if (strcasecmp(arg, "inet6") == 0)
803 value = AF_INET6;
804 else if (strcasecmp(arg, "any") == 0)
805 value = AF_UNSPEC;
806 else
807 fatal("Unsupported AddressFamily \"%s\"", arg);
808 if (*activep && *intptr == -1)
809 *intptr = value;
810 break;
811
6a9b3198 812 case oEnableSSHKeysign:
813 intptr = &options->enable_ssh_keysign;
814 goto parse_flag;
815
99be0775 816 case oIdentitiesOnly:
817 intptr = &options->identities_only;
818 goto parse_flag;
819
cdd66111 820 case oServerAliveInterval:
821 intptr = &options->server_alive_interval;
822 goto parse_time;
823
824 case oServerAliveCountMax:
825 intptr = &options->server_alive_count_max;
826 goto parse_int;
827
c9f39d2c 828 case oSendEnv:
829 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
830 if (strchr(arg, '=') != NULL)
831 fatal("%s line %d: Invalid environment name.",
832 filename, linenum);
996d5e62 833 if (!*activep)
834 continue;
c9f39d2c 835 if (options->num_send_env >= MAX_SEND_ENV)
836 fatal("%s line %d: too many send env.",
837 filename, linenum);
838 options->send_env[options->num_send_env++] =
839 xstrdup(arg);
840 }
841 break;
842
843 case oControlPath:
844 charptr = &options->control_path;
845 goto parse_string;
846
847 case oControlMaster:
848 intptr = &options->control_master;
665a873d 849 arg = strdelim(&s);
850 if (!arg || *arg == '\0')
851 fatal("%.200s line %d: Missing ControlMaster argument.",
852 filename, linenum);
853 value = 0; /* To avoid compiler warning... */
854 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
855 value = SSHCTL_MASTER_YES;
856 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
857 value = SSHCTL_MASTER_NO;
858 else if (strcmp(arg, "auto") == 0)
859 value = SSHCTL_MASTER_AUTO;
860 else if (strcmp(arg, "ask") == 0)
861 value = SSHCTL_MASTER_ASK;
862 else if (strcmp(arg, "autoask") == 0)
863 value = SSHCTL_MASTER_AUTO_ASK;
864 else
865 fatal("%.200s line %d: Bad ControlMaster argument.",
866 filename, linenum);
867 if (*activep && *intptr == -1)
868 *intptr = value;
869 break;
c9f39d2c 870
996d5e62 871 case oHashKnownHosts:
872 intptr = &options->hash_known_hosts;
873 goto parse_flag;
874
2c06c99b 875 case oTunnel:
876 intptr = &options->tun_open;
877 arg = strdelim(&s);
878 if (!arg || *arg == '\0')
879 fatal("%s line %d: Missing yes/point-to-point/"
880 "ethernet/no argument.", filename, linenum);
881 value = 0; /* silence compiler */
882 if (strcasecmp(arg, "ethernet") == 0)
883 value = SSH_TUNMODE_ETHERNET;
884 else if (strcasecmp(arg, "point-to-point") == 0)
885 value = SSH_TUNMODE_POINTOPOINT;
886 else if (strcasecmp(arg, "yes") == 0)
887 value = SSH_TUNMODE_DEFAULT;
888 else if (strcasecmp(arg, "no") == 0)
889 value = SSH_TUNMODE_NO;
890 else
891 fatal("%s line %d: Bad yes/point-to-point/ethernet/"
892 "no argument: %s", filename, linenum, arg);
893 if (*activep)
894 *intptr = value;
895 break;
896
897 case oTunnelDevice:
898 arg = strdelim(&s);
899 if (!arg || *arg == '\0')
900 fatal("%.200s line %d: Missing argument.", filename, linenum);
901 value = a2tun(arg, &value2);
902 if (value == SSH_TUNID_ERR)
903 fatal("%.200s line %d: Bad tun device.", filename, linenum);
904 if (*activep) {
905 options->tun_local = value;
906 options->tun_remote = value2;
907 }
908 break;
909
910 case oLocalCommand:
911 charptr = &options->local_command;
912 goto parse_command;
913
914 case oPermitLocalCommand:
915 intptr = &options->permit_local_command;
916 goto parse_flag;
917
f5799ae1 918 case oDeprecated:
919 debug("%s line %d: Deprecated option \"%s\"",
920 filename, linenum, keyword);
921 return 0;
922
0fff78ff 923 case oUnsupported:
924 error("%s line %d: Unsupported option \"%s\"",
925 filename, linenum, keyword);
926 return 0;
927
3c0ef626 928 default:
929 fatal("process_config_line: Unimplemented opcode %d", opcode);
930 }
931
932 /* Check that there is no garbage at end of line. */
933 if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
934 fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
665a873d 935 filename, linenum, arg);
3c0ef626 936 }
937 return 0;
938}
939
940
941/*
942 * Reads the config file and modifies the options accordingly. Options
943 * should already be initialized before this call. This never returns if
944 * there is an error. If the file does not exist, this returns 0.
945 */
946
947int
c9f39d2c 948read_config_file(const char *filename, const char *host, Options *options,
949 int checkperm)
3c0ef626 950{
951 FILE *f;
952 char line[1024];
953 int active, linenum;
954 int bad_options = 0;
955
956 /* Open the file. */
c9f39d2c 957 if ((f = fopen(filename, "r")) == NULL)
3c0ef626 958 return 0;
959
c9f39d2c 960 if (checkperm) {
961 struct stat sb;
962
963 if (fstat(fileno(f), &sb) == -1)
964 fatal("fstat %s: %s", filename, strerror(errno));
965 if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
966 (sb.st_mode & 022) != 0))
967 fatal("Bad owner or permissions on %s", filename);
968 }
969
3c0ef626 970 debug("Reading configuration data %.200s", filename);
971
972 /*
973 * Mark that we are now processing the options. This flag is turned
974 * on/off by Host specifications.
975 */
976 active = 1;
977 linenum = 0;
978 while (fgets(line, sizeof(line), f)) {
979 /* Update line number counter. */
980 linenum++;
981 if (process_config_line(options, host, line, filename, linenum, &active) != 0)
982 bad_options++;
983 }
984 fclose(f);
985 if (bad_options > 0)
986 fatal("%s: terminating, %d bad configuration options",
e9a17296 987 filename, bad_options);
3c0ef626 988 return 1;
989}
990
991/*
992 * Initializes options to special values that indicate that they have not yet
993 * been set. Read_config_file will only set options with this value. Options
994 * are processed in the following order: command line, user config file,
995 * system config file. Last, fill_default_options is called.
996 */
997
998void
999initialize_options(Options * options)
1000{
1001 memset(options, 'X', sizeof(*options));
1002 options->forward_agent = -1;
1003 options->forward_x11 = -1;
cdd66111 1004 options->forward_x11_trusted = -1;
9108f8d9 1005 options->exit_on_forward_failure = -1;
3c0ef626 1006 options->xauth_location = NULL;
1007 options->gateway_ports = -1;
1008 options->use_privileged_port = -1;
3c0ef626 1009 options->rsa_authentication = -1;
1010 options->pubkey_authentication = -1;
1011 options->challenge_response_authentication = -1;
0fff78ff 1012 options->gss_authentication = -1;
1013 options->gss_deleg_creds = -1;
3c0ef626 1014 options->password_authentication = -1;
1015 options->kbd_interactive_authentication = -1;
1016 options->kbd_interactive_devices = NULL;
1017 options->rhosts_rsa_authentication = -1;
1018 options->hostbased_authentication = -1;
3c0ef626 1019 options->batch_mode = -1;
1020 options->check_host_ip = -1;
1021 options->strict_host_key_checking = -1;
1022 options->compression = -1;
cdd66111 1023 options->tcp_keep_alive = -1;
3c0ef626 1024 options->compression_level = -1;
1025 options->port = -1;
0fff78ff 1026 options->address_family = -1;
3c0ef626 1027 options->connection_attempts = -1;
0fff78ff 1028 options->connection_timeout = -1;
3c0ef626 1029 options->number_of_password_prompts = -1;
1030 options->cipher = -1;
1031 options->ciphers = NULL;
1032 options->macs = NULL;
1033 options->hostkeyalgorithms = NULL;
1034 options->protocol = SSH_PROTO_UNKNOWN;
1035 options->num_identity_files = 0;
1036 options->hostname = NULL;
1037 options->host_key_alias = NULL;
1038 options->proxy_command = NULL;
1039 options->user = NULL;
1040 options->escape_char = -1;
1041 options->system_hostfile = NULL;
1042 options->user_hostfile = NULL;
1043 options->system_hostfile2 = NULL;
1044 options->user_hostfile2 = NULL;
1045 options->num_local_forwards = 0;
1046 options->num_remote_forwards = 0;
1047 options->clear_forwardings = -1;
e9a17296 1048 options->log_level = SYSLOG_LEVEL_NOT_SET;
3c0ef626 1049 options->preferred_authentications = NULL;
1050 options->bind_address = NULL;
1051 options->smartcard_device = NULL;
6a9b3198 1052 options->enable_ssh_keysign = - 1;
3c0ef626 1053 options->no_host_authentication_for_localhost = - 1;
99be0775 1054 options->identities_only = - 1;
0fff78ff 1055 options->rekey_limit = - 1;
1056 options->verify_host_key_dns = -1;
cdd66111 1057 options->server_alive_interval = -1;
1058 options->server_alive_count_max = -1;
c9f39d2c 1059 options->num_send_env = 0;
1060 options->control_path = NULL;
1061 options->control_master = -1;
996d5e62 1062 options->hash_known_hosts = -1;
2c06c99b 1063 options->tun_open = -1;
1064 options->tun_local = -1;
1065 options->tun_remote = -1;
1066 options->local_command = NULL;
1067 options->permit_local_command = -1;
3c0ef626 1068}
1069
1070/*
1071 * Called after processing other sources of option data, this fills those
1072 * options for which no value has been specified with their default values.
1073 */
1074
1075void
1076fill_default_options(Options * options)
1077{
1078 int len;
1079
1080 if (options->forward_agent == -1)
1081 options->forward_agent = 0;
1082 if (options->forward_x11 == -1)
1083 options->forward_x11 = 0;
cdd66111 1084 if (options->forward_x11_trusted == -1)
1085 options->forward_x11_trusted = 0;
9108f8d9 1086 if (options->exit_on_forward_failure == -1)
1087 options->exit_on_forward_failure = 0;
3c0ef626 1088 if (options->xauth_location == NULL)
1089 options->xauth_location = _PATH_XAUTH;
3c0ef626 1090 if (options->gateway_ports == -1)
1091 options->gateway_ports = 0;
1092 if (options->use_privileged_port == -1)
1093 options->use_privileged_port = 0;
3c0ef626 1094 if (options->rsa_authentication == -1)
1095 options->rsa_authentication = 1;
1096 if (options->pubkey_authentication == -1)
1097 options->pubkey_authentication = 1;
1098 if (options->challenge_response_authentication == -1)
1099 options->challenge_response_authentication = 1;
0fff78ff 1100 if (options->gss_authentication == -1)
cdd66111 1101 options->gss_authentication = 0;
0fff78ff 1102 if (options->gss_deleg_creds == -1)
1103 options->gss_deleg_creds = 0;
3c0ef626 1104 if (options->password_authentication == -1)
1105 options->password_authentication = 1;
1106 if (options->kbd_interactive_authentication == -1)
1107 options->kbd_interactive_authentication = 1;
1108 if (options->rhosts_rsa_authentication == -1)
f5799ae1 1109 options->rhosts_rsa_authentication = 0;
3c0ef626 1110 if (options->hostbased_authentication == -1)
1111 options->hostbased_authentication = 0;
3c0ef626 1112 if (options->batch_mode == -1)
1113 options->batch_mode = 0;
1114 if (options->check_host_ip == -1)
1115 options->check_host_ip = 1;
1116 if (options->strict_host_key_checking == -1)
1117 options->strict_host_key_checking = 2; /* 2 is default */
1118 if (options->compression == -1)
1119 options->compression = 0;
cdd66111 1120 if (options->tcp_keep_alive == -1)
1121 options->tcp_keep_alive = 1;
3c0ef626 1122 if (options->compression_level == -1)
1123 options->compression_level = 6;
1124 if (options->port == -1)
1125 options->port = 0; /* Filled in ssh_connect. */
0fff78ff 1126 if (options->address_family == -1)
1127 options->address_family = AF_UNSPEC;
3c0ef626 1128 if (options->connection_attempts == -1)
1129 options->connection_attempts = 1;
1130 if (options->number_of_password_prompts == -1)
1131 options->number_of_password_prompts = 3;
1132 /* Selected in ssh_login(). */
1133 if (options->cipher == -1)
1134 options->cipher = SSH_CIPHER_NOT_SET;
1135 /* options->ciphers, default set in myproposals.h */
1136 /* options->macs, default set in myproposals.h */
1137 /* options->hostkeyalgorithms, default set in myproposals.h */
1138 if (options->protocol == SSH_PROTO_UNKNOWN)
1139 options->protocol = SSH_PROTO_1|SSH_PROTO_2;
1140 if (options->num_identity_files == 0) {
1141 if (options->protocol & SSH_PROTO_1) {
1142 len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;
1143 options->identity_files[options->num_identity_files] =
1144 xmalloc(len);
1145 snprintf(options->identity_files[options->num_identity_files++],
1146 len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY);
1147 }
1148 if (options->protocol & SSH_PROTO_2) {
1149 len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1;
1150 options->identity_files[options->num_identity_files] =
1151 xmalloc(len);
1152 snprintf(options->identity_files[options->num_identity_files++],
1153 len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA);
1154
1155 len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1;
1156 options->identity_files[options->num_identity_files] =
1157 xmalloc(len);
1158 snprintf(options->identity_files[options->num_identity_files++],
1159 len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA);
1160 }
1161 }
1162 if (options->escape_char == -1)
1163 options->escape_char = '~';
1164 if (options->system_hostfile == NULL)
1165 options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
1166 if (options->user_hostfile == NULL)
1167 options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
1168 if (options->system_hostfile2 == NULL)
1169 options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
1170 if (options->user_hostfile2 == NULL)
1171 options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
e9a17296 1172 if (options->log_level == SYSLOG_LEVEL_NOT_SET)
3c0ef626 1173 options->log_level = SYSLOG_LEVEL_INFO;
1174 if (options->clear_forwardings == 1)
1175 clear_forwardings(options);
1176 if (options->no_host_authentication_for_localhost == - 1)
1177 options->no_host_authentication_for_localhost = 0;
99be0775 1178 if (options->identities_only == -1)
1179 options->identities_only = 0;
6a9b3198 1180 if (options->enable_ssh_keysign == -1)
1181 options->enable_ssh_keysign = 0;
0fff78ff 1182 if (options->rekey_limit == -1)
1183 options->rekey_limit = 0;
1184 if (options->verify_host_key_dns == -1)
1185 options->verify_host_key_dns = 0;
cdd66111 1186 if (options->server_alive_interval == -1)
1187 options->server_alive_interval = 0;
1188 if (options->server_alive_count_max == -1)
1189 options->server_alive_count_max = 3;
c9f39d2c 1190 if (options->control_master == -1)
1191 options->control_master = 0;
996d5e62 1192 if (options->hash_known_hosts == -1)
1193 options->hash_known_hosts = 0;
2c06c99b 1194 if (options->tun_open == -1)
1195 options->tun_open = SSH_TUNMODE_NO;
1196 if (options->tun_local == -1)
1197 options->tun_local = SSH_TUNID_ANY;
1198 if (options->tun_remote == -1)
1199 options->tun_remote = SSH_TUNID_ANY;
1200 if (options->permit_local_command == -1)
1201 options->permit_local_command = 0;
1202 /* options->local_command should not be set by default */
3c0ef626 1203 /* options->proxy_command should not be set by default */
1204 /* options->user will be set in the main program if appropriate */
1205 /* options->hostname will be set in the main program if appropriate */
1206 /* options->host_key_alias should not be set by default */
1207 /* options->preferred_authentications will be set in ssh */
1208}
996d5e62 1209
1210/*
1211 * parse_forward
1212 * parses a string containing a port forwarding specification of the form:
1213 * [listenhost:]listenport:connecthost:connectport
1214 * returns number of arguments parsed or zero on error
1215 */
1216int
1217parse_forward(Forward *fwd, const char *fwdspec)
1218{
1219 int i;
1220 char *p, *cp, *fwdarg[4];
1221
1222 memset(fwd, '\0', sizeof(*fwd));
1223
1224 cp = p = xstrdup(fwdspec);
1225
1226 /* skip leading spaces */
d4487008 1227 while (isspace(*cp))
996d5e62 1228 cp++;
1229
1230 for (i = 0; i < 4; ++i)
1231 if ((fwdarg[i] = hpdelim(&cp)) == NULL)
1232 break;
1233
1234 /* Check for trailing garbage in 4-arg case*/
1235 if (cp != NULL)
1236 i = 0; /* failure */
1237
1238 switch (i) {
1239 case 3:
1240 fwd->listen_host = NULL;
1241 fwd->listen_port = a2port(fwdarg[0]);
1242 fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
1243 fwd->connect_port = a2port(fwdarg[2]);
1244 break;
1245
1246 case 4:
1247 fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1248 fwd->listen_port = a2port(fwdarg[1]);
1249 fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
1250 fwd->connect_port = a2port(fwdarg[3]);
1251 break;
1252 default:
1253 i = 0; /* failure */
1254 }
1255
1256 xfree(p);
1257
47686178 1258 if (fwd->listen_port == 0 || fwd->connect_port == 0)
996d5e62 1259 goto fail_free;
1260
1261 if (fwd->connect_host != NULL &&
1262 strlen(fwd->connect_host) >= NI_MAXHOST)
1263 goto fail_free;
1264
1265 return (i);
1266
1267 fail_free:
1268 if (fwd->connect_host != NULL)
1269 xfree(fwd->connect_host);
1270 if (fwd->listen_host != NULL)
1271 xfree(fwd->listen_host);
1272 return (0);
1273}
This page took 0.470158 seconds and 5 git commands to generate.