Annotation of src/usr.bin/ssh/readconf.c, Revision 1.207
1.207 ! djm 1: /* $OpenBSD: readconf.c,v 1.206 2013/10/14 22:22:02 djm Exp $ */
1.1 deraadt 2: /*
1.18 deraadt 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.
1.26 markus 7: *
1.46 deraadt 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".
1.18 deraadt 13: */
1.1 deraadt 14:
1.147 stevesk 15: #include <sys/types.h>
16: #include <sys/stat.h>
1.152 stevesk 17: #include <sys/socket.h>
1.206 djm 18: #include <sys/wait.h>
1.152 stevesk 19:
20: #include <netinet/in.h>
1.190 djm 21: #include <netinet/in_systm.h>
22: #include <netinet/ip.h>
1.148 stevesk 23:
24: #include <ctype.h>
1.154 stevesk 25: #include <errno.h>
1.206 djm 26: #include <fcntl.h>
1.155 stevesk 27: #include <netdb.h>
1.206 djm 28: #include <paths.h>
29: #include <pwd.h>
1.159 deraadt 30: #include <signal.h>
1.158 stevesk 31: #include <stdio.h>
1.157 stevesk 32: #include <string.h>
1.156 stevesk 33: #include <unistd.h>
1.200 dtucker 34: #include <util.h>
1.1 deraadt 35:
1.159 deraadt 36: #include "xmalloc.h"
1.1 deraadt 37: #include "ssh.h"
1.25 markus 38: #include "compat.h"
1.58 markus 39: #include "cipher.h"
1.55 markus 40: #include "pathnames.h"
1.58 markus 41: #include "log.h"
1.159 deraadt 42: #include "key.h"
1.58 markus 43: #include "readconf.h"
44: #include "match.h"
45: #include "misc.h"
1.159 deraadt 46: #include "buffer.h"
1.62 markus 47: #include "kex.h"
48: #include "mac.h"
1.206 djm 49: #include "uidswap.h"
1.1 deraadt 50:
51: /* Format of the configuration file:
52:
53: # Configuration data is parsed as follows:
54: # 1. command line options
55: # 2. user-specific file
56: # 3. system-wide file
57: # Any configuration value is only changed the first time it is set.
58: # Thus, host-specific definitions should be at the beginning of the
59: # configuration file, and defaults at the end.
60:
61: # Host-specific declarations. These may override anything above. A single
62: # host may match multiple declarations; these are processed in the order
63: # that they are given in.
64:
65: Host *.ngs.fi ngs.fi
1.96 markus 66: User foo
1.1 deraadt 67:
68: Host fake.com
69: HostName another.host.name.real.org
70: User blaah
71: Port 34289
72: ForwardX11 no
73: ForwardAgent no
74:
75: Host books.com
76: RemoteForward 9999 shadows.cs.hut.fi:9999
77: Cipher 3des
78:
79: Host fascist.blob.com
80: Port 23123
81: User tylonen
82: PasswordAuthentication no
83:
84: Host puukko.hut.fi
85: User t35124p
86: ProxyCommand ssh-proxy %h %p
87:
88: Host *.fr
1.96 markus 89: PublicKeyAuthentication no
1.1 deraadt 90:
91: Host *.su
92: Cipher none
93: PasswordAuthentication no
94:
1.144 reyk 95: Host vpn.fake.com
96: Tunnel yes
97: TunnelDevice 3
98:
1.1 deraadt 99: # Defaults for various options
100: Host *
101: ForwardAgent no
1.50 markus 102: ForwardX11 no
1.1 deraadt 103: PasswordAuthentication yes
104: RSAAuthentication yes
105: RhostsRSAAuthentication yes
106: StrictHostKeyChecking yes
1.126 markus 107: TcpKeepAlive no
1.1 deraadt 108: IdentityFile ~/.ssh/identity
109: Port 22
110: EscapeChar ~
111:
112: */
113:
114: /* Keyword tokens. */
115:
1.17 markus 116: typedef enum {
117: oBadOption,
1.206 djm 118: oHost, oMatch,
1.186 djm 119: oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
120: oGatewayPorts, oExitOnForwardFailure,
1.100 deraadt 121: oPasswordAuthentication, oRSAAuthentication,
1.59 markus 122: oChallengeResponseAuthentication, oXAuthLocation,
1.17 markus 123: oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
1.206 djm 124: oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
1.17 markus 125: oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
126: oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
1.126 markus 127: oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
1.62 markus 128: oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
1.50 markus 129: oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
1.67 markus 130: oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
1.76 markus 131: oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
1.183 markus 132: oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
1.96 markus 133: oClearAllForwardings, oNoHostAuthenticationForLocalhost,
1.111 djm 134: oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
1.118 markus 135: oAddressFamily, oGssAuthentication, oGssDelegateCreds,
1.128 markus 136: oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
1.187 djm 137: oSendEnv, oControlPath, oControlMaster, oControlPersist,
138: oHashKnownHosts,
1.144 reyk 139: oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
1.182 dtucker 140: oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication,
1.205 djm 141: oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
1.199 djm 142: oIgnoredUnknownOption, oDeprecated, oUnsupported
1.1 deraadt 143: } OpCodes;
144:
145: /* Textual representations of the tokens. */
146:
1.17 markus 147: static struct {
148: const char *name;
149: OpCodes opcode;
150: } keywords[] = {
151: { "forwardagent", oForwardAgent },
152: { "forwardx11", oForwardX11 },
1.123 markus 153: { "forwardx11trusted", oForwardX11Trusted },
1.186 djm 154: { "forwardx11timeout", oForwardX11Timeout },
1.153 markus 155: { "exitonforwardfailure", oExitOnForwardFailure },
1.34 markus 156: { "xauthlocation", oXAuthLocation },
1.17 markus 157: { "gatewayports", oGatewayPorts },
158: { "useprivilegedport", oUsePrivilegedPort },
1.116 markus 159: { "rhostsauthentication", oDeprecated },
1.17 markus 160: { "passwordauthentication", oPasswordAuthentication },
1.48 markus 161: { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
162: { "kbdinteractivedevices", oKbdInteractiveDevices },
1.17 markus 163: { "rsaauthentication", oRSAAuthentication },
1.50 markus 164: { "pubkeyauthentication", oPubkeyAuthentication },
1.59 markus 165: { "dsaauthentication", oPubkeyAuthentication }, /* alias */
1.72 markus 166: { "rhostsrsaauthentication", oRhostsRSAAuthentication },
1.73 markus 167: { "hostbasedauthentication", oHostbasedAuthentication },
1.59 markus 168: { "challengeresponseauthentication", oChallengeResponseAuthentication },
169: { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
170: { "tisauthentication", oChallengeResponseAuthentication }, /* alias */
1.110 jakob 171: { "kerberosauthentication", oUnsupported },
172: { "kerberostgtpassing", oUnsupported },
173: { "afstokenpassing", oUnsupported },
1.118 markus 174: #if defined(GSSAPI)
175: { "gssapiauthentication", oGssAuthentication },
176: { "gssapidelegatecredentials", oGssDelegateCreds },
177: #else
178: { "gssapiauthentication", oUnsupported },
179: { "gssapidelegatecredentials", oUnsupported },
180: #endif
1.96 markus 181: { "fallbacktorsh", oDeprecated },
182: { "usersh", oDeprecated },
1.17 markus 183: { "identityfile", oIdentityFile },
1.174 stevesk 184: { "identityfile2", oIdentityFile }, /* obsolete */
1.128 markus 185: { "identitiesonly", oIdentitiesOnly },
1.17 markus 186: { "hostname", oHostName },
1.52 markus 187: { "hostkeyalias", oHostKeyAlias },
1.17 markus 188: { "proxycommand", oProxyCommand },
189: { "port", oPort },
190: { "cipher", oCipher },
1.25 markus 191: { "ciphers", oCiphers },
1.62 markus 192: { "macs", oMacs },
1.25 markus 193: { "protocol", oProtocol },
1.17 markus 194: { "remoteforward", oRemoteForward },
195: { "localforward", oLocalForward },
196: { "user", oUser },
197: { "host", oHost },
1.206 djm 198: { "match", oMatch },
1.17 markus 199: { "escapechar", oEscapeChar },
200: { "globalknownhostsfile", oGlobalKnownHostsFile },
1.193 djm 201: { "globalknownhostsfile2", oDeprecated },
1.174 stevesk 202: { "userknownhostsfile", oUserKnownHostsFile },
1.193 djm 203: { "userknownhostsfile2", oDeprecated },
1.17 markus 204: { "connectionattempts", oConnectionAttempts },
205: { "batchmode", oBatchMode },
206: { "checkhostip", oCheckHostIP },
207: { "stricthostkeychecking", oStrictHostKeyChecking },
208: { "compression", oCompression },
209: { "compressionlevel", oCompressionLevel },
1.126 markus 210: { "tcpkeepalive", oTCPKeepAlive },
211: { "keepalive", oTCPKeepAlive }, /* obsolete */
1.17 markus 212: { "numberofpasswordprompts", oNumberOfPasswordPrompts },
213: { "loglevel", oLogLevel },
1.71 markus 214: { "dynamicforward", oDynamicForward },
1.67 markus 215: { "preferredauthentications", oPreferredAuthentications },
1.76 markus 216: { "hostkeyalgorithms", oHostKeyAlgorithms },
1.77 markus 217: { "bindaddress", oBindAddress },
1.183 markus 218: #ifdef ENABLE_PKCS11
219: { "smartcarddevice", oPKCS11Provider },
220: { "pkcs11provider", oPKCS11Provider },
1.110 jakob 221: #else
222: { "smartcarddevice", oUnsupported },
1.183 markus 223: { "pkcs11provider", oUnsupported },
1.110 jakob 224: #endif
1.93 deraadt 225: { "clearallforwardings", oClearAllForwardings },
1.101 markus 226: { "enablesshkeysign", oEnableSSHKeysign },
1.107 jakob 227: { "verifyhostkeydns", oVerifyHostKeyDNS },
1.93 deraadt 228: { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
1.105 markus 229: { "rekeylimit", oRekeyLimit },
1.111 djm 230: { "connecttimeout", oConnectTimeout },
1.112 djm 231: { "addressfamily", oAddressFamily },
1.127 markus 232: { "serveraliveinterval", oServerAliveInterval },
233: { "serveralivecountmax", oServerAliveCountMax },
1.130 djm 234: { "sendenv", oSendEnv },
1.132 djm 235: { "controlpath", oControlPath },
236: { "controlmaster", oControlMaster },
1.187 djm 237: { "controlpersist", oControlPersist },
1.136 djm 238: { "hashknownhosts", oHashKnownHosts },
1.144 reyk 239: { "tunnel", oTunnel },
240: { "tunneldevice", oTunnelDevice },
241: { "localcommand", oLocalCommand },
242: { "permitlocalcommand", oPermitLocalCommand },
1.167 grunk 243: { "visualhostkey", oVisualHostKey },
1.177 andreas 244: { "useroaming", oUseRoaming },
1.171 djm 245: #ifdef JPAKE
246: { "zeroknowledgepasswordauthentication",
247: oZeroKnowledgePasswordAuthentication },
248: #else
249: { "zeroknowledgepasswordauthentication", oUnsupported },
250: #endif
1.189 djm 251: { "kexalgorithms", oKexAlgorithms },
1.190 djm 252: { "ipqos", oIPQoS },
1.192 djm 253: { "requesttty", oRequestTTY },
1.205 djm 254: { "proxyusefdpass", oProxyUseFdpass },
1.199 djm 255: { "ignoreunknown", oIgnoreUnknown },
1.171 djm 256:
1.92 stevesk 257: { NULL, oBadOption }
1.13 markus 258: };
259:
1.19 markus 260: /*
261: * Adds a local TCP/IP port forward to options. Never returns if there is an
262: * error.
263: */
1.1 deraadt 264:
1.26 markus 265: void
1.135 djm 266: add_local_forward(Options *options, const Forward *newfwd)
1.1 deraadt 267: {
1.17 markus 268: Forward *fwd;
269: extern uid_t original_real_uid;
1.185 djm 270:
1.135 djm 271: if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0)
1.64 millert 272: fatal("Privileged ports can only be forwarded by root.");
1.185 djm 273: options->local_forwards = xrealloc(options->local_forwards,
274: options->num_local_forwards + 1,
275: sizeof(*options->local_forwards));
1.17 markus 276: fwd = &options->local_forwards[options->num_local_forwards++];
1.135 djm 277:
1.172 stevesk 278: fwd->listen_host = newfwd->listen_host;
1.135 djm 279: fwd->listen_port = newfwd->listen_port;
1.172 stevesk 280: fwd->connect_host = newfwd->connect_host;
1.135 djm 281: fwd->connect_port = newfwd->connect_port;
1.1 deraadt 282: }
283:
1.19 markus 284: /*
285: * Adds a remote TCP/IP port forward to options. Never returns if there is
286: * an error.
287: */
1.1 deraadt 288:
1.26 markus 289: void
1.135 djm 290: add_remote_forward(Options *options, const Forward *newfwd)
1.1 deraadt 291: {
1.17 markus 292: Forward *fwd;
1.185 djm 293:
294: options->remote_forwards = xrealloc(options->remote_forwards,
295: options->num_remote_forwards + 1,
296: sizeof(*options->remote_forwards));
1.17 markus 297: fwd = &options->remote_forwards[options->num_remote_forwards++];
1.135 djm 298:
1.172 stevesk 299: fwd->listen_host = newfwd->listen_host;
1.135 djm 300: fwd->listen_port = newfwd->listen_port;
1.172 stevesk 301: fwd->connect_host = newfwd->connect_host;
1.135 djm 302: fwd->connect_port = newfwd->connect_port;
1.194 markus 303: fwd->handle = newfwd->handle;
1.184 markus 304: fwd->allocated_port = 0;
1.1 deraadt 305: }
306:
1.90 stevesk 307: static void
308: clear_forwardings(Options *options)
309: {
310: int i;
311:
1.135 djm 312: for (i = 0; i < options->num_local_forwards; i++) {
1.202 djm 313: free(options->local_forwards[i].listen_host);
314: free(options->local_forwards[i].connect_host);
1.135 djm 315: }
1.185 djm 316: if (options->num_local_forwards > 0) {
1.202 djm 317: free(options->local_forwards);
1.185 djm 318: options->local_forwards = NULL;
319: }
1.90 stevesk 320: options->num_local_forwards = 0;
1.135 djm 321: for (i = 0; i < options->num_remote_forwards; i++) {
1.202 djm 322: free(options->remote_forwards[i].listen_host);
323: free(options->remote_forwards[i].connect_host);
1.135 djm 324: }
1.185 djm 325: if (options->num_remote_forwards > 0) {
1.202 djm 326: free(options->remote_forwards);
1.185 djm 327: options->remote_forwards = NULL;
328: }
1.90 stevesk 329: options->num_remote_forwards = 0;
1.145 reyk 330: options->tun_open = SSH_TUNMODE_NO;
1.90 stevesk 331: }
332:
1.195 dtucker 333: void
334: add_identity_file(Options *options, const char *dir, const char *filename,
335: int userprovided)
336: {
337: char *path;
338:
339: if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
340: fatal("Too many identity files specified (max %d)",
341: SSH_MAX_IDENTITY_FILES);
342:
343: if (dir == NULL) /* no dir, filename is absolute */
344: path = xstrdup(filename);
345: else
346: (void)xasprintf(&path, "%.100s%.100s", dir, filename);
347:
348: options->identity_file_userprovided[options->num_identity_files] =
349: userprovided;
350: options->identity_files[options->num_identity_files++] = path;
351: }
352:
1.206 djm 353: int
354: default_ssh_port(void)
355: {
356: static int port;
357: struct servent *sp;
358:
359: if (port == 0) {
360: sp = getservbyname(SSH_SERVICE_NAME, "tcp");
361: port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
362: }
363: return port;
364: }
365:
366: /*
367: * Execute a command in a shell.
368: * Return its exit status or -1 on abnormal exit.
369: */
370: static int
371: execute_in_shell(const char *cmd)
372: {
373: char *shell, *command_string;
374: pid_t pid;
375: int devnull, status;
376: extern uid_t original_real_uid;
377:
378: if ((shell = getenv("SHELL")) == NULL)
379: shell = _PATH_BSHELL;
380:
381: /*
382: * Use "exec" to avoid "sh -c" processes on some platforms
383: * (e.g. Solaris)
384: */
385: xasprintf(&command_string, "exec %s", cmd);
386:
387: /* Need this to redirect subprocess stdin/out */
388: if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1)
389: fatal("open(/dev/null): %s", strerror(errno));
390:
391: debug("Executing command: '%.500s'", cmd);
392:
393: /* Fork and execute the command. */
394: if ((pid = fork()) == 0) {
395: char *argv[4];
396:
397: /* Child. Permanently give up superuser privileges. */
398: permanently_drop_suid(original_real_uid);
399:
400: /* Redirect child stdin and stdout. Leave stderr */
401: if (dup2(devnull, STDIN_FILENO) == -1)
402: fatal("dup2: %s", strerror(errno));
403: if (dup2(devnull, STDOUT_FILENO) == -1)
404: fatal("dup2: %s", strerror(errno));
405: if (devnull > STDERR_FILENO)
406: close(devnull);
407: closefrom(STDERR_FILENO + 1);
408:
409: argv[0] = shell;
410: argv[1] = "-c";
411: argv[2] = command_string;
412: argv[3] = NULL;
413:
414: execv(argv[0], argv);
415: error("Unable to execute '%.100s': %s", cmd, strerror(errno));
416: /* Die with signal to make this error apparent to parent. */
417: signal(SIGTERM, SIG_DFL);
418: kill(getpid(), SIGTERM);
419: _exit(1);
420: }
421: /* Parent. */
422: if (pid < 0)
423: fatal("%s: fork: %.100s", __func__, strerror(errno));
424:
425: close(devnull);
426: free(command_string);
427:
428: while (waitpid(pid, &status, 0) == -1) {
429: if (errno != EINTR && errno != EAGAIN)
430: fatal("%s: waitpid: %s", __func__, strerror(errno));
431: }
432: if (!WIFEXITED(status)) {
433: error("command '%.100s' exited abnormally", cmd);
434: return -1;
435: }
436: debug3("command returned status %d", WEXITSTATUS(status));
437: return WEXITSTATUS(status);
438: }
439:
440: /*
441: * Parse and execute a Match directive.
442: */
443: static int
444: match_cfg_line(Options *options, char **condition, struct passwd *pw,
445: const char *host_arg, const char *filename, int linenum)
446: {
447: char *arg, *attrib, *cmd, *cp = *condition;
448: const char *ruser, *host;
449: int r, port, result = 1;
450: size_t len;
451: char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
452:
453: /*
454: * Configuration is likely to be incomplete at this point so we
455: * must be prepared to use default values.
456: */
457: port = options->port <= 0 ? default_ssh_port() : options->port;
458: ruser = options->user == NULL ? pw->pw_name : options->user;
459: host = options->hostname == NULL ? host_arg : options->hostname;
460:
461: debug3("checking match for '%s' host %s", cp, host);
462: while ((attrib = strdelim(&cp)) && *attrib != '\0') {
463: if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
464: error("Missing Match criteria for %s", attrib);
465: return -1;
466: }
467: len = strlen(arg);
468: if (strcasecmp(attrib, "host") == 0) {
469: if (match_hostname(host, arg, len) != 1)
470: result = 0;
471: else
472: debug("%.200s line %d: matched 'Host %.100s' ",
473: filename, linenum, host);
474: } else if (strcasecmp(attrib, "originalhost") == 0) {
475: if (match_hostname(host_arg, arg, len) != 1)
476: result = 0;
477: else
478: debug("%.200s line %d: matched "
479: "'OriginalHost %.100s' ",
480: filename, linenum, host_arg);
481: } else if (strcasecmp(attrib, "user") == 0) {
482: if (match_pattern_list(ruser, arg, len, 0) != 1)
483: result = 0;
484: else
485: debug("%.200s line %d: matched 'User %.100s' ",
486: filename, linenum, ruser);
487: } else if (strcasecmp(attrib, "localuser") == 0) {
488: if (match_pattern_list(pw->pw_name, arg, len, 0) != 1)
489: result = 0;
490: else
491: debug("%.200s line %d: matched "
492: "'LocalUser %.100s' ",
493: filename, linenum, pw->pw_name);
494: } else if (strcasecmp(attrib, "command") == 0) {
495: if (gethostname(thishost, sizeof(thishost)) == -1)
496: fatal("gethostname: %s", strerror(errno));
497: strlcpy(shorthost, thishost, sizeof(shorthost));
498: shorthost[strcspn(thishost, ".")] = '\0';
499: snprintf(portstr, sizeof(portstr), "%d", port);
500:
501: cmd = percent_expand(arg,
502: "L", shorthost,
503: "d", pw->pw_dir,
504: "h", host,
505: "l", thishost,
506: "n", host_arg,
507: "p", portstr,
508: "r", ruser,
509: "u", pw->pw_name,
510: (char *)NULL);
511: r = execute_in_shell(cmd);
512: if (r == -1) {
513: fatal("%.200s line %d: match command '%.100s' "
514: "error", filename, linenum, cmd);
515: } else if (r == 0) {
516: debug("%.200s line %d: matched "
517: "'Command \"%.100s\"' ",
518: filename, linenum, cmd);
519: } else
520: result = 0;
521: free(cmd);
522: } else {
523: error("Unsupported Match attribute %s", attrib);
524: return -1;
525: }
526: }
527: debug3("match %sfound", result ? "" : "not ");
528: *condition = cp;
529: return result;
530: }
531:
1.19 markus 532: /*
1.70 stevesk 533: * Returns the number of the token pointed to by cp or oBadOption.
1.19 markus 534: */
1.26 markus 535: static OpCodes
1.199 djm 536: parse_token(const char *cp, const char *filename, int linenum,
537: const char *ignored_unknown)
1.1 deraadt 538: {
1.199 djm 539: int i;
1.1 deraadt 540:
1.17 markus 541: for (i = 0; keywords[i].name; i++)
1.199 djm 542: if (strcmp(cp, keywords[i].name) == 0)
1.17 markus 543: return keywords[i].opcode;
1.199 djm 544: if (ignored_unknown != NULL && match_pattern_list(cp, ignored_unknown,
545: strlen(ignored_unknown), 1) == 1)
546: return oIgnoredUnknownOption;
1.75 stevesk 547: error("%s: line %d: Bad configuration option: %s",
548: filename, linenum, cp);
1.17 markus 549: return oBadOption;
1.1 deraadt 550: }
551:
1.207 ! djm 552: /* Multistate option parsing */
! 553: struct multistate {
! 554: char *key;
! 555: int value;
! 556: };
! 557: static const struct multistate multistate_flag[] = {
! 558: { "true", 1 },
! 559: { "false", 0 },
! 560: { "yes", 1 },
! 561: { "no", 0 },
! 562: { NULL, -1 }
! 563: };
! 564: static const struct multistate multistate_yesnoask[] = {
! 565: { "true", 1 },
! 566: { "false", 0 },
! 567: { "yes", 1 },
! 568: { "no", 0 },
! 569: { "ask", 2 },
! 570: { NULL, -1 }
! 571: };
! 572: static const struct multistate multistate_addressfamily[] = {
! 573: { "inet", AF_INET },
! 574: { "inet6", AF_INET6 },
! 575: { "any", AF_UNSPEC },
! 576: { NULL, -1 }
! 577: };
! 578: static const struct multistate multistate_controlmaster[] = {
! 579: { "true", SSHCTL_MASTER_YES },
! 580: { "yes", SSHCTL_MASTER_YES },
! 581: { "false", SSHCTL_MASTER_NO },
! 582: { "no", SSHCTL_MASTER_NO },
! 583: { "auto", SSHCTL_MASTER_AUTO },
! 584: { "ask", SSHCTL_MASTER_ASK },
! 585: { "autoask", SSHCTL_MASTER_AUTO_ASK },
! 586: { NULL, -1 }
! 587: };
! 588: static const struct multistate multistate_tunnel[] = {
! 589: { "ethernet", SSH_TUNMODE_ETHERNET },
! 590: { "point-to-point", SSH_TUNMODE_POINTOPOINT },
! 591: { "true", SSH_TUNMODE_DEFAULT },
! 592: { "yes", SSH_TUNMODE_DEFAULT },
! 593: { "false", SSH_TUNMODE_NO },
! 594: { "no", SSH_TUNMODE_NO },
! 595: { NULL, -1 }
! 596: };
! 597: static const struct multistate multistate_requesttty[] = {
! 598: { "true", REQUEST_TTY_YES },
! 599: { "yes", REQUEST_TTY_YES },
! 600: { "false", REQUEST_TTY_NO },
! 601: { "no", REQUEST_TTY_NO },
! 602: { "force", REQUEST_TTY_FORCE },
! 603: { "auto", REQUEST_TTY_AUTO },
! 604: { NULL, -1 }
! 605: };
! 606:
1.19 markus 607: /*
608: * Processes a single option line as used in the configuration files. This
609: * only sets those values that have not already been set.
610: */
1.102 markus 611: #define WHITESPACE " \t\r\n"
1.14 markus 612: int
1.206 djm 613: process_config_line(Options *options, struct passwd *pw, const char *host,
614: char *line, const char *filename, int linenum, int *activep, int userconfig)
1.1 deraadt 615: {
1.193 djm 616: char *s, **charptr, *endofnumber, *keyword, *arg, *arg2;
617: char **cpptr, fwdarg[256];
1.199 djm 618: u_int i, *uintptr, max_entries = 0;
1.206 djm 619: int negated, opcode, *intptr, value, value2, cmdline = 0;
1.164 dtucker 620: LogLevel *log_level_ptr;
1.201 dtucker 621: long long val64;
1.102 markus 622: size_t len;
1.135 djm 623: Forward fwd;
1.207 ! djm 624: const struct multistate *multistate_ptr;
1.106 djm 625:
1.206 djm 626: if (activep == NULL) { /* We are processing a command line directive */
627: cmdline = 1;
628: activep = &cmdline;
629: }
630:
1.106 djm 631: /* Strip trailing whitespace */
1.139 deraadt 632: for (len = strlen(line) - 1; len > 0; len--) {
1.106 djm 633: if (strchr(WHITESPACE, line[len]) == NULL)
634: break;
635: line[len] = '\0';
636: }
1.1 deraadt 637:
1.42 provos 638: s = line;
639: /* Get the keyword. (Each line is supposed to begin with a keyword). */
1.149 djm 640: if ((keyword = strdelim(&s)) == NULL)
641: return 0;
1.42 provos 642: /* Ignore leading whitespace. */
643: if (*keyword == '\0')
1.43 markus 644: keyword = strdelim(&s);
1.56 deraadt 645: if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
1.17 markus 646: return 0;
1.199 djm 647: /* Match lowercase keyword */
1.207 ! djm 648: lowercase(keyword);
1.17 markus 649:
1.199 djm 650: opcode = parse_token(keyword, filename, linenum,
651: options->ignored_unknown);
1.17 markus 652:
653: switch (opcode) {
654: case oBadOption:
1.19 markus 655: /* don't panic, but count bad options */
656: return -1;
1.17 markus 657: /* NOTREACHED */
1.199 djm 658: case oIgnoredUnknownOption:
659: debug("%s line %d: Ignored unknown option \"%s\"",
660: filename, linenum, keyword);
661: return 0;
1.111 djm 662: case oConnectTimeout:
663: intptr = &options->connection_timeout;
1.127 markus 664: parse_time:
1.111 djm 665: arg = strdelim(&s);
666: if (!arg || *arg == '\0')
667: fatal("%s line %d: missing time value.",
668: filename, linenum);
669: if ((value = convtime(arg)) == -1)
670: fatal("%s line %d: invalid time value.",
671: filename, linenum);
1.160 dtucker 672: if (*activep && *intptr == -1)
1.111 djm 673: *intptr = value;
674: break;
675:
1.17 markus 676: case oForwardAgent:
677: intptr = &options->forward_agent;
1.207 ! djm 678: parse_flag:
! 679: multistate_ptr = multistate_flag;
! 680: parse_multistate:
1.42 provos 681: arg = strdelim(&s);
1.40 ho 682: if (!arg || *arg == '\0')
1.207 ! djm 683: fatal("%s line %d: missing argument.",
! 684: filename, linenum);
! 685: value = -1;
! 686: for (i = 0; multistate_ptr[i].key != NULL; i++) {
! 687: if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
! 688: value = multistate_ptr[i].value;
! 689: break;
! 690: }
! 691: }
! 692: if (value == -1)
! 693: fatal("%s line %d: unsupported option \"%s\".",
! 694: filename, linenum, arg);
1.17 markus 695: if (*activep && *intptr == -1)
696: *intptr = value;
697: break;
698:
699: case oForwardX11:
700: intptr = &options->forward_x11;
701: goto parse_flag;
702:
1.123 markus 703: case oForwardX11Trusted:
704: intptr = &options->forward_x11_trusted;
705: goto parse_flag;
1.186 djm 706:
707: case oForwardX11Timeout:
708: intptr = &options->forward_x11_timeout;
709: goto parse_time;
1.123 markus 710:
1.17 markus 711: case oGatewayPorts:
712: intptr = &options->gateway_ports;
713: goto parse_flag;
714:
1.153 markus 715: case oExitOnForwardFailure:
716: intptr = &options->exit_on_forward_failure;
717: goto parse_flag;
718:
1.17 markus 719: case oUsePrivilegedPort:
720: intptr = &options->use_privileged_port;
721: goto parse_flag;
722:
723: case oPasswordAuthentication:
724: intptr = &options->password_authentication;
725: goto parse_flag;
726:
1.171 djm 727: case oZeroKnowledgePasswordAuthentication:
728: intptr = &options->zero_knowledge_password_authentication;
729: goto parse_flag;
730:
1.48 markus 731: case oKbdInteractiveAuthentication:
732: intptr = &options->kbd_interactive_authentication;
733: goto parse_flag;
734:
735: case oKbdInteractiveDevices:
736: charptr = &options->kbd_interactive_devices;
737: goto parse_string;
738:
1.50 markus 739: case oPubkeyAuthentication:
740: intptr = &options->pubkey_authentication;
1.30 markus 741: goto parse_flag;
742:
1.17 markus 743: case oRSAAuthentication:
744: intptr = &options->rsa_authentication;
745: goto parse_flag;
746:
747: case oRhostsRSAAuthentication:
748: intptr = &options->rhosts_rsa_authentication;
749: goto parse_flag;
750:
1.72 markus 751: case oHostbasedAuthentication:
752: intptr = &options->hostbased_authentication;
753: goto parse_flag;
754:
1.59 markus 755: case oChallengeResponseAuthentication:
1.78 markus 756: intptr = &options->challenge_response_authentication;
1.17 markus 757: goto parse_flag;
1.108 jakob 758:
1.118 markus 759: case oGssAuthentication:
760: intptr = &options->gss_authentication;
761: goto parse_flag;
762:
763: case oGssDelegateCreds:
764: intptr = &options->gss_deleg_creds;
765: goto parse_flag;
766:
1.17 markus 767: case oBatchMode:
768: intptr = &options->batch_mode;
769: goto parse_flag;
770:
771: case oCheckHostIP:
772: intptr = &options->check_host_ip;
1.167 grunk 773: goto parse_flag;
1.17 markus 774:
1.107 jakob 775: case oVerifyHostKeyDNS:
776: intptr = &options->verify_host_key_dns;
1.207 ! djm 777: multistate_ptr = multistate_yesnoask;
! 778: goto parse_multistate;
1.107 jakob 779:
1.17 markus 780: case oStrictHostKeyChecking:
781: intptr = &options->strict_host_key_checking;
1.207 ! djm 782: multistate_ptr = multistate_yesnoask;
! 783: goto parse_multistate;
1.17 markus 784:
785: case oCompression:
786: intptr = &options->compression;
787: goto parse_flag;
788:
1.126 markus 789: case oTCPKeepAlive:
790: intptr = &options->tcp_keep_alive;
1.17 markus 791: goto parse_flag;
792:
1.91 markus 793: case oNoHostAuthenticationForLocalhost:
794: intptr = &options->no_host_authentication_for_localhost;
795: goto parse_flag;
796:
1.17 markus 797: case oNumberOfPasswordPrompts:
798: intptr = &options->number_of_password_prompts;
799: goto parse_int;
800:
801: case oCompressionLevel:
802: intptr = &options->compression_level;
803: goto parse_int;
804:
1.105 markus 805: case oRekeyLimit:
806: arg = strdelim(&s);
807: if (!arg || *arg == '\0')
1.198 dtucker 808: fatal("%.200s line %d: Missing argument.", filename,
809: linenum);
810: if (strcmp(arg, "default") == 0) {
811: val64 = 0;
812: } else {
1.200 dtucker 813: if (scan_scaled(arg, &val64) == -1)
814: fatal("%.200s line %d: Bad number '%s': %s",
815: filename, linenum, arg, strerror(errno));
816: /* check for too-large or too-small limits */
817: if (val64 > UINT_MAX)
1.198 dtucker 818: fatal("%.200s line %d: RekeyLimit too large",
819: filename, linenum);
820: if (val64 != 0 && val64 < 16)
821: fatal("%.200s line %d: RekeyLimit too small",
822: filename, linenum);
1.105 markus 823: }
1.165 djm 824: if (*activep && options->rekey_limit == -1)
825: options->rekey_limit = (u_int32_t)val64;
1.198 dtucker 826: if (s != NULL) { /* optional rekey interval present */
827: if (strcmp(s, "none") == 0) {
828: (void)strdelim(&s); /* discard */
829: break;
830: }
831: intptr = &options->rekey_interval;
832: goto parse_time;
833: }
1.105 markus 834: break;
835:
1.17 markus 836: case oIdentityFile:
1.42 provos 837: arg = strdelim(&s);
1.40 ho 838: if (!arg || *arg == '\0')
1.17 markus 839: fatal("%.200s line %d: Missing argument.", filename, linenum);
840: if (*activep) {
1.50 markus 841: intptr = &options->num_identity_files;
1.27 markus 842: if (*intptr >= SSH_MAX_IDENTITY_FILES)
1.17 markus 843: fatal("%.200s line %d: Too many identity files specified (max %d).",
1.93 deraadt 844: filename, linenum, SSH_MAX_IDENTITY_FILES);
1.196 dtucker 845: add_identity_file(options, NULL, arg, userconfig);
1.17 markus 846: }
847: break;
848:
1.34 markus 849: case oXAuthLocation:
850: charptr=&options->xauth_location;
851: goto parse_string;
852:
1.17 markus 853: case oUser:
854: charptr = &options->user;
855: parse_string:
1.42 provos 856: arg = strdelim(&s);
1.40 ho 857: if (!arg || *arg == '\0')
1.193 djm 858: fatal("%.200s line %d: Missing argument.",
859: filename, linenum);
1.17 markus 860: if (*activep && *charptr == NULL)
1.38 provos 861: *charptr = xstrdup(arg);
1.17 markus 862: break;
863:
864: case oGlobalKnownHostsFile:
1.193 djm 865: cpptr = (char **)&options->system_hostfiles;
866: uintptr = &options->num_system_hostfiles;
867: max_entries = SSH_MAX_HOSTS_FILES;
868: parse_char_array:
869: if (*activep && *uintptr == 0) {
870: while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
871: if ((*uintptr) >= max_entries)
872: fatal("%s line %d: "
873: "too many authorized keys files.",
874: filename, linenum);
875: cpptr[(*uintptr)++] = xstrdup(arg);
876: }
877: }
878: return 0;
1.17 markus 879:
880: case oUserKnownHostsFile:
1.193 djm 881: cpptr = (char **)&options->user_hostfiles;
882: uintptr = &options->num_user_hostfiles;
883: max_entries = SSH_MAX_HOSTS_FILES;
884: goto parse_char_array;
1.27 markus 885:
1.17 markus 886: case oHostName:
887: charptr = &options->hostname;
888: goto parse_string;
889:
1.52 markus 890: case oHostKeyAlias:
891: charptr = &options->host_key_alias;
892: goto parse_string;
893:
1.67 markus 894: case oPreferredAuthentications:
895: charptr = &options->preferred_authentications;
896: goto parse_string;
897:
1.77 markus 898: case oBindAddress:
899: charptr = &options->bind_address;
900: goto parse_string;
901:
1.183 markus 902: case oPKCS11Provider:
903: charptr = &options->pkcs11_provider;
1.86 markus 904: goto parse_string;
1.85 jakob 905:
1.17 markus 906: case oProxyCommand:
1.144 reyk 907: charptr = &options->proxy_command;
908: parse_command:
1.113 markus 909: if (s == NULL)
910: fatal("%.200s line %d: Missing argument.", filename, linenum);
1.102 markus 911: len = strspn(s, WHITESPACE "=");
1.17 markus 912: if (*activep && *charptr == NULL)
1.102 markus 913: *charptr = xstrdup(s + len);
1.17 markus 914: return 0;
915:
916: case oPort:
917: intptr = &options->port;
918: parse_int:
1.42 provos 919: arg = strdelim(&s);
1.40 ho 920: if (!arg || *arg == '\0')
1.17 markus 921: fatal("%.200s line %d: Missing argument.", filename, linenum);
1.38 provos 922: if (arg[0] < '0' || arg[0] > '9')
1.17 markus 923: fatal("%.200s line %d: Bad number.", filename, linenum);
1.21 markus 924:
925: /* Octal, decimal, or hex format? */
1.38 provos 926: value = strtol(arg, &endofnumber, 0);
927: if (arg == endofnumber)
1.21 markus 928: fatal("%.200s line %d: Bad number.", filename, linenum);
1.17 markus 929: if (*activep && *intptr == -1)
930: *intptr = value;
931: break;
932:
933: case oConnectionAttempts:
934: intptr = &options->connection_attempts;
935: goto parse_int;
936:
937: case oCipher:
938: intptr = &options->cipher;
1.42 provos 939: arg = strdelim(&s);
1.40 ho 940: if (!arg || *arg == '\0')
1.32 markus 941: fatal("%.200s line %d: Missing argument.", filename, linenum);
1.38 provos 942: value = cipher_number(arg);
1.17 markus 943: if (value == -1)
944: fatal("%.200s line %d: Bad cipher '%s'.",
1.93 deraadt 945: filename, linenum, arg ? arg : "<NONE>");
1.17 markus 946: if (*activep && *intptr == -1)
947: *intptr = value;
948: break;
949:
1.25 markus 950: case oCiphers:
1.42 provos 951: arg = strdelim(&s);
1.40 ho 952: if (!arg || *arg == '\0')
1.32 markus 953: fatal("%.200s line %d: Missing argument.", filename, linenum);
1.38 provos 954: if (!ciphers_valid(arg))
1.31 markus 955: fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
1.93 deraadt 956: filename, linenum, arg ? arg : "<NONE>");
1.25 markus 957: if (*activep && options->ciphers == NULL)
1.38 provos 958: options->ciphers = xstrdup(arg);
1.25 markus 959: break;
960:
1.62 markus 961: case oMacs:
962: arg = strdelim(&s);
963: if (!arg || *arg == '\0')
964: fatal("%.200s line %d: Missing argument.", filename, linenum);
965: if (!mac_valid(arg))
966: fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
1.93 deraadt 967: filename, linenum, arg ? arg : "<NONE>");
1.62 markus 968: if (*activep && options->macs == NULL)
969: options->macs = xstrdup(arg);
970: break;
971:
1.189 djm 972: case oKexAlgorithms:
973: arg = strdelim(&s);
974: if (!arg || *arg == '\0')
975: fatal("%.200s line %d: Missing argument.",
976: filename, linenum);
977: if (!kex_names_valid(arg))
978: fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
979: filename, linenum, arg ? arg : "<NONE>");
980: if (*activep && options->kex_algorithms == NULL)
981: options->kex_algorithms = xstrdup(arg);
982: break;
983:
1.76 markus 984: case oHostKeyAlgorithms:
985: arg = strdelim(&s);
986: if (!arg || *arg == '\0')
987: fatal("%.200s line %d: Missing argument.", filename, linenum);
988: if (!key_names_valid2(arg))
989: fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
1.93 deraadt 990: filename, linenum, arg ? arg : "<NONE>");
1.76 markus 991: if (*activep && options->hostkeyalgorithms == NULL)
992: options->hostkeyalgorithms = xstrdup(arg);
993: break;
994:
1.25 markus 995: case oProtocol:
996: intptr = &options->protocol;
1.42 provos 997: arg = strdelim(&s);
1.40 ho 998: if (!arg || *arg == '\0')
1.32 markus 999: fatal("%.200s line %d: Missing argument.", filename, linenum);
1.38 provos 1000: value = proto_spec(arg);
1.25 markus 1001: if (value == SSH_PROTO_UNKNOWN)
1002: fatal("%.200s line %d: Bad protocol spec '%s'.",
1.93 deraadt 1003: filename, linenum, arg ? arg : "<NONE>");
1.25 markus 1004: if (*activep && *intptr == SSH_PROTO_UNKNOWN)
1005: *intptr = value;
1006: break;
1007:
1.17 markus 1008: case oLogLevel:
1.164 dtucker 1009: log_level_ptr = &options->log_level;
1.42 provos 1010: arg = strdelim(&s);
1.38 provos 1011: value = log_level_number(arg);
1.95 markus 1012: if (value == SYSLOG_LEVEL_NOT_SET)
1.64 millert 1013: fatal("%.200s line %d: unsupported log level '%s'",
1.93 deraadt 1014: filename, linenum, arg ? arg : "<NONE>");
1.164 dtucker 1015: if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
1016: *log_level_ptr = (LogLevel) value;
1.17 markus 1017: break;
1018:
1.88 stevesk 1019: case oLocalForward:
1.17 markus 1020: case oRemoteForward:
1.168 stevesk 1021: case oDynamicForward:
1.42 provos 1022: arg = strdelim(&s);
1.135 djm 1023: if (arg == NULL || *arg == '\0')
1.88 stevesk 1024: fatal("%.200s line %d: Missing port argument.",
1025: filename, linenum);
1.135 djm 1026:
1.168 stevesk 1027: if (opcode == oLocalForward ||
1028: opcode == oRemoteForward) {
1029: arg2 = strdelim(&s);
1030: if (arg2 == NULL || *arg2 == '\0')
1031: fatal("%.200s line %d: Missing target argument.",
1032: filename, linenum);
1.135 djm 1033:
1.168 stevesk 1034: /* construct a string for parse_forward */
1035: snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
1036: } else if (opcode == oDynamicForward) {
1037: strlcpy(fwdarg, arg, sizeof(fwdarg));
1038: }
1039:
1040: if (parse_forward(&fwd, fwdarg,
1.176 djm 1041: opcode == oDynamicForward ? 1 : 0,
1042: opcode == oRemoteForward ? 1 : 0) == 0)
1.88 stevesk 1043: fatal("%.200s line %d: Bad forwarding specification.",
1044: filename, linenum);
1.135 djm 1045:
1.88 stevesk 1046: if (*activep) {
1.168 stevesk 1047: if (opcode == oLocalForward ||
1048: opcode == oDynamicForward)
1.135 djm 1049: add_local_forward(options, &fwd);
1.88 stevesk 1050: else if (opcode == oRemoteForward)
1.135 djm 1051: add_remote_forward(options, &fwd);
1.88 stevesk 1052: }
1.17 markus 1053: break;
1.71 markus 1054:
1.90 stevesk 1055: case oClearAllForwardings:
1056: intptr = &options->clear_forwardings;
1057: goto parse_flag;
1058:
1.17 markus 1059: case oHost:
1.206 djm 1060: if (cmdline)
1061: fatal("Host directive not supported as a command-line "
1062: "option");
1.17 markus 1063: *activep = 0;
1.191 djm 1064: arg2 = NULL;
1065: while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1066: negated = *arg == '!';
1067: if (negated)
1068: arg++;
1.38 provos 1069: if (match_pattern(host, arg)) {
1.191 djm 1070: if (negated) {
1071: debug("%.200s line %d: Skipping Host "
1072: "block because of negated match "
1073: "for %.100s", filename, linenum,
1074: arg);
1075: *activep = 0;
1076: break;
1077: }
1078: if (!*activep)
1079: arg2 = arg; /* logged below */
1.17 markus 1080: *activep = 1;
1081: }
1.191 djm 1082: }
1083: if (*activep)
1084: debug("%.200s line %d: Applying options for %.100s",
1085: filename, linenum, arg2);
1.42 provos 1086: /* Avoid garbage check below, as strdelim is done. */
1.17 markus 1087: return 0;
1088:
1.206 djm 1089: case oMatch:
1090: if (cmdline)
1091: fatal("Host directive not supported as a command-line "
1092: "option");
1093: value = match_cfg_line(options, &s, pw, host,
1094: filename, linenum);
1095: if (value < 0)
1096: fatal("%.200s line %d: Bad Match condition", filename,
1097: linenum);
1098: *activep = value;
1099: break;
1100:
1.17 markus 1101: case oEscapeChar:
1102: intptr = &options->escape_char;
1.42 provos 1103: arg = strdelim(&s);
1.40 ho 1104: if (!arg || *arg == '\0')
1.17 markus 1105: fatal("%.200s line %d: Missing argument.", filename, linenum);
1.38 provos 1106: if (arg[0] == '^' && arg[2] == 0 &&
1.51 markus 1107: (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
1108: value = (u_char) arg[1] & 31;
1.38 provos 1109: else if (strlen(arg) == 1)
1.51 markus 1110: value = (u_char) arg[0];
1.38 provos 1111: else if (strcmp(arg, "none") == 0)
1.79 stevesk 1112: value = SSH_ESCAPECHAR_NONE;
1.17 markus 1113: else {
1114: fatal("%.200s line %d: Bad escape character.",
1.93 deraadt 1115: filename, linenum);
1.17 markus 1116: /* NOTREACHED */
1117: value = 0; /* Avoid compiler warning. */
1118: }
1119: if (*activep && *intptr == -1)
1120: *intptr = value;
1.112 djm 1121: break;
1122:
1123: case oAddressFamily:
1.114 djm 1124: intptr = &options->address_family;
1.207 ! djm 1125: multistate_ptr = multistate_addressfamily;
! 1126: goto parse_multistate;
1.17 markus 1127:
1.101 markus 1128: case oEnableSSHKeysign:
1129: intptr = &options->enable_ssh_keysign;
1130: goto parse_flag;
1131:
1.128 markus 1132: case oIdentitiesOnly:
1133: intptr = &options->identities_only;
1134: goto parse_flag;
1135:
1.127 markus 1136: case oServerAliveInterval:
1137: intptr = &options->server_alive_interval;
1138: goto parse_time;
1139:
1140: case oServerAliveCountMax:
1141: intptr = &options->server_alive_count_max;
1142: goto parse_int;
1143:
1.130 djm 1144: case oSendEnv:
1145: while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1146: if (strchr(arg, '=') != NULL)
1147: fatal("%s line %d: Invalid environment name.",
1148: filename, linenum);
1.137 djm 1149: if (!*activep)
1150: continue;
1.130 djm 1151: if (options->num_send_env >= MAX_SEND_ENV)
1152: fatal("%s line %d: too many send env.",
1153: filename, linenum);
1154: options->send_env[options->num_send_env++] =
1155: xstrdup(arg);
1156: }
1157: break;
1158:
1.132 djm 1159: case oControlPath:
1160: charptr = &options->control_path;
1161: goto parse_string;
1162:
1163: case oControlMaster:
1164: intptr = &options->control_master;
1.207 ! djm 1165: multistate_ptr = multistate_controlmaster;
! 1166: goto parse_multistate;
1.132 djm 1167:
1.187 djm 1168: case oControlPersist:
1169: /* no/false/yes/true, or a time spec */
1170: intptr = &options->control_persist;
1171: arg = strdelim(&s);
1172: if (!arg || *arg == '\0')
1173: fatal("%.200s line %d: Missing ControlPersist"
1174: " argument.", filename, linenum);
1175: value = 0;
1176: value2 = 0; /* timeout */
1177: if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
1178: value = 0;
1179: else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
1180: value = 1;
1181: else if ((value2 = convtime(arg)) >= 0)
1182: value = 1;
1183: else
1184: fatal("%.200s line %d: Bad ControlPersist argument.",
1185: filename, linenum);
1186: if (*activep && *intptr == -1) {
1187: *intptr = value;
1188: options->control_persist_timeout = value2;
1189: }
1190: break;
1191:
1.136 djm 1192: case oHashKnownHosts:
1193: intptr = &options->hash_known_hosts;
1194: goto parse_flag;
1195:
1.144 reyk 1196: case oTunnel:
1197: intptr = &options->tun_open;
1.207 ! djm 1198: multistate_ptr = multistate_tunnel;
! 1199: goto parse_multistate;
1.144 reyk 1200:
1201: case oTunnelDevice:
1202: arg = strdelim(&s);
1203: if (!arg || *arg == '\0')
1204: fatal("%.200s line %d: Missing argument.", filename, linenum);
1205: value = a2tun(arg, &value2);
1.145 reyk 1206: if (value == SSH_TUNID_ERR)
1.144 reyk 1207: fatal("%.200s line %d: Bad tun device.", filename, linenum);
1208: if (*activep) {
1209: options->tun_local = value;
1210: options->tun_remote = value2;
1211: }
1212: break;
1213:
1214: case oLocalCommand:
1215: charptr = &options->local_command;
1216: goto parse_command;
1217:
1218: case oPermitLocalCommand:
1219: intptr = &options->permit_local_command;
1220: goto parse_flag;
1221:
1.167 grunk 1222: case oVisualHostKey:
1223: intptr = &options->visual_host_key;
1224: goto parse_flag;
1225:
1.190 djm 1226: case oIPQoS:
1227: arg = strdelim(&s);
1228: if ((value = parse_ipqos(arg)) == -1)
1229: fatal("%s line %d: Bad IPQoS value: %s",
1230: filename, linenum, arg);
1231: arg = strdelim(&s);
1232: if (arg == NULL)
1233: value2 = value;
1234: else if ((value2 = parse_ipqos(arg)) == -1)
1235: fatal("%s line %d: Bad IPQoS value: %s",
1236: filename, linenum, arg);
1237: if (*activep) {
1238: options->ip_qos_interactive = value;
1239: options->ip_qos_bulk = value2;
1240: }
1241: break;
1242:
1.177 andreas 1243: case oUseRoaming:
1244: intptr = &options->use_roaming;
1245: goto parse_flag;
1246:
1.192 djm 1247: case oRequestTTY:
1248: intptr = &options->request_tty;
1.207 ! djm 1249: multistate_ptr = multistate_requesttty;
! 1250: goto parse_multistate;
1.192 djm 1251:
1.199 djm 1252: case oIgnoreUnknown:
1253: charptr = &options->ignored_unknown;
1254: goto parse_string;
1255:
1.205 djm 1256: case oProxyUseFdpass:
1257: intptr = &options->proxy_use_fdpass;
1258: goto parse_flag;
1259:
1.96 markus 1260: case oDeprecated:
1.98 markus 1261: debug("%s line %d: Deprecated option \"%s\"",
1.96 markus 1262: filename, linenum, keyword);
1.98 markus 1263: return 0;
1.96 markus 1264:
1.110 jakob 1265: case oUnsupported:
1266: error("%s line %d: Unsupported option \"%s\"",
1267: filename, linenum, keyword);
1268: return 0;
1269:
1.17 markus 1270: default:
1271: fatal("process_config_line: Unimplemented opcode %d", opcode);
1272: }
1273:
1274: /* Check that there is no garbage at end of line. */
1.57 djm 1275: if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1.39 ho 1276: fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
1.142 djm 1277: filename, linenum, arg);
1.39 ho 1278: }
1.17 markus 1279: return 0;
1.1 deraadt 1280: }
1281:
1282:
1.19 markus 1283: /*
1284: * Reads the config file and modifies the options accordingly. Options
1285: * should already be initialized before this call. This never returns if
1.89 stevesk 1286: * there is an error. If the file does not exist, this returns 0.
1.19 markus 1287: */
1.1 deraadt 1288:
1.89 stevesk 1289: int
1.206 djm 1290: read_config_file(const char *filename, struct passwd *pw, const char *host,
1291: Options *options, int flags)
1.1 deraadt 1292: {
1.17 markus 1293: FILE *f;
1294: char line[1024];
1295: int active, linenum;
1296: int bad_options = 0;
1297:
1.129 djm 1298: if ((f = fopen(filename, "r")) == NULL)
1.89 stevesk 1299: return 0;
1.129 djm 1300:
1.196 dtucker 1301: if (flags & SSHCONF_CHECKPERM) {
1.129 djm 1302: struct stat sb;
1.134 deraadt 1303:
1.131 dtucker 1304: if (fstat(fileno(f), &sb) == -1)
1.129 djm 1305: fatal("fstat %s: %s", filename, strerror(errno));
1306: if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
1.131 dtucker 1307: (sb.st_mode & 022) != 0))
1.129 djm 1308: fatal("Bad owner or permissions on %s", filename);
1309: }
1.17 markus 1310:
1311: debug("Reading configuration data %.200s", filename);
1312:
1.19 markus 1313: /*
1314: * Mark that we are now processing the options. This flag is turned
1315: * on/off by Host specifications.
1316: */
1.17 markus 1317: active = 1;
1318: linenum = 0;
1319: while (fgets(line, sizeof(line), f)) {
1320: /* Update line number counter. */
1321: linenum++;
1.206 djm 1322: if (process_config_line(options, pw, host, line, filename,
1323: linenum, &active, flags & SSHCONF_USERCONF) != 0)
1.17 markus 1324: bad_options++;
1325: }
1326: fclose(f);
1327: if (bad_options > 0)
1.64 millert 1328: fatal("%s: terminating, %d bad configuration options",
1.93 deraadt 1329: filename, bad_options);
1.89 stevesk 1330: return 1;
1.1 deraadt 1331: }
1332:
1.19 markus 1333: /*
1334: * Initializes options to special values that indicate that they have not yet
1335: * been set. Read_config_file will only set options with this value. Options
1336: * are processed in the following order: command line, user config file,
1337: * system config file. Last, fill_default_options is called.
1338: */
1.1 deraadt 1339:
1.26 markus 1340: void
1.17 markus 1341: initialize_options(Options * options)
1.1 deraadt 1342: {
1.17 markus 1343: memset(options, 'X', sizeof(*options));
1344: options->forward_agent = -1;
1345: options->forward_x11 = -1;
1.123 markus 1346: options->forward_x11_trusted = -1;
1.186 djm 1347: options->forward_x11_timeout = -1;
1.153 markus 1348: options->exit_on_forward_failure = -1;
1.34 markus 1349: options->xauth_location = NULL;
1.17 markus 1350: options->gateway_ports = -1;
1351: options->use_privileged_port = -1;
1352: options->rsa_authentication = -1;
1.50 markus 1353: options->pubkey_authentication = -1;
1.78 markus 1354: options->challenge_response_authentication = -1;
1.118 markus 1355: options->gss_authentication = -1;
1356: options->gss_deleg_creds = -1;
1.17 markus 1357: options->password_authentication = -1;
1.48 markus 1358: options->kbd_interactive_authentication = -1;
1359: options->kbd_interactive_devices = NULL;
1.17 markus 1360: options->rhosts_rsa_authentication = -1;
1.72 markus 1361: options->hostbased_authentication = -1;
1.17 markus 1362: options->batch_mode = -1;
1363: options->check_host_ip = -1;
1364: options->strict_host_key_checking = -1;
1365: options->compression = -1;
1.126 markus 1366: options->tcp_keep_alive = -1;
1.17 markus 1367: options->compression_level = -1;
1368: options->port = -1;
1.114 djm 1369: options->address_family = -1;
1.17 markus 1370: options->connection_attempts = -1;
1.111 djm 1371: options->connection_timeout = -1;
1.17 markus 1372: options->number_of_password_prompts = -1;
1373: options->cipher = -1;
1.25 markus 1374: options->ciphers = NULL;
1.62 markus 1375: options->macs = NULL;
1.189 djm 1376: options->kex_algorithms = NULL;
1.76 markus 1377: options->hostkeyalgorithms = NULL;
1.25 markus 1378: options->protocol = SSH_PROTO_UNKNOWN;
1.17 markus 1379: options->num_identity_files = 0;
1380: options->hostname = NULL;
1.52 markus 1381: options->host_key_alias = NULL;
1.17 markus 1382: options->proxy_command = NULL;
1383: options->user = NULL;
1384: options->escape_char = -1;
1.193 djm 1385: options->num_system_hostfiles = 0;
1386: options->num_user_hostfiles = 0;
1.185 djm 1387: options->local_forwards = NULL;
1.17 markus 1388: options->num_local_forwards = 0;
1.185 djm 1389: options->remote_forwards = NULL;
1.17 markus 1390: options->num_remote_forwards = 0;
1.90 stevesk 1391: options->clear_forwardings = -1;
1.95 markus 1392: options->log_level = SYSLOG_LEVEL_NOT_SET;
1.67 markus 1393: options->preferred_authentications = NULL;
1.77 markus 1394: options->bind_address = NULL;
1.183 markus 1395: options->pkcs11_provider = NULL;
1.101 markus 1396: options->enable_ssh_keysign = - 1;
1.91 markus 1397: options->no_host_authentication_for_localhost = - 1;
1.128 markus 1398: options->identities_only = - 1;
1.105 markus 1399: options->rekey_limit = - 1;
1.198 dtucker 1400: options->rekey_interval = -1;
1.107 jakob 1401: options->verify_host_key_dns = -1;
1.127 markus 1402: options->server_alive_interval = -1;
1403: options->server_alive_count_max = -1;
1.130 djm 1404: options->num_send_env = 0;
1.132 djm 1405: options->control_path = NULL;
1406: options->control_master = -1;
1.187 djm 1407: options->control_persist = -1;
1408: options->control_persist_timeout = 0;
1.136 djm 1409: options->hash_known_hosts = -1;
1.144 reyk 1410: options->tun_open = -1;
1411: options->tun_local = -1;
1412: options->tun_remote = -1;
1413: options->local_command = NULL;
1414: options->permit_local_command = -1;
1.177 andreas 1415: options->use_roaming = -1;
1.167 grunk 1416: options->visual_host_key = -1;
1.171 djm 1417: options->zero_knowledge_password_authentication = -1;
1.190 djm 1418: options->ip_qos_interactive = -1;
1419: options->ip_qos_bulk = -1;
1.192 djm 1420: options->request_tty = -1;
1.205 djm 1421: options->proxy_use_fdpass = -1;
1.199 djm 1422: options->ignored_unknown = NULL;
1.1 deraadt 1423: }
1424:
1.19 markus 1425: /*
1426: * Called after processing other sources of option data, this fills those
1427: * options for which no value has been specified with their default values.
1428: */
1.1 deraadt 1429:
1.26 markus 1430: void
1.17 markus 1431: fill_default_options(Options * options)
1.1 deraadt 1432: {
1.17 markus 1433: if (options->forward_agent == -1)
1.33 markus 1434: options->forward_agent = 0;
1.17 markus 1435: if (options->forward_x11 == -1)
1.23 markus 1436: options->forward_x11 = 0;
1.123 markus 1437: if (options->forward_x11_trusted == -1)
1438: options->forward_x11_trusted = 0;
1.186 djm 1439: if (options->forward_x11_timeout == -1)
1440: options->forward_x11_timeout = 1200;
1.153 markus 1441: if (options->exit_on_forward_failure == -1)
1442: options->exit_on_forward_failure = 0;
1.34 markus 1443: if (options->xauth_location == NULL)
1.80 markus 1444: options->xauth_location = _PATH_XAUTH;
1.17 markus 1445: if (options->gateway_ports == -1)
1446: options->gateway_ports = 0;
1447: if (options->use_privileged_port == -1)
1.65 markus 1448: options->use_privileged_port = 0;
1.17 markus 1449: if (options->rsa_authentication == -1)
1450: options->rsa_authentication = 1;
1.50 markus 1451: if (options->pubkey_authentication == -1)
1452: options->pubkey_authentication = 1;
1.78 markus 1453: if (options->challenge_response_authentication == -1)
1.83 markus 1454: options->challenge_response_authentication = 1;
1.118 markus 1455: if (options->gss_authentication == -1)
1.122 markus 1456: options->gss_authentication = 0;
1.118 markus 1457: if (options->gss_deleg_creds == -1)
1458: options->gss_deleg_creds = 0;
1.17 markus 1459: if (options->password_authentication == -1)
1460: options->password_authentication = 1;
1.48 markus 1461: if (options->kbd_interactive_authentication == -1)
1.59 markus 1462: options->kbd_interactive_authentication = 1;
1.17 markus 1463: if (options->rhosts_rsa_authentication == -1)
1.99 stevesk 1464: options->rhosts_rsa_authentication = 0;
1.72 markus 1465: if (options->hostbased_authentication == -1)
1466: options->hostbased_authentication = 0;
1.17 markus 1467: if (options->batch_mode == -1)
1468: options->batch_mode = 0;
1469: if (options->check_host_ip == -1)
1470: options->check_host_ip = 1;
1471: if (options->strict_host_key_checking == -1)
1472: options->strict_host_key_checking = 2; /* 2 is default */
1473: if (options->compression == -1)
1474: options->compression = 0;
1.126 markus 1475: if (options->tcp_keep_alive == -1)
1476: options->tcp_keep_alive = 1;
1.17 markus 1477: if (options->compression_level == -1)
1478: options->compression_level = 6;
1479: if (options->port == -1)
1480: options->port = 0; /* Filled in ssh_connect. */
1.114 djm 1481: if (options->address_family == -1)
1482: options->address_family = AF_UNSPEC;
1.17 markus 1483: if (options->connection_attempts == -1)
1.84 markus 1484: options->connection_attempts = 1;
1.17 markus 1485: if (options->number_of_password_prompts == -1)
1486: options->number_of_password_prompts = 3;
1487: /* Selected in ssh_login(). */
1488: if (options->cipher == -1)
1489: options->cipher = SSH_CIPHER_NOT_SET;
1.31 markus 1490: /* options->ciphers, default set in myproposals.h */
1.62 markus 1491: /* options->macs, default set in myproposals.h */
1.189 djm 1492: /* options->kex_algorithms, default set in myproposals.h */
1.76 markus 1493: /* options->hostkeyalgorithms, default set in myproposals.h */
1.25 markus 1494: if (options->protocol == SSH_PROTO_UNKNOWN)
1.178 markus 1495: options->protocol = SSH_PROTO_2;
1.17 markus 1496: if (options->num_identity_files == 0) {
1.50 markus 1497: if (options->protocol & SSH_PROTO_1) {
1.195 dtucker 1498: add_identity_file(options, "~/",
1499: _PATH_SSH_CLIENT_IDENTITY, 0);
1.50 markus 1500: }
1501: if (options->protocol & SSH_PROTO_2) {
1.195 dtucker 1502: add_identity_file(options, "~/",
1503: _PATH_SSH_CLIENT_ID_RSA, 0);
1504: add_identity_file(options, "~/",
1505: _PATH_SSH_CLIENT_ID_DSA, 0);
1506: add_identity_file(options, "~/",
1507: _PATH_SSH_CLIENT_ID_ECDSA, 0);
1.50 markus 1508: }
1.27 markus 1509: }
1.17 markus 1510: if (options->escape_char == -1)
1511: options->escape_char = '~';
1.193 djm 1512: if (options->num_system_hostfiles == 0) {
1513: options->system_hostfiles[options->num_system_hostfiles++] =
1514: xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
1515: options->system_hostfiles[options->num_system_hostfiles++] =
1516: xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
1517: }
1518: if (options->num_user_hostfiles == 0) {
1519: options->user_hostfiles[options->num_user_hostfiles++] =
1520: xstrdup(_PATH_SSH_USER_HOSTFILE);
1521: options->user_hostfiles[options->num_user_hostfiles++] =
1522: xstrdup(_PATH_SSH_USER_HOSTFILE2);
1523: }
1.95 markus 1524: if (options->log_level == SYSLOG_LEVEL_NOT_SET)
1.54 markus 1525: options->log_level = SYSLOG_LEVEL_INFO;
1.90 stevesk 1526: if (options->clear_forwardings == 1)
1527: clear_forwardings(options);
1.91 markus 1528: if (options->no_host_authentication_for_localhost == - 1)
1529: options->no_host_authentication_for_localhost = 0;
1.128 markus 1530: if (options->identities_only == -1)
1531: options->identities_only = 0;
1.101 markus 1532: if (options->enable_ssh_keysign == -1)
1533: options->enable_ssh_keysign = 0;
1.105 markus 1534: if (options->rekey_limit == -1)
1535: options->rekey_limit = 0;
1.198 dtucker 1536: if (options->rekey_interval == -1)
1537: options->rekey_interval = 0;
1.107 jakob 1538: if (options->verify_host_key_dns == -1)
1539: options->verify_host_key_dns = 0;
1.127 markus 1540: if (options->server_alive_interval == -1)
1541: options->server_alive_interval = 0;
1542: if (options->server_alive_count_max == -1)
1543: options->server_alive_count_max = 3;
1.132 djm 1544: if (options->control_master == -1)
1545: options->control_master = 0;
1.187 djm 1546: if (options->control_persist == -1) {
1547: options->control_persist = 0;
1548: options->control_persist_timeout = 0;
1549: }
1.136 djm 1550: if (options->hash_known_hosts == -1)
1551: options->hash_known_hosts = 0;
1.144 reyk 1552: if (options->tun_open == -1)
1.145 reyk 1553: options->tun_open = SSH_TUNMODE_NO;
1554: if (options->tun_local == -1)
1555: options->tun_local = SSH_TUNID_ANY;
1556: if (options->tun_remote == -1)
1557: options->tun_remote = SSH_TUNID_ANY;
1.144 reyk 1558: if (options->permit_local_command == -1)
1559: options->permit_local_command = 0;
1.177 andreas 1560: if (options->use_roaming == -1)
1561: options->use_roaming = 1;
1.167 grunk 1562: if (options->visual_host_key == -1)
1563: options->visual_host_key = 0;
1.171 djm 1564: if (options->zero_knowledge_password_authentication == -1)
1565: options->zero_knowledge_password_authentication = 0;
1.190 djm 1566: if (options->ip_qos_interactive == -1)
1567: options->ip_qos_interactive = IPTOS_LOWDELAY;
1568: if (options->ip_qos_bulk == -1)
1569: options->ip_qos_bulk = IPTOS_THROUGHPUT;
1.192 djm 1570: if (options->request_tty == -1)
1571: options->request_tty = REQUEST_TTY_AUTO;
1.205 djm 1572: if (options->proxy_use_fdpass == -1)
1573: options->proxy_use_fdpass = 0;
1.207 ! djm 1574: #define CLEAR_ON_NONE(v) \
! 1575: do { \
! 1576: if (v != NULL && strcasecmp(v, "none") == 0) { \
! 1577: free(v); \
! 1578: v = NULL; \
! 1579: } \
! 1580: } while(0)
! 1581: CLEAR_ON_NONE(options->local_command);
! 1582: CLEAR_ON_NONE(options->proxy_command);
! 1583: CLEAR_ON_NONE(options->control_path);
1.17 markus 1584: /* options->user will be set in the main program if appropriate */
1585: /* options->hostname will be set in the main program if appropriate */
1.52 markus 1586: /* options->host_key_alias should not be set by default */
1.67 markus 1587: /* options->preferred_authentications will be set in ssh */
1.135 djm 1588: }
1589:
1590: /*
1591: * parse_forward
1592: * parses a string containing a port forwarding specification of the form:
1.168 stevesk 1593: * dynamicfwd == 0
1.135 djm 1594: * [listenhost:]listenport:connecthost:connectport
1.168 stevesk 1595: * dynamicfwd == 1
1596: * [listenhost:]listenport
1.135 djm 1597: * returns number of arguments parsed or zero on error
1598: */
1599: int
1.176 djm 1600: parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
1.135 djm 1601: {
1602: int i;
1603: char *p, *cp, *fwdarg[4];
1604:
1605: memset(fwd, '\0', sizeof(*fwd));
1606:
1607: cp = p = xstrdup(fwdspec);
1608:
1609: /* skip leading spaces */
1.162 tedu 1610: while (isspace(*cp))
1.135 djm 1611: cp++;
1612:
1613: for (i = 0; i < 4; ++i)
1614: if ((fwdarg[i] = hpdelim(&cp)) == NULL)
1615: break;
1616:
1.170 stevesk 1617: /* Check for trailing garbage */
1.135 djm 1618: if (cp != NULL)
1619: i = 0; /* failure */
1620:
1621: switch (i) {
1.168 stevesk 1622: case 1:
1623: fwd->listen_host = NULL;
1624: fwd->listen_port = a2port(fwdarg[0]);
1625: fwd->connect_host = xstrdup("socks");
1626: break;
1627:
1628: case 2:
1629: fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1630: fwd->listen_port = a2port(fwdarg[1]);
1631: fwd->connect_host = xstrdup("socks");
1632: break;
1633:
1.135 djm 1634: case 3:
1635: fwd->listen_host = NULL;
1636: fwd->listen_port = a2port(fwdarg[0]);
1637: fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
1638: fwd->connect_port = a2port(fwdarg[2]);
1639: break;
1640:
1641: case 4:
1642: fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1643: fwd->listen_port = a2port(fwdarg[1]);
1644: fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
1645: fwd->connect_port = a2port(fwdarg[3]);
1646: break;
1647: default:
1648: i = 0; /* failure */
1649: }
1650:
1.202 djm 1651: free(p);
1.135 djm 1652:
1.168 stevesk 1653: if (dynamicfwd) {
1654: if (!(i == 1 || i == 2))
1655: goto fail_free;
1656: } else {
1657: if (!(i == 3 || i == 4))
1658: goto fail_free;
1.175 djm 1659: if (fwd->connect_port <= 0)
1.168 stevesk 1660: goto fail_free;
1661: }
1662:
1.176 djm 1663: if (fwd->listen_port < 0 || (!remotefwd && fwd->listen_port == 0))
1.135 djm 1664: goto fail_free;
1665:
1666: if (fwd->connect_host != NULL &&
1667: strlen(fwd->connect_host) >= NI_MAXHOST)
1668: goto fail_free;
1.176 djm 1669: if (fwd->listen_host != NULL &&
1670: strlen(fwd->listen_host) >= NI_MAXHOST)
1671: goto fail_free;
1672:
1.135 djm 1673:
1674: return (i);
1675:
1676: fail_free:
1.202 djm 1677: free(fwd->connect_host);
1678: fwd->connect_host = NULL;
1679: free(fwd->listen_host);
1680: fwd->listen_host = NULL;
1.135 djm 1681: return (0);
1.1 deraadt 1682: }