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