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