- djm@cvs.openbsd.org 2013/10/14 23:28:23
[canohost.c misc.c misc.h readconf.c sftp-server.c ssh.c]
refactor client config code a little:
add multistate option partsing to readconf.c, similar to servconf.c's
existing code.
move checking of options that accept "none" as an argument to readconf.c
add a lowercase() function and use it instead of explicit tolower() in
loops
part of a larger diff that was ok markus@
diff --git a/readconf.c b/readconf.c
index f7b912e..9340eff 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.c,v 1.206 2013/10/14 22:22:02 djm Exp $ */
+/* $OpenBSD: readconf.c,v 1.207 2013/10/14 23:28:23 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -555,6 +555,61 @@
return oBadOption;
}
+/* Multistate option parsing */
+struct multistate {
+ char *key;
+ int value;
+};
+static const struct multistate multistate_flag[] = {
+ { "true", 1 },
+ { "false", 0 },
+ { "yes", 1 },
+ { "no", 0 },
+ { NULL, -1 }
+};
+static const struct multistate multistate_yesnoask[] = {
+ { "true", 1 },
+ { "false", 0 },
+ { "yes", 1 },
+ { "no", 0 },
+ { "ask", 2 },
+ { NULL, -1 }
+};
+static const struct multistate multistate_addressfamily[] = {
+ { "inet", AF_INET },
+ { "inet6", AF_INET6 },
+ { "any", AF_UNSPEC },
+ { NULL, -1 }
+};
+static const struct multistate multistate_controlmaster[] = {
+ { "true", SSHCTL_MASTER_YES },
+ { "yes", SSHCTL_MASTER_YES },
+ { "false", SSHCTL_MASTER_NO },
+ { "no", SSHCTL_MASTER_NO },
+ { "auto", SSHCTL_MASTER_AUTO },
+ { "ask", SSHCTL_MASTER_ASK },
+ { "autoask", SSHCTL_MASTER_AUTO_ASK },
+ { NULL, -1 }
+};
+static const struct multistate multistate_tunnel[] = {
+ { "ethernet", SSH_TUNMODE_ETHERNET },
+ { "point-to-point", SSH_TUNMODE_POINTOPOINT },
+ { "true", SSH_TUNMODE_DEFAULT },
+ { "yes", SSH_TUNMODE_DEFAULT },
+ { "false", SSH_TUNMODE_NO },
+ { "no", SSH_TUNMODE_NO },
+ { NULL, -1 }
+};
+static const struct multistate multistate_requesttty[] = {
+ { "true", REQUEST_TTY_YES },
+ { "yes", REQUEST_TTY_YES },
+ { "false", REQUEST_TTY_NO },
+ { "no", REQUEST_TTY_NO },
+ { "force", REQUEST_TTY_FORCE },
+ { "auto", REQUEST_TTY_AUTO },
+ { NULL, -1 }
+};
+
/*
* Processes a single option line as used in the configuration files. This
* only sets those values that have not already been set.
@@ -572,6 +627,7 @@
long long val64;
size_t len;
Forward fwd;
+ const struct multistate *multistate_ptr;
if (activep == NULL) { /* We are processing a command line directive */
cmdline = 1;
@@ -595,8 +651,7 @@
if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
return 0;
/* Match lowercase keyword */
- for (i = 0; i < strlen(keyword); i++)
- keyword[i] = tolower(keyword[i]);
+ lowercase(keyword);
opcode = parse_token(keyword, filename, linenum,
options->ignored_unknown);
@@ -626,17 +681,23 @@
case oForwardAgent:
intptr = &options->forward_agent;
-parse_flag:
+ parse_flag:
+ multistate_ptr = multistate_flag;
+ parse_multistate:
arg = strdelim(&s);
if (!arg || *arg == '\0')
- fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
- value = 0; /* To avoid compiler warning... */
- if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
- value = 1;
- else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
- value = 0;
- else
- fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
+ fatal("%s line %d: missing argument.",
+ filename, linenum);
+ value = -1;
+ for (i = 0; multistate_ptr[i].key != NULL; i++) {
+ if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
+ value = multistate_ptr[i].value;
+ break;
+ }
+ }
+ if (value == -1)
+ fatal("%s line %d: unsupported option \"%s\".",
+ filename, linenum, arg);
if (*activep && *intptr == -1)
*intptr = value;
break;
@@ -719,27 +780,13 @@
case oVerifyHostKeyDNS:
intptr = &options->verify_host_key_dns;
- goto parse_yesnoask;
+ multistate_ptr = multistate_yesnoask;
+ goto parse_multistate;
case oStrictHostKeyChecking:
intptr = &options->strict_host_key_checking;
-parse_yesnoask:
- arg = strdelim(&s);
- if (!arg || *arg == '\0')
- fatal("%.200s line %d: Missing yes/no/ask argument.",
- filename, linenum);
- value = 0; /* To avoid compiler warning... */
- if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
- value = 1;
- else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
- value = 0;
- else if (strcmp(arg, "ask") == 0)
- value = 2;
- else
- fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
- if (*activep && *intptr == -1)
- *intptr = value;
- break;
+ multistate_ptr = multistate_yesnoask;
+ goto parse_multistate;
case oCompression:
intptr = &options->compression;
@@ -1080,22 +1127,9 @@
break;
case oAddressFamily:
- arg = strdelim(&s);
- if (!arg || *arg == '\0')
- fatal("%s line %d: missing address family.",
- filename, linenum);
intptr = &options->address_family;
- if (strcasecmp(arg, "inet") == 0)
- value = AF_INET;
- else if (strcasecmp(arg, "inet6") == 0)
- value = AF_INET6;
- else if (strcasecmp(arg, "any") == 0)
- value = AF_UNSPEC;
- else
- fatal("Unsupported AddressFamily \"%s\"", arg);
- if (*activep && *intptr == -1)
- *intptr = value;
- break;
+ multistate_ptr = multistate_addressfamily;
+ goto parse_multistate;
case oEnableSSHKeysign:
intptr = &options->enable_ssh_keysign;
@@ -1134,27 +1168,8 @@
case oControlMaster:
intptr = &options->control_master;
- arg = strdelim(&s);
- if (!arg || *arg == '\0')
- fatal("%.200s line %d: Missing ControlMaster argument.",
- filename, linenum);
- value = 0; /* To avoid compiler warning... */
- if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
- value = SSHCTL_MASTER_YES;
- else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
- value = SSHCTL_MASTER_NO;
- else if (strcmp(arg, "auto") == 0)
- value = SSHCTL_MASTER_AUTO;
- else if (strcmp(arg, "ask") == 0)
- value = SSHCTL_MASTER_ASK;
- else if (strcmp(arg, "autoask") == 0)
- value = SSHCTL_MASTER_AUTO_ASK;
- else
- fatal("%.200s line %d: Bad ControlMaster argument.",
- filename, linenum);
- if (*activep && *intptr == -1)
- *intptr = value;
- break;
+ multistate_ptr = multistate_controlmaster;
+ goto parse_multistate;
case oControlPersist:
/* no/false/yes/true, or a time spec */
@@ -1186,25 +1201,8 @@
case oTunnel:
intptr = &options->tun_open;
- arg = strdelim(&s);
- if (!arg || *arg == '\0')
- fatal("%s line %d: Missing yes/point-to-point/"
- "ethernet/no argument.", filename, linenum);
- value = 0; /* silence compiler */
- if (strcasecmp(arg, "ethernet") == 0)
- value = SSH_TUNMODE_ETHERNET;
- else if (strcasecmp(arg, "point-to-point") == 0)
- value = SSH_TUNMODE_POINTOPOINT;
- else if (strcasecmp(arg, "yes") == 0)
- value = SSH_TUNMODE_DEFAULT;
- else if (strcasecmp(arg, "no") == 0)
- value = SSH_TUNMODE_NO;
- else
- fatal("%s line %d: Bad yes/point-to-point/ethernet/"
- "no argument: %s", filename, linenum, arg);
- if (*activep)
- *intptr = value;
- break;
+ multistate_ptr = multistate_tunnel;
+ goto parse_multistate;
case oTunnelDevice:
arg = strdelim(&s);
@@ -1253,24 +1251,9 @@
goto parse_flag;
case oRequestTTY:
- arg = strdelim(&s);
- if (!arg || *arg == '\0')
- fatal("%s line %d: missing argument.",
- filename, linenum);
intptr = &options->request_tty;
- if (strcasecmp(arg, "yes") == 0)
- value = REQUEST_TTY_YES;
- else if (strcasecmp(arg, "no") == 0)
- value = REQUEST_TTY_NO;
- else if (strcasecmp(arg, "force") == 0)
- value = REQUEST_TTY_FORCE;
- else if (strcasecmp(arg, "auto") == 0)
- value = REQUEST_TTY_AUTO;
- else
- fatal("Unsupported RequestTTY \"%s\"", arg);
- if (*activep && *intptr == -1)
- *intptr = value;
- break;
+ multistate_ptr = multistate_requesttty;
+ goto parse_multistate;
case oIgnoreUnknown:
charptr = &options->ignored_unknown;
@@ -1596,8 +1579,16 @@
options->request_tty = REQUEST_TTY_AUTO;
if (options->proxy_use_fdpass == -1)
options->proxy_use_fdpass = 0;
- /* options->local_command should not be set by default */
- /* options->proxy_command should not be set by default */
+#define CLEAR_ON_NONE(v) \
+ do { \
+ if (v != NULL && strcasecmp(v, "none") == 0) { \
+ free(v); \
+ v = NULL; \
+ } \
+ } while(0)
+ CLEAR_ON_NONE(options->local_command);
+ CLEAR_ON_NONE(options->proxy_command);
+ CLEAR_ON_NONE(options->control_path);
/* options->user will be set in the main program if appropriate */
/* options->hostname will be set in the main program if appropriate */
/* options->host_key_alias should not be set by default */