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