/* opt_file handles file options */
static ParameterError opt_file(struct OperationConfig *config,
const struct LongShort *a,
- const char *nextarg)
+ const char *nextarg,
+ int max_recursive)
{
ParameterError err = PARAM_OK;
if((nextarg[0] == '-') && nextarg[1]) {
GetFileAndPassword(nextarg, &config->cert, &config->key_passwd);
break;
case C_CONFIG: /* --config */
- if(parseconfig(nextarg)) {
- errorf("cannot read config from '%s'", nextarg);
- err = PARAM_READ_ERROR;
+ if(--max_recursive < 0) {
+ errorf("Max config file recursion level reached (%u)",
+ CONFIG_MAX_LEVELS);
+ err = PARAM_BAD_USE;
+ }
+ else {
+ err = parseconfig(nextarg, max_recursive);
}
break;
case C_CRLFILE: /* --crlfile */
const char *nextarg, /* NULL if unset */
bool *usedarg, /* set to TRUE if the arg
has been used */
- struct OperationConfig *config)
+ struct OperationConfig *config,
+ int max_recursive)
{
const char *parse = NULL;
bool longopt = FALSE;
"Maybe ASCII was intended?", nextarg);
}
if(ARGTYPE(a->desc) == ARG_FILE)
- err = opt_file(config, a, nextarg);
+ err = opt_file(config, a, nextarg, max_recursive);
else /* if(ARGTYPE(a->desc) == ARG_STRG) */
err = opt_string(config, a, nextarg);
if(a->desc & ARG_CLEAR)
}
}
- result = getparameter(orig_opt, nextarg, &passarg, config);
+ result = getparameter(orig_opt, nextarg, &passarg, config,
+ CONFIG_MAX_LEVELS);
unicodefree(nextarg);
config = global->last;
bool used;
/* Just add the URL please */
- result = getparameter("--url", orig_opt, &used, config);
+ result = getparameter("--url", orig_opt, &used, config, 0);
}
if(!result) {
typedef enum {
PARAM_OK = 0,
- PARAM_OPTION_AMBIGUOUS,
PARAM_OPTION_UNKNOWN,
PARAM_REQUIRES_PARAMETER,
PARAM_BAD_USE,
PARAM_EXPAND_ERROR, /* --expand problem */
PARAM_BLANK_STRING,
PARAM_VAR_SYNTAX, /* --variable syntax error */
+ PARAM_RECURSION,
PARAM_LAST
} ParameterError;
ParameterError getparameter(const char *flag, const char *nextarg,
bool *usedarg,
- struct OperationConfig *config);
+ struct OperationConfig *config,
+ int max_recursive);
#ifdef UNITTESTS
void parse_cert_parameter(const char *cert_parameter,
return "had unsupported trailing garbage";
case PARAM_OPTION_UNKNOWN:
return "is unknown";
- case PARAM_OPTION_AMBIGUOUS:
- return "is ambiguous";
case PARAM_REQUIRES_PARAMETER:
return "requires parameter";
case PARAM_BAD_USE:
if((argc == 1) ||
(first_arg && strncmp(first_arg, "-q", 2) &&
strcmp(first_arg, "--disable"))) {
- parseconfig(NULL); /* ignore possible failure */
+ parseconfig(NULL, CONFIG_MAX_LEVELS); /* ignore possible failure */
/* If we had no arguments then make sure a url was specified in .curlrc */
if((argc < 2) && (!global->first->url_list)) {
#define MAX_CONFIG_LINE_LENGTH (10*1024*1024)
/* return 0 on everything-is-fine, and non-zero otherwise */
-int parseconfig(const char *filename)
+ParameterError parseconfig(const char *filename, int max_recursive)
{
FILE *file = NULL;
bool usedarg = FALSE;
- int rc = 0;
+ ParameterError err = PARAM_OK;
struct OperationConfig *config = global->last;
char *pathalloc = NULL;
file = curlx_fopen(curlrc, FOPEN_READTEXT);
if(!file) {
free(curlrc);
- return 1;
+ return PARAM_READ_ERROR;
}
filename = pathalloc = curlrc;
}
curlx_dyn_init(&pbuf, MAX_CONFIG_LINE_LENGTH);
DEBUGASSERT(filename);
- while(!rc && my_get_line(file, &buf, &fileerror)) {
+ while(!err && my_get_line(file, &buf, &fileerror)) {
ParameterError res;
lineno++;
line = curlx_dyn_ptr(&buf);
if(!line) {
- rc = 1; /* out of memory */
+ err = PARAM_NO_MEM; /* out of memory */
break;
}
/* the parameter starts here (unless quoted) */
if(*line == '\"') {
/* quoted parameter, do the quote dance */
- rc = unslashquote(++line, &pbuf);
- if(rc)
+ int rc = unslashquote(++line, &pbuf);
+ if(rc) {
+ err = PARAM_BAD_USE;
break;
+ }
param = curlx_dyn_len(&pbuf) ? curlx_dyn_ptr(&pbuf) : CURL_UNCONST("");
}
else {
#ifdef DEBUG_CONFIG
curl_mfprintf(tool_stderr, "PARAM: \"%s\"\n",(param ? param : "(null)"));
#endif
- res = getparameter(option, param, &usedarg, config);
+ res = getparameter(option, param, &usedarg, config, max_recursive);
config = global->last;
if(!res && param && *param && !usedarg)
res != PARAM_VERSION_INFO_REQUESTED &&
res != PARAM_ENGINES_REQUESTED &&
res != PARAM_CA_EMBED_REQUESTED) {
- const char *reason = param2text(res);
- errorf("%s:%d: '%s' %s",
- filename, lineno, option, reason);
- rc = (int)res;
+ /* only show error in the first level config call */
+ if(max_recursive == CONFIG_MAX_LEVELS) {
+ const char *reason = param2text(res);
+ errorf("%s:%d: '%s' %s", filename, lineno, option, reason);
+ }
+ err = res;
}
}
}
if(file != stdin)
curlx_fclose(file);
if(fileerror)
- rc = 1;
+ err = PARAM_READ_ERROR;
}
else
- rc = 1; /* could not open the file */
+ err = PARAM_READ_ERROR; /* could not open the file */
+
+ if((err == PARAM_READ_ERROR) && filename)
+ errorf("cannot read config from '%s'", filename);
free(pathalloc);
- return rc;
+ return err;
}
***************************************************************************/
#include "tool_setup.h"
-int parseconfig(const char *filename);
+/* only allow this many levels of recursive --config use */
+#define CONFIG_MAX_LEVELS 5
+ParameterError parseconfig(const char *filename, int max_recursive);
bool my_get_line(FILE *fp, struct dynbuf *db, bool *error);
#endif /* HEADER_CURL_TOOL_PARSECFG_H */
test745 test746 test747 test748 test749 test750 test751 test752 test753 \
test754 test755 test756 test757 test758 test759 test760 test761 test762 \
test763 test764 test765 test766 test767 test768 test769 test770 test771 \
-test772 test773 \
+test772 test773 test774 \
test780 test781 test782 test783 test784 test785 test786 test787 test788 \
test789 test790 test791 test792 test793 test794 test796 test797 \
\
<verify>
# the used option in the config file is too long
<errorcode>
-26
+2
</errorcode>
</verify>
</testcase>
# Verify data after the test has been "shot"
<verify>
<errorcode>
-26
+2
</errorcode>
</verify>
</testcase>
--- /dev/null
+<testcase>
+<info>
+<keywords>
+--config
+</keywords>
+</info>
+
+<client>
+<name>
+config file recursively including itself
+</name>
+<file name="%LOGDIR/cmd">
+--config %LOGDIR/cmd
+</file>
+<command>
+http://%HOSTIP:%HTTPPORT/ -K %LOGDIR/cmd
+</command>
+</client>
+
+<verify>
+<errorcode>
+2
+</errorcode>
+</verify>
+</testcase>